@keyou007/agent-bot 0.1.13-alpha.2 → 0.1.13-alpha.3
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 +5 -0
- package/README.md +1 -1
- package/README.zh.md +1 -1
- package/dist/cli/InitializationWelcome.js +116 -0
- package/dist/cli/InitializationWelcome.js.map +1 -0
- package/dist/cli.js +54 -2
- package/dist/cli.js.map +1 -1
- package/dist/feishu/CardRenderer.js +121 -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 +3 -1
- package/docs/technical-reference.zh.md +3 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/src/cli/InitializationWelcome.ts +160 -0
- package/src/cli.ts +74 -4
- package/src/feishu/CardRenderer.ts +143 -0
- package/src/supervision/SafeRestartNotifier.ts +1 -11
package/src/cli.ts
CHANGED
|
@@ -56,6 +56,13 @@ import {
|
|
|
56
56
|
import { formatServerStatus, withConfiguredFeishuAppId } from "./cli/serverStatus.js";
|
|
57
57
|
import { resolveSystemSkillsRoot, SkillRegistry, type SkillRegistrationStatus } from "./cli/SkillRegistry.js";
|
|
58
58
|
import { readPackageVersion } from "./cli/packageVersion.js";
|
|
59
|
+
import {
|
|
60
|
+
readInitializationReceipt,
|
|
61
|
+
resolveInitializationWelcomeKind,
|
|
62
|
+
sendInitializationWelcome,
|
|
63
|
+
writeInitializationReceipt,
|
|
64
|
+
type InitializationWelcomeResult,
|
|
65
|
+
} from "./cli/InitializationWelcome.js";
|
|
59
66
|
import { applyExplicitProfile, parseGlobalOptions } from "./cli/profile.js";
|
|
60
67
|
import { printVerificationQrAndLink } from "./cli/VerificationOutput.js";
|
|
61
68
|
import {
|
|
@@ -147,6 +154,7 @@ interface InitCommandResult extends InitializationResult {
|
|
|
147
154
|
configuration?: EnsureFeishuAppConfigurationResult;
|
|
148
155
|
};
|
|
149
156
|
server: InitializationServerResult;
|
|
157
|
+
welcome: InitializationWelcomeResult;
|
|
150
158
|
}
|
|
151
159
|
|
|
152
160
|
interface InitializedAgent extends SupportedAgentInspection {
|
|
@@ -162,11 +170,13 @@ async function initCommand(
|
|
|
162
170
|
explicitProfile: boolean,
|
|
163
171
|
): Promise<void> {
|
|
164
172
|
const options = parseInitCommandOptions(input, explicitProfile);
|
|
173
|
+
const version = readPackageVersion();
|
|
174
|
+
const previousInitialization = readInitializationReceipt(agentBotHome());
|
|
165
175
|
let initializationLock = options.reset
|
|
166
176
|
? acquireInitializationLock(agentBotHome())
|
|
167
177
|
: undefined;
|
|
168
178
|
let paths: InitializationResult;
|
|
169
|
-
let initialized: Omit<InitCommandResult, "server">;
|
|
179
|
+
let initialized: Omit<InitCommandResult, "server" | "welcome">;
|
|
170
180
|
try {
|
|
171
181
|
if (options.reset) await assertResetProfileServerStopped(configPath);
|
|
172
182
|
paths = initializeAgentBot({ configPath, reset: options.reset });
|
|
@@ -189,9 +199,46 @@ async function initCommand(
|
|
|
189
199
|
process.stdout.write(cliText("\nStarting Agent Bot server...\n", "\n正在启动 Agent Bot 服务...\n"));
|
|
190
200
|
}
|
|
191
201
|
const server = await startInitializedServer({ skipFeishu: options.skipFeishu, configPath });
|
|
192
|
-
const
|
|
202
|
+
const welcomeKind = resolveInitializationWelcomeKind({
|
|
203
|
+
firstInitialization: paths.config.status === "created",
|
|
204
|
+
previousVersion: previousInitialization?.version,
|
|
205
|
+
currentVersion: version,
|
|
206
|
+
});
|
|
207
|
+
let welcome: InitializationWelcomeResult;
|
|
208
|
+
if (options.skipFeishu) {
|
|
209
|
+
welcome = { status: "skipped", kind: welcomeKind, reason: "feishu-skipped" };
|
|
210
|
+
} else {
|
|
211
|
+
try {
|
|
212
|
+
welcome = await sendInitializationWelcome({
|
|
213
|
+
configPath,
|
|
214
|
+
language: cliLanguage,
|
|
215
|
+
version,
|
|
216
|
+
previousVersion: previousInitialization?.version,
|
|
217
|
+
kind: welcomeKind,
|
|
218
|
+
activationPending: server.status === "restart-scheduled",
|
|
219
|
+
});
|
|
220
|
+
} catch (error) {
|
|
221
|
+
welcome = {
|
|
222
|
+
status: "failed",
|
|
223
|
+
kind: welcomeKind,
|
|
224
|
+
message: error instanceof Error ? error.message : String(error),
|
|
225
|
+
};
|
|
226
|
+
}
|
|
227
|
+
}
|
|
228
|
+
try {
|
|
229
|
+
writeInitializationReceipt(paths.home.path, version);
|
|
230
|
+
} catch (error) {
|
|
231
|
+
process.stderr.write(`${cliText(
|
|
232
|
+
"Warning: Could not save initialization version metadata: ",
|
|
233
|
+
"警告:无法保存初始化版本信息:",
|
|
234
|
+
)}${error instanceof Error ? error.message : String(error)}\n`);
|
|
235
|
+
}
|
|
236
|
+
const result: InitCommandResult = { ...initialized, server, welcome };
|
|
193
237
|
if (options.json) printJson(result);
|
|
194
|
-
else
|
|
238
|
+
else {
|
|
239
|
+
printInitializationServerResult(server);
|
|
240
|
+
printInitializationWelcomeResult(welcome);
|
|
241
|
+
}
|
|
195
242
|
}
|
|
196
243
|
|
|
197
244
|
async function initializeSupportedAgents(json: boolean): Promise<InitializedAgent[]> {
|
|
@@ -1002,7 +1049,7 @@ function printInitializationPaths(result: InitializationResult): void {
|
|
|
1002
1049
|
process.stdout.write(`${cliText("Log directory: ", "日志目录:")}${result.logs.path} (${initializationStatusLabel(result.logs.status)})\n`);
|
|
1003
1050
|
}
|
|
1004
1051
|
|
|
1005
|
-
function printInitializationResult(result: Omit<InitCommandResult, "server">): void {
|
|
1052
|
+
function printInitializationResult(result: Omit<InitCommandResult, "server" | "welcome">): void {
|
|
1006
1053
|
process.stdout.write(cliText(
|
|
1007
1054
|
"\nAgent Bot initialization completed.\n",
|
|
1008
1055
|
"\nAgent Bot 初始化完成。\n",
|
|
@@ -1079,6 +1126,29 @@ function printInitializationServerResult(result: InitCommandResult["server"]): v
|
|
|
1079
1126
|
printServerStartResult(result);
|
|
1080
1127
|
}
|
|
1081
1128
|
|
|
1129
|
+
function printInitializationWelcomeResult(result: InitializationWelcomeResult): void {
|
|
1130
|
+
if (result.status === "sent") {
|
|
1131
|
+
process.stdout.write(cliText(
|
|
1132
|
+
"Welcome card: sent to your Lark private chat.\n",
|
|
1133
|
+
"欢迎卡片:已发送到你的飞书私聊。\n",
|
|
1134
|
+
));
|
|
1135
|
+
return;
|
|
1136
|
+
}
|
|
1137
|
+
if (result.status === "failed") {
|
|
1138
|
+
process.stderr.write(cliText(
|
|
1139
|
+
`Warning: The private welcome card could not be sent: ${result.message}\n`,
|
|
1140
|
+
`警告:无法发送私聊欢迎卡片:${result.message}\n`,
|
|
1141
|
+
));
|
|
1142
|
+
return;
|
|
1143
|
+
}
|
|
1144
|
+
if (result.reason === "missing-user-open-id") {
|
|
1145
|
+
process.stderr.write(cliText(
|
|
1146
|
+
"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",
|
|
1147
|
+
"警告:尚未获得 FEISHU_USER_OPEN_ID,无法发送私聊欢迎卡片。请先私聊机器人,再次运行 agentbot init。\n",
|
|
1148
|
+
));
|
|
1149
|
+
}
|
|
1150
|
+
}
|
|
1151
|
+
|
|
1082
1152
|
function printServerStartResult(result: ServerStartResult): void {
|
|
1083
1153
|
process.stdout.write(
|
|
1084
1154
|
result.status === "already-running"
|
|
@@ -35,6 +35,27 @@ 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
|
+
language: "en" | "zh";
|
|
49
|
+
version: string;
|
|
50
|
+
previousVersion?: string;
|
|
51
|
+
activationPending?: boolean;
|
|
52
|
+
defaultAgentName: string;
|
|
53
|
+
defaultAgentTitle: string;
|
|
54
|
+
availableAgents: string[];
|
|
55
|
+
logoPath: string;
|
|
56
|
+
features: InitializationWelcomeFeature[];
|
|
57
|
+
}
|
|
58
|
+
|
|
38
59
|
export interface SafeRestartStatusView {
|
|
39
60
|
scheduleId: number;
|
|
40
61
|
reason: string;
|
|
@@ -679,6 +700,128 @@ export class CardRenderer {
|
|
|
679
700
|
return sectionCard("Agent Bot 已启动", [markdown(lines.join("\n"))], "green");
|
|
680
701
|
}
|
|
681
702
|
|
|
703
|
+
renderInitializationWelcome(view: InitializationWelcomeView): Record<string, unknown> {
|
|
704
|
+
const chinese = view.language === "zh";
|
|
705
|
+
const title = view.kind === "first"
|
|
706
|
+
? (chinese ? "欢迎使用 Agent Bot" : "Welcome to Agent Bot")
|
|
707
|
+
: view.kind === "upgrade"
|
|
708
|
+
? (chinese ? "Agent Bot 已更新" : "Agent Bot is updated")
|
|
709
|
+
: (chinese ? "Agent Bot 已准备就绪" : "Agent Bot is ready");
|
|
710
|
+
const subtitle = view.activationPending
|
|
711
|
+
? (chinese ? "配置已完成,安全重启后生效" : "Configured and pending a safe restart")
|
|
712
|
+
: view.kind === "first"
|
|
713
|
+
? (chinese ? "本地 Agent 已接入飞书" : "Your local Agents are now available in Lark")
|
|
714
|
+
: view.kind === "upgrade"
|
|
715
|
+
? (chinese ? `新版本 ${view.version} 已生效` : `Version ${view.version} is now active`)
|
|
716
|
+
: (chinese ? "初始化配置已刷新" : "Initialization settings were refreshed");
|
|
717
|
+
const activationNote = view.activationPending
|
|
718
|
+
? (chinese ? "当前任务完成并安全重启后生效。" : "It will take effect after active work finishes and the safe restart completes.")
|
|
719
|
+
: undefined;
|
|
720
|
+
const intro = view.kind === "first"
|
|
721
|
+
? (chinese
|
|
722
|
+
? "**初始化完成**\n从现在起,你可以直接在飞书里把任务交给本机 Agent,并随时查看进度、切换任务或创建分支。"
|
|
723
|
+
: "**Setup complete**\nYou can now work with local Agents from Lark, follow progress, switch tasks, and branch conversations.")
|
|
724
|
+
: view.kind === "upgrade"
|
|
725
|
+
? (chinese
|
|
726
|
+
? `**升级完成**\n${view.previousVersion ? `${inlineCode(view.previousVersion)} → ` : ""}${inlineCode(view.version)} 已准备好。${activationNote ?? "下面是本版值得关注的能力。"}`
|
|
727
|
+
: `**Upgrade complete**\n${view.previousVersion ? `${inlineCode(view.previousVersion)} → ` : ""}${inlineCode(view.version)} is ready. ${activationNote ?? "Here is what is new."}`)
|
|
728
|
+
: (chinese
|
|
729
|
+
? `**配置刷新完成**\n${inlineCode(view.version)} 已重新检查配置、Agent 和飞书连接。${activationNote ?? ""}`
|
|
730
|
+
: `**Configuration refreshed**\n${inlineCode(view.version)} rechecked your configuration, Agents, and Lark connection. ${activationNote ?? ""}`);
|
|
731
|
+
const logo = {
|
|
732
|
+
...localCardImage(view.logoPath, "Agent Bot logo"),
|
|
733
|
+
preview: false,
|
|
734
|
+
};
|
|
735
|
+
const featureColumns = view.features.slice(0, 4).map((feature) => ({
|
|
736
|
+
tag: "column",
|
|
737
|
+
width: "weighted",
|
|
738
|
+
weight: 1,
|
|
739
|
+
vertical_align: "top",
|
|
740
|
+
elements: [markdown([
|
|
741
|
+
`${feature.icon} **${feature.title}**`,
|
|
742
|
+
`<font color='grey'>${feature.description}</font>`,
|
|
743
|
+
].join("\n"))],
|
|
744
|
+
}));
|
|
745
|
+
const featureRows = [0, 2].flatMap((start) => {
|
|
746
|
+
const columns = featureColumns.slice(start, start + 2);
|
|
747
|
+
return columns.length > 0
|
|
748
|
+
? [{
|
|
749
|
+
tag: "column_set",
|
|
750
|
+
flex_mode: "none",
|
|
751
|
+
horizontal_spacing: "16px",
|
|
752
|
+
vertical_align: "top",
|
|
753
|
+
columns,
|
|
754
|
+
}]
|
|
755
|
+
: [];
|
|
756
|
+
});
|
|
757
|
+
const availableAgents = view.availableAgents.length > 0
|
|
758
|
+
? view.availableAgents.map((agent) => inlineCode(agent)).join(" · ")
|
|
759
|
+
: inlineCode(view.defaultAgentName);
|
|
760
|
+
return {
|
|
761
|
+
schema: "2.0",
|
|
762
|
+
config: {
|
|
763
|
+
update_multi: true,
|
|
764
|
+
width_mode: "fill",
|
|
765
|
+
},
|
|
766
|
+
header: {
|
|
767
|
+
template: view.kind === "first" ? "turquoise" : view.kind === "upgrade" ? "blue" : "green",
|
|
768
|
+
title: { tag: "plain_text", content: title },
|
|
769
|
+
subtitle: { tag: "plain_text", content: subtitle },
|
|
770
|
+
padding: "12px 12px 12px 12px",
|
|
771
|
+
},
|
|
772
|
+
body: {
|
|
773
|
+
direction: "vertical",
|
|
774
|
+
vertical_spacing: "12px",
|
|
775
|
+
padding: "12px 12px 12px 12px",
|
|
776
|
+
elements: [
|
|
777
|
+
{
|
|
778
|
+
tag: "column_set",
|
|
779
|
+
flex_mode: "none",
|
|
780
|
+
horizontal_spacing: "16px",
|
|
781
|
+
vertical_align: "center",
|
|
782
|
+
columns: [
|
|
783
|
+
{
|
|
784
|
+
tag: "column",
|
|
785
|
+
width: "weighted",
|
|
786
|
+
weight: 1,
|
|
787
|
+
vertical_align: "center",
|
|
788
|
+
elements: [logo],
|
|
789
|
+
},
|
|
790
|
+
{
|
|
791
|
+
tag: "column",
|
|
792
|
+
width: "weighted",
|
|
793
|
+
weight: 3,
|
|
794
|
+
vertical_align: "center",
|
|
795
|
+
elements: [markdown(intro)],
|
|
796
|
+
},
|
|
797
|
+
],
|
|
798
|
+
},
|
|
799
|
+
{ tag: "hr" },
|
|
800
|
+
markdown(chinese
|
|
801
|
+
? `**${view.kind === "upgrade" ? "本版亮点" : "你可以这样使用"}**`
|
|
802
|
+
: `**${view.kind === "upgrade" ? "What's new" : "What you can do"}**`),
|
|
803
|
+
...featureRows,
|
|
804
|
+
{ tag: "hr" },
|
|
805
|
+
markdown(chinese
|
|
806
|
+
? "> 直接发送消息即可开始;发送 `/new` 创建新任务;发送 `/help` 查看全部命令。"
|
|
807
|
+
: "> Send a message to begin, `/new` for a new task, or `/help` for all commands."),
|
|
808
|
+
{
|
|
809
|
+
...markdown(chinese
|
|
810
|
+
? `**版本** ${inlineCode(view.version)} · **默认 Agent** ${inlineCode(view.defaultAgentTitle)} · **可用 Agent** ${availableAgents}`
|
|
811
|
+
: `**Version** ${inlineCode(view.version)} · **Default Agent** ${inlineCode(view.defaultAgentTitle)} · **Available** ${availableAgents}`),
|
|
812
|
+
text_size: "notation",
|
|
813
|
+
},
|
|
814
|
+
{
|
|
815
|
+
...markdown(chinese
|
|
816
|
+
? "📋 [查看更新日志](https://github.com/keyou/agent-bot/blob/master/CHANGELOG.md)"
|
|
817
|
+
: "📋 [View Changelog](https://github.com/keyou/agent-bot/blob/master/CHANGELOG.md)"),
|
|
818
|
+
text_size: "notation",
|
|
819
|
+
},
|
|
820
|
+
],
|
|
821
|
+
},
|
|
822
|
+
};
|
|
823
|
+
}
|
|
824
|
+
|
|
682
825
|
renderTurn(state: TurnViewState): Record<string, unknown> {
|
|
683
826
|
const elements = renderTurnElements(state, "hidden");
|
|
684
827
|
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);
|