@keyou007/agent-bot 0.1.11 → 0.1.13-alpha.0

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 (97) hide show
  1. package/.env.example +1 -1
  2. package/CHANGELOG.md +19 -0
  3. package/README.md +63 -44
  4. package/README.zh.md +63 -44
  5. package/config.example.yaml +8 -22
  6. package/dist/cli/AgentPrerequisites.js +262 -0
  7. package/dist/cli/AgentPrerequisites.js.map +1 -0
  8. package/dist/cli/DefaultAgentSelection.js +47 -0
  9. package/dist/cli/DefaultAgentSelection.js.map +1 -0
  10. package/dist/cli/FeishuAppConfiguration.js +1 -1
  11. package/dist/cli/FeishuAppConfiguration.js.map +1 -1
  12. package/dist/cli/FeishuAppRegistration.js +2 -2
  13. package/dist/cli/FeishuAppRegistration.js.map +1 -1
  14. package/dist/cli/Initializer.js +166 -3
  15. package/dist/cli/Initializer.js.map +1 -1
  16. package/dist/cli/ServerStarter.js +7 -2
  17. package/dist/cli/ServerStarter.js.map +1 -1
  18. package/dist/cli/controlProtocol.js.map +1 -1
  19. package/dist/cli/help.js +24 -20
  20. package/dist/cli/help.js.map +1 -1
  21. package/dist/cli/taskGroupOptions.js +95 -0
  22. package/dist/cli/taskGroupOptions.js.map +1 -0
  23. package/dist/cli.js +268 -6
  24. package/dist/cli.js.map +1 -1
  25. package/dist/codex/AppServerConnection.js +3 -3
  26. package/dist/codex/AppServerConnection.js.map +1 -1
  27. package/dist/codex/CodexProcessManager.js +4 -4
  28. package/dist/codex/CodexProcessManager.js.map +1 -1
  29. package/dist/codex/CodexRuntime.js +63 -25
  30. package/dist/codex/CodexRuntime.js.map +1 -1
  31. package/dist/config/loadConfig.js +8 -22
  32. package/dist/config/loadConfig.js.map +1 -1
  33. package/dist/config/schema.js +6 -1
  34. package/dist/config/schema.js.map +1 -1
  35. package/dist/console/ConsoleConnector.js +3 -3
  36. package/dist/console/ConsoleConnector.js.map +1 -1
  37. package/dist/console/ConsoleTurnPresenter.js +14 -7
  38. package/dist/console/ConsoleTurnPresenter.js.map +1 -1
  39. package/dist/deprecated-cli.js +5 -0
  40. package/dist/deprecated-cli.js.map +1 -0
  41. package/dist/feishu/CardRenderer.js +13 -12
  42. package/dist/feishu/CardRenderer.js.map +1 -1
  43. package/dist/feishu/FeishuTurnPresenter.js +9 -5
  44. package/dist/feishu/FeishuTurnPresenter.js.map +1 -1
  45. package/dist/feishu/transport.js +1 -1
  46. package/dist/feishu/transport.js.map +1 -1
  47. package/dist/index.js +21 -3
  48. package/dist/index.js.map +1 -1
  49. package/dist/presentation/OutboundRouter.js +2 -2
  50. package/dist/presentation/OutboundRouter.js.map +1 -1
  51. package/dist/presentation/TurnStateReducer.js +2 -1
  52. package/dist/presentation/TurnStateReducer.js.map +1 -1
  53. package/dist/proxy/ProxySessionController.js +128 -72
  54. package/dist/proxy/ProxySessionController.js.map +1 -1
  55. package/dist/runtime/AcpRuntimeAdapter.js +3 -2
  56. package/dist/runtime/AcpRuntimeAdapter.js.map +1 -1
  57. package/dist/runtime/createAgentRuntimeRegistry.js +1 -1
  58. package/dist/runtime/createAgentRuntimeRegistry.js.map +1 -1
  59. package/dist/supervision/systemEnvironment.js +129 -0
  60. package/dist/supervision/systemEnvironment.js.map +1 -0
  61. package/dist/supervisor.js +13 -1
  62. package/dist/supervisor.js.map +1 -1
  63. package/docs/technical-reference.md +53 -34
  64. package/docs/technical-reference.zh.md +53 -34
  65. package/npm-shrinkwrap.json +4 -3
  66. package/package.json +9 -4
  67. package/skills/agent-bot/SKILL.md +72 -33
  68. package/src/cli/AgentPrerequisites.ts +377 -0
  69. package/src/cli/DefaultAgentSelection.ts +56 -0
  70. package/src/cli/FeishuAppConfiguration.ts +2 -2
  71. package/src/cli/FeishuAppRegistration.ts +4 -4
  72. package/src/cli/Initializer.ts +206 -5
  73. package/src/cli/ServerStarter.ts +8 -3
  74. package/src/cli/controlProtocol.ts +21 -1
  75. package/src/cli/help.ts +24 -20
  76. package/src/cli/taskGroupOptions.ts +149 -0
  77. package/src/cli.ts +391 -9
  78. package/src/codex/AppServerConnection.ts +3 -3
  79. package/src/codex/CodexProcessManager.ts +4 -4
  80. package/src/codex/CodexRuntime.ts +84 -31
  81. package/src/config/loadConfig.ts +8 -22
  82. package/src/config/schema.ts +7 -1
  83. package/src/console/ConsoleConnector.ts +3 -3
  84. package/src/console/ConsoleTurnPresenter.ts +20 -7
  85. package/src/deprecated-cli.ts +9 -0
  86. package/src/feishu/CardRenderer.ts +13 -12
  87. package/src/feishu/FeishuTurnPresenter.ts +15 -1
  88. package/src/feishu/transport.ts +1 -1
  89. package/src/index.ts +34 -3
  90. package/src/presentation/OutboundRouter.ts +15 -3
  91. package/src/presentation/TurnStateReducer.ts +2 -0
  92. package/src/presentation/turnViewTypes.ts +1 -0
  93. package/src/proxy/ProxySessionController.ts +217 -73
  94. package/src/runtime/AcpRuntimeAdapter.ts +3 -1
  95. package/src/runtime/createAgentRuntimeRegistry.ts +1 -1
  96. package/src/supervision/systemEnvironment.ts +174 -0
  97. package/src/supervisor.ts +12 -1
@@ -99,7 +99,9 @@ export class AcpRuntimeAdapter implements AgentRuntime {
99
99
 
100
100
  async startTurn(sessionId: string, prompt: RuntimePrompt): Promise<string> {
101
101
  const { text, localImagePaths } = normalizeRuntimePrompt(prompt);
102
- if (localImagePaths.length > 0) throw new Error("当前 ACP Agent 不支持图片输入,请切换到 Codex 后重试。");
102
+ if (localImagePaths.length > 0) {
103
+ throw new Error("当前 ACP Agent 不支持图片输入,请切换到支持图片输入的 App Server Agent 后重试。");
104
+ }
103
105
  const session = this.requireSession(sessionId);
104
106
  const turnId = createId("turn");
105
107
  session.activeTurnId = turnId;
@@ -12,7 +12,7 @@ export function createAgentRuntimeRegistry(config: AppConfig, logger: Logger): A
12
12
  const runtimes: Record<string, AgentRuntime> = {};
13
13
  for (const [agentName, agent] of Object.entries(config.agents)) {
14
14
  const runtimeLogger = logger.child({ agentName, runtimeKind: agent.kind });
15
- if (agent.kind === "codex") {
15
+ if (agent.kind === "app-server") {
16
16
  const processManager = new CodexProcessManager(agent.command, agent.args, agent.env, runtimeLogger);
17
17
  runtimes[agentName] = new CodexRuntime(processManager, runtimeLogger);
18
18
  continue;
@@ -0,0 +1,174 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import path from "node:path";
3
+
4
+ export interface WindowsEnvironmentSnapshot {
5
+ machine: Record<string, string>;
6
+ user: Record<string, string>;
7
+ }
8
+
9
+ export interface EnvironmentRefreshResult {
10
+ environment: NodeJS.ProcessEnv;
11
+ refreshed: boolean;
12
+ pathChanged: boolean;
13
+ error?: string;
14
+ }
15
+
16
+ type WindowsEnvironmentLoader = () => WindowsEnvironmentSnapshot;
17
+
18
+ const PROCESS_LOCAL_ENVIRONMENT_PREFIXES = ["AGENT_BOT_", "FEISHU_"];
19
+
20
+ export function refreshedSystemEnvironment(
21
+ inherited: NodeJS.ProcessEnv = process.env,
22
+ platform: NodeJS.Platform = process.platform,
23
+ loadWindowsEnvironment: WindowsEnvironmentLoader = readWindowsEnvironment,
24
+ ): EnvironmentRefreshResult {
25
+ const fallback = { ...inherited };
26
+ if (platform !== "win32") {
27
+ return { environment: fallback, refreshed: false, pathChanged: false };
28
+ }
29
+
30
+ try {
31
+ const snapshot = loadWindowsEnvironment();
32
+ const environment = mergeWindowsEnvironment(inherited, snapshot);
33
+ return {
34
+ environment,
35
+ refreshed: true,
36
+ pathChanged: environmentValue(environment, "Path") !== environmentValue(inherited, "Path"),
37
+ };
38
+ } catch (error) {
39
+ return {
40
+ environment: fallback,
41
+ refreshed: false,
42
+ pathChanged: false,
43
+ error: error instanceof Error ? error.message : String(error),
44
+ };
45
+ }
46
+ }
47
+
48
+ export function mergeWindowsEnvironment(
49
+ inherited: NodeJS.ProcessEnv,
50
+ snapshot: WindowsEnvironmentSnapshot,
51
+ ): NodeJS.ProcessEnv {
52
+ const environment = { ...inherited };
53
+ applyEnvironment(environment, snapshot.machine);
54
+ applyEnvironment(environment, snapshot.user);
55
+
56
+ const machinePath = environmentValue(snapshot.machine, "Path")?.trim();
57
+ const userPath = environmentValue(snapshot.user, "Path")?.trim();
58
+ if (machinePath || userPath) {
59
+ const inheritedPath = environmentValue(inherited, "Path")?.trim();
60
+ setEnvironmentValue(
61
+ environment,
62
+ "Path",
63
+ mergePathValues(
64
+ expandEnvironmentReferences(
65
+ [machinePath, userPath, inheritedPath].filter(Boolean).join(";"),
66
+ environment,
67
+ ),
68
+ ),
69
+ );
70
+ }
71
+ return environment;
72
+ }
73
+
74
+ function readWindowsEnvironment(): WindowsEnvironmentSnapshot {
75
+ const systemRoot = process.env.SystemRoot ?? "C:\\Windows";
76
+ const executable = path.join(systemRoot, "System32", "WindowsPowerShell", "v1.0", "powershell.exe");
77
+ const script = [
78
+ "[Console]::OutputEncoding = [System.Text.UTF8Encoding]::new($false)",
79
+ "$machine = @{}",
80
+ "foreach ($entry in [Environment]::GetEnvironmentVariables([EnvironmentVariableTarget]::Machine).GetEnumerator()) { $machine[[string]$entry.Key] = [string]$entry.Value }",
81
+ "$user = @{}",
82
+ "foreach ($entry in [Environment]::GetEnvironmentVariables([EnvironmentVariableTarget]::User).GetEnumerator()) { $user[[string]$entry.Key] = [string]$entry.Value }",
83
+ "[pscustomobject]@{ machine = $machine; user = $user } | ConvertTo-Json -Compress -Depth 3",
84
+ ].join("; ");
85
+ const result = spawnSync(executable, [
86
+ "-NoLogo",
87
+ "-NoProfile",
88
+ "-NonInteractive",
89
+ "-ExecutionPolicy",
90
+ "Bypass",
91
+ "-Command",
92
+ script,
93
+ ], {
94
+ encoding: "utf8",
95
+ windowsHide: true,
96
+ timeout: 5_000,
97
+ maxBuffer: 8 * 1024 * 1024,
98
+ });
99
+ if (result.error) throw result.error;
100
+ if (result.status !== 0) {
101
+ throw new Error(result.stderr.trim() || `PowerShell exited with code ${result.status ?? "unknown"}.`);
102
+ }
103
+ const parsed = JSON.parse(result.stdout) as Partial<WindowsEnvironmentSnapshot>;
104
+ return {
105
+ machine: environmentRecord(parsed.machine),
106
+ user: environmentRecord(parsed.user),
107
+ };
108
+ }
109
+
110
+ function environmentRecord(value: unknown): Record<string, string> {
111
+ if (!value || typeof value !== "object" || Array.isArray(value)) return {};
112
+ return Object.fromEntries(
113
+ Object.entries(value).flatMap(([name, entry]) =>
114
+ typeof entry === "string" ? [[name, entry]] : []),
115
+ );
116
+ }
117
+
118
+ function applyEnvironment(
119
+ target: NodeJS.ProcessEnv,
120
+ source: Record<string, string>,
121
+ ): void {
122
+ for (const [name, value] of Object.entries(source)) {
123
+ if (name.toLowerCase() === "path" || isProcessLocalEnvironmentName(name)) continue;
124
+ setEnvironmentValue(target, name, value);
125
+ }
126
+ }
127
+
128
+ function isProcessLocalEnvironmentName(name: string): boolean {
129
+ const normalized = name.toUpperCase();
130
+ return PROCESS_LOCAL_ENVIRONMENT_PREFIXES.some((prefix) => normalized.startsWith(prefix));
131
+ }
132
+
133
+ function setEnvironmentValue(environment: NodeJS.ProcessEnv, name: string, value: string): void {
134
+ for (const existingName of Object.keys(environment)) {
135
+ if (existingName !== name && existingName.toLowerCase() === name.toLowerCase()) {
136
+ delete environment[existingName];
137
+ }
138
+ }
139
+ environment[name] = value;
140
+ }
141
+
142
+ function environmentValue(
143
+ environment: NodeJS.ProcessEnv | Record<string, string>,
144
+ name: string,
145
+ ): string | undefined {
146
+ const key = Object.keys(environment).find((candidate) => candidate.toLowerCase() === name.toLowerCase());
147
+ return key === undefined ? undefined : environment[key];
148
+ }
149
+
150
+ function expandEnvironmentReferences(value: string, environment: NodeJS.ProcessEnv): string {
151
+ let expanded = value;
152
+ for (let attempt = 0; attempt < 5; attempt += 1) {
153
+ const next = expanded.replace(/%([^%]+)%/g, (match, name: string) =>
154
+ environmentValue(environment, name) ?? match);
155
+ if (next === expanded) break;
156
+ expanded = next;
157
+ }
158
+ return expanded;
159
+ }
160
+
161
+ function mergePathValues(value: string): string {
162
+ const seen = new Set<string>();
163
+ return value
164
+ .split(";")
165
+ .map((entry) => entry.trim())
166
+ .filter((entry) => {
167
+ if (!entry) return false;
168
+ const normalized = entry.replace(/[\\/]+$/, "").toLowerCase();
169
+ if (seen.has(normalized)) return false;
170
+ seen.add(normalized);
171
+ return true;
172
+ })
173
+ .join(";");
174
+ }
package/src/supervisor.ts CHANGED
@@ -13,6 +13,7 @@ import {
13
13
  STOP_EXIT_CODE,
14
14
  } from "./supervision/restartPolicy.js";
15
15
  import { SupervisorDiagnostics, nodeDiagnosticReportArguments } from "./supervision/SupervisorDiagnostics.js";
16
+ import { refreshedSystemEnvironment } from "./supervision/systemEnvironment.js";
16
17
 
17
18
  const childEntry = fileURLToPath(new URL("./index.js", import.meta.url));
18
19
  const config = loadConfig();
@@ -38,13 +39,23 @@ async function startChild(): Promise<void> {
38
39
  const restartReason = nextStartReason;
39
40
  nextStartReason = "Supervisor 重新拉起进程";
40
41
  const workerStderr = diagnostics.openWorkerStderr();
42
+ const environmentRefresh = refreshedSystemEnvironment();
43
+ if (environmentRefresh.error) {
44
+ writeSupervisorLog("environment_refresh_failed", { error: environmentRefresh.error });
45
+ } else if (environmentRefresh.refreshed) {
46
+ writeSupervisorLog("environment_refreshed", { pathChanged: environmentRefresh.pathChanged });
47
+ }
41
48
  try {
42
49
  child = spawn(process.execPath, [
43
50
  ...nodeDiagnosticReportArguments(diagnostics.paths.crashReportDirectory),
44
51
  childEntry,
45
52
  ], {
46
53
  cwd: process.cwd(),
47
- env: { ...process.env, AGENT_BOT_SUPERVISED: "1", AGENT_BOT_RESTART_REASON: restartReason },
54
+ env: {
55
+ ...environmentRefresh.environment,
56
+ AGENT_BOT_SUPERVISED: "1",
57
+ AGENT_BOT_RESTART_REASON: restartReason,
58
+ },
48
59
  stdio: ["ignore", "ignore", workerStderr],
49
60
  windowsHide: true,
50
61
  });