aws-runtime-bridge 1.9.79 → 1.9.81

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 (596) hide show
  1. package/dist/adapter/AcodeSdkAdapter.d.ts +0 -1
  2. package/dist/adapter/AcodeSdkAdapter.js +11 -1986
  3. package/dist/adapter/AdapterRegistry.d.ts +0 -1
  4. package/dist/adapter/AdapterRegistry.js +2 -100
  5. package/dist/adapter/ClaudeSdkAdapter.d.ts +0 -1
  6. package/dist/adapter/ClaudeSdkAdapter.js +4 -1300
  7. package/dist/adapter/CodexSdkAdapter.d.ts +0 -1
  8. package/dist/adapter/CodexSdkAdapter.js +4 -836
  9. package/dist/adapter/OpencodeSdkAdapter.d.ts +0 -1
  10. package/dist/adapter/OpencodeSdkAdapter.js +4 -879
  11. package/dist/adapter/SdkProviderSpi.d.ts +0 -1
  12. package/dist/adapter/SdkProviderSpi.js +2 -55
  13. package/dist/adapter/acode-tool-names.d.ts +0 -1
  14. package/dist/adapter/acode-tool-names.js +2 -37
  15. package/dist/adapter/idle-poll-loop.d.ts +0 -1
  16. package/dist/adapter/idle-poll-loop.js +2 -59
  17. package/dist/adapter/index.d.ts +0 -1
  18. package/dist/adapter/index.js +2 -11
  19. package/dist/adapter/instance-ai-config-resolver.d.ts +0 -1
  20. package/dist/adapter/instance-ai-config-resolver.js +2 -46
  21. package/dist/adapter/types.d.ts +0 -1
  22. package/dist/adapter/types.js +2 -443
  23. package/dist/adapters/cc-switch/common.d.ts +0 -1
  24. package/dist/adapters/cc-switch/common.js +2 -61
  25. package/dist/adapters/cc-switch/index.d.ts +0 -1
  26. package/dist/adapters/cc-switch/index.js +2 -57
  27. package/dist/adapters/cc-switch/mcp-acode.d.ts +0 -1
  28. package/dist/adapters/cc-switch/mcp-acode.js +2 -71
  29. package/dist/adapters/cc-switch/mcp-claude.d.ts +0 -1
  30. package/dist/adapters/cc-switch/mcp-claude.js +2 -89
  31. package/dist/adapters/cc-switch/mcp-claudecode.d.ts +0 -1
  32. package/dist/adapters/cc-switch/mcp-claudecode.js +2 -77
  33. package/dist/adapters/cc-switch/mcp-codex.d.ts +0 -1
  34. package/dist/adapters/cc-switch/mcp-codex.js +11 -249
  35. package/dist/adapters/cc-switch/mcp-opencode.d.ts +0 -1
  36. package/dist/adapters/cc-switch/mcp-opencode.js +2 -97
  37. package/dist/adapters/cc-switch/mcp-placeholder.d.ts +0 -1
  38. package/dist/adapters/cc-switch/mcp-placeholder.js +2 -19
  39. package/dist/adapters/cc-switch/skill-acode.d.ts +0 -1
  40. package/dist/adapters/cc-switch/skill-acode.js +2 -12
  41. package/dist/adapters/cc-switch/skill-claude.d.ts +0 -1
  42. package/dist/adapters/cc-switch/skill-claude.js +2 -11
  43. package/dist/adapters/cc-switch/skill-claudecode.d.ts +0 -1
  44. package/dist/adapters/cc-switch/skill-claudecode.js +2 -11
  45. package/dist/adapters/cc-switch/skill-codex.d.ts +0 -1
  46. package/dist/adapters/cc-switch/skill-codex.js +2 -6
  47. package/dist/adapters/cc-switch/skill-directory.d.ts +0 -1
  48. package/dist/adapters/cc-switch/skill-directory.js +3 -137
  49. package/dist/adapters/cc-switch/skill-opencode.d.ts +0 -1
  50. package/dist/adapters/cc-switch/skill-opencode.js +2 -11
  51. package/dist/adapters/cc-switch/skill-placeholder.d.ts +0 -1
  52. package/dist/adapters/cc-switch/skill-placeholder.js +2 -19
  53. package/dist/config.d.ts +0 -1
  54. package/dist/config.js +2 -290
  55. package/dist/index.d.ts +0 -1
  56. package/dist/index.js +2 -573
  57. package/dist/middleware/auth.d.ts +0 -1
  58. package/dist/middleware/auth.js +2 -98
  59. package/dist/routes/acode-todos.d.ts +0 -1
  60. package/dist/routes/acode-todos.js +2 -75
  61. package/dist/routes/ai-sources.d.ts +0 -1
  62. package/dist/routes/ai-sources.js +2 -132
  63. package/dist/routes/dashboard.d.ts +0 -1
  64. package/dist/routes/dashboard.js +182 -649
  65. package/dist/routes/events.d.ts +0 -1
  66. package/dist/routes/events.js +2 -22
  67. package/dist/routes/file-browser.d.ts +0 -1
  68. package/dist/routes/file-browser.js +2 -781
  69. package/dist/routes/file-diff-rollback.d.ts +0 -1
  70. package/dist/routes/file-diff-rollback.js +2 -301
  71. package/dist/routes/file-snapshot.d.ts +0 -1
  72. package/dist/routes/file-snapshot.js +2 -156
  73. package/dist/routes/git.d.ts +0 -1
  74. package/dist/routes/git.js +28 -1900
  75. package/dist/routes/instance.d.ts +0 -1
  76. package/dist/routes/instance.js +3 -748
  77. package/dist/routes/mcp.d.ts +0 -1
  78. package/dist/routes/mcp.js +2 -196
  79. package/dist/routes/processes.d.ts +0 -1
  80. package/dist/routes/processes.js +2 -252
  81. package/dist/routes/properties.d.ts +0 -1
  82. package/dist/routes/properties.js +2 -72
  83. package/dist/routes/pty.d.ts +0 -1
  84. package/dist/routes/pty.js +6 -560
  85. package/dist/routes/runtime-binding.d.ts +0 -1
  86. package/dist/routes/runtime-binding.js +2 -263
  87. package/dist/routes/sessions.d.ts +0 -1
  88. package/dist/routes/sessions.js +2 -758
  89. package/dist/routes/skills.d.ts +0 -1
  90. package/dist/routes/skills.js +2 -187
  91. package/dist/routes/sub-agents.d.ts +0 -1
  92. package/dist/routes/sub-agents.js +20 -279
  93. package/dist/routes/system-metrics.d.ts +0 -1
  94. package/dist/routes/system-metrics.js +2 -20
  95. package/dist/routes/task-context.d.ts +0 -1
  96. package/dist/routes/task-context.js +2 -78
  97. package/dist/routes/terminal.d.ts +0 -1
  98. package/dist/routes/terminal.js +54 -2882
  99. package/dist/routes/yml.d.ts +0 -1
  100. package/dist/routes/yml.js +2 -223
  101. package/dist/services/acode-package.d.ts +0 -1
  102. package/dist/services/acode-package.js +2 -111
  103. package/dist/services/agent-event-store.d.ts +0 -1
  104. package/dist/services/agent-event-store.js +2 -81
  105. package/dist/services/agent-process-manager.d.ts +0 -1
  106. package/dist/services/agent-process-manager.js +2 -796
  107. package/dist/services/ai-source-apply.d.ts +0 -1
  108. package/dist/services/ai-source-apply.js +2 -83
  109. package/dist/services/auto-register.d.ts +5 -1
  110. package/dist/services/auto-register.js +2 -1053
  111. package/dist/services/aws-client-agent-mcp.d.ts +0 -1
  112. package/dist/services/aws-client-agent-mcp.js +3 -337
  113. package/dist/services/bridge-package-publish-hooks.d.ts +0 -1
  114. package/dist/services/bridge-package-publish-hooks.js +2 -115
  115. package/dist/services/cc-switch-sdk.d.ts +0 -1
  116. package/dist/services/cc-switch-sdk.js +2 -135
  117. package/dist/services/cli-commands.d.ts +6 -1
  118. package/dist/services/cli-commands.js +6 -645
  119. package/dist/services/event-delta-pusher.d.ts +0 -1
  120. package/dist/services/event-delta-pusher.js +2 -95
  121. package/dist/services/fileSnapshotStore.d.ts +0 -1
  122. package/dist/services/fileSnapshotStore.js +2 -500
  123. package/dist/services/instance-ai-config-service.d.ts +0 -1
  124. package/dist/services/instance-ai-config-service.js +2 -174
  125. package/dist/services/instance-init-service.d.ts +0 -1
  126. package/dist/services/instance-init-service.js +2 -193
  127. package/dist/services/instance-service.d.ts +0 -1
  128. package/dist/services/instance-service.js +2 -237
  129. package/dist/services/instance-state.d.ts +0 -1
  130. package/dist/services/instance-state.js +2 -94
  131. package/dist/services/legacy-path-migration.d.ts +0 -1
  132. package/dist/services/legacy-path-migration.js +2 -66
  133. package/dist/services/lifecycle-state.d.ts +0 -1
  134. package/dist/services/lifecycle-state.js +3 -110
  135. package/dist/services/mcp-launch-binding-queue.d.ts +0 -1
  136. package/dist/services/mcp-launch-binding-queue.js +2 -175
  137. package/dist/services/orphan-monitor.d.ts +0 -1
  138. package/dist/services/orphan-monitor.js +2 -382
  139. package/dist/services/panel-auth.d.ts +0 -1
  140. package/dist/services/panel-auth.js +2 -168
  141. package/dist/services/process-detector.d.ts +0 -1
  142. package/dist/services/process-detector.js +18 -1019
  143. package/dist/services/process-registry.d.ts +0 -1
  144. package/dist/services/process-registry.js +2 -375
  145. package/dist/services/ring-buffer.d.ts +0 -1
  146. package/dist/services/ring-buffer.js +2 -103
  147. package/dist/services/runtime-binding.d.ts +0 -1
  148. package/dist/services/runtime-binding.js +6 -363
  149. package/dist/services/runtime-lifecycle-policy.d.ts +0 -1
  150. package/dist/services/runtime-lifecycle-policy.js +2 -35
  151. package/dist/services/session-output.d.ts +0 -1
  152. package/dist/services/session-output.js +5 -539
  153. package/dist/services/startup-config-wizard.d.ts +0 -1
  154. package/dist/services/startup-config-wizard.js +14 -258
  155. package/dist/services/sub-agent-manager-instance.d.ts +0 -1
  156. package/dist/services/sub-agent-manager-instance.js +2 -12
  157. package/dist/services/system-metrics.d.ts +0 -1
  158. package/dist/services/system-metrics.js +2 -252
  159. package/dist/services/terminal-persistence.d.ts +0 -1
  160. package/dist/services/terminal-persistence.js +2 -176
  161. package/dist/services/tool-installer.d.ts +0 -1
  162. package/dist/services/tool-installer.js +5 -751
  163. package/dist/services/tunnel-client.d.ts +0 -1
  164. package/dist/services/tunnel-client.js +2 -402
  165. package/dist/services/windows-service-manager.d.ts +3 -3
  166. package/dist/services/windows-service-manager.js +2 -59
  167. package/dist/services/workspace-files.d.ts +0 -1
  168. package/dist/services/workspace-files.js +2 -1275
  169. package/dist/services/workspace-watch.d.ts +0 -1
  170. package/dist/services/workspace-watch.js +2 -123
  171. package/dist/services/workspaceTaskChangeWatcher.d.ts +0 -1
  172. package/dist/services/workspaceTaskChangeWatcher.js +2 -483
  173. package/dist/types.d.ts +0 -1
  174. package/dist/types.js +1 -1
  175. package/dist/utils/file-utils.d.ts +0 -1
  176. package/dist/utils/file-utils.js +3 -208
  177. package/dist/utils/instance-ai-config-debug-logger.d.ts +0 -1
  178. package/dist/utils/instance-ai-config-debug-logger.js +4 -63
  179. package/dist/utils/logger.d.ts +0 -1
  180. package/dist/utils/logger.js +2 -154
  181. package/dist/utils/mcp-utils.d.ts +0 -1
  182. package/dist/utils/mcp-utils.js +2 -187
  183. package/dist/utils/path-utils.d.ts +0 -1
  184. package/dist/utils/path-utils.js +2 -44
  185. package/dist/utils/sdk-package-loader.d.ts +0 -1
  186. package/dist/utils/sdk-package-loader.js +2 -78
  187. package/dist/utils/validation.d.ts +0 -1
  188. package/dist/utils/validation.js +2 -53
  189. package/dist/utils/yaml-utils.d.ts +0 -1
  190. package/dist/utils/yaml-utils.js +2 -312
  191. package/node_modules/@cc-switch/sdk/dist/constants.d.ts +0 -1
  192. package/node_modules/@cc-switch/sdk/dist/constants.js +2 -63
  193. package/node_modules/@cc-switch/sdk/dist/errors.d.ts +0 -1
  194. package/node_modules/@cc-switch/sdk/dist/errors.js +2 -8
  195. package/node_modules/@cc-switch/sdk/dist/index.d.ts +0 -1
  196. package/node_modules/@cc-switch/sdk/dist/index.js +2 -9
  197. package/node_modules/@cc-switch/sdk/dist/schemas.d.ts +0 -1
  198. package/node_modules/@cc-switch/sdk/dist/schemas.js +2 -38
  199. package/node_modules/@cc-switch/sdk/dist/sdk.d.ts +0 -1
  200. package/node_modules/@cc-switch/sdk/dist/sdk.js +2 -470
  201. package/node_modules/@cc-switch/sdk/dist/services/ai-config-service.d.ts +0 -1
  202. package/node_modules/@cc-switch/sdk/dist/services/ai-config-service.js +4 -307
  203. package/node_modules/@cc-switch/sdk/dist/services/mcp-model.d.ts +0 -1
  204. package/node_modules/@cc-switch/sdk/dist/services/mcp-model.js +2 -37
  205. package/node_modules/@cc-switch/sdk/dist/services/mcp-service.d.ts +0 -1
  206. package/node_modules/@cc-switch/sdk/dist/services/mcp-service.js +2 -9
  207. package/node_modules/@cc-switch/sdk/dist/services/skill-model.d.ts +0 -1
  208. package/node_modules/@cc-switch/sdk/dist/services/skill-model.js +2 -41
  209. package/node_modules/@cc-switch/sdk/dist/services/skill-service.d.ts +0 -1
  210. package/node_modules/@cc-switch/sdk/dist/services/skill-service.js +2 -9
  211. package/node_modules/@cc-switch/sdk/dist/state.d.ts +0 -1
  212. package/node_modules/@cc-switch/sdk/dist/state.js +2 -19
  213. package/node_modules/@cc-switch/sdk/dist/types.d.ts +0 -1
  214. package/node_modules/@cc-switch/sdk/dist/types.js +1 -1
  215. package/node_modules/@cc-switch/sdk/dist/utils/fs.d.ts +0 -1
  216. package/node_modules/@cc-switch/sdk/dist/utils/fs.js +3 -114
  217. package/node_modules/@cc-switch/sdk/dist/utils/id.d.ts +0 -1
  218. package/node_modules/@cc-switch/sdk/dist/utils/id.js +2 -12
  219. package/node_modules/@cc-switch/sdk/package.json +1 -1
  220. package/package/acode/dist/ask-user-question-tool.d.ts +0 -1
  221. package/package/acode/dist/ask-user-question-tool.js +4 -233
  222. package/package/acode/dist/built-in-file-tools.d.ts +0 -1
  223. package/package/acode/dist/built-in-file-tools.js +4 -966
  224. package/package/acode/dist/built-in-symbols-tool.d.ts +0 -1
  225. package/package/acode/dist/built-in-symbols-tool.js +2 -117
  226. package/package/acode/dist/builtins/commandArtifacts.d.ts +0 -1
  227. package/package/acode/dist/builtins/commandArtifacts.js +9 -97
  228. package/package/acode/dist/builtins/commandOutputEvents.d.ts +0 -1
  229. package/package/acode/dist/builtins/commandOutputEvents.js +2 -56
  230. package/package/acode/dist/builtins/shellCommandPreparation.d.ts +0 -1
  231. package/package/acode/dist/builtins/shellCommandPreparation.js +5 -44
  232. package/package/acode/dist/builtins/shellCommandResult.d.ts +0 -1
  233. package/package/acode/dist/builtins/shellCommandResult.js +2 -71
  234. package/package/acode/dist/builtins/shellCommandRunner.d.ts +0 -1
  235. package/package/acode/dist/builtins/shellCommandRunner.js +2 -115
  236. package/package/acode/dist/builtins/shellOutputDecoder.d.ts +0 -1
  237. package/package/acode/dist/builtins/shellOutputDecoder.js +2 -94
  238. package/package/acode/dist/cli.d.ts +0 -1
  239. package/package/acode/dist/cli.js +4 -38
  240. package/package/acode/dist/commands/commandLoader.d.ts +0 -1
  241. package/package/acode/dist/commands/commandLoader.js +2 -33
  242. package/package/acode/dist/commands/commandParser.d.ts +0 -1
  243. package/package/acode/dist/commands/commandParser.js +3 -77
  244. package/package/acode/dist/commands/commandRegistry.d.ts +0 -1
  245. package/package/acode/dist/commands/commandRegistry.js +2 -30
  246. package/package/acode/dist/compaction.d.ts +0 -1
  247. package/package/acode/dist/compaction.js +7 -919
  248. package/package/acode/dist/config.d.ts +0 -1
  249. package/package/acode/dist/config.js +5 -105
  250. package/package/acode/dist/fs-utils.d.ts +0 -1
  251. package/package/acode/dist/fs-utils.js +2 -79
  252. package/package/acode/dist/hooks/hookBus.d.ts +0 -1
  253. package/package/acode/dist/hooks/hookBus.js +2 -40
  254. package/package/acode/dist/index.d.ts +0 -1
  255. package/package/acode/dist/index.js +2 -19
  256. package/package/acode/dist/mcpToolNames.d.ts +0 -1
  257. package/package/acode/dist/mcpToolNames.js +2 -17
  258. package/package/acode/dist/parsers/ast-cache.d.ts +0 -1
  259. package/package/acode/dist/parsers/ast-cache.js +2 -76
  260. package/package/acode/dist/parsers/language-detector.d.ts +0 -1
  261. package/package/acode/dist/parsers/language-detector.js +2 -44
  262. package/package/acode/dist/parsers/language-queries.d.ts +0 -1
  263. package/package/acode/dist/parsers/language-queries.js +12 -602
  264. package/package/acode/dist/parsers/symbol-extractor.d.ts +0 -1
  265. package/package/acode/dist/parsers/symbol-extractor.js +3 -164
  266. package/package/acode/dist/parsers/tree-sitter-loader.d.ts +0 -1
  267. package/package/acode/dist/parsers/tree-sitter-loader.js +2 -64
  268. package/package/acode/dist/parsers/types.d.ts +0 -1
  269. package/package/acode/dist/parsers/types.js +1 -7
  270. package/package/acode/dist/runtime.d.ts +0 -1
  271. package/package/acode/dist/runtime.js +86 -3771
  272. package/package/acode/dist/skill-tool.d.ts +0 -1
  273. package/package/acode/dist/skill-tool.js +5 -174
  274. package/package/acode/dist/sub-agent-manager.d.ts +0 -1
  275. package/package/acode/dist/sub-agent-manager.js +2 -1159
  276. package/package/acode/dist/sub-agent-store.d.ts +0 -1
  277. package/package/acode/dist/sub-agent-store.js +4 -236
  278. package/package/acode/dist/sub-agent-tools.d.ts +0 -1
  279. package/package/acode/dist/sub-agent-tools.js +15 -369
  280. package/package/acode/dist/sub-agent-types.d.ts +0 -1
  281. package/package/acode/dist/sub-agent-types.js +1 -8
  282. package/package/acode/dist/todo-store.d.ts +0 -1
  283. package/package/acode/dist/todo-store.js +2 -73
  284. package/package/acode/dist/todo-tool.d.ts +0 -1
  285. package/package/acode/dist/todo-tool.js +5 -121
  286. package/package/acode/dist/types.d.ts +0 -1
  287. package/package/acode/dist/types.js +1 -1
  288. package/package/acode/package.json +2 -2
  289. package/package/aws-client-agent-mcp/dist/agent-client.d.ts +0 -1
  290. package/package/aws-client-agent-mcp/dist/agent-client.js +2 -890
  291. package/package/aws-client-agent-mcp/dist/agent-client.test.d.ts +0 -1
  292. package/package/aws-client-agent-mcp/dist/agent-client.test.js +0 -1
  293. package/package/aws-client-agent-mcp/dist/config.d.ts +0 -1
  294. package/package/aws-client-agent-mcp/dist/config.js +2 -243
  295. package/package/aws-client-agent-mcp/dist/config.test.d.ts +0 -1
  296. package/package/aws-client-agent-mcp/dist/config.test.js +0 -1
  297. package/package/aws-client-agent-mcp/dist/constants.d.ts +0 -1
  298. package/package/aws-client-agent-mcp/dist/constants.js +2 -24
  299. package/package/aws-client-agent-mcp/dist/context-manager.d.ts +0 -1
  300. package/package/aws-client-agent-mcp/dist/context-manager.js +2 -477
  301. package/package/aws-client-agent-mcp/dist/context-manager.test.d.ts +0 -1
  302. package/package/aws-client-agent-mcp/dist/context-manager.test.js +0 -1
  303. package/package/aws-client-agent-mcp/dist/http-client.d.ts +0 -1
  304. package/package/aws-client-agent-mcp/dist/http-client.js +2 -446
  305. package/package/aws-client-agent-mcp/dist/http-client.test.d.ts +0 -1
  306. package/package/aws-client-agent-mcp/dist/http-client.test.js +0 -1
  307. package/package/aws-client-agent-mcp/dist/index.d.ts +0 -1
  308. package/package/aws-client-agent-mcp/dist/index.js +2 -34
  309. package/package/aws-client-agent-mcp/dist/logger.d.ts +0 -1
  310. package/package/aws-client-agent-mcp/dist/logger.js +3 -178
  311. package/package/aws-client-agent-mcp/dist/logger.test.d.ts +0 -1
  312. package/package/aws-client-agent-mcp/dist/logger.test.js +0 -1
  313. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +0 -1
  314. package/package/aws-client-agent-mcp/dist/mcp-server.js +38 -2709
  315. package/package/aws-client-agent-mcp/dist/mcp-server.test.d.ts +0 -1
  316. package/package/aws-client-agent-mcp/dist/mcp-server.test.js +0 -1
  317. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +0 -1
  318. package/package/aws-client-agent-mcp/dist/mcp-tools.js +22 -562
  319. package/package/aws-client-agent-mcp/dist/mcp-tools.test.d.ts +0 -1
  320. package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +0 -1
  321. package/package/aws-client-agent-mcp/dist/memory-store.d.ts +0 -1
  322. package/package/aws-client-agent-mcp/dist/memory-store.js +4 -826
  323. package/package/aws-client-agent-mcp/dist/memory-store.test.d.ts +0 -1
  324. package/package/aws-client-agent-mcp/dist/memory-store.test.js +0 -1
  325. package/package/aws-client-agent-mcp/dist/memory-tools.d.ts +0 -1
  326. package/package/aws-client-agent-mcp/dist/memory-tools.js +31 -294
  327. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts +0 -1
  328. package/package/aws-client-agent-mcp/dist/message-buffer.js +2 -288
  329. package/package/aws-client-agent-mcp/dist/message-buffer.test.d.ts +0 -1
  330. package/package/aws-client-agent-mcp/dist/message-buffer.test.js +0 -1
  331. package/package/aws-client-agent-mcp/dist/messageContent.d.ts +0 -1
  332. package/package/aws-client-agent-mcp/dist/messageContent.js +2 -125
  333. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.d.ts +0 -1
  334. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js +2 -103
  335. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.d.ts +0 -1
  336. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +0 -1
  337. package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts +0 -1
  338. package/package/aws-client-agent-mcp/dist/server-memory-store.js +2 -96
  339. package/package/aws-client-agent-mcp/dist/status-reporter.d.ts +0 -1
  340. package/package/aws-client-agent-mcp/dist/status-reporter.js +3 -327
  341. package/package/aws-client-agent-mcp/dist/status-reporter.test.d.ts +0 -1
  342. package/package/aws-client-agent-mcp/dist/status-reporter.test.js +0 -1
  343. package/package/aws-client-agent-mcp/dist/types.d.ts +0 -1
  344. package/package/aws-client-agent-mcp/dist/types.js +2 -9
  345. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts +0 -1
  346. package/package/aws-client-agent-mcp/dist/websocket-client.js +2 -677
  347. package/package/aws-client-agent-mcp/dist/websocket-client.test.d.ts +0 -1
  348. package/package/aws-client-agent-mcp/dist/websocket-client.test.js +0 -1
  349. package/package/aws-client-agent-mcp/package.json +1 -1
  350. package/package/cc-switch-sdk/dist/constants.d.ts +0 -1
  351. package/package/cc-switch-sdk/dist/constants.js +2 -63
  352. package/package/cc-switch-sdk/dist/errors.d.ts +0 -1
  353. package/package/cc-switch-sdk/dist/errors.js +2 -8
  354. package/package/cc-switch-sdk/dist/index.d.ts +0 -1
  355. package/package/cc-switch-sdk/dist/index.js +2 -9
  356. package/package/cc-switch-sdk/dist/schemas.d.ts +0 -1
  357. package/package/cc-switch-sdk/dist/schemas.js +2 -38
  358. package/package/cc-switch-sdk/dist/sdk.d.ts +0 -1
  359. package/package/cc-switch-sdk/dist/sdk.js +2 -470
  360. package/package/cc-switch-sdk/dist/services/ai-config-service.d.ts +0 -1
  361. package/package/cc-switch-sdk/dist/services/ai-config-service.js +4 -307
  362. package/package/cc-switch-sdk/dist/services/mcp-model.d.ts +0 -1
  363. package/package/cc-switch-sdk/dist/services/mcp-model.js +2 -37
  364. package/package/cc-switch-sdk/dist/services/mcp-service.d.ts +0 -1
  365. package/package/cc-switch-sdk/dist/services/mcp-service.js +2 -9
  366. package/package/cc-switch-sdk/dist/services/skill-model.d.ts +0 -1
  367. package/package/cc-switch-sdk/dist/services/skill-model.js +2 -41
  368. package/package/cc-switch-sdk/dist/services/skill-service.d.ts +0 -1
  369. package/package/cc-switch-sdk/dist/services/skill-service.js +2 -9
  370. package/package/cc-switch-sdk/dist/state.d.ts +0 -1
  371. package/package/cc-switch-sdk/dist/state.js +2 -19
  372. package/package/cc-switch-sdk/dist/types.d.ts +0 -1
  373. package/package/cc-switch-sdk/dist/types.js +1 -1
  374. package/package/cc-switch-sdk/dist/utils/fs.d.ts +0 -1
  375. package/package/cc-switch-sdk/dist/utils/fs.js +3 -114
  376. package/package/cc-switch-sdk/dist/utils/id.d.ts +0 -1
  377. package/package/cc-switch-sdk/dist/utils/id.js +2 -12
  378. package/package/cc-switch-sdk/package.json +1 -1
  379. package/package.json +4 -2
  380. package/dist/adapter/AcodeSdkAdapter.d.ts.map +0 -1
  381. package/dist/adapter/AdapterRegistry.d.ts.map +0 -1
  382. package/dist/adapter/ClaudeSdkAdapter.d.ts.map +0 -1
  383. package/dist/adapter/CodexSdkAdapter.d.ts.map +0 -1
  384. package/dist/adapter/OpencodeSdkAdapter.d.ts.map +0 -1
  385. package/dist/adapter/SdkProviderSpi.d.ts.map +0 -1
  386. package/dist/adapter/acode-tool-names.d.ts.map +0 -1
  387. package/dist/adapter/idle-poll-loop.d.ts.map +0 -1
  388. package/dist/adapter/index.d.ts.map +0 -1
  389. package/dist/adapter/instance-ai-config-resolver.d.ts.map +0 -1
  390. package/dist/adapter/types.d.ts.map +0 -1
  391. package/dist/adapters/cc-switch/common.d.ts.map +0 -1
  392. package/dist/adapters/cc-switch/index.d.ts.map +0 -1
  393. package/dist/adapters/cc-switch/mcp-acode.d.ts.map +0 -1
  394. package/dist/adapters/cc-switch/mcp-claude.d.ts.map +0 -1
  395. package/dist/adapters/cc-switch/mcp-claudecode.d.ts.map +0 -1
  396. package/dist/adapters/cc-switch/mcp-codex.d.ts.map +0 -1
  397. package/dist/adapters/cc-switch/mcp-opencode.d.ts.map +0 -1
  398. package/dist/adapters/cc-switch/mcp-placeholder.d.ts.map +0 -1
  399. package/dist/adapters/cc-switch/skill-acode.d.ts.map +0 -1
  400. package/dist/adapters/cc-switch/skill-claude.d.ts.map +0 -1
  401. package/dist/adapters/cc-switch/skill-claudecode.d.ts.map +0 -1
  402. package/dist/adapters/cc-switch/skill-codex.d.ts.map +0 -1
  403. package/dist/adapters/cc-switch/skill-directory.d.ts.map +0 -1
  404. package/dist/adapters/cc-switch/skill-opencode.d.ts.map +0 -1
  405. package/dist/adapters/cc-switch/skill-placeholder.d.ts.map +0 -1
  406. package/dist/config.d.ts.map +0 -1
  407. package/dist/index.d.ts.map +0 -1
  408. package/dist/middleware/auth.d.ts.map +0 -1
  409. package/dist/routes/acode-todos.d.ts.map +0 -1
  410. package/dist/routes/ai-sources.d.ts.map +0 -1
  411. package/dist/routes/dashboard.d.ts.map +0 -1
  412. package/dist/routes/events.d.ts.map +0 -1
  413. package/dist/routes/file-browser.d.ts.map +0 -1
  414. package/dist/routes/file-diff-rollback.d.ts.map +0 -1
  415. package/dist/routes/file-snapshot.d.ts.map +0 -1
  416. package/dist/routes/git.d.ts.map +0 -1
  417. package/dist/routes/instance.d.ts.map +0 -1
  418. package/dist/routes/mcp.d.ts.map +0 -1
  419. package/dist/routes/processes.d.ts.map +0 -1
  420. package/dist/routes/properties.d.ts.map +0 -1
  421. package/dist/routes/pty.d.ts.map +0 -1
  422. package/dist/routes/runtime-binding.d.ts.map +0 -1
  423. package/dist/routes/sessions.d.ts.map +0 -1
  424. package/dist/routes/skills.d.ts.map +0 -1
  425. package/dist/routes/sub-agents.d.ts.map +0 -1
  426. package/dist/routes/system-metrics.d.ts.map +0 -1
  427. package/dist/routes/task-context.d.ts.map +0 -1
  428. package/dist/routes/terminal.d.ts.map +0 -1
  429. package/dist/routes/yml.d.ts.map +0 -1
  430. package/dist/services/acode-package.d.ts.map +0 -1
  431. package/dist/services/agent-event-store.d.ts.map +0 -1
  432. package/dist/services/agent-process-manager.d.ts.map +0 -1
  433. package/dist/services/ai-source-apply.d.ts.map +0 -1
  434. package/dist/services/auto-register.d.ts.map +0 -1
  435. package/dist/services/aws-client-agent-mcp.d.ts.map +0 -1
  436. package/dist/services/bridge-package-publish-hooks.d.ts.map +0 -1
  437. package/dist/services/cc-switch-sdk.d.ts.map +0 -1
  438. package/dist/services/cli-commands.d.ts.map +0 -1
  439. package/dist/services/event-delta-pusher.d.ts.map +0 -1
  440. package/dist/services/fileSnapshotStore.d.ts.map +0 -1
  441. package/dist/services/instance-ai-config-service.d.ts.map +0 -1
  442. package/dist/services/instance-init-service.d.ts.map +0 -1
  443. package/dist/services/instance-service.d.ts.map +0 -1
  444. package/dist/services/instance-state.d.ts.map +0 -1
  445. package/dist/services/legacy-path-migration.d.ts.map +0 -1
  446. package/dist/services/lifecycle-state.d.ts.map +0 -1
  447. package/dist/services/mcp-launch-binding-queue.d.ts.map +0 -1
  448. package/dist/services/orphan-monitor.d.ts.map +0 -1
  449. package/dist/services/panel-auth.d.ts.map +0 -1
  450. package/dist/services/process-detector.d.ts.map +0 -1
  451. package/dist/services/process-registry.d.ts.map +0 -1
  452. package/dist/services/ring-buffer.d.ts.map +0 -1
  453. package/dist/services/runtime-binding.d.ts.map +0 -1
  454. package/dist/services/runtime-lifecycle-policy.d.ts.map +0 -1
  455. package/dist/services/session-output.d.ts.map +0 -1
  456. package/dist/services/startup-config-wizard.d.ts.map +0 -1
  457. package/dist/services/sub-agent-manager-instance.d.ts.map +0 -1
  458. package/dist/services/system-metrics.d.ts.map +0 -1
  459. package/dist/services/terminal-persistence.d.ts.map +0 -1
  460. package/dist/services/tool-installer.d.ts.map +0 -1
  461. package/dist/services/tunnel-client.d.ts.map +0 -1
  462. package/dist/services/windows-service-manager.d.ts.map +0 -1
  463. package/dist/services/workspace-files.d.ts.map +0 -1
  464. package/dist/services/workspace-watch.d.ts.map +0 -1
  465. package/dist/services/workspaceTaskChangeWatcher.d.ts.map +0 -1
  466. package/dist/types.d.ts.map +0 -1
  467. package/dist/utils/file-utils.d.ts.map +0 -1
  468. package/dist/utils/instance-ai-config-debug-logger.d.ts.map +0 -1
  469. package/dist/utils/logger.d.ts.map +0 -1
  470. package/dist/utils/mcp-utils.d.ts.map +0 -1
  471. package/dist/utils/path-utils.d.ts.map +0 -1
  472. package/dist/utils/sdk-package-loader.d.ts.map +0 -1
  473. package/dist/utils/validation.d.ts.map +0 -1
  474. package/dist/utils/yaml-utils.d.ts.map +0 -1
  475. package/node_modules/@cc-switch/sdk/dist/constants.d.ts.map +0 -1
  476. package/node_modules/@cc-switch/sdk/dist/errors.d.ts.map +0 -1
  477. package/node_modules/@cc-switch/sdk/dist/index.d.ts.map +0 -1
  478. package/node_modules/@cc-switch/sdk/dist/schemas.d.ts.map +0 -1
  479. package/node_modules/@cc-switch/sdk/dist/sdk.d.ts.map +0 -1
  480. package/node_modules/@cc-switch/sdk/dist/services/ai-config-service.d.ts.map +0 -1
  481. package/node_modules/@cc-switch/sdk/dist/services/mcp-model.d.ts.map +0 -1
  482. package/node_modules/@cc-switch/sdk/dist/services/mcp-service.d.ts.map +0 -1
  483. package/node_modules/@cc-switch/sdk/dist/services/skill-model.d.ts.map +0 -1
  484. package/node_modules/@cc-switch/sdk/dist/services/skill-service.d.ts.map +0 -1
  485. package/node_modules/@cc-switch/sdk/dist/state.d.ts.map +0 -1
  486. package/node_modules/@cc-switch/sdk/dist/types.d.ts.map +0 -1
  487. package/node_modules/@cc-switch/sdk/dist/utils/fs.d.ts.map +0 -1
  488. package/node_modules/@cc-switch/sdk/dist/utils/id.d.ts.map +0 -1
  489. package/package/acode/dist/ask-user-question-tool.d.ts.map +0 -1
  490. package/package/acode/dist/built-in-file-tools.d.ts.map +0 -1
  491. package/package/acode/dist/built-in-symbols-tool.d.ts.map +0 -1
  492. package/package/acode/dist/builtins/commandArtifacts.d.ts.map +0 -1
  493. package/package/acode/dist/builtins/commandOutputEvents.d.ts.map +0 -1
  494. package/package/acode/dist/builtins/shellCommandPreparation.d.ts.map +0 -1
  495. package/package/acode/dist/builtins/shellCommandResult.d.ts.map +0 -1
  496. package/package/acode/dist/builtins/shellCommandRunner.d.ts.map +0 -1
  497. package/package/acode/dist/builtins/shellOutputDecoder.d.ts.map +0 -1
  498. package/package/acode/dist/cli.d.ts.map +0 -1
  499. package/package/acode/dist/commands/commandLoader.d.ts.map +0 -1
  500. package/package/acode/dist/commands/commandParser.d.ts.map +0 -1
  501. package/package/acode/dist/commands/commandRegistry.d.ts.map +0 -1
  502. package/package/acode/dist/compaction.d.ts.map +0 -1
  503. package/package/acode/dist/config.d.ts.map +0 -1
  504. package/package/acode/dist/fs-utils.d.ts.map +0 -1
  505. package/package/acode/dist/hooks/hookBus.d.ts.map +0 -1
  506. package/package/acode/dist/index.d.ts.map +0 -1
  507. package/package/acode/dist/mcpToolNames.d.ts.map +0 -1
  508. package/package/acode/dist/parsers/ast-cache.d.ts.map +0 -1
  509. package/package/acode/dist/parsers/language-detector.d.ts.map +0 -1
  510. package/package/acode/dist/parsers/language-queries.d.ts.map +0 -1
  511. package/package/acode/dist/parsers/symbol-extractor.d.ts.map +0 -1
  512. package/package/acode/dist/parsers/tree-sitter-loader.d.ts.map +0 -1
  513. package/package/acode/dist/parsers/types.d.ts.map +0 -1
  514. package/package/acode/dist/runtime.d.ts.map +0 -1
  515. package/package/acode/dist/skill-tool.d.ts.map +0 -1
  516. package/package/acode/dist/sub-agent-manager.d.ts.map +0 -1
  517. package/package/acode/dist/sub-agent-store.d.ts.map +0 -1
  518. package/package/acode/dist/sub-agent-tools.d.ts.map +0 -1
  519. package/package/acode/dist/sub-agent-types.d.ts.map +0 -1
  520. package/package/acode/dist/todo-store.d.ts.map +0 -1
  521. package/package/acode/dist/todo-tool.d.ts.map +0 -1
  522. package/package/acode/dist/types.d.ts.map +0 -1
  523. package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +0 -1
  524. package/package/aws-client-agent-mcp/dist/agent-client.js.map +0 -1
  525. package/package/aws-client-agent-mcp/dist/agent-client.test.d.ts.map +0 -1
  526. package/package/aws-client-agent-mcp/dist/agent-client.test.js.map +0 -1
  527. package/package/aws-client-agent-mcp/dist/config.d.ts.map +0 -1
  528. package/package/aws-client-agent-mcp/dist/config.js.map +0 -1
  529. package/package/aws-client-agent-mcp/dist/config.test.d.ts.map +0 -1
  530. package/package/aws-client-agent-mcp/dist/config.test.js.map +0 -1
  531. package/package/aws-client-agent-mcp/dist/constants.d.ts.map +0 -1
  532. package/package/aws-client-agent-mcp/dist/constants.js.map +0 -1
  533. package/package/aws-client-agent-mcp/dist/context-manager.d.ts.map +0 -1
  534. package/package/aws-client-agent-mcp/dist/context-manager.js.map +0 -1
  535. package/package/aws-client-agent-mcp/dist/context-manager.test.d.ts.map +0 -1
  536. package/package/aws-client-agent-mcp/dist/context-manager.test.js.map +0 -1
  537. package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +0 -1
  538. package/package/aws-client-agent-mcp/dist/http-client.js.map +0 -1
  539. package/package/aws-client-agent-mcp/dist/http-client.test.d.ts.map +0 -1
  540. package/package/aws-client-agent-mcp/dist/http-client.test.js.map +0 -1
  541. package/package/aws-client-agent-mcp/dist/index.d.ts.map +0 -1
  542. package/package/aws-client-agent-mcp/dist/index.js.map +0 -1
  543. package/package/aws-client-agent-mcp/dist/logger.d.ts.map +0 -1
  544. package/package/aws-client-agent-mcp/dist/logger.js.map +0 -1
  545. package/package/aws-client-agent-mcp/dist/logger.test.d.ts.map +0 -1
  546. package/package/aws-client-agent-mcp/dist/logger.test.js.map +0 -1
  547. package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +0 -1
  548. package/package/aws-client-agent-mcp/dist/mcp-server.js.map +0 -1
  549. package/package/aws-client-agent-mcp/dist/mcp-server.test.d.ts.map +0 -1
  550. package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +0 -1
  551. package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +0 -1
  552. package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +0 -1
  553. package/package/aws-client-agent-mcp/dist/mcp-tools.test.d.ts.map +0 -1
  554. package/package/aws-client-agent-mcp/dist/mcp-tools.test.js.map +0 -1
  555. package/package/aws-client-agent-mcp/dist/memory-store.d.ts.map +0 -1
  556. package/package/aws-client-agent-mcp/dist/memory-store.js.map +0 -1
  557. package/package/aws-client-agent-mcp/dist/memory-store.test.d.ts.map +0 -1
  558. package/package/aws-client-agent-mcp/dist/memory-store.test.js.map +0 -1
  559. package/package/aws-client-agent-mcp/dist/memory-tools.d.ts.map +0 -1
  560. package/package/aws-client-agent-mcp/dist/memory-tools.js.map +0 -1
  561. package/package/aws-client-agent-mcp/dist/message-buffer.d.ts.map +0 -1
  562. package/package/aws-client-agent-mcp/dist/message-buffer.js.map +0 -1
  563. package/package/aws-client-agent-mcp/dist/message-buffer.test.d.ts.map +0 -1
  564. package/package/aws-client-agent-mcp/dist/message-buffer.test.js.map +0 -1
  565. package/package/aws-client-agent-mcp/dist/messageContent.d.ts.map +0 -1
  566. package/package/aws-client-agent-mcp/dist/messageContent.js.map +0 -1
  567. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.d.ts.map +0 -1
  568. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js.map +0 -1
  569. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.d.ts.map +0 -1
  570. package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js.map +0 -1
  571. package/package/aws-client-agent-mcp/dist/server-memory-store.d.ts.map +0 -1
  572. package/package/aws-client-agent-mcp/dist/server-memory-store.js.map +0 -1
  573. package/package/aws-client-agent-mcp/dist/status-reporter.d.ts.map +0 -1
  574. package/package/aws-client-agent-mcp/dist/status-reporter.js.map +0 -1
  575. package/package/aws-client-agent-mcp/dist/status-reporter.test.d.ts.map +0 -1
  576. package/package/aws-client-agent-mcp/dist/status-reporter.test.js.map +0 -1
  577. package/package/aws-client-agent-mcp/dist/types.d.ts.map +0 -1
  578. package/package/aws-client-agent-mcp/dist/types.js.map +0 -1
  579. package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +0 -1
  580. package/package/aws-client-agent-mcp/dist/websocket-client.js.map +0 -1
  581. package/package/aws-client-agent-mcp/dist/websocket-client.test.d.ts.map +0 -1
  582. package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +0 -1
  583. package/package/cc-switch-sdk/dist/constants.d.ts.map +0 -1
  584. package/package/cc-switch-sdk/dist/errors.d.ts.map +0 -1
  585. package/package/cc-switch-sdk/dist/index.d.ts.map +0 -1
  586. package/package/cc-switch-sdk/dist/schemas.d.ts.map +0 -1
  587. package/package/cc-switch-sdk/dist/sdk.d.ts.map +0 -1
  588. package/package/cc-switch-sdk/dist/services/ai-config-service.d.ts.map +0 -1
  589. package/package/cc-switch-sdk/dist/services/mcp-model.d.ts.map +0 -1
  590. package/package/cc-switch-sdk/dist/services/mcp-service.d.ts.map +0 -1
  591. package/package/cc-switch-sdk/dist/services/skill-model.d.ts.map +0 -1
  592. package/package/cc-switch-sdk/dist/services/skill-service.d.ts.map +0 -1
  593. package/package/cc-switch-sdk/dist/state.d.ts.map +0 -1
  594. package/package/cc-switch-sdk/dist/types.d.ts.map +0 -1
  595. package/package/cc-switch-sdk/dist/utils/fs.d.ts.map +0 -1
  596. package/package/cc-switch-sdk/dist/utils/id.d.ts.map +0 -1
@@ -1,1159 +1,2 @@
1
- import { randomUUID } from "node:crypto";
2
- import { ACodeRuntime } from "./runtime.js";
3
- /** 已完成 entry 在内存中的保留时长(30 分钟),超时后清理释放内存 */
4
- const COMPLETED_ENTRY_TTL_MS = 30 * 60 * 1000;
5
- /**
6
- * pending 子 agent 超过该时长仍未翻成 running,视为僵尸。
7
- * pending 本应在 spawn 后数秒内翻转(runEntryToCompletion* 立即设置 running),
8
- * 若长时间保持 pending,说明 startWithRecheck 抛错被静默吞掉、或启动函数从未执行,
9
- * 必须回收,否则 URIs 会被 runtime.pendingMemorySubAgents 永久锁死、永不重试。
10
- */
11
- const SUBAGENT_PENDING_ZOMBIE_MS = 2 * 60 * 1000;
12
- /**
13
- * running 子 agent 超过该时长仍未到达终态,视为僵尸。
14
- * 正常 LLM 子任务即便较长也应有上界;卡死多因 runtime.start()/submit() 挂起
15
- * (如复用的父 MCP 连接异常、模型调用无响应),需回收以释放资源并解除锁。
16
- *
17
- * ★ 设为 12min(> SUBAGENT_SUBMIT_TIMEOUT_MS=10min):
18
- * - 子 agent 卡死时,submit() 10min 超时会先触发,给出明确的错误信息
19
- * (如 "runtime.submit() turn=1 timed out after 600000ms")
20
- * - zombie 兜底覆盖 submit 内部无超时保护的步骤(如 hookBus.dispatch)
21
- * - 之前 5min 比 submit 10min 更早触发,导致用户永远看不到真正的 submit 超时错误
22
- * - task 工具显式调用的 sub-agent 不走此自动路径,不受影响
23
- */
24
- const SUBAGENT_RUNNING_ZOMBIE_MS = 12 * 60 * 1000;
25
- /**
26
- * store 写入超时兜底(毫秒)。
27
- * SubAgentStore.write 使用 writeChain 串行化所有文件写入,若前一个 write 卡住
28
- * (磁盘 IO 慢、tmp 文件 rename 卡住、文件系统问题等),后续所有 write 都会
29
- * 被永久阻塞,导致 sub-agent 卡在 store.updateStatus 处无法继续 start()。
30
- * 5s 超时足够覆盖正常文件 IO(通常 < 100ms),超时后放弃落盘(不影响内存态)。
31
- *
32
- * ★ 仅用于 running 态写入(非阻塞路径不需要超时)。
33
- * 终态写入走 persistFinalStatus 的指数退避重试,不再使用 withTimeout。
34
- */
35
- const STORE_WRITE_TIMEOUT_MS = 5_000;
36
- /**
37
- * 终态落盘的指数退避序列(毫秒)。
38
- *
39
- * 终态写入失败时按此序列重试,覆盖以下瞬时错误场景:
40
- * - Windows fs.rename EPERM(reader 持有 fd,退避后释放即可成功)
41
- * - writeChain 临时拥堵(前一个 write 慢,退避后队列消化)
42
- * - 磁盘瞬时不可用
43
- *
44
- * 总耗时 ≈ 100+500+2000+8000 = 10.6s,远大于 EPERM 退避窗口和 writeChain 排队时长,
45
- * 同时不至过长影响 bridge 关闭时的 dispose 流程。
46
- */
47
- const PERSIST_BACKOFF_MS = [100, 500, 2_000, 8_000];
48
- /**
49
- * 子 agent runtime.start() 整体超时兜底(毫秒)。
50
- * start() 内部正常路径秒级完成(loadSkills/resolveProvider/filterMcp/fetchProfile/emitStatus),
51
- * 超过此时长基本可判定为卡死(如 hookBus.dispatch 卡住、fetchProfile 的 MCP 调用挂起)。
52
- * fetchProfilePrompt 内部已有 withTimeout,但其他步骤无保护,需外层兜底。
53
- */
54
- const SUBAGENT_START_TIMEOUT_MS = 60_000;
55
- /**
56
- * 子 agent runtime.submit() 整体超时兜底(毫秒)。
57
- * submit 内部 fetch 已有 provider.requestTimeoutMs 保护,但 hookBus.dispatch /
58
- * materializeImageContent / truncateConversationIfNeeded 等步骤无超时;
59
- * 主动压缩路径(performCompaction → summarizeConversationWithLLM)亦独立有 withTimeout。
60
- * 此 10min 兜底覆盖极端长 LLM 响应 + 多轮工具调用,超此时长视为整体卡死。
61
- */
62
- const SUBAGENT_SUBMIT_TIMEOUT_MS = 10 * 60 * 1000;
63
- /**
64
- * SubAgentManager:管理独立 ACodeRuntime 实例池。
65
- *
66
- * 核心职责:
67
- * 1. spawn 创建独立 ACodeRuntime 实例(避免父 agent 的 submitQueue 死锁)
68
- * 2. start 异步启动子 agent(不阻塞),awaitCompletion 显式等待完成
69
- * 3. abort 取消运行中的 sub-agent
70
- * 4. 维护父子关系映射(parentAgentId -> subIds)
71
- * 5. SSE 事件订阅(subscribe/unsubscribe)
72
- * 6. 状态持久化到 SubAgentStore
73
- *
74
- * 线程模型:单进程 Node.js,所有 ACodeRuntime 实例共享事件循环。
75
- * 非阻塞模式:spawn 后调 start 立即返回,主 agent 可继续工作;
76
- * 主 agent 通过 awaitCompletion 显式阻塞等待指定 sub-agent 数组完成。
77
- *
78
- * 重要:ACodeRuntime.submit() 返回 Promise<void>,assistant 文本通过
79
- * "event" 上的 "assistant_delta" 事件传递,turn 结束时发出 "turn_complete"。
80
- * 因此 start 内部注册事件监听器累积输出文本,awaitCompletion 通过 Promise 等待。
81
- *
82
- * Entry 生命周期:
83
- * - pending: spawn 后未 start
84
- * - running: start 后运行中
85
- * - completed/failed/cancelled: 终态,entry 保留在内存中 TTL=30min,
86
- * 供 list/get_status 查询;超时后从内存清理(store 仍持久化)
87
- */
88
- export class SubAgentManager {
89
- constructor(opts) {
90
- this.subAgents = new Map();
91
- this.parentToSubs = new Map();
92
- this.subscribers = new Map(); // subId 或 "*" -> subs
93
- /** 已完成 entry 的清理定时器 */
94
- this.cleanupTimer = null;
95
- /**
96
- * 终态通知队列:子 agent 到达终态时入队,takeCompletedSubAgents 消费。
97
- * 供 poll_message 在 ACode 运行时层检测子 agent 完成事件。
98
- */
99
- this.completionQueue = [];
100
- /**
101
- * waitForAnyCompletion 的 resolve 回调,终态事件到达时调用。
102
- * null 表示当前没有等待者。
103
- */
104
- this.completionWaiterResolve = null;
105
- /**
106
- * 正在执行的异步终态落盘 Promise 集合。
107
- *
108
- * 用于:
109
- * - 测试等待异步落盘完成后再读取 store 验证状态
110
- * - dispose 时确保所有落盘完成后再清理(避免文件句柄占用导致目录非空)
111
- *
112
- * persistFinalStatus 启动时入集,resolve/reject 后出集。
113
- */
114
- this.pendingPersists = new Set();
115
- this.store = opts.store;
116
- this.maxConcurrent = opts.maxConcurrent ?? 5;
117
- // 启动定期清理已完成 entry 的定时器(每 5 分钟扫一次)
118
- this.cleanupTimer = setInterval(() => {
119
- this.cleanupCompletedEntries();
120
- this.recoverZombieEntries();
121
- }, 5 * 60 * 1000);
122
- // 不阻止进程退出
123
- if (this.cleanupTimer.unref)
124
- this.cleanupTimer.unref();
125
- // 启动时回收上次进程异常退出留下的僵尸记录(reconcileZombies 此前未被任何调用方触发)
126
- void this.store.reconcileZombies().catch(() => { });
127
- }
128
- /** 创建 sub-agent(不立即运行;调 start 才执行) */
129
- async spawn(opts) {
130
- // 并发上限检查(pending + running 都算占用配额)
131
- const activeCount = this.countByStatus(opts.parentAgentId, "running", "pending");
132
- if (activeCount >= this.maxConcurrent) {
133
- throw new Error(`concurrent sub-agent limit reached (${this.maxConcurrent}) for agent ${opts.parentAgentId}`);
134
- }
135
- const subId = `sub-${randomUUID()}`;
136
- const startedAt = Date.now();
137
- const abortController = new AbortController();
138
- // 构造子 agent 的 config(继承父 agent 的 model/prompt,但独立 sessionId)
139
- // 若父 agent 配置了 subAgentModel/subAgentEffort,则覆盖子 agent 的 model/effort
140
- const childConfig = {
141
- ...opts.parentConfig,
142
- sessionId: subId,
143
- workingDirectory: opts.workingDirectory,
144
- agentId: `${opts.parentAgentId}__sub__${subId}`,
145
- // sub-agent 不继承 initialPrompt(用 submit 触发)
146
- initialPrompt: undefined,
147
- // sub-agent 不允许再 spawn 自己的子 agent(禁止递归嵌套)
148
- subAgentManager: undefined,
149
- // ★ 注入 subagentType:runtime.start() 据此过滤内建写入工具。
150
- // explore 类型仅暴露只读工具(read_file/grep/symbols 等),
151
- // 防止 explore 子 agent 改写主工作区文件,违背只读语义。
152
- subagentType: opts.subagentType,
153
- // Sub Agent 模型/强度覆盖:有值则覆盖继承的 model/effort
154
- ...(opts.parentConfig.subAgentModel
155
- ? { model: opts.parentConfig.subAgentModel }
156
- : {}),
157
- ...(opts.parentConfig.subAgentEffort
158
- ? { effort: opts.parentConfig.subAgentEffort }
159
- : {}),
160
- // 子 agent 不再继承 subAgent 专用覆盖字段(防止孙 agent 二次覆盖)
161
- subAgentModel: undefined,
162
- subAgentEffort: undefined,
163
- };
164
- const runtime = new ACodeRuntime(childConfig);
165
- const entry = {
166
- subId,
167
- parentAgentId: opts.parentAgentId,
168
- parentSessionId: opts.parentSessionId,
169
- subagentType: opts.subagentType,
170
- description: opts.description,
171
- prompt: opts.prompt,
172
- status: "pending",
173
- startedAt,
174
- runtime,
175
- abortController,
176
- silent: opts.silent,
177
- contextSnapshot: {
178
- tokenUsage: { input: 0, output: 0 },
179
- messageCount: 0,
180
- updatedAt: new Date().toISOString(),
181
- },
182
- availableTools: [],
183
- };
184
- this.subAgents.set(subId, entry);
185
- this.addToParentMap(opts.parentAgentId, subId);
186
- // 持久化初始记录
187
- const record = this.toRecord(entry);
188
- await this.store.upsert(opts.parentAgentId, record);
189
- // 监听 runtime 事件以更新 contextSnapshot
190
- runtime.on("event", (event) => {
191
- this.handleRuntimeEvent(subId, event);
192
- });
193
- this.emitEvent(subId, "spawned", {});
194
- return subId;
195
- }
196
- /**
197
- * 异步启动 sub-agent(不阻塞,立即返回)。
198
- *
199
- * 内部创建 completionPromise 供后续 awaitCompletion 等待。
200
- * 启动后立即返回,主 agent 可继续做其他事。
201
- *
202
- * 同一 sub-agent 只能 start 一次;重复 start 抛错。
203
- */
204
- async start(subId) {
205
- const entry = this.subAgents.get(subId);
206
- if (!entry) {
207
- throw new Error(`sub-agent not found: ${subId}`);
208
- }
209
- if (entry.status !== "pending") {
210
- throw new Error(`sub-agent ${subId} cannot start from status: ${entry.status}`);
211
- }
212
- // 创建 completionPromise(在 finally 中 settle)
213
- entry.completionPromise = new Promise((resolve, reject) => {
214
- entry.completionResolve = resolve;
215
- entry.completionReject = reject;
216
- });
217
- // 异步启动,不阻塞调用方
218
- void this.runEntryToCompletion(entry).catch(() => {
219
- // runEntryToCompletion 内部已处理异常并更新状态;
220
- // 这里捕获防止 unhandled rejection
221
- });
222
- }
223
- /**
224
- * 带 recheck 循环的异步启动(不阻塞,立即返回)。
225
- *
226
- * 与 start 的区别:每轮 submit 完成后调用 recheck 回调查询服务端真实状态。
227
- * 若 recheck 返回 { done: false, continueMessage },将 continueMessage 作为
228
- * 下一轮 submit 注入同一 sub-agent(保持上下文连续性),最多重试 maxRetries 次。
229
- *
230
- * 适用场景:memory 过期整理 / 文件变更更新 / 容量整理等需要系统级硬保证
231
- * "确实完成"的场景,不依赖 LLM 自报结果。
232
- */
233
- async startWithRecheck(subId, recheck, maxRetries = 3) {
234
- const entry = this.subAgents.get(subId);
235
- if (!entry) {
236
- throw new Error(`sub-agent not found: ${subId}`);
237
- }
238
- if (entry.status !== "pending") {
239
- throw new Error(`sub-agent ${subId} cannot start from status: ${entry.status}`);
240
- }
241
- // 创建 completionPromise(在 finally 中 settle)
242
- entry.completionPromise = new Promise((resolve, reject) => {
243
- entry.completionResolve = resolve;
244
- entry.completionReject = reject;
245
- });
246
- // 异步启动,不阻塞调用方
247
- void this.runEntryToCompletionWithRecheck(entry, recheck, maxRetries).catch(() => {
248
- // 内部已处理异常并更新状态;这里捕获防止 unhandled rejection
249
- });
250
- }
251
- /**
252
- * 阻塞等待指定 sub-agent 数组全部完成(completed/failed/cancelled)。
253
- *
254
- * - 已完成的立即 resolve
255
- * - 未 start 的会先 start(自动启动)
256
- * - 返回每个 sub-agent 的最终结果
257
- *
258
- * 注意:本方法不取消 sub-agent,仅等待。如需取消用 abort。
259
- */
260
- async awaitCompletion(subIds, timeoutMs = 0) {
261
- if (subIds.length === 0)
262
- return [];
263
- const results = [];
264
- // 对每个 subId 准备等待 Promise
265
- const waitPromises = subIds.map(async (subId) => {
266
- const entry = this.subAgents.get(subId);
267
- if (!entry) {
268
- // entry 已从内存清理,从 store 查
269
- const record = await this.findRecordInStore(subId);
270
- if (record) {
271
- results.push({
272
- subId,
273
- output: record.result ?? "",
274
- error: record.errorMessage,
275
- status: record.status,
276
- });
277
- }
278
- else {
279
- results.push({
280
- subId,
281
- output: "",
282
- error: `sub-agent not found: ${subId}`,
283
- status: "failed",
284
- });
285
- }
286
- return;
287
- }
288
- // 标记为 awaited:防止 enqueueCompletion 将终态通知推入 completionQueue
289
- // (避免后续 poll_message 重复返回已被 await 消费的结果)
290
- entry.awaited = true;
291
- // 如果还在 pending,自动 start
292
- if (entry.status === "pending") {
293
- await this.start(subId);
294
- }
295
- // 等待 completionPromise(可能已被 start 创建)
296
- const promise = entry.completionPromise ?? Promise.resolve({ output: "", error: "not started" });
297
- try {
298
- const result = await promise;
299
- results.push({
300
- subId,
301
- output: result.output,
302
- error: result.error,
303
- status: entry.status,
304
- });
305
- }
306
- catch (err) {
307
- results.push({
308
- subId,
309
- output: "",
310
- error: err instanceof Error ? err.message : String(err),
311
- status: entry.status,
312
- });
313
- }
314
- });
315
- // 等待全部完成后,清理 completionQueue 中可能已存在的这些 subId 的通知
316
- // (处理子 agent 在 awaited 标记设置前已完成入队的情况)
317
- const subIdSet = new Set(subIds);
318
- for (let i = this.completionQueue.length - 1; i >= 0; i--) {
319
- if (subIdSet.has(this.completionQueue[i].subId)) {
320
- this.completionQueue.splice(i, 1);
321
- }
322
- }
323
- if (timeoutMs > 0) {
324
- await Promise.race([
325
- Promise.allSettled(waitPromises),
326
- new Promise((resolve) => setTimeout(() => resolve(), timeoutMs)),
327
- ]);
328
- }
329
- else {
330
- await Promise.allSettled(waitPromises);
331
- }
332
- return results;
333
- }
334
- /**
335
- * 内部方法:执行 entry 直到完成。
336
- *
337
- * 实际 ACodeRuntime.submit() 返回 Promise<void>,assistant 文本通过
338
- * assistant_delta 事件传递。本方法注册临时监听器累积输出文本,
339
- * 同时检测 turn_complete 事件中的 failed 标志以处理运行时内部错误。
340
- *
341
- * 完成后:
342
- * - 更新 entry 状态(completed/failed)
343
- * - 持久化到 store
344
- * - settle completionPromise
345
- * - 清理 runtime 实例(释放内存)
346
- * - **不删除 entry**(保留在内存供 list/get_status 查询,30min 后由定时器清理)
347
- */
348
- async runEntryToCompletion(entry) {
349
- // 收集 assistant_delta 文本 + 检测 turn 失败标志
350
- const chunks = [];
351
- let turnFailed = false;
352
- let turnErrorMessage;
353
- const onEvent = (event) => {
354
- if (!event)
355
- return;
356
- switch (event.type) {
357
- case "assistant_delta":
358
- if (typeof event.data?.text === "string") {
359
- chunks.push(event.data.text);
360
- }
361
- break;
362
- case "turn_complete":
363
- if (event.data?.failed) {
364
- turnFailed = true;
365
- }
366
- break;
367
- case "error":
368
- if (typeof event.data?.message === "string") {
369
- turnErrorMessage = event.data.message;
370
- }
371
- break;
372
- }
373
- };
374
- entry.runtime.on("event", onEvent);
375
- // ★ 状态 -> running:先同步设置 + emit + currentTool 标记,再异步落盘。
376
- // 之前顺序是 status=running → await store.updateStatus → emit running,
377
- // 若 store.updateStatus 因 writeChain 串行化卡住(前一个 write 卡死),
378
- // emit running 不会执行,start() 也不会被调用,前端 modal 永远显示
379
- // 初始 snapshot(0消息 0tokens 当前工具-),与"从未运行"无法区分。
380
- // 调整顺序后即使落盘卡住,前端也能立即看到 [starting] 标记。
381
- entry.status = "running";
382
- entry.contextSnapshot.currentTool = "[starting]";
383
- entry.contextSnapshot.updatedAt = new Date().toISOString();
384
- this.emitEvent(entry.subId, "running", { snapshot: { ...entry.contextSnapshot } });
385
- // 落盘带超时保护:writeChain 串行化可能卡住,超时后放弃落盘(不影响内存态)
386
- try {
387
- await withTimeout(this.store.updateStatus(entry.parentAgentId, entry.subId, { status: "running" }), STORE_WRITE_TIMEOUT_MS, `sub-agent ${entry.subId} store.updateStatus(running)`);
388
- }
389
- catch (err) {
390
- console.error(`[SubAgentManager] store.updateStatus(running) failed for subId=${entry.subId}: ` +
391
- `${err instanceof Error ? err.message : String(err)}`);
392
- }
393
- try {
394
- await entry.runtime.start();
395
- // 记录启动后的可用工具列表
396
- entry.availableTools = entry.runtime.getAvailableTools();
397
- await entry.runtime.submit(entry.prompt);
398
- // 实际 API 中 submit 解析后所有事件已同步触发完毕(EventEmitter.emit 是同步的)
399
- // 若 turn_complete 标记 failed,抛错走 catch
400
- if (turnFailed) {
401
- throw new Error(turnErrorMessage ?? "sub-agent turn failed");
402
- }
403
- const output = chunks.join("");
404
- entry.status = "completed";
405
- entry.result = output;
406
- entry.endedAt = Date.now();
407
- entry.durationMs = entry.endedAt - entry.startedAt;
408
- // ★ emit 前置:先把 completed 事件发出,让前端 modal 立即看到状态变化
409
- // (subscribers 同步执行,SSE 路由立即推送)。
410
- this.emitEvent(entry.subId, "completed", { result: output });
411
- // ★ 终态落盘改为非阻塞:内存已置 completed,立即 settle completionPromise
412
- // + 入队通知,磁盘写入走 persistFinalStatus 的指数退避重试,不阻塞主流程。
413
- // 即使落盘最终失败,前端看到的仍是真实 completed 状态(内存态是真相源),
414
- // 不会触发列表接口的 "status mismatch" 兜底(兜底逻辑已移除)。
415
- entry.completionResolve?.({ output });
416
- this.enqueueCompletion(entry, output, undefined);
417
- void this.persistFinalStatus(entry, {
418
- status: "completed",
419
- result: output,
420
- endedAt: entry.endedAt,
421
- durationMs: entry.durationMs,
422
- // ★ 持久化 availableTools:start() 后才填充,必须随终态落盘,
423
- // 否则 entry 从内存清理后 store 永远是 spawn 时的空数组,
424
- // 前端 modal "可用工具" tab 始终显示"暂无工具信息"。
425
- availableTools: entry.availableTools,
426
- contextSnapshot: undefined, // 完成后清空快照
427
- });
428
- }
429
- catch (err) {
430
- const errorMessage = err instanceof Error ? err.message : String(err);
431
- entry.status = "failed";
432
- entry.errorMessage = errorMessage;
433
- entry.endedAt = Date.now();
434
- entry.durationMs = entry.endedAt - entry.startedAt;
435
- // ★ emit 前置 + 终态非阻塞落盘(同 completed 路径的设计理由)
436
- this.emitEvent(entry.subId, "failed", { error: errorMessage });
437
- entry.completionResolve?.({ output: "", error: errorMessage });
438
- this.enqueueCompletion(entry, "", errorMessage);
439
- void this.persistFinalStatus(entry, {
440
- status: "failed",
441
- errorMessage,
442
- endedAt: entry.endedAt,
443
- durationMs: entry.durationMs,
444
- availableTools: entry.availableTools,
445
- contextSnapshot: undefined,
446
- });
447
- }
448
- finally {
449
- // 移除临时监听器
450
- try {
451
- entry.runtime.removeListener?.("event", onEvent);
452
- }
453
- catch {
454
- /* 忽略移除失败 */
455
- }
456
- // 完成后清理 runtime 实例(释放内存),但保留 entry 供查询
457
- try {
458
- await entry.runtime.stop();
459
- }
460
- catch {
461
- /* 忽略 stop 失败 */
462
- }
463
- }
464
- }
465
- /**
466
- * 带 recheck 循环的 entry 执行(多轮 submit)。
467
- *
468
- * 与 runEntryToCompletion 的区别:
469
- * 1. 第一轮 submit(entry.prompt) 完成后,调用 recheck 回调查询服务端真实状态
470
- * 2. 若 recheck 返回 { done: false, continueMessage },将 continueMessage 注入下一轮 submit
471
- * 3. 最多重试 maxRetries 次;超过后视为完成(不再继续)
472
- * 4. onEvent 监听器跨所有轮次累积 assistant_delta,最终 output 包含全部轮次的文本
473
- *
474
- * turnFailed 标志在每轮 submit 前重置,确保上一轮的失败状态不影响下一轮判断。
475
- * recheck 自身抛错时视为 done(不阻塞 sub-agent 结束),仅记录日志。
476
- */
477
- async runEntryToCompletionWithRecheck(entry, recheck, maxRetries) {
478
- const chunks = [];
479
- let turnFailed = false;
480
- let turnErrorMessage;
481
- const onEvent = (event) => {
482
- if (!event)
483
- return;
484
- switch (event.type) {
485
- case "assistant_delta":
486
- if (typeof event.data?.text === "string") {
487
- chunks.push(event.data.text);
488
- }
489
- break;
490
- case "turn_complete":
491
- if (event.data?.failed) {
492
- turnFailed = true;
493
- }
494
- break;
495
- case "error":
496
- if (typeof event.data?.message === "string") {
497
- turnErrorMessage = event.data.message;
498
- }
499
- break;
500
- }
501
- };
502
- entry.runtime.on("event", onEvent);
503
- // ★ 状态 -> running:先同步设置 + emit + currentTool 标记,再异步落盘。
504
- // 之前顺序是 status=running → await store.updateStatus → emit running,
505
- // 若 store.updateStatus 因 writeChain 串行化卡住(前一个 write 卡死),
506
- // emit running 不会执行,start() 也不会被调用,前端 modal 永远显示
507
- // 初始 snapshot(0消息 0tokens 当前工具-),与"从未运行"无法区分。
508
- // 调整顺序后即使落盘卡住,前端也能立即看到 [starting] 标记。
509
- entry.status = "running";
510
- entry.contextSnapshot.currentTool = "[starting]";
511
- entry.contextSnapshot.updatedAt = new Date().toISOString();
512
- this.emitEvent(entry.subId, "running", { snapshot: { ...entry.contextSnapshot } });
513
- // 落盘带超时保护:writeChain 串行化可能卡住,超时后放弃落盘(不影响内存态)
514
- try {
515
- await withTimeout(this.store.updateStatus(entry.parentAgentId, entry.subId, { status: "running" }), STORE_WRITE_TIMEOUT_MS, `sub-agent ${entry.subId} store.updateStatus(running)`);
516
- }
517
- catch (err) {
518
- console.error(`[SubAgentManager] store.updateStatus(running) failed for subId=${entry.subId}: ` +
519
- `${err instanceof Error ? err.message : String(err)}`);
520
- }
521
- try {
522
- // ★ 超时兜底:start() 通常秒级完成,超时说明卡在 hookBus/fetchProfile/loadCommands
523
- // 等无超时保护的步骤。抛错后被外层 catch 标记为 failed,前端可见。
524
- await withTimeout(entry.runtime.start(), SUBAGENT_START_TIMEOUT_MS, `sub-agent ${entry.subId} runtime.start()`);
525
- // ★ 可见性修正:start() 完成后、submit() 之前显式标记,让 submit 早期阶段
526
- // (hookBus.dispatch("UserPromptSubmit")、materializeImageContent 等)的卡点可见。
527
- // 之前 skill_status 标记会停留到 ai_request 覆盖,但若 submit 卡在 ai_request 之前,
528
- // 前端会显示 "[skill_loaded]"——容易误判为卡在 start()。这里覆盖为 "[submitting]"
529
- // 明确表示已进入 submit 阶段。
530
- entry.contextSnapshot.currentTool = "[submitting]";
531
- entry.contextSnapshot.updatedAt = new Date().toISOString();
532
- entry.availableTools = entry.runtime.getAvailableTools();
533
- this.emitEvent(entry.subId, "progress", { snapshot: { ...entry.contextSnapshot } });
534
- // 第一轮:使用初始 prompt
535
- // ★ 超时兜底:submit 内部 fetch/performCompaction 已有 withTimeout,
536
- // 但 hookBus.dispatch/materializeImageContent 等无保护,整体 10min 兜底。
537
- await withTimeout(entry.runtime.submit(entry.prompt), SUBAGENT_SUBMIT_TIMEOUT_MS, `sub-agent ${entry.subId} runtime.submit() turn=1`);
538
- if (turnFailed) {
539
- throw new Error(turnErrorMessage ?? "sub-agent turn failed");
540
- }
541
- let turn = 1;
542
- // recheck 循环:最多 maxRetries 次
543
- while (turn <= maxRetries) {
544
- let recheckResult;
545
- try {
546
- recheckResult = await recheck(chunks.join(""), turn);
547
- }
548
- catch (recheckErr) {
549
- // recheck 自身出错:不阻塞 sub-agent 结束,视为完成
550
- console.error(`[SubAgentManager] recheck threw error for subId=${entry.subId} turn=${turn}, treating as done:`, recheckErr instanceof Error ? recheckErr.message : String(recheckErr));
551
- break;
552
- }
553
- if (recheckResult.done) {
554
- break;
555
- }
556
- // 未完成:注入 continueMessage 进行下一轮
557
- const continueMessage = recheckResult.continueMessage ?? "经检查,未完成处理,请继续。";
558
- // 重置 turn 失败标记,确保本轮失败状态不影响下一轮判断
559
- turnFailed = false;
560
- turnErrorMessage = undefined;
561
- console.error(`[SubAgentManager] recheck not done for subId=${entry.subId} turn=${turn}/${maxRetries}, ` +
562
- `injecting continue message (${continueMessage.length} chars)`);
563
- // ★ 超时兜底:recheck 续轮 submit 同样需要保护,避免卡死
564
- await withTimeout(entry.runtime.submit(continueMessage), SUBAGENT_SUBMIT_TIMEOUT_MS, `sub-agent ${entry.subId} runtime.submit() recheck turn=${turn + 1}`);
565
- if (turnFailed) {
566
- throw new Error(turnErrorMessage ?? `sub-agent turn ${turn + 1} failed during recheck continuation`);
567
- }
568
- turn++;
569
- }
570
- if (turn > maxRetries) {
571
- console.error(`[SubAgentManager] recheck reached maxRetries=${maxRetries} for subId=${entry.subId}, ` +
572
- `completing with potentially unfinished work`);
573
- }
574
- const output = chunks.join("");
575
- entry.status = "completed";
576
- entry.result = output;
577
- entry.endedAt = Date.now();
578
- entry.durationMs = entry.endedAt - entry.startedAt;
579
- // ★ emit 前置 + 终态非阻塞落盘 + 立即 settle completionPromise
580
- // (设计理由同 runEntryToCompletion:内存态是真相源,磁盘写入不阻塞主流程)
581
- this.emitEvent(entry.subId, "completed", { result: output });
582
- entry.completionResolve?.({ output });
583
- this.enqueueCompletion(entry, output, undefined);
584
- void this.persistFinalStatus(entry, {
585
- status: "completed",
586
- result: output,
587
- endedAt: entry.endedAt,
588
- durationMs: entry.durationMs,
589
- availableTools: entry.availableTools,
590
- contextSnapshot: undefined,
591
- });
592
- }
593
- catch (err) {
594
- const errorMessage = err instanceof Error ? err.message : String(err);
595
- entry.status = "failed";
596
- entry.errorMessage = errorMessage;
597
- entry.endedAt = Date.now();
598
- entry.durationMs = entry.endedAt - entry.startedAt;
599
- // ★ emit 前置 + 终态非阻塞落盘(同 completed 路径的设计理由)
600
- this.emitEvent(entry.subId, "failed", { error: errorMessage });
601
- entry.completionResolve?.({ output: "", error: errorMessage });
602
- this.enqueueCompletion(entry, "", errorMessage);
603
- void this.persistFinalStatus(entry, {
604
- status: "failed",
605
- errorMessage,
606
- endedAt: entry.endedAt,
607
- durationMs: entry.durationMs,
608
- availableTools: entry.availableTools,
609
- contextSnapshot: undefined,
610
- });
611
- }
612
- finally {
613
- // 移除临时监听器
614
- try {
615
- entry.runtime.removeListener?.("event", onEvent);
616
- }
617
- catch {
618
- /* 忽略移除失败 */
619
- }
620
- // 完成后清理 runtime 实例(释放内存),但保留 entry 供查询
621
- try {
622
- await entry.runtime.stop();
623
- }
624
- catch {
625
- /* 忽略 stop 失败 */
626
- }
627
- }
628
- }
629
- /**
630
- * @deprecated 兼容旧接口:spawn + 阻塞等待完成。
631
- * 新代码应使用 spawn + start + awaitCompletion。
632
- */
633
- async runToCompletion(subId) {
634
- const entry = this.subAgents.get(subId);
635
- if (!entry) {
636
- throw new Error(`sub-agent not found: ${subId}`);
637
- }
638
- if (entry.status === "running") {
639
- throw new Error(`sub-agent already running: ${subId}`);
640
- }
641
- // 重置 status 以便 runEntryToCompletion 能进入 running
642
- if (entry.status !== "pending") {
643
- entry.status = "pending";
644
- }
645
- await this.start(subId);
646
- return (await entry.completionPromise) ?? { output: "", error: "not started" };
647
- }
648
- /** 取消运行中的 sub-agent */
649
- async abort(subId) {
650
- const entry = this.subAgents.get(subId);
651
- if (!entry)
652
- return;
653
- if (entry.status === "completed" || entry.status === "failed" || entry.status === "cancelled") {
654
- return;
655
- }
656
- entry.abortController.abort();
657
- try {
658
- await entry.runtime.abort();
659
- }
660
- catch {
661
- /* 忽略 */
662
- }
663
- entry.status = "cancelled";
664
- entry.endedAt = Date.now();
665
- entry.durationMs = entry.endedAt - entry.startedAt;
666
- // ★ emit 前置 + 终态非阻塞落盘 + 立即 settle completionPromise
667
- // (设计理由同 completed 路径:内存态是真相源,磁盘写入不阻塞主流程)
668
- this.emitEvent(subId, "cancelled", {});
669
- entry.completionResolve?.({ output: "", error: "aborted" });
670
- this.enqueueCompletion(entry, "", "aborted");
671
- void this.persistFinalStatus(entry, {
672
- status: "cancelled",
673
- endedAt: entry.endedAt,
674
- durationMs: entry.durationMs,
675
- availableTools: entry.availableTools,
676
- contextSnapshot: undefined,
677
- });
678
- }
679
- /** 获取内存中的 entry */
680
- getSubAgent(subId) {
681
- return this.subAgents.get(subId);
682
- }
683
- /** 列出某 agent 的全部内存中 sub-agent(含运行中和已完成未清理) */
684
- listByParent(parentAgentId) {
685
- const subIds = this.parentToSubs.get(parentAgentId);
686
- if (!subIds)
687
- return [];
688
- return Array.from(subIds)
689
- .map((id) => this.subAgents.get(id))
690
- .filter((e) => e !== undefined);
691
- }
692
- /**
693
- * 列出某父 agent 下处于活跃状态(pending / running)且对用户可见的 sub-agent。
694
- *
695
- * 已完成/失败/取消的 entry 在内存中仍保留 TTL=30min 供查询,但不应计入
696
- * "进行中" 列表。前端 "进行中" tab 与 SSE snapshot 都应使用此方法。
697
- *
698
- * silent 子 agent(如 memory 自动整理的后台 explore 子代理)属于系统级后台任务,
699
- * 不应展示给用户,否则会导致 tag 数量多于用户实际可见的子 agent,故此处一并过滤,
700
- * 与 enqueueCompletion 对 silent 的语义保持一致。并发计数 countByParent 不受影响,
701
- * 仍会统计 silent 子 agent 占用的并发槽位。
702
- */
703
- listActiveByParent(parentAgentId) {
704
- return this.listByParent(parentAgentId).filter((e) => (e.status === "pending" || e.status === "running") && !e.silent);
705
- }
706
- /**
707
- * 取走并清空终态通知队列。
708
- *
709
- * 主流程:返回 completionQueue 中的所有通知并清空队列。
710
- * 供 ACode 运行时在 poll_message 调用前后检查子 agent 是否已完成。
711
- * 每次 poll_message 调用前先调此方法,若有已完成子 agent 则直接返回,无需等待 MCP。
712
- */
713
- takeCompletedSubAgents() {
714
- if (this.completionQueue.length === 0)
715
- return [];
716
- const drained = this.completionQueue.splice(0);
717
- return drained;
718
- }
719
- /**
720
- * 等待任意子 agent 到达终态(completed/failed/cancelled)。
721
- *
722
- * 主流程:如果 completionQueue 中已有通知,立即 resolve;
723
- * 否则注册一个 resolve 回调,在下次子 agent 终态事件到达时触发。
724
- * 供 ACode 运行时在 poll_message 期间 race 子 agent 完成事件。
725
- *
726
- * 返回 { promise, cancel }:
727
- * - promise: 子 agent 终态时 resolve
728
- * - cancel: 取消等待(poll_message 先返回时调用,清理 resolve 回调)
729
- */
730
- waitForAnyCompletion() {
731
- // 如果队列中已有通知,立即返回
732
- if (this.completionQueue.length > 0) {
733
- const notif = this.completionQueue.shift();
734
- return {
735
- promise: Promise.resolve(notif),
736
- cancel: () => { },
737
- };
738
- }
739
- let cancelled = false;
740
- const promise = new Promise((resolve) => {
741
- this.completionWaiterResolve = (notif) => {
742
- if (!cancelled)
743
- resolve(notif);
744
- };
745
- });
746
- const cancel = () => {
747
- cancelled = true;
748
- this.completionWaiterResolve = null;
749
- };
750
- return { promise, cancel };
751
- }
752
- /** 订阅 sub-agent 事件(subId 或 "*" 全局) */
753
- subscribe(subId, cb) {
754
- let set = this.subscribers.get(subId);
755
- if (!set) {
756
- set = new Set();
757
- this.subscribers.set(subId, set);
758
- }
759
- set.add(cb);
760
- return () => {
761
- set?.delete(cb);
762
- if (set && set.size === 0)
763
- this.subscribers.delete(subId);
764
- };
765
- }
766
- /** 清理所有运行中的 sub-agent(bridge 关闭时调用) */
767
- async dispose() {
768
- if (this.cleanupTimer) {
769
- clearInterval(this.cleanupTimer);
770
- this.cleanupTimer = null;
771
- }
772
- const entries = Array.from(this.subAgents.values());
773
- await Promise.allSettled(entries.map((e) => this.abort(e.subId)));
774
- // 等待所有异步终态落盘完成(abort 触发的 cancelled 落盘是异步的),
775
- // 避免文件句柄占用导致测试 cleanup 时目录非空
776
- await this.flushPendingPersists();
777
- this.subAgents.clear();
778
- this.parentToSubs.clear();
779
- this.subscribers.clear();
780
- }
781
- // ---------- 内部方法 ----------
782
- /**
783
- * 异步落盘终态记录(指数退避重试),不阻塞主流程。
784
- *
785
- * 设计要点:
786
- * - 内存态已是终态(completed/failed/cancelled),落盘只做历史归档
787
- * - 落盘失败不回滚内存态,前端看到的是真实终态
788
- * - 重试覆盖瞬时错误:Windows fs.rename EPERM、writeChain 拥堵、磁盘瞬时不可用
789
- * - 全部重试失败后仅打日志,下次 bridge 启动时 reconcileZombies 会清理残留
790
- *
791
- * 调用方约定:必须用 `void this.persistFinalStatus(...)` 触发,不 await。
792
- * entry.completionResolve 与 enqueueCompletion 应在此调用之前完成,
793
- * 保证主流程不被落盘 IO 阻塞。
794
- *
795
- * Promise 加入 pendingPersists 集合,供 flushPendingPersists / dispose 等待。
796
- */
797
- persistFinalStatus(entry, patch) {
798
- const run = (async () => {
799
- let lastErr;
800
- for (let attempt = 0; attempt <= PERSIST_BACKOFF_MS.length; attempt++) {
801
- try {
802
- await this.store.updateStatus(entry.parentAgentId, entry.subId, patch);
803
- return;
804
- }
805
- catch (err) {
806
- lastErr = err;
807
- if (attempt < PERSIST_BACKOFF_MS.length) {
808
- await new Promise((r) => setTimeout(r, PERSIST_BACKOFF_MS[attempt]));
809
- }
810
- }
811
- }
812
- console.error(`[SubAgentManager] persistFinalStatus(${patch.status}) failed after ${PERSIST_BACKOFF_MS.length + 1} attempts ` +
813
- `for subId=${entry.subId}: ${lastErr instanceof Error ? lastErr.message : String(lastErr)}`);
814
- })();
815
- // 入集供测试/dispose 等待
816
- this.pendingPersists.add(run);
817
- run.finally(() => this.pendingPersists.delete(run));
818
- return run;
819
- }
820
- /**
821
- * 等待所有正在执行的异步终态落盘完成。
822
- *
823
- * 主要用途:
824
- * - 测试在终态后读取 store 前调用,确保落盘已完成
825
- * - dispose 前调用,避免文件句柄占用导致目录清理失败
826
- *
827
- * 生产环境一般不需要调用——落盘失败不影响内存态正确性。
828
- */
829
- async flushPendingPersists() {
830
- if (this.pendingPersists.size === 0)
831
- return;
832
- await Promise.allSettled(Array.from(this.pendingPersists));
833
- }
834
- /**
835
- * 将子 agent 终态事件入队并通知等待者。
836
- * 主流程:构建通知对象 -> 入队 completionQueue -> 若有 waitForAnyCompletion 等待者则立即 resolve。
837
- */
838
- enqueueCompletion(entry, output, error) {
839
- // 静默完成或已被 awaitCompletion 消费的子 agent 不进入 completionQueue
840
- if (entry.silent || entry.awaited) {
841
- return;
842
- }
843
- const notif = {
844
- subId: entry.subId,
845
- subagentType: entry.subagentType,
846
- description: entry.description,
847
- status: entry.status,
848
- output,
849
- error,
850
- durationMs: entry.durationMs,
851
- };
852
- this.completionQueue.push(notif);
853
- // 如果有 poll_message 正在等待子 agent 完成事件,立即通知
854
- if (this.completionWaiterResolve) {
855
- const resolve = this.completionWaiterResolve;
856
- this.completionWaiterResolve = null;
857
- // 从队列中取出刚入队的通知(即此条)
858
- const queued = this.completionQueue.pop();
859
- resolve(queued ?? notif);
860
- }
861
- }
862
- countByStatus(parentAgentId, ...statuses) {
863
- return this.listByParent(parentAgentId).filter((e) => statuses.includes(e.status)).length;
864
- }
865
- addToParentMap(parentAgentId, subId) {
866
- let set = this.parentToSubs.get(parentAgentId);
867
- if (!set) {
868
- set = new Set();
869
- this.parentToSubs.set(parentAgentId, set);
870
- }
871
- set.add(subId);
872
- }
873
- removeFromParentMap(parentAgentId, subId) {
874
- const set = this.parentToSubs.get(parentAgentId);
875
- if (set) {
876
- set.delete(subId);
877
- if (set.size === 0)
878
- this.parentToSubs.delete(parentAgentId);
879
- }
880
- }
881
- /**
882
- * 清理已超过 TTL 的终态 entry(completed/failed/cancelled)。
883
- * 释放内存,store 仍保留历史记录供查询。
884
- */
885
- cleanupCompletedEntries() {
886
- const now = Date.now();
887
- for (const [subId, entry] of this.subAgents) {
888
- if ((entry.status === "completed" || entry.status === "failed" || entry.status === "cancelled") &&
889
- entry.endedAt &&
890
- now - entry.endedAt > COMPLETED_ENTRY_TTL_MS) {
891
- this.subAgents.delete(subId);
892
- this.removeFromParentMap(entry.parentAgentId, subId);
893
- }
894
- }
895
- }
896
- /**
897
- * 存活期僵尸回收:扫描卡在 pending / running 过久的子 agent 并标记为 failed。
898
- *
899
- * 背景:runEntryToCompletion* 会在启动后数秒内把状态翻成 running;若长时间保持
900
- * pending,说明 startWithRecheck 抛错被调用方静默吞掉、或启动函数从未真正执行,
901
- * 子 agent 成了孤儿却仍占着 runtime.pendingMemorySubAgents 的 URI 锁,导致该
902
- * memory 的文件变更通知被永久抑制、永不重试(reconcileZombies 仅在 bridge 启动时跑)。
903
- * running 卡死则多因 runtime.start()/submit() 挂起。
904
- *
905
- * 回收时复用与正常终态一致的处理(store 落盘 failed + emit failed 事件 +
906
- * 释放 completion + 停 runtime)。runtime 订阅了 failed 事件,会据此清除
907
- * pendingMemorySubAgents 中的 URI 并进入冷却,从而解除死锁、允许下次重新委托。
908
- */
909
- recoverZombieEntries() {
910
- const now = Date.now();
911
- for (const [subId, entry] of this.subAgents) {
912
- if (entry.status === "pending" && now - entry.startedAt > SUBAGENT_PENDING_ZOMBIE_MS) {
913
- void this.recoverZombie(entry, `stuck in pending >${SUBAGENT_PENDING_ZOMBIE_MS}ms (never started)`);
914
- }
915
- else if (entry.status === "running" && now - entry.startedAt > SUBAGENT_RUNNING_ZOMBIE_MS) {
916
- void this.recoverZombie(entry, `stuck in running >${SUBAGENT_RUNNING_ZOMBIE_MS}ms (no completion)`);
917
- }
918
- }
919
- }
920
- /** 将孤儿/卡死子 agent 标记为 failed 并走正常终态流程(不依赖 LLM 自报) */
921
- async recoverZombie(entry, reason) {
922
- // 启动函数可能在扫描与执行之间恰好把状态翻成 running/终态,二次确认避免误杀
923
- if (entry.status !== "pending" && entry.status !== "running")
924
- return;
925
- const errorMessage = `zombie recovered: ${reason}`;
926
- entry.status = "failed";
927
- entry.errorMessage = errorMessage;
928
- entry.endedAt = Date.now();
929
- entry.durationMs = entry.endedAt - entry.startedAt;
930
- // ★ emit 前置 + 终态非阻塞落盘 + 立即 settle completionPromise
931
- // (与其他终态路径保持一致,zombie 回收路径若 writeChain 卡住,
932
- // 也应保证 runtime 收到 failed 事件从而释放 pendingMemorySubAgents URI 锁)
933
- this.emitEvent(entry.subId, "failed", { error: errorMessage });
934
- entry.completionResolve?.({ output: "", error: errorMessage });
935
- this.enqueueCompletion(entry, "", errorMessage);
936
- void this.persistFinalStatus(entry, {
937
- status: "failed",
938
- errorMessage,
939
- endedAt: entry.endedAt,
940
- durationMs: entry.durationMs,
941
- availableTools: entry.availableTools,
942
- contextSnapshot: undefined,
943
- });
944
- try {
945
- await entry.runtime.stop();
946
- }
947
- catch {
948
- /* 忽略 stop 失败 */
949
- }
950
- }
951
- /** 从 store 中查找记录(entry 已从内存清理时使用) */
952
- async findRecordInStore(subId) {
953
- // store 按父 agent 组织,无法直接按 subId 查;遍历所有 parent
954
- // 注意:此方法仅在 awaitCompletion 时调用,频率低
955
- for (const parentAgentId of this.parentToSubs.keys()) {
956
- const doc = await this.store.read(parentAgentId);
957
- const record = doc.subAgents.find((r) => r.subId === subId);
958
- if (record)
959
- return record;
960
- }
961
- return undefined;
962
- }
963
- handleRuntimeEvent(subId, event) {
964
- const entry = this.subAgents.get(subId);
965
- if (!entry)
966
- return;
967
- // 更新 contextSnapshot
968
- const snapshot = entry.contextSnapshot;
969
- snapshot.updatedAt = new Date().toISOString();
970
- switch (event?.type) {
971
- case "session_started":
972
- // ★ 可见性修正:start() 早期阶段标记(runtime.ts start() 中的首个 emit)。
973
- // 之前 session_started/mcp_status(状态报告)/skill_status 都不在 switch 中,
974
- // 导致子 agent 卡在 start() 内部(如 hookBus.dispatch、fetchProfilePrompt、
975
- // loadAcodeCommands 等)时前端 snapshot 永远显示 0/0/"-",与"子 agent 从未运行"
976
- // 无法区分。加上阶段标记后可定位卡点位置。
977
- snapshot.currentTool = "[starting]";
978
- this.emitEvent(subId, "progress", { snapshot: { ...snapshot } });
979
- break;
980
- case "startup_phase":
981
- // ★ 可见性修正:start() 内部细分阶段标记(session_started 之前 emit)。
982
- // 子 agent 卡在 loadAcodeConfig/loadAllSkills/fetchProfilePrompt/
983
- // loadAcodeCommands/hookBus.dispatch("SessionStart") 等步骤时,
984
- // 前端可精确定位卡点(currentTool 显示 "[startup:<phase>]"),
985
- // 而非笼统的 "-"。
986
- snapshot.currentTool = `[startup:${event.data?.phase ?? "unknown"}]`;
987
- this.emitEvent(subId, "progress", { snapshot: { ...snapshot } });
988
- break;
989
- case "mcp_status":
990
- // runtime 发射的 mcp_status 使用 action 字段(而非 phase)
991
- if (event.data?.action === "call_tool") {
992
- snapshot.currentTool = event.data?.tool;
993
- this.emitEvent(subId, "tool_start", { tool: snapshot.currentTool, snapshot: { ...snapshot } });
994
- }
995
- else if (event.data?.action === "tool_result") {
996
- this.emitEvent(subId, "tool_end", { tool: snapshot.currentTool, snapshot: { ...snapshot } });
997
- snapshot.currentTool = undefined;
998
- }
999
- else {
1000
- // ★ 可见性修正:start() 阶段 emit 的 mcp_status(无 action 字段,是连接状态报告),
1001
- // 标记 MCP 初始化阶段。位于 session_started 之后、skill_status 之前。
1002
- snapshot.currentTool = "[mcp_init]";
1003
- this.emitEvent(subId, "progress", { snapshot: { ...snapshot } });
1004
- }
1005
- break;
1006
- case "skill_status":
1007
- // ★ 可见性修正:start() 末尾阶段标记。skill_status 是 start() 最后 emit 的事件,
1008
- // 之后 start() 完成、submit() 开始;submit 早期到 ai_request 之间无事件,
1009
- // 若卡在此区间,前端会显示 "[skill_loaded]",可定位为 submit 早期卡死
1010
- // (如 hookBus.dispatch("UserPromptSubmit")、materializeImageContent 等)。
1011
- snapshot.currentTool = "[skill_loaded]";
1012
- this.emitEvent(subId, "progress", { snapshot: { ...snapshot } });
1013
- break;
1014
- case "ai_request":
1015
- // estimatedContextTokens 是请求前的上下文估算,可作为 input 近似值
1016
- if (event.data?.estimatedContextTokens != null) {
1017
- snapshot.tokenUsage.input = (event.data.estimatedContextTokens ?? snapshot.tokenUsage.input);
1018
- }
1019
- // ★ 可见性修正:标记当前处于模型请求阶段,便于前端区分"卡在模型请求"与"未启动"。
1020
- // 否则子 agent 卡在 fetch 时 snapshot.currentTool 仍为 undefined,前端显示"-",
1021
- // 与"子 agent 从未运行"无法区分。
1022
- snapshot.currentTool = "[model_request]";
1023
- this.emitEvent(subId, "progress", { snapshot: { ...snapshot } });
1024
- break;
1025
- case "context_compaction":
1026
- // ★ 可见性修正:标记当前处于上下文压缩阶段。
1027
- // 子 agent 初始上下文触发主动压缩时,requestChatCompletion 会先执行 performCompaction
1028
- // (调用 summarizeConversationWithLLM 发起摘要 LLM 请求),此时 ai_request 尚未发射,
1029
- // 前端 snapshot 会显示全 0。标记 currentTool 为压缩阶段,让"卡在压缩"可见。
1030
- if (event.data?.action === "start") {
1031
- snapshot.currentTool = "[context_compaction]";
1032
- this.emitEvent(subId, "progress", { snapshot: { ...snapshot } });
1033
- }
1034
- else if (event.data?.action === "end") {
1035
- // 压缩结束后清除标记,后续 ai_request 会覆盖
1036
- if (snapshot.currentTool === "[context_compaction]") {
1037
- snapshot.currentTool = undefined;
1038
- this.emitEvent(subId, "progress", { snapshot: { ...snapshot } });
1039
- }
1040
- }
1041
- break;
1042
- case "turn_complete":
1043
- // turn_complete 携带实际的 token 用量,覆盖 ai_request 的估算值
1044
- if (event.data?.usage) {
1045
- snapshot.tokenUsage.input = (event.data.usage.inputTokens ?? snapshot.tokenUsage.input);
1046
- snapshot.tokenUsage.output = (event.data.usage.outputTokens ?? snapshot.tokenUsage.output);
1047
- this.emitEvent(subId, "progress", { snapshot: { ...snapshot } });
1048
- }
1049
- else if (event.data?.failed || event.data?.aborted) {
1050
- // 失败/中止路径不携带 usage,重置 output 避免残留上一轮值
1051
- snapshot.tokenUsage.output = 0;
1052
- }
1053
- break;
1054
- case "assistant_delta":
1055
- // 累积文本,截断到最近 500 字符
1056
- snapshot.lastAssistantText = ((snapshot.lastAssistantText ?? "") + (event.data?.text ?? "")).slice(-500);
1057
- snapshot.messageCount += 1;
1058
- this.emitEvent(subId, "delta", { text: event.data?.text });
1059
- break;
1060
- case "session_complete":
1061
- snapshot.messageCount += 1;
1062
- break;
1063
- }
1064
- }
1065
- emitEvent(subId, type, data) {
1066
- const event = {
1067
- type,
1068
- subId,
1069
- timestamp: new Date().toISOString(),
1070
- data,
1071
- };
1072
- // 通知该 subId 的订阅者
1073
- const subs = this.subscribers.get(subId);
1074
- if (subs) {
1075
- for (const cb of subs) {
1076
- try {
1077
- cb(event);
1078
- }
1079
- catch {
1080
- /* 忽略订阅者错误 */
1081
- }
1082
- }
1083
- }
1084
- // 通知全局订阅者
1085
- const globalSubs = this.subscribers.get("*");
1086
- if (globalSubs) {
1087
- for (const cb of globalSubs) {
1088
- try {
1089
- cb(event);
1090
- }
1091
- catch {
1092
- /* 忽略 */
1093
- }
1094
- }
1095
- }
1096
- // tool_start / tool_end 异步落盘(fire-and-forget,不阻塞事件发射)
1097
- if (type === "tool_start" || type === "tool_end") {
1098
- const entry = this.subAgents.get(subId);
1099
- if (entry) {
1100
- console.error(`[SubAgentManager] appendEvent: subId=${subId} type=${type} tool=${data.tool ?? "?"} parentAgentId=${entry.parentAgentId}`);
1101
- void this.store.appendEvent(entry.parentAgentId, subId, event).catch((err) => {
1102
- console.error(`[SubAgentManager] appendEvent FAILED: subId=${subId} error=${err instanceof Error ? err.message : String(err)}`);
1103
- });
1104
- }
1105
- else {
1106
- console.error(`[SubAgentManager] appendEvent SKIPPED (entry not found): subId=${subId} type=${type}`);
1107
- }
1108
- }
1109
- }
1110
- toRecord(entry) {
1111
- return {
1112
- subId: entry.subId,
1113
- parentAgentId: entry.parentAgentId,
1114
- parentSessionId: entry.parentSessionId,
1115
- subagentType: entry.subagentType,
1116
- description: entry.description,
1117
- prompt: entry.prompt,
1118
- status: entry.status,
1119
- result: entry.result,
1120
- errorMessage: entry.errorMessage,
1121
- startedAt: entry.startedAt,
1122
- endedAt: entry.endedAt,
1123
- durationMs: entry.durationMs,
1124
- contextSnapshot: entry.status === "running" ? entry.contextSnapshot : undefined,
1125
- availableTools: entry.availableTools,
1126
- };
1127
- }
1128
- /** 获取当前上下文快照(供 HTTP 路由调用) */
1129
- getContextSnapshot(subId) {
1130
- return this.subAgents.get(subId)?.contextSnapshot;
1131
- }
1132
- }
1133
- /**
1134
- * 简易超时兜底,仅用于 sub-agent 的 start()/submit() 整体保护。
1135
- *
1136
- * 与 runtime.ts 中的 withTimeout 行为一致:
1137
- * - 超时后 reject,让外层 catch 把 sub-agent 标记为 failed(前端可见)
1138
- * - 不取消 underlying promise(runtime 内部的 fetch 已有自己的 AbortController)
1139
- * - timeoutMs <= 0 时跳过保护,直接 await
1140
- *
1141
- * 未抽到独立工具文件是因为仅此处使用;如未来有其他模块需要,再考虑提取到 shared。
1142
- */
1143
- async function withTimeout(operation, timeoutMs, label) {
1144
- if (timeoutMs <= 0) {
1145
- return await operation;
1146
- }
1147
- let timer;
1148
- try {
1149
- return await new Promise((resolve, reject) => {
1150
- timer = setTimeout(() => reject(new Error(`${label} timed out after ${timeoutMs}ms`)), timeoutMs);
1151
- operation.then(resolve, reject);
1152
- });
1153
- }
1154
- finally {
1155
- if (timer) {
1156
- clearTimeout(timer);
1157
- }
1158
- }
1159
- }
1
+ import{randomUUID as S}from"node:crypto";import{ACodeRuntime as w}from"./runtime.js";const T=30*60*1e3,m=2*60*1e3,f=12*60*1e3,b=5e3,d=[100,500,2e3,8e3],E=6e4,A=10*60*1e3;class _{constructor(t){this.subAgents=new Map,this.parentToSubs=new Map,this.subscribers=new Map,this.cleanupTimer=null,this.completionQueue=[],this.completionWaiterResolve=null,this.pendingPersists=new Set,this.store=t.store,this.maxConcurrent=t.maxConcurrent??5,this.cleanupTimer=setInterval(()=>{this.cleanupCompletedEntries(),this.recoverZombieEntries()},5*60*1e3),this.cleanupTimer.unref&&this.cleanupTimer.unref(),this.store.reconcileZombies().catch(()=>{})}async spawn(t){if(this.countByStatus(t.parentAgentId,"running","pending")>=this.maxConcurrent)throw new Error(`concurrent sub-agent limit reached (${this.maxConcurrent}) for agent ${t.parentAgentId}`);const s=`sub-${S()}`,n=Date.now(),i=new AbortController,o={...t.parentConfig,sessionId:s,workingDirectory:t.workingDirectory,agentId:`${t.parentAgentId}__sub__${s}`,initialPrompt:void 0,subAgentManager:void 0,subagentType:t.subagentType,...t.parentConfig.subAgentModel?{model:t.parentConfig.subAgentModel}:{},...t.parentConfig.subAgentEffort?{effort:t.parentConfig.subAgentEffort}:{},subAgentModel:void 0,subAgentEffort:void 0},r=new w(o),a={subId:s,parentAgentId:t.parentAgentId,parentSessionId:t.parentSessionId,subagentType:t.subagentType,description:t.description,prompt:t.prompt,status:"pending",startedAt:n,runtime:r,abortController:i,silent:t.silent,contextSnapshot:{tokenUsage:{input:0,output:0},messageCount:0,updatedAt:new Date().toISOString()},availableTools:[]};this.subAgents.set(s,a),this.addToParentMap(t.parentAgentId,s);const u=this.toRecord(a);return await this.store.upsert(t.parentAgentId,u),r.on("event",l=>{this.handleRuntimeEvent(s,l)}),this.emitEvent(s,"spawned",{}),s}async start(t){const e=this.subAgents.get(t);if(!e)throw new Error(`sub-agent not found: ${t}`);if(e.status!=="pending")throw new Error(`sub-agent ${t} cannot start from status: ${e.status}`);e.completionPromise=new Promise((s,n)=>{e.completionResolve=s,e.completionReject=n}),this.runEntryToCompletion(e).catch(()=>{})}async startWithRecheck(t,e,s=3){const n=this.subAgents.get(t);if(!n)throw new Error(`sub-agent not found: ${t}`);if(n.status!=="pending")throw new Error(`sub-agent ${t} cannot start from status: ${n.status}`);n.completionPromise=new Promise((i,o)=>{n.completionResolve=i,n.completionReject=o}),this.runEntryToCompletionWithRecheck(n,e,s).catch(()=>{})}async awaitCompletion(t,e=0){if(t.length===0)return[];const s=[],n=t.map(async o=>{const r=this.subAgents.get(o);if(!r){const u=await this.findRecordInStore(o);u?s.push({subId:o,output:u.result??"",error:u.errorMessage,status:u.status}):s.push({subId:o,output:"",error:`sub-agent not found: ${o}`,status:"failed"});return}r.awaited=!0,r.status==="pending"&&await this.start(o);const a=r.completionPromise??Promise.resolve({output:"",error:"not started"});try{const u=await a;s.push({subId:o,output:u.output,error:u.error,status:r.status})}catch(u){s.push({subId:o,output:"",error:u instanceof Error?u.message:String(u),status:r.status})}}),i=new Set(t);for(let o=this.completionQueue.length-1;o>=0;o--)i.has(this.completionQueue[o].subId)&&this.completionQueue.splice(o,1);return e>0?await Promise.race([Promise.allSettled(n),new Promise(o=>setTimeout(()=>o(),e))]):await Promise.allSettled(n),s}async runEntryToCompletion(t){const e=[];let s=!1,n;const i=o=>{if(o)switch(o.type){case"assistant_delta":typeof o.data?.text=="string"&&e.push(o.data.text);break;case"turn_complete":o.data?.failed&&(s=!0);break;case"error":typeof o.data?.message=="string"&&(n=o.data.message);break}};t.runtime.on("event",i),t.status="running",t.contextSnapshot.currentTool="[starting]",t.contextSnapshot.updatedAt=new Date().toISOString(),this.emitEvent(t.subId,"running",{snapshot:{...t.contextSnapshot}});try{await c(this.store.updateStatus(t.parentAgentId,t.subId,{status:"running"}),b,`sub-agent ${t.subId} store.updateStatus(running)`)}catch(o){console.error(`[SubAgentManager] store.updateStatus(running) failed for subId=${t.subId}: ${o instanceof Error?o.message:String(o)}`)}try{if(await t.runtime.start(),t.availableTools=t.runtime.getAvailableTools(),await t.runtime.submit(t.prompt),s)throw new Error(n??"sub-agent turn failed");const o=e.join("");t.status="completed",t.result=o,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"completed",{result:o}),t.completionResolve?.({output:o}),this.enqueueCompletion(t,o,void 0),this.persistFinalStatus(t,{status:"completed",result:o,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}catch(o){const r=o instanceof Error?o.message:String(o);t.status="failed",t.errorMessage=r,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:r}),t.completionResolve?.({output:"",error:r}),this.enqueueCompletion(t,"",r),this.persistFinalStatus(t,{status:"failed",errorMessage:r,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}finally{try{t.runtime.removeListener?.("event",i)}catch{}try{await t.runtime.stop()}catch{}}}async runEntryToCompletionWithRecheck(t,e,s){const n=[];let i=!1,o;const r=a=>{if(a)switch(a.type){case"assistant_delta":typeof a.data?.text=="string"&&n.push(a.data.text);break;case"turn_complete":a.data?.failed&&(i=!0);break;case"error":typeof a.data?.message=="string"&&(o=a.data.message);break}};t.runtime.on("event",r),t.status="running",t.contextSnapshot.currentTool="[starting]",t.contextSnapshot.updatedAt=new Date().toISOString(),this.emitEvent(t.subId,"running",{snapshot:{...t.contextSnapshot}});try{await c(this.store.updateStatus(t.parentAgentId,t.subId,{status:"running"}),b,`sub-agent ${t.subId} store.updateStatus(running)`)}catch(a){console.error(`[SubAgentManager] store.updateStatus(running) failed for subId=${t.subId}: ${a instanceof Error?a.message:String(a)}`)}try{if(await c(t.runtime.start(),E,`sub-agent ${t.subId} runtime.start()`),t.contextSnapshot.currentTool="[submitting]",t.contextSnapshot.updatedAt=new Date().toISOString(),t.availableTools=t.runtime.getAvailableTools(),this.emitEvent(t.subId,"progress",{snapshot:{...t.contextSnapshot}}),await c(t.runtime.submit(t.prompt),A,`sub-agent ${t.subId} runtime.submit() turn=1`),i)throw new Error(o??"sub-agent turn failed");let a=1;for(;a<=s;){let l;try{l=await e(n.join(""),a)}catch(g){console.error(`[SubAgentManager] recheck threw error for subId=${t.subId} turn=${a}, treating as done:`,g instanceof Error?g.message:String(g));break}if(l.done)break;const h=l.continueMessage??"\u7ECF\u68C0\u67E5\uFF0C\u672A\u5B8C\u6210\u5904\u7406\uFF0C\u8BF7\u7EE7\u7EED\u3002";if(i=!1,o=void 0,console.error(`[SubAgentManager] recheck not done for subId=${t.subId} turn=${a}/${s}, injecting continue message (${h.length} chars)`),await c(t.runtime.submit(h),A,`sub-agent ${t.subId} runtime.submit() recheck turn=${a+1}`),i)throw new Error(o??`sub-agent turn ${a+1} failed during recheck continuation`);a++}a>s&&console.error(`[SubAgentManager] recheck reached maxRetries=${s} for subId=${t.subId}, completing with potentially unfinished work`);const u=n.join("");t.status="completed",t.result=u,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"completed",{result:u}),t.completionResolve?.({output:u}),this.enqueueCompletion(t,u,void 0),this.persistFinalStatus(t,{status:"completed",result:u,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}catch(a){const u=a instanceof Error?a.message:String(a);t.status="failed",t.errorMessage=u,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:u}),t.completionResolve?.({output:"",error:u}),this.enqueueCompletion(t,"",u),this.persistFinalStatus(t,{status:"failed",errorMessage:u,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0})}finally{try{t.runtime.removeListener?.("event",r)}catch{}try{await t.runtime.stop()}catch{}}}async runToCompletion(t){const e=this.subAgents.get(t);if(!e)throw new Error(`sub-agent not found: ${t}`);if(e.status==="running")throw new Error(`sub-agent already running: ${t}`);return e.status!=="pending"&&(e.status="pending"),await this.start(t),await e.completionPromise??{output:"",error:"not started"}}async abort(t){const e=this.subAgents.get(t);if(e&&!(e.status==="completed"||e.status==="failed"||e.status==="cancelled")){e.abortController.abort();try{await e.runtime.abort()}catch{}e.status="cancelled",e.endedAt=Date.now(),e.durationMs=e.endedAt-e.startedAt,this.emitEvent(t,"cancelled",{}),e.completionResolve?.({output:"",error:"aborted"}),this.enqueueCompletion(e,"","aborted"),this.persistFinalStatus(e,{status:"cancelled",endedAt:e.endedAt,durationMs:e.durationMs,availableTools:e.availableTools,contextSnapshot:void 0})}}getSubAgent(t){return this.subAgents.get(t)}listByParent(t){const e=this.parentToSubs.get(t);return e?Array.from(e).map(s=>this.subAgents.get(s)).filter(s=>s!==void 0):[]}listActiveByParent(t){return this.listByParent(t).filter(e=>(e.status==="pending"||e.status==="running")&&!e.silent)}takeCompletedSubAgents(){return this.completionQueue.length===0?[]:this.completionQueue.splice(0)}waitForAnyCompletion(){if(this.completionQueue.length>0){const n=this.completionQueue.shift();return{promise:Promise.resolve(n),cancel:()=>{}}}let t=!1;return{promise:new Promise(n=>{this.completionWaiterResolve=i=>{t||n(i)}}),cancel:()=>{t=!0,this.completionWaiterResolve=null}}}subscribe(t,e){let s=this.subscribers.get(t);return s||(s=new Set,this.subscribers.set(t,s)),s.add(e),()=>{s?.delete(e),s&&s.size===0&&this.subscribers.delete(t)}}async dispose(){this.cleanupTimer&&(clearInterval(this.cleanupTimer),this.cleanupTimer=null);const t=Array.from(this.subAgents.values());await Promise.allSettled(t.map(e=>this.abort(e.subId))),await this.flushPendingPersists(),this.subAgents.clear(),this.parentToSubs.clear(),this.subscribers.clear()}persistFinalStatus(t,e){const s=(async()=>{let n;for(let i=0;i<=d.length;i++)try{await this.store.updateStatus(t.parentAgentId,t.subId,e);return}catch(o){n=o,i<d.length&&await new Promise(r=>setTimeout(r,d[i]))}console.error(`[SubAgentManager] persistFinalStatus(${e.status}) failed after ${d.length+1} attempts for subId=${t.subId}: ${n instanceof Error?n.message:String(n)}`)})();return this.pendingPersists.add(s),s.finally(()=>this.pendingPersists.delete(s)),s}async flushPendingPersists(){this.pendingPersists.size!==0&&await Promise.allSettled(Array.from(this.pendingPersists))}enqueueCompletion(t,e,s){if(t.silent||t.awaited)return;const n={subId:t.subId,subagentType:t.subagentType,description:t.description,status:t.status,output:e,error:s,durationMs:t.durationMs};if(this.completionQueue.push(n),this.completionWaiterResolve){const i=this.completionWaiterResolve;this.completionWaiterResolve=null;const o=this.completionQueue.pop();i(o??n)}}countByStatus(t,...e){return this.listByParent(t).filter(s=>e.includes(s.status)).length}addToParentMap(t,e){let s=this.parentToSubs.get(t);s||(s=new Set,this.parentToSubs.set(t,s)),s.add(e)}removeFromParentMap(t,e){const s=this.parentToSubs.get(t);s&&(s.delete(e),s.size===0&&this.parentToSubs.delete(t))}cleanupCompletedEntries(){const t=Date.now();for(const[e,s]of this.subAgents)(s.status==="completed"||s.status==="failed"||s.status==="cancelled")&&s.endedAt&&t-s.endedAt>T&&(this.subAgents.delete(e),this.removeFromParentMap(s.parentAgentId,e))}recoverZombieEntries(){const t=Date.now();for(const[e,s]of this.subAgents)s.status==="pending"&&t-s.startedAt>m?this.recoverZombie(s,`stuck in pending >${m}ms (never started)`):s.status==="running"&&t-s.startedAt>f&&this.recoverZombie(s,`stuck in running >${f}ms (no completion)`)}async recoverZombie(t,e){if(t.status!=="pending"&&t.status!=="running")return;const s=`zombie recovered: ${e}`;t.status="failed",t.errorMessage=s,t.endedAt=Date.now(),t.durationMs=t.endedAt-t.startedAt,this.emitEvent(t.subId,"failed",{error:s}),t.completionResolve?.({output:"",error:s}),this.enqueueCompletion(t,"",s),this.persistFinalStatus(t,{status:"failed",errorMessage:s,endedAt:t.endedAt,durationMs:t.durationMs,availableTools:t.availableTools,contextSnapshot:void 0});try{await t.runtime.stop()}catch{}}async findRecordInStore(t){for(const e of this.parentToSubs.keys()){const n=(await this.store.read(e)).subAgents.find(i=>i.subId===t);if(n)return n}}handleRuntimeEvent(t,e){const s=this.subAgents.get(t);if(!s)return;const n=s.contextSnapshot;switch(n.updatedAt=new Date().toISOString(),e?.type){case"session_started":n.currentTool="[starting]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"startup_phase":n.currentTool=`[startup:${e.data?.phase??"unknown"}]`,this.emitEvent(t,"progress",{snapshot:{...n}});break;case"mcp_status":e.data?.action==="call_tool"?(n.currentTool=e.data?.tool,this.emitEvent(t,"tool_start",{tool:n.currentTool,snapshot:{...n}})):e.data?.action==="tool_result"?(this.emitEvent(t,"tool_end",{tool:n.currentTool,snapshot:{...n}}),n.currentTool=void 0):(n.currentTool="[mcp_init]",this.emitEvent(t,"progress",{snapshot:{...n}}));break;case"skill_status":n.currentTool="[skill_loaded]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"ai_request":e.data?.estimatedContextTokens!=null&&(n.tokenUsage.input=e.data.estimatedContextTokens??n.tokenUsage.input),n.currentTool="[model_request]",this.emitEvent(t,"progress",{snapshot:{...n}});break;case"context_compaction":e.data?.action==="start"?(n.currentTool="[context_compaction]",this.emitEvent(t,"progress",{snapshot:{...n}})):e.data?.action==="end"&&n.currentTool==="[context_compaction]"&&(n.currentTool=void 0,this.emitEvent(t,"progress",{snapshot:{...n}}));break;case"turn_complete":e.data?.usage?(n.tokenUsage.input=e.data.usage.inputTokens??n.tokenUsage.input,n.tokenUsage.output=e.data.usage.outputTokens??n.tokenUsage.output,this.emitEvent(t,"progress",{snapshot:{...n}})):(e.data?.failed||e.data?.aborted)&&(n.tokenUsage.output=0);break;case"assistant_delta":n.lastAssistantText=((n.lastAssistantText??"")+(e.data?.text??"")).slice(-500),n.messageCount+=1,this.emitEvent(t,"delta",{text:e.data?.text});break;case"session_complete":n.messageCount+=1;break}}emitEvent(t,e,s){const n={type:e,subId:t,timestamp:new Date().toISOString(),data:s},i=this.subscribers.get(t);if(i)for(const r of i)try{r(n)}catch{}const o=this.subscribers.get("*");if(o)for(const r of o)try{r(n)}catch{}if(e==="tool_start"||e==="tool_end"){const r=this.subAgents.get(t);r?(console.error(`[SubAgentManager] appendEvent: subId=${t} type=${e} tool=${s.tool??"?"} parentAgentId=${r.parentAgentId}`),this.store.appendEvent(r.parentAgentId,t,n).catch(a=>{console.error(`[SubAgentManager] appendEvent FAILED: subId=${t} error=${a instanceof Error?a.message:String(a)}`)})):console.error(`[SubAgentManager] appendEvent SKIPPED (entry not found): subId=${t} type=${e}`)}}toRecord(t){return{subId:t.subId,parentAgentId:t.parentAgentId,parentSessionId:t.parentSessionId,subagentType:t.subagentType,description:t.description,prompt:t.prompt,status:t.status,result:t.result,errorMessage:t.errorMessage,startedAt:t.startedAt,endedAt:t.endedAt,durationMs:t.durationMs,contextSnapshot:t.status==="running"?t.contextSnapshot:void 0,availableTools:t.availableTools}}getContextSnapshot(t){return this.subAgents.get(t)?.contextSnapshot}}async function c(p,t,e){if(t<=0)return await p;let s;try{return await new Promise((n,i)=>{s=setTimeout(()=>i(new Error(`${e} timed out after ${t}ms`)),t),p.then(n,i)})}finally{s&&clearTimeout(s)}}export{_ as SubAgentManager};
2
+