@keyou007/agent-bot 0.1.10 → 0.1.12
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/.env.example +1 -1
- package/CHANGELOG.md +25 -0
- package/README.md +55 -43
- package/README.zh.md +55 -43
- package/assets/agent-bot-logo.png +0 -0
- package/config.example.yaml +11 -1
- package/dist/acp/AcpSessionManager.js +78 -46
- package/dist/acp/AcpSessionManager.js.map +1 -1
- package/dist/cli/FeishuAppConfiguration.js +1 -1
- package/dist/cli/FeishuAppConfiguration.js.map +1 -1
- package/dist/cli/FeishuAppRegistration.js +2 -2
- package/dist/cli/FeishuAppRegistration.js.map +1 -1
- package/dist/cli/Initializer.js +1 -1
- package/dist/cli/Initializer.js.map +1 -1
- package/dist/cli/ServerStarter.js +7 -2
- package/dist/cli/ServerStarter.js.map +1 -1
- package/dist/cli/controlProtocol.js.map +1 -1
- package/dist/cli/help.js +20 -16
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/taskGroupOptions.js +95 -0
- package/dist/cli/taskGroupOptions.js.map +1 -0
- package/dist/cli.js +74 -2
- package/dist/cli.js.map +1 -1
- package/dist/codex/AppServerConnection.js +15 -1
- package/dist/codex/AppServerConnection.js.map +1 -1
- package/dist/codex/CodexLocalActivityDetector.js +4 -1
- package/dist/codex/CodexLocalActivityDetector.js.map +1 -1
- package/dist/codex/CodexProcessManager.js +1 -0
- package/dist/codex/CodexProcessManager.js.map +1 -1
- package/dist/codex/CodexRuntime.js +112 -11
- package/dist/codex/CodexRuntime.js.map +1 -1
- package/dist/commands/CommandRouter.js +64 -49
- package/dist/commands/CommandRouter.js.map +1 -1
- package/dist/config/loadConfig.js +11 -1
- package/dist/config/loadConfig.js.map +1 -1
- package/dist/config/schema.js +6 -1
- package/dist/config/schema.js.map +1 -1
- package/dist/console/ConsoleConnector.js +1 -1
- package/dist/console/ConsoleConnector.js.map +1 -1
- package/dist/console/ConsoleTurnPresenter.js +15 -8
- package/dist/console/ConsoleTurnPresenter.js.map +1 -1
- package/dist/deprecated-cli.js +5 -0
- package/dist/deprecated-cli.js.map +1 -0
- package/dist/feishu/CardRenderer.js +350 -15
- package/dist/feishu/CardRenderer.js.map +1 -1
- package/dist/feishu/FeishuMessageClient.js +51 -5
- package/dist/feishu/FeishuMessageClient.js.map +1 -1
- package/dist/feishu/FeishuTurnPresenter.js +17 -8
- package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
- package/dist/feishu/transport.js +1 -1
- package/dist/feishu/transport.js.map +1 -1
- package/dist/index.js +38 -19
- package/dist/index.js.map +1 -1
- package/dist/presentation/OutboundRouter.js +2 -2
- package/dist/presentation/OutboundRouter.js.map +1 -1
- package/dist/presentation/TurnStateReducer.js +2 -1
- package/dist/presentation/TurnStateReducer.js.map +1 -1
- package/dist/proxy/ProxySessionController.js +665 -225
- package/dist/proxy/ProxySessionController.js.map +1 -1
- package/dist/runtime/AcpRuntimeAdapter.js +1 -0
- package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
- package/dist/runtime/AgentRuntimeRegistry.js +7 -4
- package/dist/runtime/AgentRuntimeRegistry.js.map +1 -1
- package/dist/runtime/createAgentRuntimeRegistry.js +22 -0
- package/dist/runtime/createAgentRuntimeRegistry.js.map +1 -0
- package/dist/startup/SessionMetadataHydrator.js +2 -2
- package/dist/startup/SessionMetadataHydrator.js.map +1 -1
- package/dist/startup/StartupNotifier.js +1 -0
- package/dist/startup/StartupNotifier.js.map +1 -1
- package/dist/state/StateStore.js +21 -15
- package/dist/state/StateStore.js.map +1 -1
- package/dist/supervision/SafeRestartScheduler.js +5 -0
- package/dist/supervision/SafeRestartScheduler.js.map +1 -1
- package/dist/supervision/systemEnvironment.js +129 -0
- package/dist/supervision/systemEnvironment.js.map +1 -0
- package/dist/supervisor.js +13 -1
- package/dist/supervisor.js.map +1 -1
- package/docs/technical-reference.md +35 -21
- package/docs/technical-reference.zh.md +35 -21
- package/npm-shrinkwrap.json +4 -3
- package/package.json +4 -2
- package/skills/agent-bot/SKILL.md +73 -30
- package/src/acp/AcpSessionManager.ts +73 -54
- package/src/cli/FeishuAppConfiguration.ts +2 -2
- package/src/cli/FeishuAppRegistration.ts +4 -4
- package/src/cli/Initializer.ts +2 -2
- package/src/cli/ServerStarter.ts +8 -3
- package/src/cli/controlProtocol.ts +21 -1
- package/src/cli/help.ts +20 -16
- package/src/cli/taskGroupOptions.ts +149 -0
- package/src/cli.ts +98 -4
- package/src/codex/AppServerConnection.ts +21 -1
- package/src/codex/CodexLocalActivityDetector.ts +8 -1
- package/src/codex/CodexProcessManager.ts +1 -0
- package/src/codex/CodexRuntime.ts +137 -15
- package/src/commands/CommandRouter.ts +71 -49
- package/src/commands/commandTypes.ts +6 -11
- package/src/config/loadConfig.ts +11 -1
- package/src/config/schema.ts +7 -1
- package/src/console/ConsoleConnector.ts +1 -1
- package/src/console/ConsoleTurnPresenter.ts +21 -8
- package/src/deprecated-cli.ts +9 -0
- package/src/feishu/CardRenderer.ts +423 -15
- package/src/feishu/FeishuMessageClient.ts +66 -3
- package/src/feishu/FeishuTurnPresenter.ts +22 -3
- package/src/feishu/transport.ts +1 -1
- package/src/index.ts +54 -24
- package/src/presentation/OutboundRouter.ts +15 -3
- package/src/presentation/TurnStateReducer.ts +2 -0
- package/src/presentation/turnViewTypes.ts +1 -0
- package/src/proxy/ProxySessionController.ts +870 -228
- package/src/runtime/AcpRuntimeAdapter.ts +1 -0
- package/src/runtime/AgentRuntimeRegistry.ts +7 -6
- package/src/runtime/createAgentRuntimeRegistry.ts +25 -0
- package/src/runtime/types.ts +18 -0
- package/src/startup/SessionMetadataHydrator.ts +2 -2
- package/src/startup/StartupNotifier.ts +1 -0
- package/src/state/StateStore.ts +29 -15
- package/src/supervision/SafeRestartScheduler.ts +5 -0
- package/src/supervision/systemEnvironment.ts +174 -0
- package/src/supervisor.ts +12 -1
|
@@ -2,19 +2,16 @@ import type { Command } from "./commandTypes.js";
|
|
|
2
2
|
|
|
3
3
|
const COMMAND_NAMES = [
|
|
4
4
|
"agent",
|
|
5
|
-
"agents",
|
|
6
|
-
"ask",
|
|
7
5
|
"fork",
|
|
8
6
|
"forkgroup",
|
|
9
7
|
"goal",
|
|
10
8
|
"help",
|
|
11
|
-
"mode",
|
|
12
9
|
"model",
|
|
13
|
-
"modes",
|
|
14
10
|
"new",
|
|
15
11
|
"newgroup",
|
|
16
12
|
"nosteer",
|
|
17
13
|
"permissions",
|
|
14
|
+
"provider",
|
|
18
15
|
"queue",
|
|
19
16
|
"restart",
|
|
20
17
|
"sessions",
|
|
@@ -23,7 +20,6 @@ const COMMAND_NAMES = [
|
|
|
23
20
|
"switch",
|
|
24
21
|
"thinking",
|
|
25
22
|
"title",
|
|
26
|
-
"use",
|
|
27
23
|
] as const;
|
|
28
24
|
|
|
29
25
|
type CommandName = (typeof COMMAND_NAMES)[number];
|
|
@@ -34,6 +30,8 @@ const COMMAND_INITIALISMS: Partial<Record<CommandName, string>> = {
|
|
|
34
30
|
nosteer: "ns",
|
|
35
31
|
};
|
|
36
32
|
|
|
33
|
+
const DISABLED_COMMAND_NAMES = new Set(["mode", "modes"]);
|
|
34
|
+
|
|
37
35
|
export class CommandRouter {
|
|
38
36
|
parse(text: string): Command {
|
|
39
37
|
const trimmed = text.trim();
|
|
@@ -50,25 +48,17 @@ export class CommandRouter {
|
|
|
50
48
|
const command = resolveCommandName(rawCommand);
|
|
51
49
|
|
|
52
50
|
switch (command) {
|
|
53
|
-
case "agents":
|
|
54
|
-
return { type: "agent" };
|
|
55
51
|
case "new":
|
|
56
52
|
return parseNewCommand(args);
|
|
57
53
|
case "newgroup":
|
|
58
54
|
return parseNewGroupCommand(args);
|
|
59
55
|
case "forkgroup":
|
|
60
|
-
return
|
|
61
|
-
type: "forkgroup",
|
|
62
|
-
title: args.join(" ").trim() || undefined,
|
|
63
|
-
};
|
|
56
|
+
return parseForkGroupCommand(args);
|
|
64
57
|
case "fork":
|
|
65
|
-
|
|
66
|
-
return args[0] ? { type: "fork", sessionId: args[0] } : { type: "fork" };
|
|
58
|
+
return parseForkCommand(args);
|
|
67
59
|
case "title":
|
|
68
60
|
if (args.length === 0) throw new Error("请输入新标题,例如:/title 修复会话列表。");
|
|
69
61
|
return { type: "title", title: args.join(" ") };
|
|
70
|
-
case "ask":
|
|
71
|
-
return { type: "ask", text: trimmed.slice(rawCommand.length).trim() };
|
|
72
62
|
case "queue":
|
|
73
63
|
case "nosteer": {
|
|
74
64
|
const prompt = trimmed.slice(rawCommand.length).trim();
|
|
@@ -81,8 +71,6 @@ export class CommandRouter {
|
|
|
81
71
|
return args[0] ? { type: "switch", sessionId: args[0] } : { type: "switch" };
|
|
82
72
|
case "agent":
|
|
83
73
|
return args[0] ? { type: "agent", agent: args[0] } : { type: "agent" };
|
|
84
|
-
case "use":
|
|
85
|
-
return requireArg(args[0], "agent name", (agent) => ({ type: "use", agent, cwd: args[1] }));
|
|
86
74
|
case "stop":
|
|
87
75
|
return { type: "stop" };
|
|
88
76
|
case "status":
|
|
@@ -102,22 +90,17 @@ export class CommandRouter {
|
|
|
102
90
|
return { type: "goal", action: "set", objective: args.join(" ") };
|
|
103
91
|
}
|
|
104
92
|
case "restart":
|
|
105
|
-
return { type: "restart" };
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
case "mode":
|
|
109
|
-
return requireArg(args[0], "mode value", (value) => ({ type: "mode", value }));
|
|
93
|
+
if (args.length === 0) return { type: "restart" };
|
|
94
|
+
if (args.length === 1 && args[0] === "--force") return { type: "restart", force: true };
|
|
95
|
+
throw new Error("/restart 只接受一个可选的 --force 参数。");
|
|
110
96
|
case "model":
|
|
111
|
-
return { type: "model"
|
|
97
|
+
return settingsCommand("/model", args, { type: "model" });
|
|
98
|
+
case "provider":
|
|
99
|
+
return settingsCommand("/provider", args, { type: "provider" });
|
|
112
100
|
case "thinking":
|
|
113
|
-
return { type: "thinking"
|
|
114
|
-
case "permissions":
|
|
115
|
-
|
|
116
|
-
if (mode !== undefined && mode !== "auto" && mode !== "confirm") {
|
|
117
|
-
throw new Error("权限模式只能是 auto 或 confirm。");
|
|
118
|
-
}
|
|
119
|
-
return { type: "permissions", mode };
|
|
120
|
-
}
|
|
101
|
+
return settingsCommand("/thinking", args, { type: "thinking" });
|
|
102
|
+
case "permissions":
|
|
103
|
+
return settingsCommand("/permissions", args, { type: "permissions" });
|
|
121
104
|
case "help":
|
|
122
105
|
return { type: "help" };
|
|
123
106
|
}
|
|
@@ -127,6 +110,7 @@ export class CommandRouter {
|
|
|
127
110
|
function resolveCommandName(rawCommand: string): CommandName {
|
|
128
111
|
const input = rawCommand.slice(1).toLowerCase();
|
|
129
112
|
if (!input) throw unknownCommand(rawCommand);
|
|
113
|
+
if (DISABLED_COMMAND_NAMES.has(input)) throw unknownCommand(rawCommand);
|
|
130
114
|
|
|
131
115
|
const exact = COMMAND_NAMES.find((command) => command === input);
|
|
132
116
|
if (exact) return exact;
|
|
@@ -147,23 +131,47 @@ function unknownCommand(rawCommand: string): Error {
|
|
|
147
131
|
return new Error(`未知命令:${rawCommand}。发送 /help 查看可用命令。`);
|
|
148
132
|
}
|
|
149
133
|
|
|
150
|
-
function
|
|
151
|
-
if (
|
|
152
|
-
throw new Error(
|
|
134
|
+
function settingsCommand<T extends Command>(name: string, args: string[], command: T): T {
|
|
135
|
+
if (args.length > 0) {
|
|
136
|
+
throw new Error(`${name} 不接受参数,请在设置卡片中完成选择。`);
|
|
153
137
|
}
|
|
154
|
-
|
|
155
|
-
return create(value);
|
|
138
|
+
return command;
|
|
156
139
|
}
|
|
157
140
|
|
|
158
141
|
function parseNewCommand(args: string[]): Extract<Command, { type: "new" }> {
|
|
142
|
+
const options = parseNewTaskOptions("/new", args, "工作目录", "D:\\dev\\project");
|
|
143
|
+
return {
|
|
144
|
+
type: "new",
|
|
145
|
+
title: options.title,
|
|
146
|
+
cwd: options.cwd,
|
|
147
|
+
...(options.projectless ? { projectless: true } : {}),
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
function parseNewGroupCommand(args: string[]): Extract<Command, { type: "newgroup" }> {
|
|
152
|
+
const options = parseNewTaskOptions("/newgroup", args, "项目目录", "~/dev/project");
|
|
153
|
+
return {
|
|
154
|
+
type: "newgroup",
|
|
155
|
+
title: options.title,
|
|
156
|
+
...(options.cwd === undefined ? {} : { cwd: options.cwd }),
|
|
157
|
+
...(options.projectless ? { projectless: true } : {}),
|
|
158
|
+
};
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
function parseNewTaskOptions(
|
|
162
|
+
commandName: "/new" | "/newgroup",
|
|
163
|
+
args: string[],
|
|
164
|
+
directoryLabel: string,
|
|
165
|
+
exampleDirectory: string,
|
|
166
|
+
): { title?: string; cwd?: string; projectless: boolean } {
|
|
159
167
|
const titleParts: string[] = [];
|
|
160
168
|
let cwd: string | undefined;
|
|
161
169
|
let projectless = false;
|
|
162
170
|
for (let index = 0; index < args.length; index += 1) {
|
|
163
171
|
const argument = args[index]!;
|
|
164
172
|
if (argument === "--nodir") {
|
|
165
|
-
if (projectless) throw new Error(
|
|
166
|
-
if (cwd !== undefined) throw new Error(
|
|
173
|
+
if (projectless) throw new Error(`${commandName} 只能指定一次 --nodir。`);
|
|
174
|
+
if (cwd !== undefined) throw new Error(`${commandName} 的 --dir 和 --nodir 不能同时使用。`);
|
|
167
175
|
projectless = true;
|
|
168
176
|
continue;
|
|
169
177
|
}
|
|
@@ -171,33 +179,47 @@ function parseNewCommand(args: string[]): Extract<Command, { type: "new" }> {
|
|
|
171
179
|
titleParts.push(argument);
|
|
172
180
|
continue;
|
|
173
181
|
}
|
|
174
|
-
if (projectless) throw new Error(
|
|
175
|
-
if (cwd !== undefined) throw new Error(
|
|
182
|
+
if (projectless) throw new Error(`${commandName} 的 --dir 和 --nodir 不能同时使用。`);
|
|
183
|
+
if (cwd !== undefined) throw new Error(`${commandName} 只能指定一次 --dir。`);
|
|
176
184
|
const directory = args[index + 1];
|
|
177
|
-
if (!directory || directory === "--dir") {
|
|
178
|
-
throw new Error(
|
|
185
|
+
if (!directory || directory === "--dir" || directory === "--nodir") {
|
|
186
|
+
throw new Error(
|
|
187
|
+
`请在 --dir 后指定${directoryLabel},例如:${commandName} 修复会话列表 --dir ${exampleDirectory}。`,
|
|
188
|
+
);
|
|
179
189
|
}
|
|
180
190
|
cwd = directory;
|
|
181
191
|
index += 1;
|
|
182
192
|
}
|
|
183
193
|
return {
|
|
184
|
-
type: "new",
|
|
185
194
|
title: titleParts.join(" ").trim() || undefined,
|
|
186
195
|
cwd,
|
|
187
|
-
|
|
196
|
+
projectless,
|
|
188
197
|
};
|
|
189
198
|
}
|
|
190
199
|
|
|
191
|
-
function
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
}
|
|
200
|
+
function parseForkCommand(args: string[]): Extract<Command, { type: "fork" }> {
|
|
201
|
+
rejectOptions("/fork", args);
|
|
202
|
+
if (args.length > 1) throw new Error("/fork 只接受一个可选的任务序号或任务 ID。");
|
|
195
203
|
return {
|
|
196
|
-
type: "
|
|
204
|
+
type: "fork",
|
|
205
|
+
...(args[0] ? { sessionId: args[0] } : {}),
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
|
|
209
|
+
function parseForkGroupCommand(args: string[]): Extract<Command, { type: "forkgroup" }> {
|
|
210
|
+
rejectOptions("/forkgroup", args);
|
|
211
|
+
return {
|
|
212
|
+
type: "forkgroup",
|
|
197
213
|
title: args.join(" ").trim() || undefined,
|
|
198
214
|
};
|
|
199
215
|
}
|
|
200
216
|
|
|
217
|
+
function rejectOptions(command: string, args: string[]): void {
|
|
218
|
+
for (const argument of args) {
|
|
219
|
+
if (argument.startsWith("--")) throw new Error(`${command} 不支持参数:${argument}。`);
|
|
220
|
+
}
|
|
221
|
+
}
|
|
222
|
+
|
|
201
223
|
function splitArgs(input: string): string[] {
|
|
202
224
|
const args: string[] = [];
|
|
203
225
|
let current = "";
|
|
@@ -1,28 +1,23 @@
|
|
|
1
|
-
import type { PermissionMode } from "../runtime/types.js";
|
|
2
|
-
|
|
3
1
|
export type Command =
|
|
4
2
|
| { type: "shell"; command: string }
|
|
5
3
|
| { type: "new"; title?: string; cwd?: string; projectless?: boolean }
|
|
6
|
-
| { type: "newgroup"; title?: string }
|
|
4
|
+
| { type: "newgroup"; title?: string; cwd?: string; projectless?: boolean }
|
|
7
5
|
| { type: "forkgroup"; title?: string }
|
|
8
6
|
| { type: "fork"; sessionId?: string }
|
|
9
7
|
| { type: "title"; title: string }
|
|
10
|
-
| { type: "ask"; text: string }
|
|
11
8
|
| { type: "nosteer"; text: string }
|
|
12
9
|
| { type: "sessions"; searchTerm?: string }
|
|
13
10
|
| { type: "switch"; sessionId?: string }
|
|
14
11
|
| { type: "agent"; agent?: string }
|
|
15
|
-
| { type: "use"; agent: string; cwd?: string }
|
|
16
12
|
| { type: "stop" }
|
|
17
13
|
| { type: "status"; sessionId?: string }
|
|
18
14
|
| { type: "goal"; action: "show" }
|
|
19
15
|
| { type: "goal"; action: "set" | "edit"; objective: string }
|
|
20
16
|
| { type: "goal"; action: "pause" | "resume" | "clear" }
|
|
21
|
-
| { type: "restart" }
|
|
22
|
-
| { type: "
|
|
23
|
-
| { type: "
|
|
24
|
-
| { type: "
|
|
25
|
-
| { type: "
|
|
26
|
-
| { type: "permissions"; mode?: PermissionMode }
|
|
17
|
+
| { type: "restart"; force?: boolean }
|
|
18
|
+
| { type: "model" }
|
|
19
|
+
| { type: "provider" }
|
|
20
|
+
| { type: "thinking" }
|
|
21
|
+
| { type: "permissions" }
|
|
27
22
|
| { type: "help" }
|
|
28
23
|
| { type: "prompt"; text: string };
|
package/src/config/loadConfig.ts
CHANGED
|
@@ -22,7 +22,7 @@ console:
|
|
|
22
22
|
|
|
23
23
|
agents:
|
|
24
24
|
codex:
|
|
25
|
-
kind: "
|
|
25
|
+
kind: "app-server"
|
|
26
26
|
title: "Codex"
|
|
27
27
|
command: "codex"
|
|
28
28
|
args:
|
|
@@ -33,6 +33,16 @@ agents:
|
|
|
33
33
|
- "stdio://"
|
|
34
34
|
env: {}
|
|
35
35
|
|
|
36
|
+
traex:
|
|
37
|
+
kind: "app-server"
|
|
38
|
+
title: "TraeX"
|
|
39
|
+
command: "traex"
|
|
40
|
+
args:
|
|
41
|
+
- "app-server"
|
|
42
|
+
- "--listen"
|
|
43
|
+
- "stdio://"
|
|
44
|
+
env: {}
|
|
45
|
+
|
|
36
46
|
coco:
|
|
37
47
|
title: "Coco"
|
|
38
48
|
command: "coco"
|
package/src/config/schema.ts
CHANGED
|
@@ -3,8 +3,14 @@ import { DEFAULT_LOG_PATH, DEFAULT_SQLITE_PATH } from "./paths.js";
|
|
|
3
3
|
|
|
4
4
|
const envRecordSchema = z.record(z.string(), z.string()).default({});
|
|
5
5
|
|
|
6
|
+
const agentKindSchema = z.union([
|
|
7
|
+
z.literal("acp"),
|
|
8
|
+
z.literal("app-server"),
|
|
9
|
+
z.literal("codex").transform(() => "app-server" as const),
|
|
10
|
+
]).default("acp");
|
|
11
|
+
|
|
6
12
|
export const agentConfigSchema = z.object({
|
|
7
|
-
kind:
|
|
13
|
+
kind: agentKindSchema,
|
|
8
14
|
title: z.string().min(1),
|
|
9
15
|
command: z.string().min(1),
|
|
10
16
|
args: z.array(z.string()).default([]),
|
|
@@ -14,7 +14,7 @@ export class ConsoleConnector {
|
|
|
14
14
|
if (this.reader) return;
|
|
15
15
|
this.logger.info("Starting local Codex test console.");
|
|
16
16
|
console.log("Codex console ready. Type /help or enter a prompt.");
|
|
17
|
-
const reader = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: "
|
|
17
|
+
const reader = readline.createInterface({ input: process.stdin, output: process.stdout, prompt: "agentbot> " });
|
|
18
18
|
this.reader = reader;
|
|
19
19
|
reader.prompt();
|
|
20
20
|
reader.on("line", (line) => {
|
|
@@ -4,27 +4,36 @@ import type { TurnPresenter } from "../presentation/OutboundRouter.js";
|
|
|
4
4
|
|
|
5
5
|
export class ConsoleTurnPresenter implements TurnPresenter {
|
|
6
6
|
private readonly contexts = new Map<string, string>();
|
|
7
|
+
private readonly agentLabels = new Map<string, string>();
|
|
7
8
|
private readonly delivered = new Set<string>();
|
|
8
9
|
|
|
9
10
|
constructor(private readonly outbound: FeishuOutbound) {}
|
|
10
11
|
|
|
11
|
-
registerSession(
|
|
12
|
+
registerSession(
|
|
13
|
+
sessionId: string,
|
|
14
|
+
contextKey: string,
|
|
15
|
+
_taskTitle?: string,
|
|
16
|
+
_projectCwd?: string,
|
|
17
|
+
agentLabel?: string,
|
|
18
|
+
): void {
|
|
12
19
|
this.contexts.set(sessionId, contextKey);
|
|
20
|
+
if (agentLabel) this.agentLabels.set(sessionId, agentLabel);
|
|
13
21
|
}
|
|
14
22
|
|
|
15
23
|
updateSessionTitle(): void {}
|
|
16
24
|
|
|
17
25
|
unregisterSession(sessionId: string): void {
|
|
18
26
|
this.contexts.delete(sessionId);
|
|
27
|
+
this.agentLabels.delete(sessionId);
|
|
19
28
|
}
|
|
20
29
|
|
|
21
|
-
async startPendingTurn(
|
|
22
|
-
await this.outbound.sendText(contextKey,
|
|
30
|
+
async startPendingTurn(sessionId: string, contextKey: string): Promise<void> {
|
|
31
|
+
await this.outbound.sendText(contextKey, `Connecting to ${this.agentLabel(sessionId)}...`);
|
|
23
32
|
}
|
|
24
33
|
|
|
25
34
|
async failPendingTurn(sessionId: string, message: string): Promise<void> {
|
|
26
35
|
const contextKey = this.contexts.get(sessionId);
|
|
27
|
-
if (contextKey) await this.outbound.sendText(contextKey,
|
|
36
|
+
if (contextKey) await this.outbound.sendText(contextKey, `${this.agentLabel(sessionId)} failed to start: ${message}`);
|
|
28
37
|
}
|
|
29
38
|
|
|
30
39
|
async appendSteerMessage(): Promise<void> {}
|
|
@@ -33,20 +42,20 @@ export class ConsoleTurnPresenter implements TurnPresenter {
|
|
|
33
42
|
const contextKey = this.contexts.get(event.sessionId);
|
|
34
43
|
if (!contextKey) return;
|
|
35
44
|
if (event.type === "turn_started") {
|
|
36
|
-
await this.outbound.sendText(contextKey,
|
|
45
|
+
await this.outbound.sendText(contextKey, `${this.agentLabel(event.sessionId)} started (${event.turnId})`);
|
|
37
46
|
} else if (event.type === "progress") {
|
|
38
47
|
await this.outbound.sendText(contextKey, event.text);
|
|
39
48
|
} else if (event.type === "tool_started") {
|
|
40
49
|
await this.outbound.sendText(contextKey, `> ${event.tool.title}`);
|
|
41
50
|
} else if (event.type === "approval_requested") {
|
|
42
|
-
await this.outbound.sendText(contextKey, `Approval required: ${event.request.title}. Use Feishu
|
|
51
|
+
await this.outbound.sendText(contextKey, `Approval required: ${event.request.title}. Use Feishu's Permission settings card.`);
|
|
43
52
|
} else if (event.type === "turn_completed" && !this.delivered.has(event.turnId)) {
|
|
44
53
|
this.delivered.add(event.turnId);
|
|
45
54
|
await this.outbound.sendMarkdown(contextKey, event.finalResponse || "(completed without text)");
|
|
46
55
|
} else if (event.type === "turn_failed") {
|
|
47
|
-
await this.outbound.sendText(contextKey,
|
|
56
|
+
await this.outbound.sendText(contextKey, `${this.agentLabel(event.sessionId)} failed: ${event.message}`);
|
|
48
57
|
} else if (event.type === "turn_cancelled") {
|
|
49
|
-
await this.outbound.sendText(contextKey,
|
|
58
|
+
await this.outbound.sendText(contextKey, `${this.agentLabel(event.sessionId)} stopped.`);
|
|
50
59
|
}
|
|
51
60
|
}
|
|
52
61
|
|
|
@@ -61,4 +70,8 @@ export class ConsoleTurnPresenter implements TurnPresenter {
|
|
|
61
70
|
async resumeDelivery(): Promise<void> {}
|
|
62
71
|
|
|
63
72
|
async flushAll(): Promise<void> {}
|
|
73
|
+
|
|
74
|
+
private agentLabel(sessionId: string): string {
|
|
75
|
+
return this.agentLabels.get(sessionId) ?? "Agent";
|
|
76
|
+
}
|
|
64
77
|
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { cliText } from "./cli/i18n.js";
|
|
3
|
+
|
|
4
|
+
process.stderr.write(`${cliText(
|
|
5
|
+
"Warning: `agent-bot` is deprecated and will be removed in a future release. Use `agentbot` instead.",
|
|
6
|
+
"警告:`agent-bot` 已弃用,并将在后续版本中移除。请改用 `agentbot`。",
|
|
7
|
+
)}\n`);
|
|
8
|
+
|
|
9
|
+
await import("./cli.js");
|