@keyou007/agent-bot 0.1.14-alpha.0 → 0.1.14-alpha.2

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.
Files changed (113) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +82 -55
  3. package/README.zh.md +82 -55
  4. package/config.example.yaml +5 -1
  5. package/dist/cli/AutostartManager.js +431 -0
  6. package/dist/cli/AutostartManager.js.map +1 -0
  7. package/dist/cli/FeishuAppConfiguration.js +17 -13
  8. package/dist/cli/FeishuAppConfiguration.js.map +1 -1
  9. package/dist/cli/Initializer.js +35 -0
  10. package/dist/cli/Initializer.js.map +1 -1
  11. package/dist/cli/SelfUpdateRunner.js +552 -0
  12. package/dist/cli/SelfUpdateRunner.js.map +1 -0
  13. package/dist/cli/SelfUpdater.js +431 -0
  14. package/dist/cli/SelfUpdater.js.map +1 -0
  15. package/dist/cli/autostartOutput.js +63 -0
  16. package/dist/cli/autostartOutput.js.map +1 -0
  17. package/dist/cli/controlProtocol.js.map +1 -1
  18. package/dist/cli/help.js +92 -18
  19. package/dist/cli/help.js.map +1 -1
  20. package/dist/cli/taskGroupOptions.js +14 -11
  21. package/dist/cli/taskGroupOptions.js.map +1 -1
  22. package/dist/cli/taskListOutput.js +3 -0
  23. package/dist/cli/taskListOutput.js.map +1 -1
  24. package/dist/cli/taskTarget.js +99 -0
  25. package/dist/cli/taskTarget.js.map +1 -0
  26. package/dist/cli.js +643 -58
  27. package/dist/cli.js.map +1 -1
  28. package/dist/codex/CodexRuntime.js +16 -5
  29. package/dist/codex/CodexRuntime.js.map +1 -1
  30. package/dist/commands/CommandRouter.js +20 -1
  31. package/dist/commands/CommandRouter.js.map +1 -1
  32. package/dist/config/loadConfig.js +2 -0
  33. package/dist/config/loadConfig.js.map +1 -1
  34. package/dist/config/schema.js +2 -0
  35. package/dist/config/schema.js.map +1 -1
  36. package/dist/console/ConsoleTurnPresenter.js +2 -0
  37. package/dist/console/ConsoleTurnPresenter.js.map +1 -1
  38. package/dist/feishu/CardRenderer.js +584 -16
  39. package/dist/feishu/CardRenderer.js.map +1 -1
  40. package/dist/feishu/FeishuConnector.js +29 -8
  41. package/dist/feishu/FeishuConnector.js.map +1 -1
  42. package/dist/feishu/FeishuMarkdown.js +25 -1
  43. package/dist/feishu/FeishuMarkdown.js.map +1 -1
  44. package/dist/feishu/FeishuMessageClient.js +43 -0
  45. package/dist/feishu/FeishuMessageClient.js.map +1 -1
  46. package/dist/feishu/FeishuTurnPresenter.js +29 -1
  47. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  48. package/dist/feishu/ownerAccess.js +7 -0
  49. package/dist/feishu/ownerAccess.js.map +1 -0
  50. package/dist/index.js +148 -19
  51. package/dist/index.js.map +1 -1
  52. package/dist/presentation/OutboundRouter.js +19 -1
  53. package/dist/presentation/OutboundRouter.js.map +1 -1
  54. package/dist/proxy/ProxySessionController.js +1444 -66
  55. package/dist/proxy/ProxySessionController.js.map +1 -1
  56. package/dist/startup/StartupNotifier.js +65 -16
  57. package/dist/startup/StartupNotifier.js.map +1 -1
  58. package/dist/startup/startFeishu.js +2 -2
  59. package/dist/startup/startFeishu.js.map +1 -1
  60. package/dist/state/StateStore.js +268 -67
  61. package/dist/state/StateStore.js.map +1 -1
  62. package/dist/state/migrations.js +26 -0
  63. package/dist/state/migrations.js.map +1 -1
  64. package/dist/supervision/SafeRestartNotifier.js +17 -16
  65. package/dist/supervision/SafeRestartNotifier.js.map +1 -1
  66. package/dist/supervision/SafeRestartScheduler.js +12 -7
  67. package/dist/supervision/SafeRestartScheduler.js.map +1 -1
  68. package/dist/supervision/replacementSupervisor.js +45 -4
  69. package/dist/supervision/replacementSupervisor.js.map +1 -1
  70. package/dist/supervisor.js +30 -18
  71. package/dist/supervisor.js.map +1 -1
  72. package/docs/technical-reference.md +33 -10
  73. package/docs/technical-reference.zh.md +33 -10
  74. package/npm-shrinkwrap.json +2 -2
  75. package/package.json +2 -2
  76. package/skills/agent-bot/SKILL.md +107 -182
  77. package/src/cli/AutostartManager.ts +579 -0
  78. package/src/cli/FeishuAppConfiguration.ts +22 -7
  79. package/src/cli/Initializer.ts +57 -0
  80. package/src/cli/SelfUpdateRunner.ts +817 -0
  81. package/src/cli/SelfUpdater.ts +688 -0
  82. package/src/cli/autostartOutput.ts +75 -0
  83. package/src/cli/controlProtocol.ts +111 -1
  84. package/src/cli/help.ts +92 -18
  85. package/src/cli/taskGroupOptions.ts +27 -17
  86. package/src/cli/taskListOutput.ts +10 -0
  87. package/src/cli/taskTarget.ts +168 -0
  88. package/src/cli.ts +781 -65
  89. package/src/codex/CodexRuntime.ts +17 -5
  90. package/src/commands/CommandRouter.ts +19 -1
  91. package/src/commands/commandTypes.ts +3 -0
  92. package/src/config/loadConfig.ts +2 -0
  93. package/src/config/schema.ts +2 -0
  94. package/src/console/ConsoleTurnPresenter.ts +4 -1
  95. package/src/feishu/CardRenderer.ts +716 -16
  96. package/src/feishu/FeishuConnector.ts +44 -10
  97. package/src/feishu/FeishuMarkdown.ts +27 -1
  98. package/src/feishu/FeishuMessageClient.ts +58 -0
  99. package/src/feishu/FeishuTurnPresenter.ts +35 -2
  100. package/src/feishu/ownerAccess.ts +7 -0
  101. package/src/feishu/types.ts +7 -0
  102. package/src/index.ts +192 -22
  103. package/src/presentation/OutboundRouter.ts +28 -3
  104. package/src/proxy/ProxySessionController.ts +1707 -70
  105. package/src/runtime/types.ts +1 -0
  106. package/src/startup/StartupNotifier.ts +67 -17
  107. package/src/startup/startFeishu.ts +5 -3
  108. package/src/state/StateStore.ts +413 -65
  109. package/src/state/migrations.ts +26 -0
  110. package/src/supervision/SafeRestartNotifier.ts +17 -17
  111. package/src/supervision/SafeRestartScheduler.ts +13 -6
  112. package/src/supervision/replacementSupervisor.ts +50 -4
  113. package/src/supervisor.ts +35 -16
@@ -14,6 +14,7 @@ export type SafeRestartPhase =
14
14
  export interface RestartNotificationTarget {
15
15
  contextKey: string;
16
16
  replyMessageId?: string;
17
+ reason?: string;
17
18
  }
18
19
 
19
20
  export interface SafeRestartStatus {
@@ -60,7 +61,7 @@ export class SafeRestartScheduler {
60
61
  this.scheduleId += 1;
61
62
  this.notificationTargets = [];
62
63
  }
63
- this.addNotificationTarget(notificationTarget);
64
+ this.addNotificationTarget(notificationTarget, reason);
64
65
  this.reason = reason;
65
66
  this.idleSince = undefined;
66
67
  this.idleInboundAt = undefined;
@@ -215,8 +216,8 @@ export class SafeRestartScheduler {
215
216
  });
216
217
  }
217
218
 
218
- private addNotificationTarget(value: RestartNotificationTarget | undefined): void {
219
- const target = normalizedNotificationTarget(value);
219
+ private addNotificationTarget(value: RestartNotificationTarget | undefined, reason: string): void {
220
+ const target = normalizedNotificationTarget(value, reason);
220
221
  if (!target) return;
221
222
  const existingIndex = this.notificationTargets.findIndex(
222
223
  (candidate) => candidate.contextKey === target.contextKey,
@@ -226,9 +227,13 @@ export class SafeRestartScheduler {
226
227
  return;
227
228
  }
228
229
  const existing = this.notificationTargets[existingIndex]!;
229
- if (!existing.replyMessageId && target.replyMessageId) {
230
- this.notificationTargets[existingIndex] = target;
231
- }
230
+ this.notificationTargets[existingIndex] = {
231
+ ...existing,
232
+ reason: target.reason,
233
+ ...(!existing.replyMessageId && target.replyMessageId
234
+ ? { replyMessageId: target.replyMessageId }
235
+ : {}),
236
+ };
232
237
  }
233
238
 
234
239
  private notificationTargetsSnapshot(): RestartNotificationTarget[] {
@@ -238,6 +243,7 @@ export class SafeRestartScheduler {
238
243
 
239
244
  function normalizedNotificationTarget(
240
245
  value: RestartNotificationTarget | undefined,
246
+ reason: string,
241
247
  ): RestartNotificationTarget | undefined {
242
248
  const contextKey = value?.contextKey.trim();
243
249
  if (!contextKey) return undefined;
@@ -245,5 +251,6 @@ function normalizedNotificationTarget(
245
251
  return {
246
252
  contextKey,
247
253
  ...(replyMessageId ? { replyMessageId } : {}),
254
+ reason,
248
255
  };
249
256
  }
@@ -1,24 +1,47 @@
1
+ import type { RestartNotificationTarget } from "./SafeRestartScheduler.js";
2
+
1
3
  export const RESTART_GROUP_CONTEXTS_ENV = "AGENT_BOT_RESTART_GROUP_CONTEXTS";
4
+ export const RESTART_NOTIFICATION_TARGETS_ENV = "AGENT_BOT_RESTART_NOTIFICATION_TARGETS";
2
5
 
3
6
  export function replacementSupervisorEnvironment(
4
7
  restartReason: string,
5
8
  environment: NodeJS.ProcessEnv = process.env,
6
- restartGroupContextKeys: readonly string[] = [],
9
+ restartNotificationTargets: readonly RestartNotificationTarget[] = [],
7
10
  ): NodeJS.ProcessEnv {
8
11
  const result: NodeJS.ProcessEnv = {
9
12
  ...environment,
10
13
  AGENT_BOT_START_DELAY_MS: "250",
11
14
  AGENT_BOT_RESTART_REASON: restartReason,
12
15
  };
13
- const normalized = normalizedContextKeys(restartGroupContextKeys);
16
+ const normalized = normalizedNotificationTargets(restartNotificationTargets);
14
17
  if (normalized.length > 0) {
15
- result[RESTART_GROUP_CONTEXTS_ENV] = JSON.stringify(normalized);
18
+ result[RESTART_NOTIFICATION_TARGETS_ENV] = JSON.stringify(normalized);
16
19
  } else {
17
- delete result[RESTART_GROUP_CONTEXTS_ENV];
20
+ delete result[RESTART_NOTIFICATION_TARGETS_ENV];
18
21
  }
22
+ delete result[RESTART_GROUP_CONTEXTS_ENV];
19
23
  return result;
20
24
  }
21
25
 
26
+ export function restartNotificationTargetsFromEnvironment(
27
+ value: string | undefined,
28
+ ): RestartNotificationTarget[] {
29
+ if (!value?.trim()) return [];
30
+ try {
31
+ const parsed = JSON.parse(value) as unknown;
32
+ return Array.isArray(parsed)
33
+ ? normalizedNotificationTargets(parsed.flatMap((entry) => {
34
+ if (!isRecord(entry)) return [];
35
+ const contextKey = typeof entry.contextKey === "string" ? entry.contextKey : "";
36
+ const replyMessageId = typeof entry.replyMessageId === "string" ? entry.replyMessageId : undefined;
37
+ return [{ contextKey, ...(replyMessageId ? { replyMessageId } : {}) }];
38
+ }))
39
+ : [];
40
+ } catch {
41
+ return [];
42
+ }
43
+ }
44
+
22
45
  export function restartGroupContextKeysFromEnvironment(value: string | undefined): string[] {
23
46
  if (!value?.trim()) return [];
24
47
  try {
@@ -34,3 +57,26 @@ export function restartGroupContextKeysFromEnvironment(value: string | undefined
34
57
  function normalizedContextKeys(values: readonly string[]): string[] {
35
58
  return [...new Set(values.map((value) => value.trim()).filter(Boolean))];
36
59
  }
60
+
61
+ function normalizedNotificationTargets(
62
+ values: readonly RestartNotificationTarget[],
63
+ ): RestartNotificationTarget[] {
64
+ const targets = new Map<string, RestartNotificationTarget>();
65
+ for (const value of values) {
66
+ const contextKey = value.contextKey.trim();
67
+ if (!contextKey) continue;
68
+ const replyMessageId = value.replyMessageId?.trim();
69
+ const existing = targets.get(contextKey);
70
+ targets.set(contextKey, {
71
+ contextKey,
72
+ ...(existing?.replyMessageId || replyMessageId
73
+ ? { replyMessageId: existing?.replyMessageId ?? replyMessageId }
74
+ : {}),
75
+ });
76
+ }
77
+ return [...targets.values()];
78
+ }
79
+
80
+ function isRecord(value: unknown): value is Record<string, unknown> {
81
+ return typeof value === "object" && value !== null && !Array.isArray(value);
82
+ }
package/src/supervisor.ts CHANGED
@@ -16,8 +16,11 @@ import { SupervisorDiagnostics, nodeDiagnosticReportArguments } from "./supervis
16
16
  import { refreshedSystemEnvironment } from "./supervision/systemEnvironment.js";
17
17
  import {
18
18
  RESTART_GROUP_CONTEXTS_ENV,
19
+ RESTART_NOTIFICATION_TARGETS_ENV,
19
20
  restartGroupContextKeysFromEnvironment,
21
+ restartNotificationTargetsFromEnvironment,
20
22
  } from "./supervision/replacementSupervisor.js";
23
+ import type { RestartNotificationTarget } from "./supervision/SafeRestartScheduler.js";
21
24
 
22
25
  const childEntry = fileURLToPath(new URL("./index.js", import.meta.url));
23
26
  const config = loadConfig();
@@ -28,12 +31,14 @@ const diagnostics = new SupervisorDiagnostics(config);
28
31
  diagnostics.initialize();
29
32
  let child: ChildProcess | undefined;
30
33
  let restartTimer: NodeJS.Timeout | undefined;
31
- let restartGroupContextExpiryTimer: NodeJS.Timeout | undefined;
34
+ let restartNotificationTargetExpiryTimer: NodeJS.Timeout | undefined;
32
35
  let stopping = false;
33
36
  let consecutiveFailures = 0;
34
37
  let nextStartReason = process.env.AGENT_BOT_RESTART_REASON?.trim() || "Supervisor 启动";
35
- let nextRestartGroupContextKeys = restartGroupContextKeysFromEnvironment(
36
- process.env[RESTART_GROUP_CONTEXTS_ENV],
38
+ let nextRestartNotificationTargets = mergeRestartNotificationTargets(
39
+ restartNotificationTargetsFromEnvironment(process.env[RESTART_NOTIFICATION_TARGETS_ENV]),
40
+ restartGroupContextKeysFromEnvironment(process.env[RESTART_GROUP_CONTEXTS_ENV])
41
+ .map((contextKey) => ({ contextKey })),
37
42
  );
38
43
 
39
44
  async function startChild(): Promise<void> {
@@ -45,7 +50,7 @@ async function startChild(): Promise<void> {
45
50
  }
46
51
  const startedAt = Date.now();
47
52
  const restartReason = nextStartReason;
48
- const restartGroupContextKeys = nextRestartGroupContextKeys;
53
+ const restartNotificationTargets = nextRestartNotificationTargets;
49
54
  nextStartReason = "Supervisor 重新拉起进程";
50
55
  const workerStderr = diagnostics.openWorkerStderr();
51
56
  const environmentRefresh = refreshedSystemEnvironment();
@@ -64,7 +69,7 @@ async function startChild(): Promise<void> {
64
69
  ...environmentRefresh.environment,
65
70
  AGENT_BOT_SUPERVISED: "1",
66
71
  AGENT_BOT_RESTART_REASON: restartReason,
67
- }, restartGroupContextKeys),
72
+ }, restartNotificationTargets),
68
73
  stdio: ["ignore", "ignore", workerStderr],
69
74
  windowsHide: true,
70
75
  });
@@ -75,7 +80,7 @@ async function startChild(): Promise<void> {
75
80
  writeSupervisorLog("started", {
76
81
  pid: child.pid,
77
82
  restartReason,
78
- restartGroupContextKeys,
83
+ restartNotificationTargets,
79
84
  workerStderrPath: diagnostics.paths.workerStderrPath,
80
85
  crashReportDirectory: diagnostics.paths.crashReportDirectory,
81
86
  });
@@ -86,25 +91,26 @@ async function startChild(): Promise<void> {
86
91
  child.once("exit", (code, signal) => {
87
92
  void handleChildExit(code, signal, startedAt, workerPid);
88
93
  });
89
- if (restartGroupContextKeys.length > 0) {
90
- if (restartGroupContextExpiryTimer) clearTimeout(restartGroupContextExpiryTimer);
91
- restartGroupContextExpiryTimer = setTimeout(() => {
92
- nextRestartGroupContextKeys = [];
93
- restartGroupContextExpiryTimer = undefined;
94
+ if (restartNotificationTargets.length > 0) {
95
+ if (restartNotificationTargetExpiryTimer) clearTimeout(restartNotificationTargetExpiryTimer);
96
+ restartNotificationTargetExpiryTimer = setTimeout(() => {
97
+ nextRestartNotificationTargets = [];
98
+ restartNotificationTargetExpiryTimer = undefined;
94
99
  }, STABLE_UPTIME_MS);
95
100
  }
96
101
  }
97
102
 
98
103
  function workerEnvironment(
99
104
  environment: NodeJS.ProcessEnv,
100
- restartGroupContextKeys: readonly string[],
105
+ restartNotificationTargets: readonly RestartNotificationTarget[],
101
106
  ): NodeJS.ProcessEnv {
102
107
  const result = { ...environment };
103
- if (restartGroupContextKeys.length > 0) {
104
- result[RESTART_GROUP_CONTEXTS_ENV] = JSON.stringify(restartGroupContextKeys);
108
+ if (restartNotificationTargets.length > 0) {
109
+ result[RESTART_NOTIFICATION_TARGETS_ENV] = JSON.stringify(restartNotificationTargets);
105
110
  } else {
106
- delete result[RESTART_GROUP_CONTEXTS_ENV];
111
+ delete result[RESTART_NOTIFICATION_TARGETS_ENV];
107
112
  }
113
+ delete result[RESTART_GROUP_CONTEXTS_ENV];
108
114
  return result;
109
115
  }
110
116
 
@@ -164,7 +170,7 @@ function stop(signal: NodeJS.Signals): void {
164
170
  if (stopping) return;
165
171
  stopping = true;
166
172
  if (restartTimer) clearTimeout(restartTimer);
167
- if (restartGroupContextExpiryTimer) clearTimeout(restartGroupContextExpiryTimer);
173
+ if (restartNotificationTargetExpiryTimer) clearTimeout(restartNotificationTargetExpiryTimer);
168
174
  if (child && !child.killed) {
169
175
  child.kill(signal);
170
176
  return;
@@ -176,6 +182,19 @@ function writeSupervisorLog(event: string, data: Record<string, unknown>): void
176
182
  diagnostics.writeEvent(event, data);
177
183
  }
178
184
 
185
+ function mergeRestartNotificationTargets(
186
+ ...targetGroups: RestartNotificationTarget[][]
187
+ ): RestartNotificationTarget[] {
188
+ const targets = new Map<string, RestartNotificationTarget>();
189
+ for (const target of targetGroups.flat()) {
190
+ const existing = targets.get(target.contextKey);
191
+ if (!existing || (!existing.replyMessageId && target.replyMessageId)) {
192
+ targets.set(target.contextKey, { ...target });
193
+ }
194
+ }
195
+ return [...targets.values()];
196
+ }
197
+
179
198
  process.on("SIGINT", () => stop("SIGINT"));
180
199
  process.on("SIGTERM", () => stop("SIGTERM"));
181
200
  const initialDelayMs = Number(process.env.AGENT_BOT_START_DELAY_MS ?? 0);