@f5xc-salesdemos/xcsh 19.18.7 → 19.19.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "type": "module",
3
3
  "name": "@f5xc-salesdemos/xcsh",
4
- "version": "19.18.7",
4
+ "version": "19.19.1",
5
5
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
6
6
  "homepage": "https://github.com/f5xc-salesdemos/xcsh",
7
7
  "author": "Can Boluk",
@@ -50,12 +50,12 @@
50
50
  "dependencies": {
51
51
  "@agentclientprotocol/sdk": "0.16.1",
52
52
  "@mozilla/readability": "^0.6",
53
- "@f5xc-salesdemos/xcsh-stats": "19.18.7",
54
- "@f5xc-salesdemos/pi-agent-core": "19.18.7",
55
- "@f5xc-salesdemos/pi-ai": "19.18.7",
56
- "@f5xc-salesdemos/pi-natives": "19.18.7",
57
- "@f5xc-salesdemos/pi-tui": "19.18.7",
58
- "@f5xc-salesdemos/pi-utils": "19.18.7",
53
+ "@f5xc-salesdemos/xcsh-stats": "19.19.1",
54
+ "@f5xc-salesdemos/pi-agent-core": "19.19.1",
55
+ "@f5xc-salesdemos/pi-ai": "19.19.1",
56
+ "@f5xc-salesdemos/pi-natives": "19.19.1",
57
+ "@f5xc-salesdemos/pi-tui": "19.19.1",
58
+ "@f5xc-salesdemos/pi-utils": "19.19.1",
59
59
  "@sinclair/typebox": "^0.34",
60
60
  "@xterm/headless": "^6.0",
61
61
  "ajv": "^8.20",
@@ -4,7 +4,7 @@
4
4
  import * as fs from "node:fs";
5
5
  import * as path from "node:path";
6
6
  import type { ImageContent } from "@f5xc-salesdemos/pi-ai";
7
- import { getProjectDir, isEnoent, readImageMetadata } from "@f5xc-salesdemos/pi-utils";
7
+ import { getProjectDir, isEnoent, readImageMetadata, t } from "@f5xc-salesdemos/pi-utils";
8
8
  import chalk from "chalk";
9
9
  import { resolveReadPath } from "../tools/path-utils";
10
10
  import { formatBytes } from "../tools/render-utils";
@@ -37,7 +37,7 @@ export async function processFileArguments(fileArgs: string[], options?: Process
37
37
 
38
38
  const stat = fs.statSync(absolutePath, { throwIfNoEntry: false });
39
39
  if (!stat) {
40
- console.error(chalk.red(`Error: File not found: ${absolutePath}`));
40
+ console.error(chalk.red(t("file.errors.notFound", { path: absolutePath })));
41
41
  process.exit(1);
42
42
  }
43
43
 
@@ -45,9 +45,7 @@ export async function processFileArguments(fileArgs: string[], options?: Process
45
45
  const mimeType = imageMetadata?.mimeType;
46
46
  const maxBytes = mimeType ? MAX_CLI_IMAGE_BYTES : MAX_CLI_TEXT_BYTES;
47
47
  if (stat.size > maxBytes) {
48
- console.error(
49
- chalk.yellow(`Warning: Skipping file contents (too large: ${formatBytes(stat.size)}): ${absolutePath}`),
50
- );
48
+ console.error(chalk.yellow(t("file.warnings.tooLarge", { size: formatBytes(stat.size), path: absolutePath })));
51
49
  text += `<file name="${absolutePath}">(skipped: too large, ${formatBytes(stat.size)})</file>\n`;
52
50
  continue;
53
51
  }
@@ -58,7 +56,7 @@ export async function processFileArguments(fileArgs: string[], options?: Process
58
56
  buffer = await Bun.file(absolutePath).bytes();
59
57
  } catch (err) {
60
58
  if (isEnoent(err)) {
61
- console.error(chalk.red(`Error: File not found: ${absolutePath}`));
59
+ console.error(chalk.red(t("file.errors.notFound", { path: absolutePath })));
62
60
  process.exit(1);
63
61
  }
64
62
  throw err;
@@ -113,7 +111,7 @@ export async function processFileArguments(fileArgs: string[], options?: Process
113
111
  text += `<file name="${absolutePath}">\n${content}\n</file>\n`;
114
112
  } catch (error: unknown) {
115
113
  const message = error instanceof Error ? error.message : String(error);
116
- console.error(chalk.red(`Error: Could not read file ${absolutePath}: ${message}`));
114
+ console.error(chalk.red(t("file.errors.readFailed", { path: absolutePath, message })));
117
115
  process.exit(1);
118
116
  }
119
117
  }
@@ -5,7 +5,7 @@
5
5
  */
6
6
  import * as path from "node:path";
7
7
  import { GrepOutputMode, grep } from "@f5xc-salesdemos/pi-natives";
8
- import { APP_NAME } from "@f5xc-salesdemos/pi-utils";
8
+ import { APP_NAME, t } from "@f5xc-salesdemos/pi-utils";
9
9
  import chalk from "chalk";
10
10
 
11
11
  export interface GrepCommandArgs {
@@ -69,7 +69,7 @@ export function parseGrepArgs(args: string[]): GrepCommandArgs | undefined {
69
69
 
70
70
  export async function runGrepCommand(cmd: GrepCommandArgs): Promise<void> {
71
71
  if (!cmd.pattern) {
72
- console.error(chalk.red("Error: Pattern is required"));
72
+ console.error(chalk.red(t("grep.errors.patternRequired")));
73
73
  process.exit(1);
74
74
  }
75
75
 
@@ -94,9 +94,9 @@ export async function runGrepCommand(cmd: GrepCommandArgs): Promise<void> {
94
94
  gitignore: cmd.gitignore,
95
95
  });
96
96
 
97
- console.log(chalk.green(`Total matches: ${result.totalMatches}`));
98
- console.log(chalk.green(`Files with matches: ${result.filesWithMatches}`));
99
- console.log(chalk.green(`Files searched: ${result.filesSearched}`));
97
+ console.log(chalk.green(t("grep.results.totalMatches", { count: result.totalMatches })));
98
+ console.log(chalk.green(t("grep.results.filesWithMatches", { count: result.filesWithMatches })));
99
+ console.log(chalk.green(t("grep.results.filesSearched", { count: result.filesSearched })));
100
100
  if (result.limitReached) {
101
101
  console.log(chalk.yellow(`Limit reached: true`));
102
102
  }
@@ -5,6 +5,7 @@
5
5
  * and delegates URL reads through the read tool pipeline.
6
6
  */
7
7
  import * as path from "node:path";
8
+ import { t } from "@f5xc-salesdemos/pi-utils";
8
9
  import chalk from "chalk";
9
10
  import { Settings } from "../config/settings";
10
11
  import { formatChunkedRead, resolveAnchorStyle } from "../edit/modes/chunk";
@@ -44,7 +45,7 @@ export async function runReadCommand(cmd: ReadCommandArgs): Promise<void> {
44
45
  const filePath = path.resolve(cmd.path);
45
46
  const file = Bun.file(filePath);
46
47
  if (!(await file.exists())) {
47
- console.error(chalk.red(`Error: File not found: ${cmd.path}`));
48
+ console.error(chalk.red(t("read.errors.fileNotFound", { path: cmd.path })));
48
49
  process.exit(1);
49
50
  }
50
51
 
@@ -4,7 +4,7 @@
4
4
  * Handles `xcsh ssh <command>` subcommands for SSH host configuration management.
5
5
  */
6
6
 
7
- import { getSSHConfigPath } from "@f5xc-salesdemos/pi-utils";
7
+ import { getSSHConfigPath, t } from "@f5xc-salesdemos/pi-utils";
8
8
  import chalk from "chalk";
9
9
  import { addSSHHost, readSSHConfigFile, removeSSHHost, type SSHHostConfig } from "../ssh/config-writer";
10
10
 
@@ -58,7 +58,7 @@ export async function runSSHCommand(cmd: SSHCommandArgs): Promise<void> {
58
58
  async function handleAdd(cmd: SSHCommandArgs): Promise<void> {
59
59
  const name = cmd.args[0];
60
60
  if (!name) {
61
- process.stdout.write(chalk.red("Error: Host name required\n"));
61
+ process.stdout.write(chalk.red(`${t("ssh.errors.hostRequired")}\n`));
62
62
  process.stdout.write(
63
63
  chalk.dim("Usage: xcsh ssh add <name> --host <address> [--user <user>] [--port <port>] [--key <path>]\n"),
64
64
  );
@@ -68,7 +68,7 @@ async function handleAdd(cmd: SSHCommandArgs): Promise<void> {
68
68
 
69
69
  const host = cmd.flags.host;
70
70
  if (!host) {
71
- process.stdout.write(chalk.red("Error: --host is required\n"));
71
+ process.stdout.write(chalk.red(`${t("ssh.errors.hostFlagRequired")}\n`));
72
72
  process.stdout.write(chalk.dim("Usage: xcsh ssh add <name> --host <address>\n"));
73
73
  process.exitCode = 1;
74
74
  return;
@@ -78,7 +78,7 @@ async function handleAdd(cmd: SSHCommandArgs): Promise<void> {
78
78
  if (cmd.flags.port !== undefined) {
79
79
  const port = Number.parseInt(cmd.flags.port, 10);
80
80
  if (Number.isNaN(port) || port < 1 || port > 65535) {
81
- process.stdout.write(chalk.red("Error: Port must be an integer between 1 and 65535\n"));
81
+ process.stdout.write(chalk.red(`${t("ssh.errors.invalidPort")}\n`));
82
82
  process.exitCode = 1;
83
83
  return;
84
84
  }
@@ -96,7 +96,7 @@ async function handleAdd(cmd: SSHCommandArgs): Promise<void> {
96
96
 
97
97
  try {
98
98
  await addSSHHost(filePath, name, hostConfig);
99
- process.stdout.write(chalk.green(`Added SSH host "${name}" to ${scope} config\n`));
99
+ process.stdout.write(chalk.green(`${t("ssh.status.hostAdded", { name, scope })}\n`));
100
100
  } catch (err) {
101
101
  process.stdout.write(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}\n`));
102
102
  process.exitCode = 1;
@@ -106,7 +106,7 @@ async function handleAdd(cmd: SSHCommandArgs): Promise<void> {
106
106
  async function handleRemove(cmd: SSHCommandArgs): Promise<void> {
107
107
  const name = cmd.args[0];
108
108
  if (!name) {
109
- process.stdout.write(chalk.red("Error: Host name required\n"));
109
+ process.stdout.write(chalk.red(`${t("ssh.errors.hostRequired")}\n`));
110
110
  process.stdout.write(chalk.dim("Usage: xcsh ssh remove <name> [--scope project|user]\n"));
111
111
  process.exitCode = 1;
112
112
  return;
@@ -117,7 +117,7 @@ async function handleRemove(cmd: SSHCommandArgs): Promise<void> {
117
117
 
118
118
  try {
119
119
  await removeSSHHost(filePath, name);
120
- process.stdout.write(chalk.green(`Removed SSH host "${name}" from ${scope} config\n`));
120
+ process.stdout.write(chalk.green(`${t("ssh.status.hostRemoved", { name, scope })}\n`));
121
121
  } catch (err) {
122
122
  process.stdout.write(chalk.red(`Error: ${err instanceof Error ? err.message : String(err)}\n`));
123
123
  process.exitCode = 1;
package/src/cli.ts CHANGED
@@ -1,10 +1,14 @@
1
1
  #!/usr/bin/env bun
2
- import { APP_NAME, MIN_BUN_VERSION, VERSION } from "@f5xc-salesdemos/pi-utils";
2
+ import { APP_NAME, initI18n, MIN_BUN_VERSION, registerLocales, t, VERSION } from "@f5xc-salesdemos/pi-utils";
3
3
  /**
4
4
  * CLI entry point — registers all commands explicitly and delegates to the
5
5
  * lightweight CLI runner from pi-utils.
6
6
  */
7
7
  import { type CommandEntry, run } from "@f5xc-salesdemos/pi-utils/cli";
8
+ import { locales } from "./locales/index";
9
+
10
+ registerLocales(locales);
11
+ initI18n();
8
12
 
9
13
  function parseSemver(version: string): [number, number, number] {
10
14
  function toint(value: string): number {
@@ -29,14 +33,14 @@ function isAtLeastBunVersion(minimum: string): boolean {
29
33
 
30
34
  if (typeof Bun.JSONL?.parseChunk !== "function" || !isAtLeastBunVersion(MIN_BUN_VERSION)) {
31
35
  process.stderr.write(
32
- `error: Bun runtime must be >= ${MIN_BUN_VERSION} (found v${Bun.version}). Please update Bun: bun upgrade\n`,
36
+ `${t("cli.errors.bunVersion", { minVersion: MIN_BUN_VERSION, currentVersion: Bun.version })}\n`,
33
37
  );
34
38
  process.exit(1);
35
39
  }
36
40
 
37
41
  // Detect known Bun errata that cause TUI crashes (e.g. Bun.stringWidth mishandling OSC sequences).
38
42
  if (Bun.stringWidth("\x1b[0m\x1b]8;;\x07") !== 0) {
39
- process.stderr.write(`error: Bun runtime errata detected (v${Bun.version}). Please update Bun: bun upgrade\n`);
43
+ process.stderr.write(`${t("cli.errors.bunErrata", { version: Bun.version })}\n`);
40
44
  process.exit(1);
41
45
  }
42
46
 
@@ -104,4 +108,7 @@ if (process.env.XCSH_SMOKE_TEST_SPECS === "1") {
104
108
  process.exit(domainCount > 0 && categoryCount > 0 ? 0 : 1);
105
109
  }
106
110
 
111
+ const { discoverAndApplyLanguage } = await import("./discovery/language");
112
+ await discoverAndApplyLanguage();
113
+
107
114
  await runCli(process.argv.slice(2));
@@ -0,0 +1,46 @@
1
+ import { logger as log, mapToSupportedLocale, setLocale } from "@f5xc-salesdemos/pi-utils";
2
+ import { PROFILE_COLLECTORS } from "../internal-urls/profile-collectors";
3
+ import { loadProfile, mergeProfile, saveProfile } from "../internal-urls/user-profile";
4
+
5
+ /**
6
+ * Discover the user's preferred language from the OS and user profile,
7
+ * then apply it to the i18n system.
8
+ *
9
+ * Runs after Settings.init() so the profile path is accessible.
10
+ * Skipped if XCSH_LOCALE is already set (env var takes precedence).
11
+ */
12
+ export async function discoverAndApplyLanguage(): Promise<void> {
13
+ if (process.env.XCSH_LOCALE) return;
14
+
15
+ const profile = await loadProfile();
16
+
17
+ if (!profile.knowsLanguage || profile.knowsLanguage.length === 0) {
18
+ for (const collector of PROFILE_COLLECTORS) {
19
+ if (collector.id !== "system") continue;
20
+ try {
21
+ const isAvailable = await collector.available();
22
+ if (!isAvailable) continue;
23
+ const partial = await collector.collect();
24
+ if (partial.knowsLanguage && partial.knowsLanguage.length > 0) {
25
+ mergeProfile(profile, partial);
26
+ if (!profile.sources) profile.sources = {};
27
+ (profile.sources as Record<string, string>).system = new Date().toISOString();
28
+ await saveProfile(profile);
29
+ log.debug(`Discovered OS languages: ${partial.knowsLanguage.join(", ")}`);
30
+ }
31
+ } catch {
32
+ // Language detection is best-effort
33
+ }
34
+ break;
35
+ }
36
+ }
37
+
38
+ if (!profile.knowsLanguage || profile.knowsLanguage.length === 0) return;
39
+
40
+ const primary = profile.knowsLanguage[0];
41
+ const supported = mapToSupportedLocale(primary);
42
+ if (supported) {
43
+ setLocale(supported);
44
+ log.debug(`Applied locale from user profile: ${primary} → ${supported}`);
45
+ }
46
+ }
@@ -17,17 +17,17 @@ export interface BuildInfo {
17
17
  }
18
18
 
19
19
  export const BUILD_INFO: BuildInfo = {
20
- "version": "19.18.7",
21
- "commit": "c8c863341021b40abcc64a146cbbb5a0547f3008",
22
- "shortCommit": "c8c8633",
20
+ "version": "19.19.1",
21
+ "commit": "1d8f572501dac4506ac9d354e9f03b4172a8d6c6",
22
+ "shortCommit": "1d8f572",
23
23
  "branch": "main",
24
- "tag": "v19.18.7",
25
- "commitDate": "2026-06-08T22:09:08Z",
26
- "buildDate": "2026-06-08T22:31:32.784Z",
24
+ "tag": "v19.19.1",
25
+ "commitDate": "2026-06-09T00:37:10Z",
26
+ "buildDate": "2026-06-09T01:07:22.031Z",
27
27
  "dirty": true,
28
28
  "prNumber": "",
29
29
  "repoUrl": "https://github.com/f5xc-salesdemos/xcsh",
30
30
  "repoSlug": "f5xc-salesdemos/xcsh",
31
- "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/c8c863341021b40abcc64a146cbbb5a0547f3008",
32
- "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.18.7"
31
+ "commitUrl": "https://github.com/f5xc-salesdemos/xcsh/commit/1d8f572501dac4506ac9d354e9f03b4172a8d6c6",
32
+ "releaseUrl": "https://github.com/f5xc-salesdemos/xcsh/releases/tag/v19.19.1"
33
33
  };
@@ -20,26 +20,53 @@ export interface ProfileCollector {
20
20
  // System (macOS)
21
21
  // ---------------------------------------------------------------------------
22
22
 
23
+ async function detectDarwinLanguages(): Promise<string[]> {
24
+ const proc = await $`defaults read NSGlobalDomain AppleLanguages`.quiet().nothrow();
25
+ if (proc.exitCode !== 0) return [];
26
+
27
+ const raw = proc.stdout.toString().trim();
28
+ const inner = raw.replace(/^\(\s*/, "").replace(/\s*\)$/, "");
29
+ return inner
30
+ .split(",")
31
+ .map(s => s.trim().replace(/^"/, "").replace(/"$/, ""))
32
+ .filter(s => s.length > 0);
33
+ }
34
+
35
+ function detectLinuxLanguages(): string[] {
36
+ const languages: string[] = [];
37
+
38
+ // $LANGUAGE is a colon-separated priority list (e.g., "fr:de:en")
39
+ const langList = process.env.LANGUAGE;
40
+ if (langList) {
41
+ for (const l of langList.split(":")) {
42
+ const trimmed = l.trim();
43
+ if (trimmed) languages.push(trimmed);
44
+ }
45
+ }
46
+
47
+ // Fall back to $LANG (e.g., "fr_FR.UTF-8")
48
+ if (languages.length === 0) {
49
+ const lang = process.env.LANG;
50
+ if (lang) {
51
+ const code = lang.split(".")[0];
52
+ if (code && code !== "C" && code !== "POSIX") languages.push(code.replace(/_/g, "-"));
53
+ }
54
+ }
55
+
56
+ return languages;
57
+ }
58
+
23
59
  const systemCollector: ProfileCollector = {
24
60
  id: "system",
25
61
  name: "System",
26
62
 
27
63
  async available(): Promise<boolean> {
28
- return process.platform === "darwin";
64
+ return process.platform === "darwin" || process.platform === "linux";
29
65
  },
30
66
 
31
67
  async collect(): Promise<Partial<UserProfile>> {
32
68
  try {
33
- const proc = await $`defaults read NSGlobalDomain AppleLanguages`.quiet().nothrow();
34
- if (proc.exitCode !== 0) return {};
35
-
36
- const raw = proc.stdout.toString().trim();
37
- // Plist array format: (\n "en-US",\n "fr-FR"\n)
38
- const inner = raw.replace(/^\(\s*/, "").replace(/\s*\)$/, "");
39
- const languages = inner
40
- .split(",")
41
- .map(s => s.trim().replace(/^"/, "").replace(/"$/, ""))
42
- .filter(s => s.length > 0);
69
+ const languages = process.platform === "darwin" ? await detectDarwinLanguages() : detectLinuxLanguages();
43
70
 
44
71
  if (languages.length === 0) return {};
45
72
  return { knowsLanguage: languages };
@@ -0,0 +1,70 @@
1
+ {
2
+ "cli.errors.bunVersion": "خطأ: يجب أن يكون إصدار Bun >= {minVersion} (تم العثور على v{currentVersion}). يرجى تحديث Bun: bun upgrade",
3
+ "cli.errors.bunErrata": "خطأ: تم اكتشاف أخطاء في إصدار Bun (v{version}). يرجى تحديث Bun: bun upgrade",
4
+ "agents.errors.bothFlags": "اختر إما --user أو --project، وليس كليهما.",
5
+ "agents.status.bundledCount": "الوكلاء المضمّنون: {total}",
6
+ "agents.status.targetDirectory": "الدليل الهدف: {dir}",
7
+ "agents.warnings.skippedExisting": "تم تخطي الموجود: {count} (استخدم --force للكتابة فوقه)",
8
+ "config.errors.unknownCommand": "أمر config غير معروف: {action}",
9
+ "config.errors.invalidBoolean": "قيمة منطقية غير صالحة: {value}. استخدم true/false أو yes/no أو on/off أو 1/0",
10
+ "config.errors.invalidNumber": "رقم غير صالح: {value}",
11
+ "config.errors.invalidEnumValue": "قيمة غير صالحة: {value}. القيم الصالحة: {validValues}",
12
+ "config.errors.invalidArrayJson": "JSON للمصفوفة غير صالح: {value}",
13
+ "config.errors.invalidRecordJson": "JSON للسجل غير صالح: {value}",
14
+ "config.help.listKeys": "شغّل '{appName} config list' لعرض المفاتيح المتاحة",
15
+ "config.errors.unknownSetting": "إعداد غير معروف: {key}",
16
+ "config.status.valueSet": "تم تعيين {path} = {value}",
17
+ "config.status.valueReset": "تمت إعادة تعيين {path} إلى {value}",
18
+ "file.errors.notFound": "خطأ: الملف غير موجود: {path}",
19
+ "file.warnings.tooLarge": "تحذير: تخطي محتويات الملف (كبير جداً: {size}): {path}",
20
+ "file.errors.readFailed": "خطأ: تعذّر قراءة الملف {path}: {message}",
21
+ "grep.errors.patternRequired": "خطأ: النمط مطلوب",
22
+ "grep.results.totalMatches": "إجمالي التطابقات: {count}",
23
+ "grep.results.filesWithMatches": "الملفات التي تحتوي على تطابقات: {count}",
24
+ "grep.results.filesSearched": "الملفات التي تم البحث فيها: {count}",
25
+ "read.errors.fileNotFound": "خطأ: الملف غير موجود: {path}",
26
+ "setup.errors.usage": "الاستخدام: {appName} setup <component>",
27
+ "setup.python.errors.notFound": "لم يتم العثور على Python",
28
+ "setup.python.help.installPython": "ثبّت Python 3.8+ وتأكد من وجوده في PATH",
29
+ "setup.python.status.ready": "تنفيذ Python جاهز",
30
+ "setup.python.warnings.missingPackages": "مفقود: {packages}",
31
+ "setup.python.errors.noPackageManager": "لم يتم العثور على مدير حزم",
32
+ "setup.python.help.installManagers": "ثبّت uv (موصى به) أو pip:",
33
+ "setup.python.errors.installationFailed": "فشل التثبيت",
34
+ "setup.python.help.manualInstall": "جرّب التثبيت يدوياً:",
35
+ "setup.python.errors.setupIncomplete": "الإعداد غير مكتمل",
36
+ "setup.stt.status.ready": "تحويل الكلام إلى نص جاهز",
37
+ "setup.stt.errors.pythonNotFound": "لم يتم العثور على Python",
38
+ "setup.stt.status.installingWhisper": "جارٍ تثبيت openai-whisper...",
39
+ "setup.stt.errors.whisperFailed": "فشل تثبيت openai-whisper",
40
+ "setup.stt.help.manualWhisper": "جرّب يدوياً: pip install openai-whisper",
41
+ "setup.help.title": "setup - تثبيت التبعيات للميزات الاختيارية",
42
+ "setup.help.pythonDescription": "تثبيت تبعيات Jupyter kernel لتنفيذ كود Python",
43
+ "setup.help.sttDescription": "تثبيت تبعيات تحويل الكلام إلى نص (openai-whisper، أدوات التسجيل)",
44
+ "setup.litellm.errors.envNotSet": "متغيرات البيئة المطلوبة غير مضبوطة:",
45
+ "setup.litellm.errors.baseUrlHint": "LITELLM_BASE_URL — رابط وكيل LiteLLM (مثال: https://your-proxy.example.com)",
46
+ "setup.litellm.errors.apiKeyHint": "LITELLM_API_KEY — مفتاح API لوكيل LiteLLM",
47
+ "setup.litellm.help.setEnvVars": "اضبط هذه المتغيرات في ملف إعدادات الصدفة (.zshrc، .bashrc) أو ملف .env.",
48
+ "setup.litellm.status.generated": "تم إنشاء إعداد LiteLLM",
49
+ "setup.litellm.errors.generationFailed": "فشل إنشاء إعداد LiteLLM",
50
+ "ssh.errors.hostRequired": "خطأ: اسم المضيف مطلوب",
51
+ "ssh.errors.hostFlagRequired": "خطأ: --host مطلوب",
52
+ "ssh.errors.invalidPort": "خطأ: يجب أن يكون المنفذ عدداً صحيحاً بين 1 و 65535",
53
+ "ssh.status.hostAdded": "تمت إضافة مضيف SSH \"{name}\" إلى إعداد {scope}",
54
+ "ssh.status.hostRemoved": "تمت إزالة مضيف SSH \"{name}\" من إعداد {scope}",
55
+ "mode.plan.status.enabled": "تم تفعيل وضع الخطة. ملف الخطة: {path}",
56
+ "mode.plan.status.paused": "تم إيقاف وضع الخطة مؤقتاً.",
57
+ "mode.plan.status.disabled": "تم تعطيل وضع الخطة.",
58
+ "mode.plan.errors.noEditor": "لم يتم تكوين أي محرر. عيّن متغير البيئة $VISUAL أو $EDITOR.",
59
+ "mode.plan.errors.fileNotFound": "ملف الخطة غير موجود في {path}",
60
+ "mode.plan.errors.editorOpenFailed": "فشل فتح المحرر الخارجي: {message}",
61
+ "mode.plan.status.updated": "تم تحديث الخطة في المحرر الخارجي.",
62
+ "mode.plan.errors.notActive": "وضع الخطة غير نشط.",
63
+ "mode.stt.warnings.disabled": "تحويل الكلام إلى نص معطّل. فعّله في الإعدادات: stt.enabled",
64
+ "mode.subagent.status.noActive": "لا توجد جلسات وكيل فرعي نشطة",
65
+ "ui.status.sessionCompacted": "تم ضغط الجلسة {times}",
66
+ "ui.status.messageQueued": "تمت إضافة الرسالة إلى قائمة الانتظار بعد الضغط",
67
+ "ui.errors.queuedMessageFailed": "فشل إرسال الرسالة المنتظرة: {message}",
68
+ "shell.errors.ttyRequired": "خطأ: تتطلب وحدة التحكم TTY تفاعلياً.",
69
+ "search.errors.queryRequired": "خطأ: الاستعلام مطلوب"
70
+ }
@@ -0,0 +1,70 @@
1
+ {
2
+ "cli.errors.bunVersion": "Fehler: Bun-Laufzeitumgebung muss >= {minVersion} sein (gefunden v{currentVersion}). Bitte Bun aktualisieren: bun upgrade",
3
+ "cli.errors.bunErrata": "Fehler: Bun-Laufzeitumgebung Errata erkannt (v{version}). Bitte Bun aktualisieren: bun upgrade",
4
+ "agents.errors.bothFlags": "Entweder --user oder --project angeben, nicht beides.",
5
+ "agents.status.bundledCount": "Mitgelieferte Agenten: {total}",
6
+ "agents.status.targetDirectory": "Zielverzeichnis: {dir}",
7
+ "agents.warnings.skippedExisting": "Vorhandene übersprungen: {count} (--force verwenden zum Überschreiben)",
8
+ "config.errors.unknownCommand": "Unbekannter config-Befehl: {action}",
9
+ "config.errors.invalidBoolean": "Ungültiger boolescher Wert: {value}. Verwende true/false, yes/no, on/off oder 1/0",
10
+ "config.errors.invalidNumber": "Ungültige Zahl: {value}",
11
+ "config.errors.invalidEnumValue": "Ungültiger Wert: {value}. Gültige Werte: {validValues}",
12
+ "config.errors.invalidArrayJson": "Ungültiges Array-JSON: {value}",
13
+ "config.errors.invalidRecordJson": "Ungültiges Objekt-JSON: {value}",
14
+ "config.help.listKeys": "'{appName} config list' ausführen, um verfügbare Schlüssel anzuzeigen",
15
+ "config.errors.unknownSetting": "Unbekannte Einstellung: {key}",
16
+ "config.status.valueSet": "{path} = {value} gesetzt",
17
+ "config.status.valueReset": "{path} auf {value} zurückgesetzt",
18
+ "file.errors.notFound": "Fehler: Datei nicht gefunden: {path}",
19
+ "file.warnings.tooLarge": "Warnung: Dateiinhalt wird übersprungen (zu groß: {size}): {path}",
20
+ "file.errors.readFailed": "Fehler: Datei {path} konnte nicht gelesen werden: {message}",
21
+ "grep.errors.patternRequired": "Fehler: Suchmuster ist erforderlich",
22
+ "grep.results.totalMatches": "Treffer gesamt: {count}",
23
+ "grep.results.filesWithMatches": "Dateien mit Treffern: {count}",
24
+ "grep.results.filesSearched": "Durchsuchte Dateien: {count}",
25
+ "read.errors.fileNotFound": "Fehler: Datei nicht gefunden: {path}",
26
+ "setup.errors.usage": "Verwendung: {appName} setup <Komponente>",
27
+ "setup.python.errors.notFound": "Python nicht gefunden",
28
+ "setup.python.help.installPython": "Python 3.8+ installieren und sicherstellen, dass es im PATH verfügbar ist",
29
+ "setup.python.status.ready": "Python-Ausführung ist bereit",
30
+ "setup.python.warnings.missingPackages": "Fehlend: {packages}",
31
+ "setup.python.errors.noPackageManager": "Kein Paketmanager gefunden",
32
+ "setup.python.help.installManagers": "uv (empfohlen) oder pip installieren:",
33
+ "setup.python.errors.installationFailed": "Installation fehlgeschlagen",
34
+ "setup.python.help.manualInstall": "Manuelle Installation versuchen:",
35
+ "setup.python.errors.setupIncomplete": "Einrichtung unvollständig",
36
+ "setup.stt.status.ready": "Sprache-zu-Text ist bereit",
37
+ "setup.stt.errors.pythonNotFound": "Python nicht gefunden",
38
+ "setup.stt.status.installingWhisper": "openai-whisper wird installiert...",
39
+ "setup.stt.errors.whisperFailed": "Installation von openai-whisper fehlgeschlagen",
40
+ "setup.stt.help.manualWhisper": "Manuell versuchen: pip install openai-whisper",
41
+ "setup.help.title": "setup - Abhängigkeiten für optionale Funktionen installieren",
42
+ "setup.help.pythonDescription": "Jupyter-Kernel-Abhängigkeiten für Python-Codeausführung installieren",
43
+ "setup.help.sttDescription": "Sprache-zu-Text-Abhängigkeiten installieren (openai-whisper, Aufnahme-Tools)",
44
+ "setup.litellm.errors.envNotSet": "Erforderliche Umgebungsvariablen nicht gesetzt:",
45
+ "setup.litellm.errors.baseUrlHint": "LITELLM_BASE_URL — LiteLLM-Proxy-URL (z. B. https://your-proxy.example.com)",
46
+ "setup.litellm.errors.apiKeyHint": "LITELLM_API_KEY — API-Schlüssel für den LiteLLM-Proxy",
47
+ "setup.litellm.help.setEnvVars": "Diese in Ihrem Shell-Profil (.zshrc, .bashrc) oder einer .env-Datei setzen.",
48
+ "setup.litellm.status.generated": "LiteLLM-Konfiguration generiert",
49
+ "setup.litellm.errors.generationFailed": "Generierung der LiteLLM-Konfiguration fehlgeschlagen",
50
+ "ssh.errors.hostRequired": "Fehler: Hostname erforderlich",
51
+ "ssh.errors.hostFlagRequired": "Fehler: --host ist erforderlich",
52
+ "ssh.errors.invalidPort": "Fehler: Port muss eine ganze Zahl zwischen 1 und 65535 sein",
53
+ "ssh.status.hostAdded": "SSH-Host \"{name}\" zur {scope}-Konfiguration hinzugefügt",
54
+ "ssh.status.hostRemoved": "SSH-Host \"{name}\" aus der {scope}-Konfiguration entfernt",
55
+ "mode.plan.status.enabled": "Plan-Modus aktiviert. Plandatei: {path}",
56
+ "mode.plan.status.paused": "Plan-Modus pausiert.",
57
+ "mode.plan.status.disabled": "Plan-Modus deaktiviert.",
58
+ "mode.plan.errors.noEditor": "Kein Editor konfiguriert. $VISUAL oder $EDITOR Umgebungsvariable setzen.",
59
+ "mode.plan.errors.fileNotFound": "Plandatei nicht gefunden unter {path}",
60
+ "mode.plan.errors.editorOpenFailed": "Externer Editor konnte nicht geöffnet werden: {message}",
61
+ "mode.plan.status.updated": "Plan im externen Editor aktualisiert.",
62
+ "mode.plan.errors.notActive": "Plan-Modus ist nicht aktiv.",
63
+ "mode.stt.warnings.disabled": "Sprache-zu-Text ist deaktiviert. In den Einstellungen aktivieren: stt.enabled",
64
+ "mode.subagent.status.noActive": "Keine aktiven Subagenten-Sitzungen",
65
+ "ui.status.sessionCompacted": "Sitzung {times} komprimiert",
66
+ "ui.status.messageQueued": "Nachricht für nach der Komprimierung in Warteschlange gestellt",
67
+ "ui.errors.queuedMessageFailed": "Senden der Nachricht aus der Warteschlange fehlgeschlagen: {message}",
68
+ "shell.errors.ttyRequired": "Fehler: Shell-Konsole erfordert ein interaktives TTY.",
69
+ "search.errors.queryRequired": "Fehler: Suchanfrage ist erforderlich"
70
+ }
@@ -0,0 +1,82 @@
1
+ {
2
+ "cli.errors.bunVersion": "error: Bun runtime must be >= {minVersion} (found v{currentVersion}). Please update Bun: bun upgrade",
3
+ "cli.errors.bunErrata": "error: Bun runtime errata detected (v{version}). Please update Bun: bun upgrade",
4
+
5
+ "agents.errors.bothFlags": "Choose either --user or --project, not both.",
6
+ "agents.status.bundledCount": "Bundled agents: {total}",
7
+ "agents.status.targetDirectory": "Target directory: {dir}",
8
+ "agents.warnings.skippedExisting": "Skipped existing: {count} (use --force to overwrite)",
9
+
10
+ "config.errors.unknownCommand": "Unknown config command: {action}",
11
+ "config.errors.invalidBoolean": "Invalid boolean value: {value}. Use true/false, yes/no, on/off, or 1/0",
12
+ "config.errors.invalidNumber": "Invalid number: {value}",
13
+ "config.errors.invalidEnumValue": "Invalid value: {value}. Valid values: {validValues}",
14
+ "config.errors.invalidArrayJson": "Invalid array JSON: {value}",
15
+ "config.errors.invalidRecordJson": "Invalid record JSON: {value}",
16
+ "config.help.listKeys": "Run '{appName} config list' to see available keys",
17
+ "config.errors.unknownSetting": "Unknown setting: {key}",
18
+ "config.status.valueSet": "Set {path} = {value}",
19
+ "config.status.valueReset": "Reset {path} to {value}",
20
+
21
+ "file.errors.notFound": "Error: File not found: {path}",
22
+ "file.warnings.tooLarge": "Warning: Skipping file contents (too large: {size}): {path}",
23
+ "file.errors.readFailed": "Error: Could not read file {path}: {message}",
24
+
25
+ "grep.errors.patternRequired": "Error: Pattern is required",
26
+ "grep.results.totalMatches": "Total matches: {count}",
27
+ "grep.results.filesWithMatches": "Files with matches: {count}",
28
+ "grep.results.filesSearched": "Files searched: {count}",
29
+
30
+ "read.errors.fileNotFound": "Error: File not found: {path}",
31
+
32
+ "setup.errors.usage": "Usage: {appName} setup <component>",
33
+ "setup.python.errors.notFound": "Python not found",
34
+ "setup.python.help.installPython": "Install Python 3.8+ and ensure it's in your PATH",
35
+ "setup.python.status.ready": "Python execution is ready",
36
+ "setup.python.warnings.missingPackages": "Missing: {packages}",
37
+ "setup.python.errors.noPackageManager": "No package manager found",
38
+ "setup.python.help.installManagers": "Install uv (recommended) or pip:",
39
+ "setup.python.errors.installationFailed": "Installation failed",
40
+ "setup.python.help.manualInstall": "Try installing manually:",
41
+ "setup.python.errors.setupIncomplete": "Setup incomplete",
42
+ "setup.stt.status.ready": "Speech-to-text is ready",
43
+ "setup.stt.errors.pythonNotFound": "Python not found",
44
+ "setup.stt.status.installingWhisper": "Installing openai-whisper...",
45
+ "setup.stt.errors.whisperFailed": "Failed to install openai-whisper",
46
+ "setup.stt.help.manualWhisper": "Try manually: pip install openai-whisper",
47
+ "setup.help.title": "setup - Install dependencies for optional features",
48
+ "setup.help.pythonDescription": "Install Jupyter kernel dependencies for Python code execution",
49
+ "setup.help.sttDescription": "Install speech-to-text dependencies (openai-whisper, recording tools)",
50
+ "setup.litellm.errors.envNotSet": "Required environment variables not set:",
51
+ "setup.litellm.errors.baseUrlHint": "LITELLM_BASE_URL — LiteLLM proxy URL (e.g. https://your-proxy.example.com)",
52
+ "setup.litellm.errors.apiKeyHint": "LITELLM_API_KEY — API key for the LiteLLM proxy",
53
+ "setup.litellm.help.setEnvVars": "Set these in your shell profile (.zshrc, .bashrc) or a .env file.",
54
+ "setup.litellm.status.generated": "LiteLLM configuration generated",
55
+ "setup.litellm.errors.generationFailed": "Failed to generate LiteLLM configuration",
56
+
57
+ "ssh.errors.hostRequired": "Error: Host name required",
58
+ "ssh.errors.hostFlagRequired": "Error: --host is required",
59
+ "ssh.errors.invalidPort": "Error: Port must be an integer between 1 and 65535",
60
+ "ssh.status.hostAdded": "Added SSH host \"{name}\" to {scope} config",
61
+ "ssh.status.hostRemoved": "Removed SSH host \"{name}\" from {scope} config",
62
+
63
+ "mode.plan.status.enabled": "Plan mode enabled. Plan file: {path}",
64
+ "mode.plan.status.paused": "Plan mode paused.",
65
+ "mode.plan.status.disabled": "Plan mode disabled.",
66
+ "mode.plan.errors.noEditor": "No editor configured. Set $VISUAL or $EDITOR environment variable.",
67
+ "mode.plan.errors.fileNotFound": "Plan file not found at {path}",
68
+ "mode.plan.errors.editorOpenFailed": "Failed to open external editor: {message}",
69
+ "mode.plan.status.updated": "Plan updated in external editor.",
70
+ "mode.plan.errors.notActive": "Plan mode is not active.",
71
+
72
+ "mode.stt.warnings.disabled": "Speech-to-text is disabled. Enable it in settings: stt.enabled",
73
+ "mode.subagent.status.noActive": "No active subagent sessions",
74
+
75
+ "ui.status.sessionCompacted": "Session compacted {times}",
76
+ "ui.status.messageQueued": "Queued message for after compaction",
77
+ "ui.errors.queuedMessageFailed": "Failed to send queued message: {message}",
78
+
79
+ "shell.errors.ttyRequired": "Error: shell console requires an interactive TTY.",
80
+
81
+ "search.errors.queryRequired": "Error: Query is required"
82
+ }