@keyou007/agent-bot 0.1.9 → 0.1.10
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/CHANGELOG.md +8 -0
- package/README.md +7 -1
- package/README.zh.md +7 -1
- package/dist/cli/FeishuAppConfiguration.js +84 -22
- package/dist/cli/FeishuAppConfiguration.js.map +1 -1
- package/dist/cli/FeishuAppRegistration.js +12 -9
- package/dist/cli/FeishuAppRegistration.js.map +1 -1
- package/dist/cli/Initializer.js +7 -6
- package/dist/cli/Initializer.js.map +1 -1
- package/dist/cli/LocalControlClient.js +3 -2
- package/dist/cli/LocalControlClient.js.map +1 -1
- package/dist/cli/LocalControlServer.js +2 -1
- package/dist/cli/LocalControlServer.js.map +1 -1
- package/dist/cli/OptionalAuthorizationSkip.js +27 -6
- package/dist/cli/OptionalAuthorizationSkip.js.map +1 -1
- package/dist/cli/ServerStarter.js +12 -3
- package/dist/cli/ServerStarter.js.map +1 -1
- package/dist/cli/SkillRegistry.js +5 -4
- package/dist/cli/SkillRegistry.js.map +1 -1
- package/dist/cli/VerificationOutput.js +2 -1
- package/dist/cli/VerificationOutput.js.map +1 -1
- package/dist/cli/help.js +48 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/i18n.js +27 -0
- package/dist/cli/i18n.js.map +1 -0
- package/dist/cli/initOptions.js +5 -4
- package/dist/cli/initOptions.js.map +1 -1
- package/dist/cli/packageVersion.js +2 -1
- package/dist/cli/packageVersion.js.map +1 -1
- package/dist/cli/profile.js +4 -3
- package/dist/cli/profile.js.map +1 -1
- package/dist/cli/serverStatus.js +15 -14
- package/dist/cli/serverStatus.js.map +1 -1
- package/dist/cli/taskChatRoute.js +3 -2
- package/dist/cli/taskChatRoute.js.map +1 -1
- package/dist/cli.js +165 -107
- package/dist/cli.js.map +1 -1
- package/dist/commands/CommandRouter.js +49 -3
- package/dist/commands/CommandRouter.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +6 -0
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/docs/technical-reference.md +13 -2
- package/docs/technical-reference.zh.md +13 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/skills/agent-bot/SKILL.md +6 -6
- package/src/cli/FeishuAppConfiguration.ts +130 -18
- package/src/cli/FeishuAppRegistration.ts +24 -9
- package/src/cli/Initializer.ts +25 -6
- package/src/cli/LocalControlClient.ts +9 -2
- package/src/cli/LocalControlServer.ts +2 -1
- package/src/cli/OptionalAuthorizationSkip.ts +51 -6
- package/src/cli/ServerStarter.ts +20 -3
- package/src/cli/SkillRegistry.ts +17 -4
- package/src/cli/VerificationOutput.ts +4 -1
- package/src/cli/help.ts +50 -1
- package/src/cli/i18n.ts +38 -0
- package/src/cli/initOptions.ts +17 -4
- package/src/cli/packageVersion.ts +5 -1
- package/src/cli/profile.ts +13 -3
- package/src/cli/serverStatus.ts +19 -14
- package/src/cli/taskChatRoute.ts +9 -2
- package/src/cli.ts +290 -103
- package/src/commands/CommandRouter.ts +58 -3
- package/src/proxy/ProxySessionController.ts +6 -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
|
-
|
|
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 (
|
|
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(
|
|
214
|
-
process.stdout.write(
|
|
215
|
-
process.stdout.write(
|
|
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
|
|
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
|
|
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(
|
|
431
|
-
process.stdout.write(
|
|
432
|
-
process.stdout.write(
|
|
433
|
-
process.stdout.write(
|
|
434
|
-
process.stdout.write(
|
|
435
|
-
process.stdout.write(
|
|
436
|
-
process.stdout.write(
|
|
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(
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
457
|
-
process.stdout.write(
|
|
458
|
-
process.stdout.write(
|
|
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(
|
|
461
|
-
|
|
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(
|
|
489
|
+
process.stdout.write(`${cliText("Reset backup: ", "重置备份:")}${result.reset.backupPath}\n`);
|
|
468
490
|
}
|
|
469
|
-
process.stdout.write(
|
|
470
|
-
process.stdout.write(
|
|
471
|
-
process.stdout.write(
|
|
472
|
-
process.stdout.write(
|
|
473
|
-
process.stdout.write(
|
|
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:
|
|
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:
|
|
519
|
+
process.stdout.write(cliText("Lark configuration: initialization continued with missing configuration\n", "飞书配置:仍有配置缺失,初始化已继续\n"));
|
|
498
520
|
}
|
|
499
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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(
|
|
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:
|
|
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
|
|
550
|
-
process.stdout.write("Warning: some
|
|
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(
|
|
584
|
+
process.stdout.write(`${cliText("Inactive scopes: ", "未生效权限:")}${missing.scopes.join(", ")}\n`);
|
|
553
585
|
}
|
|
554
586
|
if (missing.events.length > 0) {
|
|
555
|
-
process.stdout.write(
|
|
587
|
+
process.stdout.write(`${cliText("Inactive events: ", "未生效事件:")}${missing.events.join(", ")}\n`);
|
|
556
588
|
}
|
|
557
589
|
if (missing.callbacks.length > 0) {
|
|
558
|
-
process.stdout.write(
|
|
590
|
+
process.stdout.write(`${cliText("Inactive callbacks: ", "未生效回调:")}${missing.callbacks.join(", ")}\n`);
|
|
559
591
|
}
|
|
560
|
-
for (const feature of
|
|
561
|
-
process.stdout.write(
|
|
592
|
+
for (const feature of feishuFeatureWarnings(missing)) {
|
|
593
|
+
process.stdout.write(`${cliText("Affected feature: ", "受影响功能:")}${feature}\n`);
|
|
562
594
|
}
|
|
563
595
|
}
|
|
564
|
-
function
|
|
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
|
-
|
|
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);
|