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

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 (74) hide show
  1. package/CHANGELOG.md +13 -0
  2. package/README.md +41 -44
  3. package/README.zh.md +41 -44
  4. package/config.example.yaml +4 -0
  5. package/dist/codex/CodexRuntime.js +8 -3
  6. package/dist/codex/CodexRuntime.js.map +1 -1
  7. package/dist/commands/CommandRouter.js +13 -0
  8. package/dist/commands/CommandRouter.js.map +1 -1
  9. package/dist/config/loadConfig.js +2 -0
  10. package/dist/config/loadConfig.js.map +1 -1
  11. package/dist/config/schema.js +2 -0
  12. package/dist/config/schema.js.map +1 -1
  13. package/dist/console/ConsoleTurnPresenter.js +2 -0
  14. package/dist/console/ConsoleTurnPresenter.js.map +1 -1
  15. package/dist/feishu/CardRenderer.js +428 -9
  16. package/dist/feishu/CardRenderer.js.map +1 -1
  17. package/dist/feishu/FeishuConnector.js +29 -8
  18. package/dist/feishu/FeishuConnector.js.map +1 -1
  19. package/dist/feishu/FeishuMessageClient.js +43 -0
  20. package/dist/feishu/FeishuMessageClient.js.map +1 -1
  21. package/dist/feishu/FeishuTurnPresenter.js +29 -1
  22. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  23. package/dist/feishu/ownerAccess.js +7 -0
  24. package/dist/feishu/ownerAccess.js.map +1 -0
  25. package/dist/index.js +14 -17
  26. package/dist/index.js.map +1 -1
  27. package/dist/presentation/OutboundRouter.js +19 -1
  28. package/dist/presentation/OutboundRouter.js.map +1 -1
  29. package/dist/proxy/ProxySessionController.js +1012 -58
  30. package/dist/proxy/ProxySessionController.js.map +1 -1
  31. package/dist/startup/StartupNotifier.js +65 -16
  32. package/dist/startup/StartupNotifier.js.map +1 -1
  33. package/dist/startup/startFeishu.js +2 -2
  34. package/dist/startup/startFeishu.js.map +1 -1
  35. package/dist/state/StateStore.js +250 -67
  36. package/dist/state/StateStore.js.map +1 -1
  37. package/dist/state/migrations.js +26 -0
  38. package/dist/state/migrations.js.map +1 -1
  39. package/dist/supervision/SafeRestartNotifier.js +17 -16
  40. package/dist/supervision/SafeRestartNotifier.js.map +1 -1
  41. package/dist/supervision/SafeRestartScheduler.js +12 -7
  42. package/dist/supervision/SafeRestartScheduler.js.map +1 -1
  43. package/dist/supervision/replacementSupervisor.js +45 -4
  44. package/dist/supervision/replacementSupervisor.js.map +1 -1
  45. package/dist/supervisor.js +30 -18
  46. package/dist/supervisor.js.map +1 -1
  47. package/docs/technical-reference.md +18 -5
  48. package/docs/technical-reference.zh.md +18 -5
  49. package/npm-shrinkwrap.json +2 -2
  50. package/package.json +1 -1
  51. package/skills/agent-bot/SKILL.md +8 -2
  52. package/src/codex/CodexRuntime.ts +9 -3
  53. package/src/commands/CommandRouter.ts +13 -0
  54. package/src/commands/commandTypes.ts +2 -0
  55. package/src/config/loadConfig.ts +2 -0
  56. package/src/config/schema.ts +2 -0
  57. package/src/console/ConsoleTurnPresenter.ts +4 -1
  58. package/src/feishu/CardRenderer.ts +533 -9
  59. package/src/feishu/FeishuConnector.ts +44 -10
  60. package/src/feishu/FeishuMessageClient.ts +58 -0
  61. package/src/feishu/FeishuTurnPresenter.ts +35 -2
  62. package/src/feishu/ownerAccess.ts +7 -0
  63. package/src/feishu/types.ts +7 -0
  64. package/src/index.ts +20 -20
  65. package/src/presentation/OutboundRouter.ts +28 -3
  66. package/src/proxy/ProxySessionController.ts +1177 -57
  67. package/src/startup/StartupNotifier.ts +67 -17
  68. package/src/startup/startFeishu.ts +5 -3
  69. package/src/state/StateStore.ts +394 -65
  70. package/src/state/migrations.ts +26 -0
  71. package/src/supervision/SafeRestartNotifier.ts +17 -17
  72. package/src/supervision/SafeRestartScheduler.ts +13 -6
  73. package/src/supervision/replacementSupervisor.ts +50 -4
  74. package/src/supervisor.ts +35 -16
@@ -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);