@keyou007/agent-bot 0.1.3 → 0.1.4

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 (56) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/README.md +3 -1
  3. package/README.zh.md +3 -1
  4. package/dist/cli/FeishuAppConfiguration.js +10 -10
  5. package/dist/cli/FeishuAppConfiguration.js.map +1 -1
  6. package/dist/cli/FeishuAppRegistration.js +9 -9
  7. package/dist/cli/FeishuAppRegistration.js.map +1 -1
  8. package/dist/cli/Initializer.js +4 -4
  9. package/dist/cli/Initializer.js.map +1 -1
  10. package/dist/cli/LocalControlClient.js +2 -2
  11. package/dist/cli/LocalControlClient.js.map +1 -1
  12. package/dist/cli/LocalControlServer.js +1 -1
  13. package/dist/cli/LocalControlServer.js.map +1 -1
  14. package/dist/cli/ServerStarter.js +3 -3
  15. package/dist/cli/ServerStarter.js.map +1 -1
  16. package/dist/cli/SkillRegistry.js +4 -4
  17. package/dist/cli/SkillRegistry.js.map +1 -1
  18. package/dist/cli/help.js +2 -57
  19. package/dist/cli/help.js.map +1 -1
  20. package/dist/cli/packageVersion.js +1 -1
  21. package/dist/cli/packageVersion.js.map +1 -1
  22. package/dist/cli/profile.js +3 -3
  23. package/dist/cli/profile.js.map +1 -1
  24. package/dist/cli/serverStatus.js +37 -0
  25. package/dist/cli/serverStatus.js.map +1 -0
  26. package/dist/cli/taskChatRoute.js +2 -2
  27. package/dist/cli/taskChatRoute.js.map +1 -1
  28. package/dist/cli.js +112 -116
  29. package/dist/cli.js.map +1 -1
  30. package/dist/feishu/transport.js +1 -1
  31. package/dist/feishu/transport.js.map +1 -1
  32. package/dist/index.js +5 -4
  33. package/dist/index.js.map +1 -1
  34. package/dist/proxy/ProxySessionController.js +10 -10
  35. package/dist/proxy/ProxySessionController.js.map +1 -1
  36. package/docs/technical-reference.md +2 -0
  37. package/docs/technical-reference.zh.md +2 -0
  38. package/npm-shrinkwrap.json +2 -2
  39. package/package.json +1 -1
  40. package/skills/agent-bot/SKILL.md +1 -1
  41. package/src/cli/FeishuAppConfiguration.ts +10 -10
  42. package/src/cli/FeishuAppRegistration.ts +9 -9
  43. package/src/cli/Initializer.ts +4 -4
  44. package/src/cli/LocalControlClient.ts +2 -2
  45. package/src/cli/LocalControlServer.ts +1 -1
  46. package/src/cli/ServerStarter.ts +3 -3
  47. package/src/cli/SkillRegistry.ts +4 -4
  48. package/src/cli/help.ts +2 -66
  49. package/src/cli/packageVersion.ts +1 -1
  50. package/src/cli/profile.ts +3 -3
  51. package/src/cli/serverStatus.ts +39 -0
  52. package/src/cli/taskChatRoute.ts +2 -2
  53. package/src/cli.ts +113 -119
  54. package/src/feishu/transport.ts +1 -1
  55. package/src/index.ts +5 -4
  56. package/src/proxy/ProxySessionController.ts +10 -10
package/dist/cli.js CHANGED
@@ -9,6 +9,7 @@ import { acquireInitializationLock, cleanupFeishuCredentialTemporaryFiles, initi
9
9
  import { registerFeishuApp, } from "./cli/FeishuAppRegistration.js";
10
10
  import { ensureFeishuAppConfiguration, } from "./cli/FeishuAppConfiguration.js";
11
11
  import { renderCliHelp } from "./cli/help.js";
12
+ import { formatServerStatus, withConfiguredFeishuAppId } from "./cli/serverStatus.js";
12
13
  import { resolveSystemSkillsRoot, SkillRegistry } from "./cli/SkillRegistry.js";
13
14
  import { readPackageVersion } from "./cli/packageVersion.js";
14
15
  import { applyExplicitProfile, parseGlobalOptions } from "./cli/profile.js";
@@ -18,7 +19,7 @@ import { StateStore } from "./state/StateStore.js";
18
19
  import { nodeDiagnosticReportArguments, prepareCrashReportDirectory, resolveSupervisorDiagnosticsPaths, } from "./supervision/SupervisorDiagnostics.js";
19
20
  const args = process.argv.slice(2);
20
21
  void main(args).catch((error) => {
21
- process.stderr.write(`错误:${error instanceof Error ? error.message : String(error)}\n`);
22
+ process.stderr.write(`Error: ${error instanceof Error ? error.message : String(error)}\n`);
22
23
  process.exitCode = 1;
23
24
  });
24
25
  async function main(input) {
@@ -56,18 +57,18 @@ async function main(input) {
56
57
  skillsCommand(rest);
57
58
  return;
58
59
  }
59
- throw new Error(`未知命令:${command}。使用 agent-bot --help 查看帮助。`);
60
+ throw new Error(`Unknown command: ${command}. Run agent-bot --help for usage.`);
60
61
  }
61
62
  async function initCommand(input, configPath) {
62
63
  const supported = new Set(["--json", "--skip-feishu", "--reconfigure-feishu"]);
63
64
  const unsupported = input.filter((value) => !supported.has(value));
64
65
  if (unsupported.length > 0)
65
- throw new Error(`init 不支持参数:${unsupported.join(" ")}`);
66
+ throw new Error(`Unsupported init options: ${unsupported.join(" ")}`);
66
67
  const json = input.includes("--json");
67
68
  const skipFeishu = input.includes("--skip-feishu");
68
69
  const reconfigureFeishu = input.includes("--reconfigure-feishu");
69
70
  if (skipFeishu && reconfigureFeishu) {
70
- throw new Error("--skip-feishu 和 --reconfigure-feishu 不能同时使用。");
71
+ throw new Error("--skip-feishu and --reconfigure-feishu cannot be used together.");
71
72
  }
72
73
  const paths = initializeAgentBot({ configPath });
73
74
  if (!json)
@@ -85,7 +86,7 @@ async function initCommand(input, configPath) {
85
86
  if (!json)
86
87
  printInitializationResult(initialized);
87
88
  if (!json && !skipFeishu)
88
- process.stdout.write("\n正在启动 Agent Bot server...\n");
89
+ process.stdout.write("\nStarting Agent Bot server...\n");
89
90
  const server = await startInitializedServer({ skipFeishu, configPath });
90
91
  const result = { ...initialized, server };
91
92
  if (json)
@@ -102,7 +103,7 @@ async function initializeFeishu(paths, options) {
102
103
  };
103
104
  }
104
105
  const controller = new AbortController();
105
- const onInterrupt = () => controller.abort(new Error("已取消初始化。"));
106
+ const onInterrupt = () => controller.abort(new Error("Initialization was cancelled."));
106
107
  process.once("SIGINT", onInterrupt);
107
108
  process.once("SIGTERM", onInterrupt);
108
109
  try {
@@ -118,7 +119,7 @@ async function initializeFeishu(paths, options) {
118
119
  }
119
120
  else {
120
121
  if (existing.status === "incomplete" && !options.json) {
121
- process.stdout.write("\n检测到未完整保存的飞书凭据,将重新创建机器人。\n");
122
+ process.stdout.write("\nIncomplete Lark credentials were found. A new bot will be created.\n");
122
123
  }
123
124
  credentials = await registerFeishuApp({
124
125
  signal: controller.signal,
@@ -128,7 +129,7 @@ async function initializeFeishu(paths, options) {
128
129
  status = "created";
129
130
  }
130
131
  if (!options.json)
131
- process.stdout.write("\n正在检查飞书应用权限、事件和回调配置...\n");
132
+ process.stdout.write("\nChecking Lark app permissions, events, and callbacks...\n");
132
133
  const configuration = await ensureFeishuAppConfiguration(credentials, {
133
134
  signal: controller.signal,
134
135
  onVerification: (challenge) => printFeishuConfigurationVerification(challenge, options.json),
@@ -156,8 +157,8 @@ function skillsCommand(input) {
156
157
  printJson(result);
157
158
  else
158
159
  process.stdout.write(result.updated
159
- ? `已注册 Agent Bot Skill:${result.status.targetPath}\n`
160
- : `Agent Bot Skill 已是最新版本:${result.status.targetPath}\n`);
160
+ ? `Installed the Agent Bot Skill: ${result.status.targetPath}\n`
161
+ : `The Agent Bot Skill is already up to date: ${result.status.targetPath}\n`);
161
162
  return;
162
163
  }
163
164
  if (action === "uninstall" || action === "unregister") {
@@ -166,8 +167,8 @@ function skillsCommand(input) {
166
167
  printJson({ removed, targetPath: registry.targetPath });
167
168
  else
168
169
  process.stdout.write(removed
169
- ? `已反注册 Agent Bot Skill:${registry.targetPath}\n`
170
- : `Agent Bot Skill 尚未注册:${registry.targetPath}\n`);
170
+ ? `Uninstalled the Agent Bot Skill: ${registry.targetPath}\n`
171
+ : `The Agent Bot Skill is not installed: ${registry.targetPath}\n`);
171
172
  return;
172
173
  }
173
174
  if (action === "status") {
@@ -183,20 +184,20 @@ function skillsCommand(input) {
183
184
  if (json)
184
185
  printJson(paths);
185
186
  else {
186
- process.stdout.write(`内置 Skill:${paths.sourcePath}\n`);
187
- process.stdout.write(`系统 Skills:${paths.skillsRoot}\n`);
188
- process.stdout.write(`注册位置:${paths.targetPath}\n`);
187
+ process.stdout.write(`Built-in Skill: ${paths.sourcePath}\n`);
188
+ process.stdout.write(`System Skills directory: ${paths.skillsRoot}\n`);
189
+ process.stdout.write(`Installation path: ${paths.targetPath}\n`);
189
190
  }
190
191
  return;
191
192
  }
192
- throw new Error(`未知 skills 命令:${action}`);
193
+ throw new Error(`Unknown skills command: ${action}`);
193
194
  }
194
195
  async function consoleCommand(input) {
195
196
  const config = loadConfig();
196
197
  const endpoint = controlEndpoint(config.storage.sqlitePath);
197
198
  const force = input.includes("--force");
198
199
  if (!force && await isServerReachable(endpoint)) {
199
- throw new Error("agent-bot server 正在运行。为避免争用同一任务状态,请先停止 server,或明确使用 --force。");
200
+ throw new Error("The Agent Bot server is running. Stop it first to avoid concurrent task-state access, or explicitly use --force.");
200
201
  }
201
202
  const entry = fileURLToPath(new URL("./index.js", import.meta.url));
202
203
  const reportDirectory = resolveSupervisorDiagnosticsPaths(config).crashReportDirectory;
@@ -222,16 +223,21 @@ async function serverCommand(input) {
222
223
  try {
223
224
  const response = await sendControlRequest(endpoint, { action: "health" }, 1_500);
224
225
  ensureOk(response);
226
+ const status = withConfiguredFeishuAppId(response.data, config.feishu.appId);
225
227
  if (rest.includes("--json"))
226
- printJson(response.data);
228
+ printJson(status);
227
229
  else
228
- printServerStatus(response.data);
230
+ process.stdout.write(formatServerStatus(status));
229
231
  }
230
232
  catch {
233
+ const status = {
234
+ running: false,
235
+ feishuAppId: config.feishu.appId ?? null,
236
+ };
231
237
  if (rest.includes("--json"))
232
- printJson({ running: false });
238
+ printJson(status);
233
239
  else
234
- process.stdout.write("agent-bot server:未运行\n");
240
+ process.stdout.write(formatServerStatus(status));
235
241
  process.exitCode = 3;
236
242
  }
237
243
  return;
@@ -241,21 +247,23 @@ async function serverCommand(input) {
241
247
  return;
242
248
  }
243
249
  if (action === "stop") {
244
- printResponse(await sendControlRequest(endpoint, { action: "server_stop" }));
250
+ ensureOk(await sendControlRequest(endpoint, { action: "server_stop" }));
251
+ process.stdout.write("Agent Bot server stop requested.\n");
245
252
  return;
246
253
  }
247
254
  if (action === "restart") {
248
255
  const immediate = rest.includes("--immediate") || rest.includes("--force");
249
256
  const reason = optionValue(rest, "--reason")
250
- ?? (immediate ? "通过 agent-bot CLI 立即重启" : "通过 agent-bot CLI 安全重启");
251
- printResponse(await sendControlRequest(endpoint, {
257
+ ?? (immediate ? "通过 Agent Bot CLI 立即重启" : "通过 Agent Bot CLI 安全重启");
258
+ ensureOk(await sendControlRequest(endpoint, {
252
259
  action: "server_restart",
253
260
  mode: immediate ? "immediate" : "safe",
254
261
  reason,
255
262
  }));
263
+ process.stdout.write(immediate ? "Immediate restart requested.\n" : "Safe restart requested.\n");
256
264
  return;
257
265
  }
258
- throw new Error(`未知 server 命令:${action}`);
266
+ throw new Error(`Unknown server command: ${action}`);
259
267
  }
260
268
  async function taskCommand(input) {
261
269
  const [action = "list", ...rest] = input;
@@ -266,17 +274,18 @@ async function taskCommand(input) {
266
274
  if (action === "prompt" || action === "send") {
267
275
  const [reference, ...promptParts] = rest;
268
276
  if (!reference)
269
- throw new Error(`task ${action} 需要任务序号或任务 ID。`);
277
+ throw new Error(`task ${action} requires a task number or task ID.`);
270
278
  const text = promptParts.join(" ").trim();
271
279
  if (!text)
272
- throw new Error(`task ${action} 需要要发送的 Prompt。`);
280
+ throw new Error(`task ${action} requires a Prompt.`);
273
281
  const session = resolveTask(allSessions, reference);
274
282
  const endpoint = controlEndpoint(config.storage.sqlitePath);
275
- printResponse(await sendControlRequest(endpoint, {
283
+ ensureOk(await sendControlRequest(endpoint, {
276
284
  action: "task_prompt",
277
285
  localSessionId: session.localSessionId,
278
286
  text,
279
287
  }, 60_000));
288
+ process.stdout.write("Prompt submitted.\n");
280
289
  return;
281
290
  }
282
291
  const sessions = filterSessions(allSessions, rest);
@@ -289,7 +298,7 @@ async function taskCommand(input) {
289
298
  }
290
299
  const reference = rest.find((value) => !value.startsWith("--"));
291
300
  if (!reference)
292
- throw new Error(`task ${action} 需要任务序号或任务 ID。`);
301
+ throw new Error(`task ${action} requires a task number or task ID.`);
293
302
  const session = resolveTask(sessions, reference);
294
303
  if (action === "chat") {
295
304
  const route = taskChatRoute(session);
@@ -329,7 +338,8 @@ async function taskCommand(input) {
329
338
  }
330
339
  const endpoint = controlEndpoint(config.storage.sqlitePath);
331
340
  if (action === "stop") {
332
- printResponse(await sendControlRequest(endpoint, { action: "task_stop", localSessionId: session.localSessionId }));
341
+ ensureOk(await sendControlRequest(endpoint, { action: "task_stop", localSessionId: session.localSessionId }));
342
+ process.stdout.write("Task stop requested.\n");
333
343
  return;
334
344
  }
335
345
  if (action === "title") {
@@ -338,15 +348,16 @@ async function taskCommand(input) {
338
348
  const optionIndex = titleArgs.findIndex((value) => value.startsWith("--"));
339
349
  const title = titleArgs.slice(0, optionIndex < 0 ? undefined : optionIndex).join(" ").trim();
340
350
  if (!title)
341
- throw new Error("task title 需要新标题。");
342
- printResponse(await sendControlRequest(endpoint, {
351
+ throw new Error("task title requires a new title.");
352
+ ensureOk(await sendControlRequest(endpoint, {
343
353
  action: "task_title",
344
354
  localSessionId: session.localSessionId,
345
355
  title,
346
356
  }));
357
+ process.stdout.write("Task title updated.\n");
347
358
  return;
348
359
  }
349
- throw new Error(`未知 task 命令:${action}`);
360
+ throw new Error(`Unknown task command: ${action}`);
350
361
  }
351
362
  finally {
352
363
  store.close();
@@ -363,7 +374,7 @@ function resolveTask(sessions, reference) {
363
374
  const index = Number(reference) - 1;
364
375
  const session = sessions[index];
365
376
  if (!session)
366
- throw new Error(`任务序号超出范围:${reference}`);
377
+ throw new Error(`Task number is out of range: ${reference}`);
367
378
  return session;
368
379
  }
369
380
  const exact = sessions.find((session) => session.localSessionId === reference || session.remoteSessionId === reference || session.acpSessionId === reference);
@@ -375,143 +386,128 @@ function resolveTask(sessions, reference) {
375
386
  if (matches.length === 1)
376
387
  return matches[0];
377
388
  if (matches.length > 1)
378
- throw new Error(`任务 ID 前缀不唯一:${reference}`);
379
- throw new Error(`找不到任务:${reference}`);
389
+ throw new Error(`Task ID prefix is ambiguous: ${reference}`);
390
+ throw new Error(`Task not found: ${reference}`);
380
391
  }
381
392
  function printTaskList(sessions) {
382
393
  if (sessions.length === 0) {
383
- process.stdout.write("没有任务。\n");
394
+ process.stdout.write("No tasks.\n");
384
395
  return;
385
396
  }
386
397
  for (const [index, session] of sessions.entries()) {
387
398
  const id = session.remoteSessionId ?? session.acpSessionId ?? session.localSessionId;
388
- process.stdout.write(`${index + 1}. [${session.status}/${session.lastTurnStatus ?? "-"}] ${session.title ?? "未命名任务"}\n`);
399
+ process.stdout.write(`${index + 1}. [${session.status}/${session.lastTurnStatus ?? "-"}] ${session.title ?? "Untitled task"}\n`);
389
400
  process.stdout.write(` ${id} · ${session.contextKey} · ${session.updatedAt}\n`);
390
401
  }
391
402
  }
392
403
  function printTaskStatus(session, snapshot, remote) {
393
- process.stdout.write(`标题:${session.title ?? "未命名任务"}\n`);
394
- process.stdout.write(`任务 ID:${session.remoteSessionId ?? session.acpSessionId ?? session.localSessionId}\n`);
395
- process.stdout.write(`本地 ID:${session.localSessionId}\n`);
396
- process.stdout.write(`上下文:${session.contextKey}\n`);
397
- process.stdout.write(`状态:${session.status} / ${session.lastTurnStatus ?? "-"}\n`);
398
- process.stdout.write(`目录:${session.cwd}\n`);
399
- process.stdout.write(`最后轮次:${session.lastTurnId ?? "-"}\n`);
404
+ process.stdout.write(`Title: ${session.title ?? "Untitled task"}\n`);
405
+ process.stdout.write(`Task ID: ${session.remoteSessionId ?? session.acpSessionId ?? session.localSessionId}\n`);
406
+ process.stdout.write(`Local ID: ${session.localSessionId}\n`);
407
+ process.stdout.write(`Context: ${session.contextKey}\n`);
408
+ process.stdout.write(`Status: ${session.status} / ${session.lastTurnStatus ?? "-"}\n`);
409
+ process.stdout.write(`Directory: ${session.cwd}\n`);
410
+ process.stdout.write(`Last turn: ${session.lastTurnId ?? "-"}\n`);
400
411
  let displayedFinalResponse;
401
412
  if (snapshot && typeof snapshot === "object") {
402
413
  const state = snapshot;
403
414
  if (typeof state.durationMs === "number")
404
- process.stdout.write(`耗时:${Math.round(state.durationMs / 1_000)}s\n`);
415
+ process.stdout.write(`Duration: ${Math.round(state.durationMs / 1_000)}s\n`);
405
416
  if (typeof state.totalTokens === "number")
406
417
  process.stdout.write(`Tokens:${state.totalTokens}\n`);
407
418
  if (typeof state.totalToolCount === "number")
408
- process.stdout.write(`工具调用:${state.totalToolCount}\n`);
419
+ process.stdout.write(`Tool calls: ${state.totalToolCount}\n`);
409
420
  if (typeof state.finalResponse === "string" && state.finalResponse.trim())
410
421
  displayedFinalResponse = state.finalResponse.trim();
411
422
  }
412
423
  if (!snapshot && remote?.lastTurnToolCount !== undefined)
413
- process.stdout.write(`工具调用:${remote.lastTurnToolCount}\n`);
424
+ process.stdout.write(`Tool calls: ${remote.lastTurnToolCount}\n`);
414
425
  displayedFinalResponse = remote?.finalResponse?.trim() || displayedFinalResponse;
415
426
  if (displayedFinalResponse)
416
- process.stdout.write(`最终结果:\n${displayedFinalResponse}\n`);
417
- }
418
- function printServerStatus(data) {
419
- const value = data && typeof data === "object" ? data : {};
420
- const activity = value.activity && typeof value.activity === "object"
421
- ? value.activity
422
- : {};
423
- process.stdout.write(value.ready === false
424
- ? "agent-bot server:启动中(正在连接飞书机器人)\n"
425
- : "agent-bot server:运行中\n");
426
- process.stdout.write(`PID:${value.pid ?? "-"}\n`);
427
- process.stdout.write(`启动时间:${value.startedAt ?? "-"}\n`);
428
- process.stdout.write(`Supervisor:${value.supervised ? "已启用" : "未启用"}\n`);
429
- process.stdout.write(`运行任务:${activity.runningSessions ?? 0}\n`);
430
- process.stdout.write(`待投递结果:${activity.pendingFinalDeliveries ?? 0}\n`);
431
- process.stdout.write(`安全重启:${value.safeRestartScheduled ? `等待中(${value.safeRestartReason ?? "未注明原因"})` : "未安排"}\n`);
427
+ process.stdout.write(`Final response:\n${displayedFinalResponse}\n`);
432
428
  }
433
429
  function printSkillStatus(status) {
434
- process.stdout.write(`Agent Bot Skill:${status.registered ? "已注册" : "未注册"}\n`);
435
- process.stdout.write(`系统目录:${status.skillsRoot}\n`);
436
- process.stdout.write(`注册位置:${status.targetPath}\n`);
430
+ process.stdout.write(`Agent Bot Skill: ${status.registered ? "installed" : "not installed"}\n`);
431
+ process.stdout.write(`System directory: ${status.skillsRoot}\n`);
432
+ process.stdout.write(`Installation path: ${status.targetPath}\n`);
437
433
  if (status.registered) {
438
- process.stdout.write(`归属:${status.managed ? "由 Agent Bot 管理" : "外部目录(不会覆盖或删除)"}\n`);
439
- process.stdout.write(`版本:${status.upToDate ? "最新" : "需要更新"}\n`);
434
+ process.stdout.write(`Ownership: ${status.managed ? "managed by Agent Bot" : "external directory (will not be modified or removed)"}\n`);
435
+ process.stdout.write(`Version: ${status.upToDate ? "up to date" : "update required"}\n`);
440
436
  }
441
437
  }
442
438
  function printInitializationPaths(result) {
443
- process.stdout.write("正在准备 Agent Bot 用户环境...\n");
444
- process.stdout.write(`用户目录:${result.home.path}(${initializationStatusLabel(result.home.status)})\n`);
445
- process.stdout.write(`配置文件:${result.config.path}(${initializationStatusLabel(result.config.status)})\n`);
446
- process.stdout.write(`环境文件:${result.env.path}(${initializationStatusLabel(result.env.status)})\n`);
447
- process.stdout.write(`数据目录:${result.data.path}(${initializationStatusLabel(result.data.status)})\n`);
448
- process.stdout.write(`日志目录:${result.logs.path}(${initializationStatusLabel(result.logs.status)})\n`);
439
+ process.stdout.write("Preparing the Agent Bot user environment...\n");
440
+ process.stdout.write(`Home directory: ${result.home.path} (${initializationStatusLabel(result.home.status)})\n`);
441
+ process.stdout.write(`Config file: ${result.config.path} (${initializationStatusLabel(result.config.status)})\n`);
442
+ process.stdout.write(`Environment file: ${result.env.path} (${initializationStatusLabel(result.env.status)})\n`);
443
+ process.stdout.write(`Data directory: ${result.data.path} (${initializationStatusLabel(result.data.status)})\n`);
444
+ process.stdout.write(`Log directory: ${result.logs.path} (${initializationStatusLabel(result.logs.status)})\n`);
449
445
  }
450
446
  function printInitializationResult(result) {
451
- process.stdout.write("\nAgent Bot 初始化完成。\n");
447
+ process.stdout.write("\nAgent Bot initialization completed.\n");
452
448
  if (result.feishu.status === "created") {
453
- process.stdout.write(`飞书应用:已创建并保存凭证(${result.feishu.appId})\n`);
449
+ process.stdout.write(`Lark app: created and credentials saved (${result.feishu.appId})\n`);
454
450
  }
455
451
  else if (result.feishu.status === "existing") {
456
- process.stdout.write(`飞书应用:已配置,未修改(${result.feishu.appId})\n`);
452
+ process.stdout.write(`Lark app: already configured and unchanged (${result.feishu.appId})\n`);
457
453
  }
458
454
  else {
459
- process.stdout.write("飞书应用:已跳过,可使用 Console 模式或稍后重新运行 init。\n");
455
+ process.stdout.write("Lark app: skipped; use Console mode or run init again later.\n");
460
456
  }
461
457
  if (result.feishu.configuration?.status === "updated") {
462
458
  const added = result.feishu.configuration.added;
463
- process.stdout.write(`飞书配置:已补齐 ${added.scopes.length} 项权限、${added.events.length} 项事件、${added.callbacks.length} 项回调\n`);
459
+ process.stdout.write(`Lark configuration: added ${added.scopes.length} scopes, ${added.events.length} events, and ${added.callbacks.length} callbacks\n`);
464
460
  }
465
461
  else if (result.feishu.configuration?.status === "partial") {
466
462
  const configuration = result.feishu.configuration;
467
463
  const addedCount = configuration.added.scopes.length + configuration.added.events.length + configuration.added.callbacks.length;
468
464
  if (addedCount > 0) {
469
- process.stdout.write(`飞书配置:核心能力已就绪,已补齐 ${configuration.added.scopes.length} 项权限、${configuration.added.events.length} 项事件、${configuration.added.callbacks.length} 项回调\n`);
465
+ 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`);
470
466
  }
471
467
  else {
472
- process.stdout.write("飞书配置:核心能力已就绪\n");
468
+ process.stdout.write("Lark configuration: core capabilities are ready\n");
473
469
  }
474
470
  printOptionalFeishuConfigurationWarnings(configuration.remaining);
475
471
  }
476
472
  else if (result.feishu.configuration?.status === "ready") {
477
- process.stdout.write("飞书配置:权限、事件和回调均已就绪\n");
473
+ process.stdout.write("Lark configuration: scopes, events, and callbacks are ready\n");
478
474
  }
479
- process.stdout.write(`配置文件:${result.config.path}\n`);
475
+ process.stdout.write(`Config file: ${result.config.path}\n`);
480
476
  }
481
477
  function printInitializationServerResult(result) {
482
478
  if (result.status === "skipped") {
483
- process.stdout.write("Agent Bot server:已跳过(未配置飞书,可使用 Console 模式)\n");
479
+ process.stdout.write("Agent Bot server: skipped (Lark is not configured; Console mode is available)\n");
484
480
  return;
485
481
  }
486
482
  printServerStartResult(result);
487
483
  }
488
484
  function printServerStartResult(result) {
489
485
  process.stdout.write(result.status === "already-running"
490
- ? "agent-bot server 已在运行。\n"
491
- : "agent-bot server 已启动。\n");
486
+ ? "Agent Bot server is already running.\n"
487
+ : "Agent Bot server started.\n");
492
488
  }
493
489
  function printFeishuVerification(challenge, json) {
494
- process.stderr.write("\n请使用飞书扫码,或在浏览器中打开下面的链接创建机器人应用:\n\n");
490
+ process.stderr.write("\nScan with Lark or open the link below in a browser to create the bot app:\n\n");
495
491
  process.stderr.write(`${challenge.verificationUrl}\n\n`);
496
492
  if (!json) {
497
493
  qrcode.generate(challenge.verificationUrl, { small: true }, (output) => {
498
494
  process.stderr.write(`${output}\n`);
499
495
  });
500
496
  }
501
- process.stderr.write(`链接约在 ${Math.ceil(challenge.expiresIn / 60)} 分钟后过期,正在等待确认...\n`);
497
+ process.stderr.write(`The link expires in about ${Math.ceil(challenge.expiresIn / 60)} minutes. Waiting for confirmation...\n`);
502
498
  }
503
499
  function printFeishuConfigurationVerification(challenge, json) {
504
- process.stderr.write("\n飞书应用还缺少以下配置:\n");
500
+ process.stderr.write("\nThe Lark app is missing the following configuration:\n");
505
501
  if (challenge.missing.scopes.length > 0) {
506
- process.stderr.write(`权限:${challenge.missing.scopes.join(", ")}\n`);
502
+ process.stderr.write(`Scopes: ${challenge.missing.scopes.join(", ")}\n`);
507
503
  }
508
504
  if (challenge.missing.events.length > 0) {
509
- process.stderr.write(`事件:${challenge.missing.events.join(", ")}\n`);
505
+ process.stderr.write(`Events: ${challenge.missing.events.join(", ")}\n`);
510
506
  }
511
507
  if (challenge.missing.callbacks.length > 0) {
512
- process.stderr.write(`回调:${challenge.missing.callbacks.join(", ")}\n`);
508
+ process.stderr.write(`Callbacks: ${challenge.missing.callbacks.join(", ")}\n`);
513
509
  }
514
- process.stderr.write("\n请使用飞书扫码,或在浏览器中打开下面的链接补齐配置:\n\n");
510
+ process.stderr.write("\nScan with Lark or open the link below in a browser to complete the configuration:\n\n");
515
511
  process.stderr.write(`${challenge.verificationUrl}\n\n`);
516
512
  if (!json) {
517
513
  qrcode.generate(challenge.verificationUrl, { small: true }, (output) => {
@@ -519,25 +515,25 @@ function printFeishuConfigurationVerification(challenge, json) {
519
515
  });
520
516
  }
521
517
  if (challenge.blocking) {
522
- process.stderr.write("正在等待核心权限和消息事件发布生效...\n");
518
+ process.stderr.write("Waiting for the core scopes and message event to become active...\n");
523
519
  }
524
520
  else {
525
- process.stderr.write("以上配置不影响基础消息收发;初始化将继续,可稍后打开链接授权。\n");
521
+ process.stderr.write("These optional items do not block basic messaging. Initialization will continue; grant them later using the link.\n");
526
522
  }
527
523
  }
528
524
  function printOptionalFeishuConfigurationWarnings(missing) {
529
- process.stdout.write("提醒:以下非核心配置尚未生效,部分功能可能不可用。\n");
525
+ process.stdout.write("Warning: some optional configuration is not active, so some features may be unavailable.\n");
530
526
  if (missing.scopes.length > 0) {
531
- process.stdout.write(`未生效权限:${missing.scopes.join(", ")}\n`);
527
+ process.stdout.write(`Inactive scopes: ${missing.scopes.join(", ")}\n`);
532
528
  }
533
529
  if (missing.events.length > 0) {
534
- process.stdout.write(`未生效事件:${missing.events.join(", ")}\n`);
530
+ process.stdout.write(`Inactive events: ${missing.events.join(", ")}\n`);
535
531
  }
536
532
  if (missing.callbacks.length > 0) {
537
- process.stdout.write(`未生效回调:${missing.callbacks.join(", ")}\n`);
533
+ process.stdout.write(`Inactive callbacks: ${missing.callbacks.join(", ")}\n`);
538
534
  }
539
535
  for (const feature of optionalFeishuFeatureWarnings(missing)) {
540
- process.stdout.write(`可能缺失功能:${feature}\n`);
536
+ process.stdout.write(`Affected feature: ${feature}\n`);
541
537
  }
542
538
  }
543
539
  function optionalFeishuFeatureWarnings(missing) {
@@ -546,40 +542,40 @@ function optionalFeishuFeatureWarnings(missing) {
546
542
  const callbacks = new Set(missing.callbacks);
547
543
  const warnings = [];
548
544
  if (scopes.has("im:chat:create")) {
549
- warnings.push("无法使用 /newgroup 和 /forkgroup 创建飞书群");
545
+ warnings.push("creating Lark groups with /newgroup and /forkgroup");
550
546
  }
551
547
  if (scopes.has("im:chat:read") || events.has("im.chat.updated_v1")) {
552
- warnings.push("修改飞书群名称时无法同步 Agent Bot 任务标题");
548
+ warnings.push("synchronizing Agent Bot task titles after Lark group renames");
553
549
  }
554
550
  if (scopes.has("im:message.reactions:write_only")) {
555
- warnings.push("无法用表情显示消息处理状态");
551
+ warnings.push("showing message-processing status with reactions");
556
552
  }
557
553
  if (scopes.has("im:message:readonly")) {
558
- warnings.push("可能无法读取用户消息中的图片");
554
+ warnings.push("reading images from user messages");
559
555
  }
560
556
  if (scopes.has("im:resource")) {
561
- warnings.push("可能无法上传图片、发送本地图片或设置群头像");
557
+ warnings.push("uploading images, sending local images, or setting group avatars");
562
558
  }
563
559
  if (scopes.has("im:message:update")) {
564
- warnings.push("可能无法更新已发送的进度卡片");
560
+ warnings.push("updating sent progress cards");
565
561
  }
566
562
  if (callbacks.has("card.action.trigger")) {
567
- warnings.push("卡片按钮和交互操作不可用");
563
+ warnings.push("card buttons and interactive actions");
568
564
  }
569
565
  return warnings;
570
566
  }
571
567
  function initializationStatusLabel(status) {
572
568
  if (status === "created")
573
- return "已创建";
574
- return "已存在,未修改";
575
- }
576
- function printResponse(response) {
577
- ensureOk(response);
578
- process.stdout.write(`${response.message ?? "操作成功。"}\n`);
569
+ return "created";
570
+ return "already exists; unchanged";
579
571
  }
580
572
  function ensureOk(response) {
581
- if (!response.ok)
582
- throw new Error(response.message ?? "Agent Bot 控制操作失败。");
573
+ if (response.ok)
574
+ return;
575
+ const message = response.message?.trim();
576
+ throw new Error(message && !/[一-龥]/u.test(message)
577
+ ? message
578
+ : "Agent Bot control operation failed. Check the server logs for details.");
583
579
  }
584
580
  function optionValue(args, name) {
585
581
  const index = args.indexOf(name);