) => {
+ let value = messages[key] ?? key;
+ for (const [name, replacement] of Object.entries(params ?? {})) value = value.replace(`{${name}}`, replacement);
+ return value;
+ }) as ComposerTranslation;
+ const raw = "Invalid MCP configuration: MCP config file not found: C:\\Temp\\mcp.json";
+
+ const translated = translateBackendError(t, `[claudeCodeMcpConfigInvalid] ${raw}`);
+
+ assert.match(translated, /Claude MCP config could not be parsed/);
+ assert.match(translated, /Error code: claudeCodeMcpConfigInvalid/);
+ assert.match(translated, /Include this information in the report/);
+ assert.match(translated, /Diagnostic details:/);
+ assert.match(translated, /C:\\Temp\\mcp\.json/);
+});
+
+test("every current locale defines all Claude Code CLI diagnostic messages", () => {
+ const locales = { en, es, it, ja, ptBR, zhCN, zhTW } as const;
+
+ for (const [localeName, locale] of Object.entries(locales)) {
+ assert.equal(typeof locale.ai.requestFailed, "string", `${localeName}.ai.requestFailed`);
+ assert.equal(typeof locale.ai.cliErrors.code, "string", `${localeName}.ai.cliErrors.code`);
+ assert.equal(typeof locale.ai.cliErrors.details, "string", `${localeName}.ai.cliErrors.details`);
+ assert.equal(typeof locale.ai.cliErrors.reportHint, "string", `${localeName}.ai.cliErrors.reportHint`);
+ for (const code of errorCodes) {
+ assert.equal(typeof locale.ai.cliErrors[code], "string", `${localeName}.ai.cliErrors.${code}`);
+ assert.ok(locale.ai.cliErrors[code].trim().length > 0, `${localeName}.ai.cliErrors.${code} should not be empty`);
+ }
+ }
+});
diff --git a/packages/app-tests/aiMessageLayout.test.ts b/packages/app-tests/aiMessageLayout.test.ts
index a60a7aab3b..8e5251a3d4 100644
--- a/packages/app-tests/aiMessageLayout.test.ts
+++ b/packages/app-tests/aiMessageLayout.test.ts
@@ -15,6 +15,15 @@ function userMessageTemplate(): string {
return source.slice(start, end);
}
+function assistantMessageTemplate(): string {
+ const start = source.indexOf(``, start);
+
+ assert.notEqual(start, -1, "assistant message template should exist");
+ assert.notEqual(end, -1, "assistant message template should end before the message loop");
+ return source.slice(start, end);
+}
+
test("AI assistant template compiles", () => {
const { descriptor, errors } = parse(source, { filename: aiAssistantPath });
assert.deepEqual(errors, []);
@@ -42,3 +51,13 @@ test("user message edit action remains available by pointer and keyboard", () =>
assert.match(template, /:title="t\('ai\.editMessage'\)"[\s\S]*?@click="startEditMessage\(i\)"/);
assert.match(template, /v-if="!isGenerating"/);
});
+
+test("assistant messages wrap long paths and continuous error text inside the bubble", () => {
+ const template = assistantMessageTemplate();
+
+ assert.match(template, /max-w-\[95%\][^"\n]*\[overflow-wrap:anywhere\]/);
+});
+
+test("AI request failures use localized backend diagnostics", () => {
+ assert.match(source, /messages\.value\[assistantIdx\]\.content = `\$\{t\("ai\.requestFailed"\)\}\\n\\n\$\{translateBackendError\(t, message\)\}`/);
+});
diff --git a/src-tauri/src/commands/mcp.rs b/src-tauri/src/commands/mcp.rs
index 9d45423ce8..c364deb96e 100644
--- a/src-tauri/src/commands/mcp.rs
+++ b/src-tauri/src/commands/mcp.rs
@@ -261,7 +261,7 @@ fn resolve_managed_mcp_command(
fn require_managed_mcp_command(command: Option<(String, Vec)>) -> Result<(String, Vec), String> {
command.ok_or_else(|| {
format!(
- "DBX MCP Server is unavailable: no compatible Node.js ({}) installation containing {} was found. Install MCP Server from DBX settings and try again.",
+ "[dbxMcpMissing] No compatible Node.js ({}) installation containing {} was found.",
MCP_MIN_NODE_VERSION_REQUIREMENT, MCP_PACKAGE_NAME
)
})
@@ -1137,7 +1137,7 @@ mod tests {
assert!(error.contains(MCP_MIN_NODE_VERSION_REQUIREMENT));
assert!(error.contains(MCP_PACKAGE_NAME));
- assert!(error.contains("DBX settings"));
+ assert!(error.starts_with("[dbxMcpMissing]"));
}
#[test]