@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.
- package/CHANGELOG.md +6 -0
- package/README.md +3 -1
- package/README.zh.md +3 -1
- package/dist/cli/FeishuAppConfiguration.js +10 -10
- package/dist/cli/FeishuAppConfiguration.js.map +1 -1
- package/dist/cli/FeishuAppRegistration.js +9 -9
- package/dist/cli/FeishuAppRegistration.js.map +1 -1
- package/dist/cli/Initializer.js +4 -4
- package/dist/cli/Initializer.js.map +1 -1
- package/dist/cli/LocalControlClient.js +2 -2
- package/dist/cli/LocalControlClient.js.map +1 -1
- package/dist/cli/LocalControlServer.js +1 -1
- package/dist/cli/LocalControlServer.js.map +1 -1
- package/dist/cli/ServerStarter.js +3 -3
- package/dist/cli/ServerStarter.js.map +1 -1
- package/dist/cli/SkillRegistry.js +4 -4
- package/dist/cli/SkillRegistry.js.map +1 -1
- package/dist/cli/help.js +2 -57
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/packageVersion.js +1 -1
- package/dist/cli/packageVersion.js.map +1 -1
- package/dist/cli/profile.js +3 -3
- package/dist/cli/profile.js.map +1 -1
- package/dist/cli/serverStatus.js +37 -0
- package/dist/cli/serverStatus.js.map +1 -0
- package/dist/cli/taskChatRoute.js +2 -2
- package/dist/cli/taskChatRoute.js.map +1 -1
- package/dist/cli.js +112 -116
- package/dist/cli.js.map +1 -1
- package/dist/feishu/transport.js +1 -1
- package/dist/feishu/transport.js.map +1 -1
- package/dist/index.js +5 -4
- package/dist/index.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +10 -10
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/docs/technical-reference.md +2 -0
- package/docs/technical-reference.zh.md +2 -0
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/skills/agent-bot/SKILL.md +1 -1
- package/src/cli/FeishuAppConfiguration.ts +10 -10
- package/src/cli/FeishuAppRegistration.ts +9 -9
- package/src/cli/Initializer.ts +4 -4
- package/src/cli/LocalControlClient.ts +2 -2
- package/src/cli/LocalControlServer.ts +1 -1
- package/src/cli/ServerStarter.ts +3 -3
- package/src/cli/SkillRegistry.ts +4 -4
- package/src/cli/help.ts +2 -66
- package/src/cli/packageVersion.ts +1 -1
- package/src/cli/profile.ts +3 -3
- package/src/cli/serverStatus.ts +39 -0
- package/src/cli/taskChatRoute.ts +2 -2
- package/src/cli.ts +113 -119
- package/src/feishu/transport.ts +1 -1
- package/src/index.ts +5 -4
- 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(
|
|
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(
|
|
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
|
|
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
|
|
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("\
|
|
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
|
|
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
|
|
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
|
-
?
|
|
160
|
-
: `Agent Bot Skill
|
|
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
|
-
?
|
|
170
|
-
: `Agent Bot Skill
|
|
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(
|
|
187
|
-
process.stdout.write(
|
|
188
|
-
process.stdout.write(
|
|
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(
|
|
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("
|
|
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(
|
|
228
|
+
printJson(status);
|
|
227
229
|
else
|
|
228
|
-
|
|
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(
|
|
238
|
+
printJson(status);
|
|
233
239
|
else
|
|
234
|
-
process.stdout.write(
|
|
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
|
-
|
|
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 ? "通过
|
|
251
|
-
|
|
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(
|
|
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}
|
|
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}
|
|
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
|
-
|
|
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}
|
|
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
|
-
|
|
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
|
-
|
|
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(
|
|
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(
|
|
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(
|
|
379
|
-
throw new Error(
|
|
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("
|
|
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 ?? "
|
|
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(
|
|
394
|
-
process.stdout.write(
|
|
395
|
-
process.stdout.write(
|
|
396
|
-
process.stdout.write(
|
|
397
|
-
process.stdout.write(
|
|
398
|
-
process.stdout.write(
|
|
399
|
-
process.stdout.write(
|
|
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(
|
|
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(
|
|
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(
|
|
424
|
+
process.stdout.write(`Tool calls: ${remote.lastTurnToolCount}\n`);
|
|
414
425
|
displayedFinalResponse = remote?.finalResponse?.trim() || displayedFinalResponse;
|
|
415
426
|
if (displayedFinalResponse)
|
|
416
|
-
process.stdout.write(
|
|
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
|
|
435
|
-
process.stdout.write(
|
|
436
|
-
process.stdout.write(
|
|
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(
|
|
439
|
-
process.stdout.write(
|
|
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("
|
|
444
|
-
process.stdout.write(
|
|
445
|
-
process.stdout.write(
|
|
446
|
-
process.stdout.write(
|
|
447
|
-
process.stdout.write(
|
|
448
|
-
process.stdout.write(
|
|
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
|
|
447
|
+
process.stdout.write("\nAgent Bot initialization completed.\n");
|
|
452
448
|
if (result.feishu.status === "created") {
|
|
453
|
-
process.stdout.write(
|
|
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(
|
|
452
|
+
process.stdout.write(`Lark app: already configured and unchanged (${result.feishu.appId})\n`);
|
|
457
453
|
}
|
|
458
454
|
else {
|
|
459
|
-
process.stdout.write("
|
|
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(
|
|
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(
|
|
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("
|
|
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("
|
|
473
|
+
process.stdout.write("Lark configuration: scopes, events, and callbacks are ready\n");
|
|
478
474
|
}
|
|
479
|
-
process.stdout.write(
|
|
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
|
|
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
|
-
? "
|
|
491
|
-
: "
|
|
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
|
|
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(
|
|
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
|
|
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(
|
|
502
|
+
process.stderr.write(`Scopes: ${challenge.missing.scopes.join(", ")}\n`);
|
|
507
503
|
}
|
|
508
504
|
if (challenge.missing.events.length > 0) {
|
|
509
|
-
process.stderr.write(
|
|
505
|
+
process.stderr.write(`Events: ${challenge.missing.events.join(", ")}\n`);
|
|
510
506
|
}
|
|
511
507
|
if (challenge.missing.callbacks.length > 0) {
|
|
512
|
-
process.stderr.write(
|
|
508
|
+
process.stderr.write(`Callbacks: ${challenge.missing.callbacks.join(", ")}\n`);
|
|
513
509
|
}
|
|
514
|
-
process.stderr.write("\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("
|
|
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("
|
|
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("
|
|
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(
|
|
527
|
+
process.stdout.write(`Inactive scopes: ${missing.scopes.join(", ")}\n`);
|
|
532
528
|
}
|
|
533
529
|
if (missing.events.length > 0) {
|
|
534
|
-
process.stdout.write(
|
|
530
|
+
process.stdout.write(`Inactive events: ${missing.events.join(", ")}\n`);
|
|
535
531
|
}
|
|
536
532
|
if (missing.callbacks.length > 0) {
|
|
537
|
-
process.stdout.write(
|
|
533
|
+
process.stdout.write(`Inactive callbacks: ${missing.callbacks.join(", ")}\n`);
|
|
538
534
|
}
|
|
539
535
|
for (const feature of optionalFeishuFeatureWarnings(missing)) {
|
|
540
|
-
process.stdout.write(
|
|
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("
|
|
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("
|
|
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 (
|
|
582
|
-
|
|
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);
|