@keyou007/agent-bot 0.1.13-alpha.2 → 0.1.13-alpha.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 +10 -0
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/cli/DefaultAgentSelection.js +16 -2
- package/dist/cli/DefaultAgentSelection.js.map +1 -1
- package/dist/cli/InitializationWelcome.js +94 -0
- package/dist/cli/InitializationWelcome.js.map +1 -0
- package/dist/cli/Initializer.js +44 -0
- package/dist/cli/Initializer.js.map +1 -1
- package/dist/cli/help.js +2 -2
- package/dist/cli.js +133 -31
- package/dist/cli.js.map +1 -1
- package/dist/feishu/CardRenderer.js +106 -0
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/supervision/SafeRestartNotifier.js +1 -9
- package/dist/supervision/SafeRestartNotifier.js.map +1 -1
- package/docs/technical-reference.md +4 -2
- package/docs/technical-reference.zh.md +4 -2
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/skills/agent-bot/SKILL.md +1 -1
- package/src/cli/DefaultAgentSelection.ts +19 -2
- package/src/cli/InitializationWelcome.ts +135 -0
- package/src/cli/Initializer.ts +67 -0
- package/src/cli/help.ts +2 -2
- package/src/cli.ts +185 -34
- package/src/feishu/CardRenderer.ts +127 -0
- package/src/supervision/SafeRestartNotifier.ts +1 -11
package/src/cli.ts
CHANGED
|
@@ -18,7 +18,8 @@ import {
|
|
|
18
18
|
readConfiguredAgentSelection,
|
|
19
19
|
readFeishuCredentials,
|
|
20
20
|
shouldCreateFeishuApp,
|
|
21
|
-
|
|
21
|
+
shouldConfigureAgentsDuringInitialization,
|
|
22
|
+
writeConfiguredAgentSelection,
|
|
22
23
|
writeFeishuCredentials,
|
|
23
24
|
type InitializationResult,
|
|
24
25
|
type InitializationStatus,
|
|
@@ -49,6 +50,7 @@ import {
|
|
|
49
50
|
} from "./cli/AgentPrerequisites.js";
|
|
50
51
|
import {
|
|
51
52
|
parseMaintenanceSelection,
|
|
53
|
+
resolveAgentConfigurationChoices,
|
|
52
54
|
resolveDefaultAgentChoice,
|
|
53
55
|
selectableDefaultAgents,
|
|
54
56
|
type SelectableDefaultAgent,
|
|
@@ -56,6 +58,13 @@ import {
|
|
|
56
58
|
import { formatServerStatus, withConfiguredFeishuAppId } from "./cli/serverStatus.js";
|
|
57
59
|
import { resolveSystemSkillsRoot, SkillRegistry, type SkillRegistrationStatus } from "./cli/SkillRegistry.js";
|
|
58
60
|
import { readPackageVersion } from "./cli/packageVersion.js";
|
|
61
|
+
import {
|
|
62
|
+
readInitializationReceipt,
|
|
63
|
+
resolveInitializationWelcomeKind,
|
|
64
|
+
sendInitializationWelcome,
|
|
65
|
+
writeInitializationReceipt,
|
|
66
|
+
type InitializationWelcomeResult,
|
|
67
|
+
} from "./cli/InitializationWelcome.js";
|
|
59
68
|
import { applyExplicitProfile, parseGlobalOptions } from "./cli/profile.js";
|
|
60
69
|
import { printVerificationQrAndLink } from "./cli/VerificationOutput.js";
|
|
61
70
|
import {
|
|
@@ -136,6 +145,7 @@ type FeishuInitializationStatus = "created" | "existing" | "skipped";
|
|
|
136
145
|
|
|
137
146
|
interface InitCommandResult extends InitializationResult {
|
|
138
147
|
agents: InitializedAgent[];
|
|
148
|
+
configuredAgents: string[];
|
|
139
149
|
defaultAgent: {
|
|
140
150
|
name: string;
|
|
141
151
|
status: "selected" | "existing";
|
|
@@ -147,9 +157,11 @@ interface InitCommandResult extends InitializationResult {
|
|
|
147
157
|
configuration?: EnsureFeishuAppConfigurationResult;
|
|
148
158
|
};
|
|
149
159
|
server: InitializationServerResult;
|
|
160
|
+
welcome: InitializationWelcomeResult;
|
|
150
161
|
}
|
|
151
162
|
|
|
152
163
|
interface InitializedAgent extends SupportedAgentInspection {
|
|
164
|
+
configured?: boolean;
|
|
153
165
|
assistance?: {
|
|
154
166
|
status: "completed" | "skipped" | "unavailable" | "failed";
|
|
155
167
|
error?: string;
|
|
@@ -162,24 +174,37 @@ async function initCommand(
|
|
|
162
174
|
explicitProfile: boolean,
|
|
163
175
|
): Promise<void> {
|
|
164
176
|
const options = parseInitCommandOptions(input, explicitProfile);
|
|
177
|
+
const version = readPackageVersion();
|
|
178
|
+
const previousInitialization = readInitializationReceipt(agentBotHome());
|
|
165
179
|
let initializationLock = options.reset
|
|
166
180
|
? acquireInitializationLock(agentBotHome())
|
|
167
181
|
: undefined;
|
|
168
182
|
let paths: InitializationResult;
|
|
169
|
-
let initialized: Omit<InitCommandResult, "server">;
|
|
183
|
+
let initialized: Omit<InitCommandResult, "server" | "welcome">;
|
|
170
184
|
try {
|
|
171
185
|
if (options.reset) await assertResetProfileServerStopped(configPath);
|
|
172
186
|
paths = initializeAgentBot({ configPath, reset: options.reset });
|
|
173
187
|
if (!options.json) printInitializationPaths(paths);
|
|
174
|
-
const
|
|
175
|
-
const defaultAgent = await
|
|
188
|
+
const inspectedAgents = await initializeSupportedAgents(options.json);
|
|
189
|
+
const defaultAgent = await configureAgentsAndDefault(
|
|
190
|
+
paths.config.path,
|
|
191
|
+
inspectedAgents,
|
|
192
|
+
options.json,
|
|
193
|
+
shouldConfigureAgentsDuringInitialization(paths.config.status),
|
|
194
|
+
);
|
|
195
|
+
const configuredAgents = readConfiguredAgentSelection(paths.config.path).agents.map((agent) => agent.name);
|
|
196
|
+
const configuredAgentNames = new Set(configuredAgents);
|
|
197
|
+
const agents = inspectedAgents.map((agent) => ({
|
|
198
|
+
...agent,
|
|
199
|
+
configured: configuredAgentNames.has(agent.id),
|
|
200
|
+
}));
|
|
176
201
|
initializationLock ??= acquireInitializationLock(paths.home.path);
|
|
177
202
|
cleanupFeishuCredentialTemporaryFiles(paths.env.path);
|
|
178
203
|
const feishu = await initializeFeishu(
|
|
179
204
|
paths,
|
|
180
205
|
options,
|
|
181
206
|
);
|
|
182
|
-
initialized = { ...paths, agents, defaultAgent, feishu };
|
|
207
|
+
initialized = { ...paths, agents, configuredAgents, defaultAgent, feishu };
|
|
183
208
|
} finally {
|
|
184
209
|
initializationLock?.release();
|
|
185
210
|
}
|
|
@@ -189,9 +214,45 @@ async function initCommand(
|
|
|
189
214
|
process.stdout.write(cliText("\nStarting Agent Bot server...\n", "\n正在启动 Agent Bot 服务...\n"));
|
|
190
215
|
}
|
|
191
216
|
const server = await startInitializedServer({ skipFeishu: options.skipFeishu, configPath });
|
|
192
|
-
const
|
|
217
|
+
const welcomeKind = resolveInitializationWelcomeKind({
|
|
218
|
+
firstInitialization: paths.config.status === "created",
|
|
219
|
+
previousVersion: previousInitialization?.version,
|
|
220
|
+
currentVersion: version,
|
|
221
|
+
});
|
|
222
|
+
let welcome: InitializationWelcomeResult;
|
|
223
|
+
if (options.skipFeishu) {
|
|
224
|
+
welcome = { status: "skipped", kind: welcomeKind, reason: "feishu-skipped" };
|
|
225
|
+
} else {
|
|
226
|
+
try {
|
|
227
|
+
welcome = await sendInitializationWelcome({
|
|
228
|
+
configPath,
|
|
229
|
+
version,
|
|
230
|
+
previousVersion: previousInitialization?.version,
|
|
231
|
+
kind: welcomeKind,
|
|
232
|
+
activationPending: server.status === "restart-scheduled",
|
|
233
|
+
});
|
|
234
|
+
} catch (error) {
|
|
235
|
+
welcome = {
|
|
236
|
+
status: "failed",
|
|
237
|
+
kind: welcomeKind,
|
|
238
|
+
message: error instanceof Error ? error.message : String(error),
|
|
239
|
+
};
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
try {
|
|
243
|
+
writeInitializationReceipt(paths.home.path, version);
|
|
244
|
+
} catch (error) {
|
|
245
|
+
process.stderr.write(`${cliText(
|
|
246
|
+
"Warning: Could not save initialization version metadata: ",
|
|
247
|
+
"警告:无法保存初始化版本信息:",
|
|
248
|
+
)}${error instanceof Error ? error.message : String(error)}\n`);
|
|
249
|
+
}
|
|
250
|
+
const result: InitCommandResult = { ...initialized, server, welcome };
|
|
193
251
|
if (options.json) printJson(result);
|
|
194
|
-
else
|
|
252
|
+
else {
|
|
253
|
+
printInitializationServerResult(server);
|
|
254
|
+
printInitializationWelcomeResult(welcome);
|
|
255
|
+
}
|
|
195
256
|
}
|
|
196
257
|
|
|
197
258
|
async function initializeSupportedAgents(json: boolean): Promise<InitializedAgent[]> {
|
|
@@ -277,49 +338,81 @@ async function initializeSupportedAgents(json: boolean): Promise<InitializedAgen
|
|
|
277
338
|
return initialized;
|
|
278
339
|
}
|
|
279
340
|
|
|
280
|
-
async function
|
|
341
|
+
async function configureAgentsAndDefault(
|
|
281
342
|
configPath: string,
|
|
282
343
|
inspections: InitializedAgent[],
|
|
283
344
|
json: boolean,
|
|
345
|
+
configureAgents: boolean,
|
|
284
346
|
): Promise<InitCommandResult["defaultAgent"]> {
|
|
285
347
|
const output = json ? process.stderr : process.stdout;
|
|
286
348
|
const configured = readConfiguredAgentSelection(configPath);
|
|
287
|
-
const
|
|
288
|
-
|
|
289
|
-
|
|
349
|
+
const configuredDefaultIsValid = Boolean(
|
|
350
|
+
configured.defaultAgent
|
|
351
|
+
&& configured.agents.some((agent) => agent.name === configured.defaultAgent),
|
|
352
|
+
);
|
|
353
|
+
if (!configureAgents) {
|
|
354
|
+
if (!configuredDefaultIsValid) {
|
|
290
355
|
throw new Error(cliText(
|
|
291
|
-
"
|
|
292
|
-
"
|
|
356
|
+
"The existing Profile has no valid default Agent. Set defaults.agent in config.yaml, then run agentbot init again.",
|
|
357
|
+
"现有 Profile 没有有效的默认 Agent。请在 config.yaml 中设置 defaults.agent,然后重新运行 agentbot init。",
|
|
293
358
|
));
|
|
294
359
|
}
|
|
295
360
|
output.write(cliText(
|
|
296
|
-
`Default Agent: ${configured.defaultAgent} (
|
|
297
|
-
`默认 Agent:${configured.defaultAgent}
|
|
361
|
+
`Default Agent: ${configured.defaultAgent} (unchanged)\n`,
|
|
362
|
+
`默认 Agent:${configured.defaultAgent}(保持不变)\n`,
|
|
298
363
|
));
|
|
299
|
-
return { name: configured.defaultAgent
|
|
364
|
+
return { name: configured.defaultAgent!, status: "existing" };
|
|
300
365
|
}
|
|
366
|
+
|
|
367
|
+
const choices = selectableDefaultAgents(configured.agents, inspections);
|
|
301
368
|
if (choices.length === 0) {
|
|
302
369
|
throw new Error(cliText(
|
|
303
|
-
"No
|
|
304
|
-
"
|
|
370
|
+
"No installed supported Agent was detected. Install Codex or TraeX, then run agentbot init again.",
|
|
371
|
+
"没有检测到已安装且受支持的 Agent。请安装 Codex 或 TraeX,然后重新运行 agentbot init。",
|
|
305
372
|
));
|
|
306
373
|
}
|
|
307
374
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
const
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
const
|
|
319
|
-
output.write(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
375
|
+
let selectedAgents = choices;
|
|
376
|
+
if (process.stdin.isTTY && choices.length > 1) {
|
|
377
|
+
output.write(cliText("\nSelect Agents to configure:\n", "\n请选择要配置的 Agent:\n"));
|
|
378
|
+
for (const [index, choice] of choices.entries()) {
|
|
379
|
+
output.write(` ${index + 1}. ${choice.name} - ${choice.title} (${choice.installedVersion})\n`);
|
|
380
|
+
}
|
|
381
|
+
const selectedIndexes = await promptForConfiguredAgents(choices);
|
|
382
|
+
selectedAgents = selectedIndexes.flatMap((index) => choices[index] ? [choices[index]!] : []);
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
const selectedNames = selectedAgents.map((agent) => agent.name);
|
|
386
|
+
output.write(cliText(
|
|
387
|
+
`Configured Agents: ${selectedNames.join(", ")}\n`,
|
|
388
|
+
`已配置 Agent:${selectedNames.join("、")}\n`,
|
|
389
|
+
));
|
|
390
|
+
|
|
391
|
+
let selectedDefault = selectedAgents[0]!;
|
|
392
|
+
if (selectedAgents.length > 1) {
|
|
393
|
+
if (process.stdin.isTTY) {
|
|
394
|
+
output.write(cliText("\nSelect the default Agent:\n", "\n请选择默认 Agent:\n"));
|
|
395
|
+
for (const [index, choice] of selectedAgents.entries()) {
|
|
396
|
+
const current = choice.name === configured.defaultAgent
|
|
397
|
+
? cliText(" [current]", " [当前]")
|
|
398
|
+
: "";
|
|
399
|
+
output.write(` ${index + 1}. ${choice.name} - ${choice.title} (${choice.installedVersion})${current}\n`);
|
|
400
|
+
}
|
|
401
|
+
selectedDefault = selectedAgents[
|
|
402
|
+
await promptForDefaultAgent(selectedAgents, configured.defaultAgent)
|
|
403
|
+
]!;
|
|
404
|
+
} else {
|
|
405
|
+
selectedDefault = selectedAgents.find((agent) => agent.name === configured.defaultAgent)
|
|
406
|
+
?? selectedAgents[0]!;
|
|
407
|
+
}
|
|
408
|
+
}
|
|
409
|
+
|
|
410
|
+
const updated = writeConfiguredAgentSelection(configPath, selectedNames, selectedDefault.name);
|
|
411
|
+
output.write(cliText(
|
|
412
|
+
`Default Agent: ${selectedDefault.name}${process.stdin.isTTY ? "" : " (selected automatically)"}\n`,
|
|
413
|
+
`默认 Agent:${selectedDefault.name}${process.stdin.isTTY ? "" : "(已自动选择)"}\n`,
|
|
414
|
+
));
|
|
415
|
+
return { name: selectedDefault.name, status: updated ? "selected" : "existing" };
|
|
323
416
|
}
|
|
324
417
|
|
|
325
418
|
function promptForAgentMaintenance(choiceCount: number): Promise<number[]> {
|
|
@@ -356,6 +449,40 @@ function promptForAgentMaintenance(choiceCount: number): Promise<number[]> {
|
|
|
356
449
|
});
|
|
357
450
|
}
|
|
358
451
|
|
|
452
|
+
function promptForConfiguredAgents(choices: SelectableDefaultAgent[]): Promise<number[]> {
|
|
453
|
+
const readline = createInterface({ input: process.stdin, output: process.stderr });
|
|
454
|
+
return new Promise((resolve, reject) => {
|
|
455
|
+
let settled = false;
|
|
456
|
+
const finish = (selection: number[]): void => {
|
|
457
|
+
settled = true;
|
|
458
|
+
readline.close();
|
|
459
|
+
resolve(selection);
|
|
460
|
+
};
|
|
461
|
+
const ask = (): void => {
|
|
462
|
+
readline.question(cliText(
|
|
463
|
+
"Enter numbers or Agent names separated by commas, type all, or press Enter for all: ",
|
|
464
|
+
"请输入 Agent 编号或标准名(多个用逗号分隔),输入 all 或直接回车选择全部:",
|
|
465
|
+
), (answer) => {
|
|
466
|
+
const selection = resolveAgentConfigurationChoices(answer, choices);
|
|
467
|
+
if (selection) {
|
|
468
|
+
finish(selection);
|
|
469
|
+
return;
|
|
470
|
+
}
|
|
471
|
+
process.stderr.write(cliText(
|
|
472
|
+
`Select at least one Agent using numbers from 1 to ${choices.length} or standard names.\n`,
|
|
473
|
+
`请使用 1 到 ${choices.length} 之间的编号或标准名,至少选择一个 Agent。\n`,
|
|
474
|
+
));
|
|
475
|
+
ask();
|
|
476
|
+
});
|
|
477
|
+
};
|
|
478
|
+
listenForPromptCancellation(readline, () => {
|
|
479
|
+
settled = true;
|
|
480
|
+
reject(new Error(cliText("Initialization was cancelled.", "初始化已取消。")));
|
|
481
|
+
}, () => settled);
|
|
482
|
+
ask();
|
|
483
|
+
});
|
|
484
|
+
}
|
|
485
|
+
|
|
359
486
|
function promptForDefaultAgent(
|
|
360
487
|
choices: SelectableDefaultAgent[],
|
|
361
488
|
currentAgent?: string,
|
|
@@ -1002,11 +1129,12 @@ function printInitializationPaths(result: InitializationResult): void {
|
|
|
1002
1129
|
process.stdout.write(`${cliText("Log directory: ", "日志目录:")}${result.logs.path} (${initializationStatusLabel(result.logs.status)})\n`);
|
|
1003
1130
|
}
|
|
1004
1131
|
|
|
1005
|
-
function printInitializationResult(result: Omit<InitCommandResult, "server">): void {
|
|
1132
|
+
function printInitializationResult(result: Omit<InitCommandResult, "server" | "welcome">): void {
|
|
1006
1133
|
process.stdout.write(cliText(
|
|
1007
1134
|
"\nAgent Bot initialization completed.\n",
|
|
1008
1135
|
"\nAgent Bot 初始化完成。\n",
|
|
1009
1136
|
));
|
|
1137
|
+
process.stdout.write(`${cliText("Configured Agents: ", "已配置 Agent:")}${result.configuredAgents.join(", ")}\n`);
|
|
1010
1138
|
process.stdout.write(`${cliText("Default Agent: ", "默认 Agent:")}${result.defaultAgent.name}\n`);
|
|
1011
1139
|
if (result.feishu.status === "created") {
|
|
1012
1140
|
process.stdout.write(cliText(
|
|
@@ -1079,6 +1207,29 @@ function printInitializationServerResult(result: InitCommandResult["server"]): v
|
|
|
1079
1207
|
printServerStartResult(result);
|
|
1080
1208
|
}
|
|
1081
1209
|
|
|
1210
|
+
function printInitializationWelcomeResult(result: InitializationWelcomeResult): void {
|
|
1211
|
+
if (result.status === "sent") {
|
|
1212
|
+
process.stdout.write(cliText(
|
|
1213
|
+
"Welcome card: sent to your Lark private chat.\n",
|
|
1214
|
+
"欢迎卡片:已发送到你的飞书私聊。\n",
|
|
1215
|
+
));
|
|
1216
|
+
return;
|
|
1217
|
+
}
|
|
1218
|
+
if (result.status === "failed") {
|
|
1219
|
+
process.stderr.write(cliText(
|
|
1220
|
+
`Warning: The private welcome card could not be sent: ${result.message}\n`,
|
|
1221
|
+
`警告:无法发送私聊欢迎卡片:${result.message}\n`,
|
|
1222
|
+
));
|
|
1223
|
+
return;
|
|
1224
|
+
}
|
|
1225
|
+
if (result.reason === "missing-user-open-id") {
|
|
1226
|
+
process.stderr.write(cliText(
|
|
1227
|
+
"Warning: The private welcome card was skipped because FEISHU_USER_OPEN_ID is not available. Send the bot a private message, then run agentbot init again.\n",
|
|
1228
|
+
"警告:尚未获得 FEISHU_USER_OPEN_ID,无法发送私聊欢迎卡片。请先私聊机器人,再次运行 agentbot init。\n",
|
|
1229
|
+
));
|
|
1230
|
+
}
|
|
1231
|
+
}
|
|
1232
|
+
|
|
1082
1233
|
function printServerStartResult(result: ServerStartResult): void {
|
|
1083
1234
|
process.stdout.write(
|
|
1084
1235
|
result.status === "already-running"
|
|
@@ -35,6 +35,26 @@ export interface StartupStatusView {
|
|
|
35
35
|
};
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export type InitializationWelcomeKind = "first" | "upgrade" | "refresh";
|
|
39
|
+
|
|
40
|
+
export interface InitializationWelcomeFeature {
|
|
41
|
+
icon: string;
|
|
42
|
+
title: string;
|
|
43
|
+
description: string;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export interface InitializationWelcomeView {
|
|
47
|
+
kind: InitializationWelcomeKind;
|
|
48
|
+
version: string;
|
|
49
|
+
previousVersion?: string;
|
|
50
|
+
activationPending?: boolean;
|
|
51
|
+
defaultAgentName: string;
|
|
52
|
+
defaultAgentTitle: string;
|
|
53
|
+
availableAgents: string[];
|
|
54
|
+
logoPath: string;
|
|
55
|
+
features: InitializationWelcomeFeature[];
|
|
56
|
+
}
|
|
57
|
+
|
|
38
58
|
export interface SafeRestartStatusView {
|
|
39
59
|
scheduleId: number;
|
|
40
60
|
reason: string;
|
|
@@ -679,6 +699,113 @@ export class CardRenderer {
|
|
|
679
699
|
return sectionCard("Agent Bot 已启动", [markdown(lines.join("\n"))], "green");
|
|
680
700
|
}
|
|
681
701
|
|
|
702
|
+
renderInitializationWelcome(view: InitializationWelcomeView): Record<string, unknown> {
|
|
703
|
+
const title = view.kind === "first"
|
|
704
|
+
? "欢迎使用 Agent Bot"
|
|
705
|
+
: view.kind === "upgrade"
|
|
706
|
+
? "Agent Bot 已更新"
|
|
707
|
+
: "Agent Bot 已准备就绪";
|
|
708
|
+
const subtitle = view.activationPending
|
|
709
|
+
? "配置已完成,安全重启后生效"
|
|
710
|
+
: view.kind === "first"
|
|
711
|
+
? "本地 Agent 已接入飞书"
|
|
712
|
+
: view.kind === "upgrade"
|
|
713
|
+
? `新版本 ${view.version} 已生效`
|
|
714
|
+
: "初始化配置已刷新";
|
|
715
|
+
const activationNote = view.activationPending
|
|
716
|
+
? "当前任务完成并安全重启后生效。"
|
|
717
|
+
: undefined;
|
|
718
|
+
const intro = view.kind === "first"
|
|
719
|
+
? "**初始化完成**\n从现在起,你可以直接在飞书里把任务交给本机 Agent,并随时查看进度、切换任务或创建分支。"
|
|
720
|
+
: view.kind === "upgrade"
|
|
721
|
+
? `**升级完成**\n${view.previousVersion ? `${inlineCode(view.previousVersion)} → ` : ""}${inlineCode(view.version)} 已准备好。${activationNote ?? "下面是本版值得关注的能力。"}`
|
|
722
|
+
: `**配置刷新完成**\n${inlineCode(view.version)} 已重新检查配置、Agent 和飞书连接。${activationNote ?? ""}`;
|
|
723
|
+
const logo = {
|
|
724
|
+
...localCardImage(view.logoPath, "Agent Bot logo"),
|
|
725
|
+
preview: false,
|
|
726
|
+
};
|
|
727
|
+
const featureColumns = view.features.slice(0, 4).map((feature) => ({
|
|
728
|
+
tag: "column",
|
|
729
|
+
width: "weighted",
|
|
730
|
+
weight: 1,
|
|
731
|
+
vertical_align: "top",
|
|
732
|
+
elements: [markdown([
|
|
733
|
+
`${feature.icon} **${feature.title}**`,
|
|
734
|
+
`<font color='grey'>${feature.description}</font>`,
|
|
735
|
+
].join("\n"))],
|
|
736
|
+
}));
|
|
737
|
+
const featureRows = [0, 2].flatMap((start) => {
|
|
738
|
+
const columns = featureColumns.slice(start, start + 2);
|
|
739
|
+
return columns.length > 0
|
|
740
|
+
? [{
|
|
741
|
+
tag: "column_set",
|
|
742
|
+
flex_mode: "none",
|
|
743
|
+
horizontal_spacing: "16px",
|
|
744
|
+
vertical_align: "top",
|
|
745
|
+
columns,
|
|
746
|
+
}]
|
|
747
|
+
: [];
|
|
748
|
+
});
|
|
749
|
+
const availableAgents = view.availableAgents.length > 0
|
|
750
|
+
? view.availableAgents.map((agent) => inlineCode(agent)).join(" · ")
|
|
751
|
+
: inlineCode(view.defaultAgentName);
|
|
752
|
+
return {
|
|
753
|
+
schema: "2.0",
|
|
754
|
+
config: {
|
|
755
|
+
update_multi: true,
|
|
756
|
+
width_mode: "fill",
|
|
757
|
+
},
|
|
758
|
+
header: {
|
|
759
|
+
template: view.kind === "first" ? "turquoise" : view.kind === "upgrade" ? "blue" : "green",
|
|
760
|
+
title: { tag: "plain_text", content: title },
|
|
761
|
+
subtitle: { tag: "plain_text", content: subtitle },
|
|
762
|
+
padding: "12px 12px 12px 12px",
|
|
763
|
+
},
|
|
764
|
+
body: {
|
|
765
|
+
direction: "vertical",
|
|
766
|
+
vertical_spacing: "12px",
|
|
767
|
+
padding: "12px 12px 12px 12px",
|
|
768
|
+
elements: [
|
|
769
|
+
{
|
|
770
|
+
tag: "column_set",
|
|
771
|
+
flex_mode: "none",
|
|
772
|
+
horizontal_spacing: "16px",
|
|
773
|
+
vertical_align: "center",
|
|
774
|
+
columns: [
|
|
775
|
+
{
|
|
776
|
+
tag: "column",
|
|
777
|
+
width: "weighted",
|
|
778
|
+
weight: 1,
|
|
779
|
+
vertical_align: "center",
|
|
780
|
+
elements: [logo],
|
|
781
|
+
},
|
|
782
|
+
{
|
|
783
|
+
tag: "column",
|
|
784
|
+
width: "weighted",
|
|
785
|
+
weight: 3,
|
|
786
|
+
vertical_align: "center",
|
|
787
|
+
elements: [markdown(intro)],
|
|
788
|
+
},
|
|
789
|
+
],
|
|
790
|
+
},
|
|
791
|
+
{ tag: "hr" },
|
|
792
|
+
markdown(`**${view.kind === "upgrade" ? "本版亮点" : "你可以这样使用"}**`),
|
|
793
|
+
...featureRows,
|
|
794
|
+
{ tag: "hr" },
|
|
795
|
+
markdown("> 直接发送消息即可开始;发送 `/new` 创建新任务;发送 `/help` 查看全部命令。"),
|
|
796
|
+
{
|
|
797
|
+
...markdown(`**版本** ${inlineCode(view.version)} · **默认 Agent** ${inlineCode(view.defaultAgentTitle)} · **可用 Agent** ${availableAgents}`),
|
|
798
|
+
text_size: "notation",
|
|
799
|
+
},
|
|
800
|
+
{
|
|
801
|
+
...markdown("📋 [查看更新日志](https://github.com/keyou/agent-bot/blob/master/CHANGELOG.md)"),
|
|
802
|
+
text_size: "notation",
|
|
803
|
+
},
|
|
804
|
+
],
|
|
805
|
+
},
|
|
806
|
+
};
|
|
807
|
+
}
|
|
808
|
+
|
|
682
809
|
renderTurn(state: TurnViewState): Record<string, unknown> {
|
|
683
810
|
const elements = renderTurnElements(state, "hidden");
|
|
684
811
|
if (isTurnStoppable(state.status)) {
|
|
@@ -161,17 +161,7 @@ export class SafeRestartNotifier {
|
|
|
161
161
|
}
|
|
162
162
|
|
|
163
163
|
private collectNotificationTargets(status: SafeRestartStatus): void {
|
|
164
|
-
const
|
|
165
|
-
?? this.store.listChatContexts("p2p").map(({ contextKey }) => ({ contextKey }));
|
|
166
|
-
const recentTargets: RestartNotificationTarget[] = this.store.listRecentlyActiveChatContexts(
|
|
167
|
-
new Date(Date.now() - 60_000),
|
|
168
|
-
)
|
|
169
|
-
.filter((chat) => !isThreadContextKey(chat.contextKey))
|
|
170
|
-
.map(({ contextKey }) => ({ contextKey }));
|
|
171
|
-
for (const target of [
|
|
172
|
-
...requestedTargets,
|
|
173
|
-
...recentTargets,
|
|
174
|
-
]) {
|
|
164
|
+
for (const target of status.notificationTargets ?? []) {
|
|
175
165
|
const contextKey = target.contextKey.trim();
|
|
176
166
|
if (!contextKey) continue;
|
|
177
167
|
const existing = this.notificationTargets.get(contextKey);
|