@keyou007/agent-bot 0.1.9 → 0.1.11

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.
Files changed (119) hide show
  1. package/CHANGELOG.md +23 -0
  2. package/README.md +22 -10
  3. package/README.zh.md +22 -10
  4. package/assets/agent-bot-logo.png +0 -0
  5. package/dist/acp/AcpSessionManager.js +78 -46
  6. package/dist/acp/AcpSessionManager.js.map +1 -1
  7. package/dist/cli/FeishuAppConfiguration.js +84 -22
  8. package/dist/cli/FeishuAppConfiguration.js.map +1 -1
  9. package/dist/cli/FeishuAppRegistration.js +12 -9
  10. package/dist/cli/FeishuAppRegistration.js.map +1 -1
  11. package/dist/cli/Initializer.js +7 -6
  12. package/dist/cli/Initializer.js.map +1 -1
  13. package/dist/cli/LocalControlClient.js +3 -2
  14. package/dist/cli/LocalControlClient.js.map +1 -1
  15. package/dist/cli/LocalControlServer.js +2 -1
  16. package/dist/cli/LocalControlServer.js.map +1 -1
  17. package/dist/cli/OptionalAuthorizationSkip.js +27 -6
  18. package/dist/cli/OptionalAuthorizationSkip.js.map +1 -1
  19. package/dist/cli/ServerStarter.js +12 -3
  20. package/dist/cli/ServerStarter.js.map +1 -1
  21. package/dist/cli/SkillRegistry.js +5 -4
  22. package/dist/cli/SkillRegistry.js.map +1 -1
  23. package/dist/cli/VerificationOutput.js +2 -1
  24. package/dist/cli/VerificationOutput.js.map +1 -1
  25. package/dist/cli/help.js +48 -1
  26. package/dist/cli/help.js.map +1 -1
  27. package/dist/cli/i18n.js +27 -0
  28. package/dist/cli/i18n.js.map +1 -0
  29. package/dist/cli/initOptions.js +5 -4
  30. package/dist/cli/initOptions.js.map +1 -1
  31. package/dist/cli/packageVersion.js +2 -1
  32. package/dist/cli/packageVersion.js.map +1 -1
  33. package/dist/cli/profile.js +4 -3
  34. package/dist/cli/profile.js.map +1 -1
  35. package/dist/cli/serverStatus.js +15 -14
  36. package/dist/cli/serverStatus.js.map +1 -1
  37. package/dist/cli/taskChatRoute.js +3 -2
  38. package/dist/cli/taskChatRoute.js.map +1 -1
  39. package/dist/cli.js +165 -107
  40. package/dist/cli.js.map +1 -1
  41. package/dist/codex/AppServerConnection.js +15 -1
  42. package/dist/codex/AppServerConnection.js.map +1 -1
  43. package/dist/codex/CodexLocalActivityDetector.js +4 -1
  44. package/dist/codex/CodexLocalActivityDetector.js.map +1 -1
  45. package/dist/codex/CodexProcessManager.js +1 -0
  46. package/dist/codex/CodexProcessManager.js.map +1 -1
  47. package/dist/codex/CodexRuntime.js +77 -2
  48. package/dist/codex/CodexRuntime.js.map +1 -1
  49. package/dist/commands/CommandRouter.js +108 -47
  50. package/dist/commands/CommandRouter.js.map +1 -1
  51. package/dist/console/ConsoleTurnPresenter.js +1 -1
  52. package/dist/console/ConsoleTurnPresenter.js.map +1 -1
  53. package/dist/feishu/CardRenderer.js +345 -11
  54. package/dist/feishu/CardRenderer.js.map +1 -1
  55. package/dist/feishu/FeishuMessageClient.js +51 -5
  56. package/dist/feishu/FeishuMessageClient.js.map +1 -1
  57. package/dist/feishu/FeishuTurnPresenter.js +8 -3
  58. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  59. package/dist/index.js +18 -17
  60. package/dist/index.js.map +1 -1
  61. package/dist/proxy/ProxySessionController.js +595 -205
  62. package/dist/proxy/ProxySessionController.js.map +1 -1
  63. package/dist/runtime/AcpRuntimeAdapter.js +1 -0
  64. package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
  65. package/dist/runtime/AgentRuntimeRegistry.js +7 -4
  66. package/dist/runtime/AgentRuntimeRegistry.js.map +1 -1
  67. package/dist/runtime/createAgentRuntimeRegistry.js +22 -0
  68. package/dist/runtime/createAgentRuntimeRegistry.js.map +1 -0
  69. package/dist/startup/SessionMetadataHydrator.js +2 -2
  70. package/dist/startup/SessionMetadataHydrator.js.map +1 -1
  71. package/dist/startup/StartupNotifier.js +1 -0
  72. package/dist/startup/StartupNotifier.js.map +1 -1
  73. package/dist/state/StateStore.js +21 -15
  74. package/dist/state/StateStore.js.map +1 -1
  75. package/dist/supervision/SafeRestartScheduler.js +5 -0
  76. package/dist/supervision/SafeRestartScheduler.js.map +1 -1
  77. package/docs/technical-reference.md +27 -6
  78. package/docs/technical-reference.zh.md +27 -6
  79. package/npm-shrinkwrap.json +2 -2
  80. package/package.json +2 -1
  81. package/skills/agent-bot/SKILL.md +19 -9
  82. package/src/acp/AcpSessionManager.ts +73 -54
  83. package/src/cli/FeishuAppConfiguration.ts +130 -18
  84. package/src/cli/FeishuAppRegistration.ts +24 -9
  85. package/src/cli/Initializer.ts +25 -6
  86. package/src/cli/LocalControlClient.ts +9 -2
  87. package/src/cli/LocalControlServer.ts +2 -1
  88. package/src/cli/OptionalAuthorizationSkip.ts +51 -6
  89. package/src/cli/ServerStarter.ts +20 -3
  90. package/src/cli/SkillRegistry.ts +17 -4
  91. package/src/cli/VerificationOutput.ts +4 -1
  92. package/src/cli/help.ts +50 -1
  93. package/src/cli/i18n.ts +38 -0
  94. package/src/cli/initOptions.ts +17 -4
  95. package/src/cli/packageVersion.ts +5 -1
  96. package/src/cli/profile.ts +13 -3
  97. package/src/cli/serverStatus.ts +19 -14
  98. package/src/cli/taskChatRoute.ts +9 -2
  99. package/src/cli.ts +290 -103
  100. package/src/codex/AppServerConnection.ts +21 -1
  101. package/src/codex/CodexLocalActivityDetector.ts +8 -1
  102. package/src/codex/CodexProcessManager.ts +1 -0
  103. package/src/codex/CodexRuntime.ts +91 -2
  104. package/src/commands/CommandRouter.ts +123 -46
  105. package/src/commands/commandTypes.ts +6 -11
  106. package/src/console/ConsoleTurnPresenter.ts +1 -1
  107. package/src/feishu/CardRenderer.ts +418 -11
  108. package/src/feishu/FeishuMessageClient.ts +66 -3
  109. package/src/feishu/FeishuTurnPresenter.ts +7 -2
  110. package/src/index.ts +21 -22
  111. package/src/proxy/ProxySessionController.ts +712 -208
  112. package/src/runtime/AcpRuntimeAdapter.ts +1 -0
  113. package/src/runtime/AgentRuntimeRegistry.ts +7 -6
  114. package/src/runtime/createAgentRuntimeRegistry.ts +25 -0
  115. package/src/runtime/types.ts +18 -0
  116. package/src/startup/SessionMetadataHydrator.ts +2 -2
  117. package/src/startup/StartupNotifier.ts +1 -0
  118. package/src/state/StateStore.ts +29 -15
  119. package/src/supervision/SafeRestartScheduler.ts +5 -0
package/dist/cli.js CHANGED
@@ -7,10 +7,11 @@ import { sendControlRequest, isServerReachable } from "./cli/LocalControlClient.
7
7
  import { controlEndpoint, } from "./cli/controlProtocol.js";
8
8
  import { acquireInitializationLock, cleanupFeishuCredentialTemporaryFiles, initializeAgentBot, readFeishuCredentials, shouldCreateFeishuApp, writeFeishuCredentials, } from "./cli/Initializer.js";
9
9
  import { parseInitCommandOptions } from "./cli/initOptions.js";
10
- import { listenForOptionalAuthorizationSkip, } from "./cli/OptionalAuthorizationSkip.js";
10
+ import { listenForManualPermissionSkip, listenForOptionalAuthorizationSkip, } from "./cli/OptionalAuthorizationSkip.js";
11
11
  import { registerFeishuApp, } from "./cli/FeishuAppRegistration.js";
12
12
  import { ensureFeishuAppConfiguration, } from "./cli/FeishuAppConfiguration.js";
13
13
  import { renderCliHelp } from "./cli/help.js";
14
+ import { cliLanguage, cliText, localizeCliErrorMessage } from "./cli/i18n.js";
14
15
  import { formatServerStatus, withConfiguredFeishuAppId } from "./cli/serverStatus.js";
15
16
  import { resolveSystemSkillsRoot, SkillRegistry } from "./cli/SkillRegistry.js";
16
17
  import { readPackageVersion } from "./cli/packageVersion.js";
@@ -23,7 +24,8 @@ import { nodeDiagnosticReportArguments, prepareCrashReportDirectory, resolveSupe
23
24
  import { agentBotHome, defaultSqlitePath } from "./config/paths.js";
24
25
  const args = process.argv.slice(2);
25
26
  void main(args).catch((error) => {
26
- process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}\n`);
27
+ const message = error instanceof Error ? error.message : String(error);
28
+ process.stderr.write(`${cliText("Error: ", "错误:")}${localizeCliErrorMessage(message)}\n`);
27
29
  process.exitCode = 1;
28
30
  });
29
31
  async function main(input) {
@@ -61,7 +63,7 @@ async function main(input) {
61
63
  skillsCommand(rest);
62
64
  return;
63
65
  }
64
- throw new Error(`Unknown command: ${command}. Run agent-bot --help for usage.`);
66
+ throw new Error(cliText(`Unknown command: ${command}. Run agent-bot --help for usage.`, `未知命令:${command}。运行 agent-bot --help 查看用法。`));
65
67
  }
66
68
  async function initCommand(input, configPath, explicitProfile) {
67
69
  const options = parseInitCommandOptions(input, explicitProfile);
@@ -86,8 +88,9 @@ async function initCommand(input, configPath, explicitProfile) {
86
88
  }
87
89
  if (!options.json)
88
90
  printInitializationResult(initialized);
89
- if (!options.json && !options.skipFeishu)
90
- process.stdout.write("\nStarting Agent Bot server...\n");
91
+ if (!options.json && !options.skipFeishu) {
92
+ process.stdout.write(cliText("\nStarting Agent Bot server...\n", "\n正在启动 Agent Bot 服务...\n"));
93
+ }
91
94
  const server = await startInitializedServer({ skipFeishu: options.skipFeishu, configPath });
92
95
  const result = { ...initialized, server };
93
96
  if (options.json)
@@ -104,7 +107,7 @@ async function initializeFeishu(paths, options) {
104
107
  };
105
108
  }
106
109
  const controller = new AbortController();
107
- const onInterrupt = () => controller.abort(new Error("Initialization was cancelled."));
110
+ const onInterrupt = () => controller.abort(new Error(cliText("Initialization was cancelled.", "初始化已取消。")));
108
111
  process.once("SIGINT", onInterrupt);
109
112
  process.once("SIGTERM", onInterrupt);
110
113
  try {
@@ -120,7 +123,7 @@ async function initializeFeishu(paths, options) {
120
123
  }
121
124
  else {
122
125
  if (existing.status === "incomplete" && !options.json) {
123
- process.stdout.write("\nIncomplete Lark credentials were found. A new bot will be created.\n");
126
+ process.stdout.write(cliText("\nIncomplete Lark credentials were found. A new bot will be created.\n", "\n发现不完整的飞书凭据,将创建一个新机器人。\n"));
124
127
  }
125
128
  credentials = await registerFeishuApp({
126
129
  signal: controller.signal,
@@ -129,16 +132,24 @@ async function initializeFeishu(paths, options) {
129
132
  writeFeishuCredentials(paths.env.path, credentials);
130
133
  status = "created";
131
134
  }
132
- if (!options.json)
133
- process.stdout.write("\nChecking Lark app permissions, events, and callbacks...\n");
135
+ if (!options.json) {
136
+ process.stdout.write(cliText("\nChecking Lark app permissions, events, and callbacks...\n", "\n正在检查飞书应用权限、事件和回调...\n"));
137
+ }
138
+ const manualPermissionSkip = new AbortController();
134
139
  const optionalSkip = new AbortController();
135
140
  let skipListener;
136
141
  const configuration = await ensureFeishuAppConfiguration(credentials, {
137
142
  signal: controller.signal,
143
+ manualPermissionSkipSignal: manualPermissionSkip.signal,
138
144
  optionalSkipSignal: optionalSkip.signal,
139
145
  onVerification: (challenge) => {
140
146
  printFeishuConfigurationVerification(challenge, options.json);
141
- if (!challenge.blocking) {
147
+ if (challenge.kind === "manual_scope" && challenge.blocking) {
148
+ skipListener?.close();
149
+ skipListener = listenForManualPermissionSkip(() => manualPermissionSkip.abort());
150
+ }
151
+ else if (!challenge.blocking) {
152
+ skipListener?.close();
142
153
  skipListener = listenForOptionalAuthorizationSkip(() => optionalSkip.abort());
143
154
  }
144
155
  },
@@ -167,7 +178,7 @@ async function assertResetProfileServerStopped(configPath) {
167
178
  }
168
179
  for (const endpoint of endpoints) {
169
180
  if (await isServerReachable(endpoint)) {
170
- throw new Error("Cannot reset a running profile. Stop it with agent-bot --profile <directory> server stop, then try again.");
181
+ throw new Error(cliText("Cannot reset a running profile. Stop it with agent-bot --profile <directory> server stop, then try again.", "无法重置正在运行的 Profile。请先执行 agent-bot --profile <目录> server stop,然后重试。"));
171
182
  }
172
183
  }
173
184
  }
@@ -183,8 +194,8 @@ function skillsCommand(input) {
183
194
  printJson(result);
184
195
  else
185
196
  process.stdout.write(result.updated
186
- ? `Installed the Agent Bot Skill: ${result.status.targetPath}\n`
187
- : `The Agent Bot Skill is already up to date: ${result.status.targetPath}\n`);
197
+ ? cliText(`Installed the Agent Bot Skill: ${result.status.targetPath}\n`, `已安装 Agent Bot Skill:${result.status.targetPath}\n`)
198
+ : cliText(`The Agent Bot Skill is already up to date: ${result.status.targetPath}\n`, `Agent Bot Skill 已是最新版本:${result.status.targetPath}\n`));
188
199
  return;
189
200
  }
190
201
  if (action === "uninstall" || action === "unregister") {
@@ -193,8 +204,8 @@ function skillsCommand(input) {
193
204
  printJson({ removed, targetPath: registry.targetPath });
194
205
  else
195
206
  process.stdout.write(removed
196
- ? `Uninstalled the Agent Bot Skill: ${registry.targetPath}\n`
197
- : `The Agent Bot Skill is not installed: ${registry.targetPath}\n`);
207
+ ? cliText(`Uninstalled the Agent Bot Skill: ${registry.targetPath}\n`, `已卸载 Agent Bot Skill:${registry.targetPath}\n`)
208
+ : cliText(`The Agent Bot Skill is not installed: ${registry.targetPath}\n`, `Agent Bot Skill 尚未安装:${registry.targetPath}\n`));
198
209
  return;
199
210
  }
200
211
  if (action === "status") {
@@ -210,20 +221,20 @@ function skillsCommand(input) {
210
221
  if (json)
211
222
  printJson(paths);
212
223
  else {
213
- process.stdout.write(`Built-in Skill: ${paths.sourcePath}\n`);
214
- process.stdout.write(`System Skills directory: ${paths.skillsRoot}\n`);
215
- process.stdout.write(`Installation path: ${paths.targetPath}\n`);
224
+ process.stdout.write(`${cliText("Built-in Skill: ", "内置 Skill:")}${paths.sourcePath}\n`);
225
+ process.stdout.write(`${cliText("System Skills directory: ", "系统 Skills 目录:")}${paths.skillsRoot}\n`);
226
+ process.stdout.write(`${cliText("Installation path: ", "安装路径:")}${paths.targetPath}\n`);
216
227
  }
217
228
  return;
218
229
  }
219
- throw new Error(`Unknown skills command: ${action}`);
230
+ throw new Error(cliText(`Unknown skills command: ${action}`, `未知的 skills 命令:${action}`));
220
231
  }
221
232
  async function consoleCommand(input) {
222
233
  const config = loadConfig();
223
234
  const endpoint = controlEndpoint(config.storage.sqlitePath);
224
235
  const force = input.includes("--force");
225
236
  if (!force && await isServerReachable(endpoint)) {
226
- throw new Error("The Agent Bot server is running. Stop it first to avoid concurrent task-state access, or explicitly use --force.");
237
+ throw new Error(cliText("The Agent Bot server is running. Stop it first to avoid concurrent task-state access, or explicitly use --force.", "Agent Bot 服务正在运行。请先停止服务以避免并发访问任务状态,或显式使用 --force。"));
227
238
  }
228
239
  const entry = fileURLToPath(new URL("./index.js", import.meta.url));
229
240
  const reportDirectory = resolveSupervisorDiagnosticsPaths(config).crashReportDirectory;
@@ -274,7 +285,7 @@ async function serverCommand(input) {
274
285
  }
275
286
  if (action === "stop") {
276
287
  ensureOk(await sendControlRequest(endpoint, { action: "server_stop" }));
277
- process.stdout.write("Agent Bot server stop requested.\n");
288
+ process.stdout.write(cliText("Agent Bot server stop requested.\n", "已请求停止 Agent Bot 服务。\n"));
278
289
  return;
279
290
  }
280
291
  if (action === "restart") {
@@ -286,10 +297,12 @@ async function serverCommand(input) {
286
297
  mode: immediate ? "immediate" : "safe",
287
298
  reason,
288
299
  }));
289
- process.stdout.write(immediate ? "Immediate restart requested.\n" : "Safe restart requested.\n");
300
+ process.stdout.write(immediate
301
+ ? cliText("Immediate restart requested.\n", "已请求立即重启。\n")
302
+ : cliText("Safe restart requested.\n", "已请求安全重启。\n"));
290
303
  return;
291
304
  }
292
- throw new Error(`Unknown server command: ${action}`);
305
+ throw new Error(cliText(`Unknown server command: ${action}`, `未知的 server 命令:${action}`));
293
306
  }
294
307
  async function taskCommand(input) {
295
308
  const [action = "list", ...rest] = input;
@@ -300,10 +313,10 @@ async function taskCommand(input) {
300
313
  if (action === "prompt" || action === "send") {
301
314
  const [reference, ...promptParts] = rest;
302
315
  if (!reference)
303
- throw new Error(`task ${action} requires a task number or task ID.`);
316
+ throw new Error(cliText(`task ${action} requires a task number or task ID.`, `task ${action} 需要任务序号或任务 ID。`));
304
317
  const text = promptParts.join(" ").trim();
305
318
  if (!text)
306
- throw new Error(`task ${action} requires a Prompt.`);
319
+ throw new Error(cliText(`task ${action} requires a Prompt.`, `task ${action} 需要提示词。`));
307
320
  const session = resolveTask(allSessions, reference);
308
321
  const endpoint = controlEndpoint(config.storage.sqlitePath);
309
322
  ensureOk(await sendControlRequest(endpoint, {
@@ -311,7 +324,7 @@ async function taskCommand(input) {
311
324
  localSessionId: session.localSessionId,
312
325
  text,
313
326
  }, 60_000));
314
- process.stdout.write("Prompt submitted.\n");
327
+ process.stdout.write(cliText("Prompt submitted.\n", "提示词已提交。\n"));
315
328
  return;
316
329
  }
317
330
  const sessions = filterSessions(allSessions, rest);
@@ -324,7 +337,7 @@ async function taskCommand(input) {
324
337
  }
325
338
  const reference = rest.find((value) => !value.startsWith("--"));
326
339
  if (!reference)
327
- throw new Error(`task ${action} requires a task number or task ID.`);
340
+ throw new Error(cliText(`task ${action} requires a task number or task ID.`, `task ${action} 需要任务序号或任务 ID。`));
328
341
  const session = resolveTask(sessions, reference);
329
342
  if (action === "chat") {
330
343
  const route = taskChatRoute(session);
@@ -365,7 +378,7 @@ async function taskCommand(input) {
365
378
  const endpoint = controlEndpoint(config.storage.sqlitePath);
366
379
  if (action === "stop") {
367
380
  ensureOk(await sendControlRequest(endpoint, { action: "task_stop", localSessionId: session.localSessionId }));
368
- process.stdout.write("Task stop requested.\n");
381
+ process.stdout.write(cliText("Task stop requested.\n", "已请求停止任务。\n"));
369
382
  return;
370
383
  }
371
384
  if (action === "title") {
@@ -374,16 +387,16 @@ async function taskCommand(input) {
374
387
  const optionIndex = titleArgs.findIndex((value) => value.startsWith("--"));
375
388
  const title = titleArgs.slice(0, optionIndex < 0 ? undefined : optionIndex).join(" ").trim();
376
389
  if (!title)
377
- throw new Error("task title requires a new title.");
390
+ throw new Error(cliText("task title requires a new title.", "task title 需要新标题。"));
378
391
  ensureOk(await sendControlRequest(endpoint, {
379
392
  action: "task_title",
380
393
  localSessionId: session.localSessionId,
381
394
  title,
382
395
  }));
383
- process.stdout.write("Task title updated.\n");
396
+ process.stdout.write(cliText("Task title updated.\n", "任务标题已更新。\n"));
384
397
  return;
385
398
  }
386
- throw new Error(`Unknown task command: ${action}`);
399
+ throw new Error(cliText(`Unknown task command: ${action}`, `未知的 task 命令:${action}`));
387
400
  }
388
401
  finally {
389
402
  store.close();
@@ -400,7 +413,7 @@ function resolveTask(sessions, reference) {
400
413
  const index = Number(reference) - 1;
401
414
  const session = sessions[index];
402
415
  if (!session)
403
- throw new Error(`Task number is out of range: ${reference}`);
416
+ throw new Error(cliText(`Task number is out of range: ${reference}`, `任务序号超出范围:${reference}`));
404
417
  return session;
405
418
  }
406
419
  const exact = sessions.find((session) => session.localSessionId === reference || session.remoteSessionId === reference || session.acpSessionId === reference);
@@ -412,197 +425,242 @@ function resolveTask(sessions, reference) {
412
425
  if (matches.length === 1)
413
426
  return matches[0];
414
427
  if (matches.length > 1)
415
- throw new Error(`Task ID prefix is ambiguous: ${reference}`);
416
- throw new Error(`Task not found: ${reference}`);
428
+ throw new Error(cliText(`Task ID prefix is ambiguous: ${reference}`, `任务 ID 前缀不唯一:${reference}`));
429
+ throw new Error(cliText(`Task not found: ${reference}`, `未找到任务:${reference}`));
417
430
  }
418
431
  function printTaskList(sessions) {
419
432
  if (sessions.length === 0) {
420
- process.stdout.write("No tasks.\n");
433
+ process.stdout.write(cliText("No tasks.\n", "没有任务。\n"));
421
434
  return;
422
435
  }
423
436
  for (const [index, session] of sessions.entries()) {
424
437
  const id = session.remoteSessionId ?? session.acpSessionId ?? session.localSessionId;
425
- process.stdout.write(`${index + 1}. [${session.status}/${session.lastTurnStatus ?? "-"}] ${session.title ?? "Untitled task"}\n`);
438
+ process.stdout.write(`${index + 1}. [${taskStateLabel(session.status)}/${taskStateLabel(session.lastTurnStatus)}] ${session.title ?? cliText("Untitled task", "未命名任务")}\n`);
426
439
  process.stdout.write(` ${id} · ${session.contextKey} · ${session.updatedAt}\n`);
427
440
  }
428
441
  }
429
442
  function printTaskStatus(session, snapshot, remote) {
430
- process.stdout.write(`Title: ${session.title ?? "Untitled task"}\n`);
431
- process.stdout.write(`Task ID: ${session.remoteSessionId ?? session.acpSessionId ?? session.localSessionId}\n`);
432
- process.stdout.write(`Local ID: ${session.localSessionId}\n`);
433
- process.stdout.write(`Context: ${session.contextKey}\n`);
434
- process.stdout.write(`Status: ${session.status} / ${session.lastTurnStatus ?? "-"}\n`);
435
- process.stdout.write(`Directory: ${session.cwd}\n`);
436
- process.stdout.write(`Last turn: ${session.lastTurnId ?? "-"}\n`);
443
+ process.stdout.write(`${cliText("Title: ", "标题:")}${session.title ?? cliText("Untitled task", "未命名任务")}\n`);
444
+ process.stdout.write(`${cliText("Task ID: ", "任务 ID:")}${session.remoteSessionId ?? session.acpSessionId ?? session.localSessionId}\n`);
445
+ process.stdout.write(`${cliText("Local ID: ", "本地 ID:")}${session.localSessionId}\n`);
446
+ process.stdout.write(`${cliText("Context: ", "上下文:")}${session.contextKey}\n`);
447
+ process.stdout.write(`${cliText("Status: ", "状态:")}${taskStateLabel(session.status)} / ${taskStateLabel(session.lastTurnStatus)}\n`);
448
+ process.stdout.write(`${cliText("Directory: ", "目录:")}${session.cwd}\n`);
449
+ process.stdout.write(`${cliText("Last turn: ", "上一轮:")}${session.lastTurnId ?? "-"}\n`);
437
450
  let displayedFinalResponse;
438
451
  if (snapshot && typeof snapshot === "object") {
439
452
  const state = snapshot;
440
- if (typeof state.durationMs === "number")
441
- process.stdout.write(`Duration: ${Math.round(state.durationMs / 1_000)}s\n`);
442
- if (typeof state.totalTokens === "number")
443
- process.stdout.write(`Tokens:${state.totalTokens}\n`);
444
- if (typeof state.totalToolCount === "number")
445
- process.stdout.write(`Tool calls: ${state.totalToolCount}\n`);
453
+ if (typeof state.durationMs === "number") {
454
+ process.stdout.write(`${cliText("Duration: ", "耗时:")}${Math.round(state.durationMs / 1_000)}s\n`);
455
+ }
456
+ if (typeof state.totalTokens === "number") {
457
+ process.stdout.write(`${cliText("Tokens: ", "Tokens:")}${state.totalTokens}\n`);
458
+ }
459
+ if (typeof state.totalToolCount === "number") {
460
+ process.stdout.write(`${cliText("Tool calls: ", "工具调用:")}${state.totalToolCount}\n`);
461
+ }
446
462
  if (typeof state.finalResponse === "string" && state.finalResponse.trim())
447
463
  displayedFinalResponse = state.finalResponse.trim();
448
464
  }
449
- if (!snapshot && remote?.lastTurnToolCount !== undefined)
450
- process.stdout.write(`Tool calls: ${remote.lastTurnToolCount}\n`);
465
+ if (!snapshot && remote?.lastTurnToolCount !== undefined) {
466
+ process.stdout.write(`${cliText("Tool calls: ", "工具调用:")}${remote.lastTurnToolCount}\n`);
467
+ }
451
468
  displayedFinalResponse = remote?.finalResponse?.trim() || displayedFinalResponse;
452
- if (displayedFinalResponse)
453
- process.stdout.write(`Final response:\n${displayedFinalResponse}\n`);
469
+ if (displayedFinalResponse) {
470
+ process.stdout.write(`${cliText("Final response:\n", "最终回答:\n")}${displayedFinalResponse}\n`);
471
+ }
454
472
  }
455
473
  function printSkillStatus(status) {
456
- process.stdout.write(`Agent Bot Skill: ${status.registered ? "installed" : "not installed"}\n`);
457
- process.stdout.write(`System directory: ${status.skillsRoot}\n`);
458
- process.stdout.write(`Installation path: ${status.targetPath}\n`);
474
+ process.stdout.write(`${cliText("Agent Bot Skill: ", "Agent Bot Skill:")}${status.registered ? cliText("installed", "已安装") : cliText("not installed", "未安装")}\n`);
475
+ process.stdout.write(`${cliText("System directory: ", "系统目录:")}${status.skillsRoot}\n`);
476
+ process.stdout.write(`${cliText("Installation path: ", "安装路径:")}${status.targetPath}\n`);
459
477
  if (status.registered) {
460
- process.stdout.write(`Ownership: ${status.managed ? "managed by Agent Bot" : "external directory (will not be modified or removed)"}\n`);
461
- process.stdout.write(`Version: ${status.upToDate ? "up to date" : "update required"}\n`);
478
+ process.stdout.write(`${cliText("Ownership: ", "所有权:")}${status.managed
479
+ ? cliText("managed by Agent Bot", "由 Agent Bot 管理")
480
+ : cliText("external directory (will not be modified or removed)", "外部目录(不会修改或删除)")}\n`);
481
+ process.stdout.write(`${cliText("Version: ", "版本:")}${status.upToDate
482
+ ? cliText("up to date", "已是最新")
483
+ : cliText("update required", "需要更新")}\n`);
462
484
  }
463
485
  }
464
486
  function printInitializationPaths(result) {
465
- process.stdout.write("Preparing the Agent Bot user environment...\n");
487
+ process.stdout.write(cliText("Preparing the Agent Bot user environment...\n", "正在准备 Agent Bot 用户环境...\n"));
466
488
  if (result.reset) {
467
- process.stdout.write(`Reset backup: ${result.reset.backupPath}\n`);
489
+ process.stdout.write(`${cliText("Reset backup: ", "重置备份:")}${result.reset.backupPath}\n`);
468
490
  }
469
- process.stdout.write(`Home directory: ${result.home.path} (${initializationStatusLabel(result.home.status)})\n`);
470
- process.stdout.write(`Config file: ${result.config.path} (${initializationStatusLabel(result.config.status)})\n`);
471
- process.stdout.write(`Environment file: ${result.env.path} (${initializationStatusLabel(result.env.status)})\n`);
472
- process.stdout.write(`Data directory: ${result.data.path} (${initializationStatusLabel(result.data.status)})\n`);
473
- process.stdout.write(`Log directory: ${result.logs.path} (${initializationStatusLabel(result.logs.status)})\n`);
491
+ process.stdout.write(`${cliText("Home directory: ", "主目录:")}${result.home.path} (${initializationStatusLabel(result.home.status)})\n`);
492
+ process.stdout.write(`${cliText("Config file: ", "配置文件:")}${result.config.path} (${initializationStatusLabel(result.config.status)})\n`);
493
+ process.stdout.write(`${cliText("Environment file: ", "环境文件:")}${result.env.path} (${initializationStatusLabel(result.env.status)})\n`);
494
+ process.stdout.write(`${cliText("Data directory: ", "数据目录:")}${result.data.path} (${initializationStatusLabel(result.data.status)})\n`);
495
+ process.stdout.write(`${cliText("Log directory: ", "日志目录:")}${result.logs.path} (${initializationStatusLabel(result.logs.status)})\n`);
474
496
  }
475
497
  function printInitializationResult(result) {
476
- process.stdout.write("\nAgent Bot initialization completed.\n");
498
+ process.stdout.write(cliText("\nAgent Bot initialization completed.\n", "\nAgent Bot 初始化完成。\n"));
477
499
  if (result.feishu.status === "created") {
478
- process.stdout.write(`Lark app: created and credentials saved (${result.feishu.appId})\n`);
500
+ process.stdout.write(cliText(`Lark app: created and credentials saved (${result.feishu.appId})\n`, `飞书应用:已创建并保存凭据 (${result.feishu.appId})\n`));
479
501
  }
480
502
  else if (result.feishu.status === "existing") {
481
- process.stdout.write(`Lark app: already configured and unchanged (${result.feishu.appId})\n`);
503
+ process.stdout.write(cliText(`Lark app: already configured and unchanged (${result.feishu.appId})\n`, `飞书应用:已配置,未做修改 (${result.feishu.appId})\n`));
482
504
  }
483
505
  else {
484
- process.stdout.write("Lark app: skipped; use Console mode or run init again later.\n");
506
+ process.stdout.write(cliText("Lark app: skipped; use Console mode or run init again later.\n", "飞书应用:已跳过;请使用 Console 模式或稍后重新运行 init。\n"));
485
507
  }
486
508
  if (result.feishu.configuration?.status === "updated") {
487
509
  const added = result.feishu.configuration.added;
488
- process.stdout.write(`Lark configuration: added ${added.scopes.length} scopes, ${added.events.length} events, and ${added.callbacks.length} callbacks\n`);
510
+ process.stdout.write(cliText(`Lark configuration: added ${added.scopes.length} scopes, ${added.events.length} events, and ${added.callbacks.length} callbacks\n`, `飞书配置:已新增 ${added.scopes.length} 项权限、${added.events.length} 个事件和 ${added.callbacks.length} 个回调\n`));
489
511
  }
490
512
  else if (result.feishu.configuration?.status === "partial") {
491
513
  const configuration = result.feishu.configuration;
492
514
  const addedCount = configuration.added.scopes.length + configuration.added.events.length + configuration.added.callbacks.length;
493
515
  if (addedCount > 0) {
494
- process.stdout.write(`Lark configuration: core capabilities are ready; added ${configuration.added.scopes.length} scopes, ${configuration.added.events.length} events, and ${configuration.added.callbacks.length} callbacks\n`);
516
+ process.stdout.write(cliText(`Lark configuration: initialization continued with missing configuration; added ${configuration.added.scopes.length} scopes, ${configuration.added.events.length} events, and ${configuration.added.callbacks.length} callbacks\n`, `飞书配置:仍有配置缺失,初始化已继续;新增 ${configuration.added.scopes.length} 项权限、${configuration.added.events.length} 个事件和 ${configuration.added.callbacks.length} 个回调\n`));
495
517
  }
496
518
  else {
497
- process.stdout.write("Lark configuration: core capabilities are ready\n");
519
+ process.stdout.write(cliText("Lark configuration: initialization continued with missing configuration\n", "飞书配置:仍有配置缺失,初始化已继续\n"));
498
520
  }
499
- printOptionalFeishuConfigurationWarnings(configuration.remaining);
521
+ printFeishuConfigurationWarnings(configuration.remaining);
500
522
  }
501
523
  else if (result.feishu.configuration?.status === "ready") {
502
- process.stdout.write("Lark configuration: scopes, events, and callbacks are ready\n");
524
+ process.stdout.write(cliText("Lark configuration: scopes, events, and callbacks are ready\n", "飞书配置:权限、事件和回调均已就绪\n"));
503
525
  }
504
- process.stdout.write(`Config file: ${result.config.path}\n`);
526
+ process.stdout.write(`${cliText("Config file: ", "配置文件:")}${result.config.path}\n`);
505
527
  }
506
528
  function printInitializationServerResult(result) {
507
529
  if (result.status === "skipped") {
508
- process.stdout.write("Agent Bot server: skipped (Lark is not configured; Console mode is available)\n");
530
+ process.stdout.write(cliText("Agent Bot server: skipped (Lark is not configured; Console mode is available)\n", "Agent Bot 服务:已跳过(未配置飞书;可使用 Console 模式)\n"));
509
531
  return;
510
532
  }
511
533
  printServerStartResult(result);
512
534
  }
513
535
  function printServerStartResult(result) {
514
536
  process.stdout.write(result.status === "already-running"
515
- ? "Agent Bot server is already running.\n"
516
- : "Agent Bot server started.\n");
537
+ ? cliText("Agent Bot server is already running.\n", "Agent Bot 服务已在运行。\n")
538
+ : cliText("Agent Bot server started.\n", "Agent Bot 服务已启动。\n"));
517
539
  }
518
540
  function printFeishuVerification(challenge, json) {
519
541
  printVerificationQrAndLink({
520
542
  verificationUrl: challenge.verificationUrl,
521
543
  json,
522
- qrInstruction: "Scan this QR code with Lark to create the bot app:",
544
+ qrInstruction: cliText("Scan this QR code with Lark to create the bot app:", "使用飞书扫描此二维码以创建机器人应用:"),
523
545
  });
524
- process.stderr.write(`The link expires in about ${Math.ceil(challenge.expiresIn / 60)} minutes. Waiting for confirmation...\n`);
546
+ process.stderr.write(cliText(`The link expires in about ${Math.ceil(challenge.expiresIn / 60)} minutes. Waiting for confirmation...\n`, `链接将在约 ${Math.ceil(challenge.expiresIn / 60)} 分钟后过期,正在等待确认...\n`));
525
547
  }
526
548
  function printFeishuConfigurationVerification(challenge, json) {
527
- process.stderr.write("\nThe Lark app is missing the following configuration:\n");
549
+ process.stderr.write(challenge.kind === "manual_scope"
550
+ ? cliText("\nThe following Lark permission must be added manually in Developer Console:\n", "\n必须在飞书开发者后台手动添加以下权限:\n")
551
+ : cliText("\nThe Lark app is missing the following configuration:\n", "\n飞书应用缺少以下配置:\n"));
528
552
  if (challenge.missing.scopes.length > 0) {
529
- process.stderr.write(`Scopes: ${challenge.missing.scopes.join(", ")}\n`);
553
+ process.stderr.write(`${cliText("Scopes: ", "权限:")}${challenge.missing.scopes.join(", ")}\n`);
530
554
  }
531
555
  if (challenge.missing.events.length > 0) {
532
- process.stderr.write(`Events: ${challenge.missing.events.join(", ")}\n`);
556
+ process.stderr.write(`${cliText("Events: ", "事件:")}${challenge.missing.events.join(", ")}\n`);
533
557
  }
534
558
  if (challenge.missing.callbacks.length > 0) {
535
- process.stderr.write(`Callbacks: ${challenge.missing.callbacks.join(", ")}\n`);
559
+ process.stderr.write(`${cliText("Callbacks: ", "回调:")}${challenge.missing.callbacks.join(", ")}\n`);
536
560
  }
537
561
  printVerificationQrAndLink({
538
562
  verificationUrl: challenge.verificationUrl,
539
563
  json,
540
- qrInstruction: "Scan this QR code with Lark to complete the configuration:",
564
+ qrInstruction: challenge.kind === "manual_scope"
565
+ ? cliText("Scan this QR code with Lark to open the filtered permission page:", "使用飞书扫描此二维码以打开已筛选的权限页面:")
566
+ : cliText("Scan this QR code with Lark to complete the configuration:", "使用飞书扫描此二维码以完成配置:"),
567
+ linkLabel: challenge.kind === "manual_scope"
568
+ ? cliText("Permission page", "权限页面")
569
+ : undefined,
541
570
  });
571
+ if (challenge.kind === "manual_scope") {
572
+ process.stderr.write(cliText("Add the filtered permission, publish the app version, and complete tenant approval if required.\n", "请添加已筛选的权限、发布应用版本,并在需要时完成租户管理员审批。\n"));
573
+ }
542
574
  if (challenge.blocking) {
543
- process.stderr.write("Waiting for the core scopes and message event to become active...\n");
575
+ process.stderr.write(cliText("Waiting for the core scopes and message event to become active...\n", "正在等待核心权限和消息事件生效...\n"));
544
576
  }
545
577
  else {
546
- process.stderr.write("Waiting up to 5 minutes for these optional items to become active...\n");
578
+ process.stderr.write(cliText("Waiting up to 5 minutes for these optional items to become active...\n", "将等待最多 5 分钟,直到这些可选配置生效...\n"));
547
579
  }
548
580
  }
549
- function printOptionalFeishuConfigurationWarnings(missing) {
550
- process.stdout.write("Warning: some optional configuration is not active, so some features may be unavailable.\n");
581
+ function printFeishuConfigurationWarnings(missing) {
582
+ process.stdout.write(cliText("Warning: some Lark configuration is not active, so some features may be unavailable.\n", "警告:部分飞书配置尚未生效,某些功能可能不可用。\n"));
551
583
  if (missing.scopes.length > 0) {
552
- process.stdout.write(`Inactive scopes: ${missing.scopes.join(", ")}\n`);
584
+ process.stdout.write(`${cliText("Inactive scopes: ", "未生效权限:")}${missing.scopes.join(", ")}\n`);
553
585
  }
554
586
  if (missing.events.length > 0) {
555
- process.stdout.write(`Inactive events: ${missing.events.join(", ")}\n`);
587
+ process.stdout.write(`${cliText("Inactive events: ", "未生效事件:")}${missing.events.join(", ")}\n`);
556
588
  }
557
589
  if (missing.callbacks.length > 0) {
558
- process.stdout.write(`Inactive callbacks: ${missing.callbacks.join(", ")}\n`);
590
+ process.stdout.write(`${cliText("Inactive callbacks: ", "未生效回调:")}${missing.callbacks.join(", ")}\n`);
559
591
  }
560
- for (const feature of optionalFeishuFeatureWarnings(missing)) {
561
- process.stdout.write(`Affected feature: ${feature}\n`);
592
+ for (const feature of feishuFeatureWarnings(missing)) {
593
+ process.stdout.write(`${cliText("Affected feature: ", "受影响功能:")}${feature}\n`);
562
594
  }
563
595
  }
564
- function optionalFeishuFeatureWarnings(missing) {
596
+ function feishuFeatureWarnings(missing) {
565
597
  const scopes = new Set(missing.scopes);
566
598
  const events = new Set(missing.events);
567
599
  const callbacks = new Set(missing.callbacks);
568
600
  const warnings = [];
601
+ if (scopes.has("im:message.group_msg")) {
602
+ warnings.push(cliText("responding to ordinary group messages that do not mention the bot", "响应未 @ 机器人的普通群消息"));
603
+ }
569
604
  if (scopes.has("im:chat:create")) {
570
- warnings.push("creating Lark groups with /newgroup and /forkgroup");
605
+ warnings.push(cliText("creating Lark groups with /newgroup and /forkgroup", "使用 /newgroup 和 /forkgroup 创建飞书群"));
571
606
  }
572
607
  if (scopes.has("im:chat:read") || events.has("im.chat.updated_v1")) {
573
- warnings.push("synchronizing Agent Bot task titles after Lark group renames");
608
+ warnings.push(cliText("synchronizing Agent Bot task titles after Lark group renames", "飞书群重命名后同步 Agent Bot 任务标题"));
574
609
  }
575
610
  if (scopes.has("im:message.reactions:write_only")) {
576
- warnings.push("showing message-processing status with reactions");
611
+ warnings.push(cliText("showing message-processing status with reactions", "使用 Reaction 显示消息处理状态"));
577
612
  }
578
613
  if (scopes.has("im:message:readonly")) {
579
- warnings.push("reading images from user messages");
614
+ warnings.push(cliText("reading images from user messages", "读取用户消息中的图片"));
580
615
  }
581
616
  if (scopes.has("im:resource")) {
582
- warnings.push("uploading images, sending local images, or setting group avatars");
617
+ warnings.push(cliText("uploading images, sending local images, or setting group avatars", "上传图片、发送本地图片或设置群头像"));
583
618
  }
584
619
  if (scopes.has("im:message:update")) {
585
- warnings.push("updating sent progress cards");
620
+ warnings.push(cliText("updating sent progress cards", "更新已发送的进度卡片"));
586
621
  }
587
622
  if (callbacks.has("card.action.trigger")) {
588
- warnings.push("card buttons and interactive actions");
623
+ warnings.push(cliText("card buttons and interactive actions", "卡片按钮和交互操作"));
589
624
  }
590
625
  return warnings;
591
626
  }
592
627
  function initializationStatusLabel(status) {
593
628
  if (status === "created")
594
- return "created";
629
+ return cliText("created", "已创建");
595
630
  if (status === "reset")
596
- return "reset from template";
597
- return "already exists; unchanged";
631
+ return cliText("reset from template", "已从模板重置");
632
+ return cliText("already exists; unchanged", "已存在,未修改");
633
+ }
634
+ function taskStateLabel(status) {
635
+ if (!status)
636
+ return "-";
637
+ const chinese = {
638
+ starting: "启动中",
639
+ ready: "就绪",
640
+ running: "运行中",
641
+ closed: "已关闭",
642
+ failed: "失败",
643
+ completed: "已完成",
644
+ cancelled: "已取消",
645
+ interrupted: "已中断",
646
+ inProgress: "进行中",
647
+ active: "活动中",
648
+ idle: "空闲",
649
+ not_loaded: "未加载",
650
+ error: "错误",
651
+ };
652
+ return cliLanguage === "zh" ? chinese[status] ?? status : status;
598
653
  }
599
654
  function ensureOk(response) {
600
655
  if (response.ok)
601
656
  return;
602
657
  const message = response.message?.trim();
603
- throw new Error(message && !/[一-龥]/u.test(message)
658
+ const matchesLanguage = cliLanguage === "zh"
659
+ ? Boolean(message && /[一-龥]/u.test(message))
660
+ : Boolean(message && !/[一-龥]/u.test(message));
661
+ throw new Error(matchesLanguage
604
662
  ? message
605
- : "Agent Bot control operation failed. Check the server logs for details.");
663
+ : cliText("Agent Bot control operation failed. Check the server logs for details.", "Agent Bot 控制操作失败,请查看服务日志了解详情。"));
606
664
  }
607
665
  function optionValue(args, name) {
608
666
  const index = args.indexOf(name);