attocode 0.2.2 → 0.2.4

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 (382) hide show
  1. package/CHANGELOG.md +169 -3
  2. package/README.md +65 -5
  3. package/dist/src/adapters.d.ts.map +1 -1
  4. package/dist/src/adapters.js +15 -11
  5. package/dist/src/adapters.js.map +1 -1
  6. package/dist/src/agent.d.ts +44 -98
  7. package/dist/src/agent.d.ts.map +1 -1
  8. package/dist/src/agent.js +716 -2648
  9. package/dist/src/agent.js.map +1 -1
  10. package/dist/src/cli.d.ts.map +1 -1
  11. package/dist/src/cli.js +25 -3
  12. package/dist/src/cli.js.map +1 -1
  13. package/dist/src/commands/handler.d.ts.map +1 -1
  14. package/dist/src/commands/handler.js +11 -3
  15. package/dist/src/commands/handler.js.map +1 -1
  16. package/dist/src/commands/init-commands.d.ts.map +1 -1
  17. package/dist/src/commands/init-commands.js +16 -1
  18. package/dist/src/commands/init-commands.js.map +1 -1
  19. package/dist/src/commands/init.d.ts.map +1 -1
  20. package/dist/src/commands/init.js +31 -0
  21. package/dist/src/commands/init.js.map +1 -1
  22. package/dist/src/config/base-types.d.ts +45 -0
  23. package/dist/src/config/base-types.d.ts.map +1 -0
  24. package/dist/src/config/base-types.js +9 -0
  25. package/dist/src/config/base-types.js.map +1 -0
  26. package/dist/src/config/config-manager.d.ts +35 -0
  27. package/dist/src/config/config-manager.d.ts.map +1 -0
  28. package/dist/src/config/config-manager.js +108 -0
  29. package/dist/src/config/config-manager.js.map +1 -0
  30. package/dist/src/config/index.d.ts +4 -0
  31. package/dist/src/config/index.d.ts.map +1 -0
  32. package/dist/src/config/index.js +3 -0
  33. package/dist/src/config/index.js.map +1 -0
  34. package/dist/src/config/schema.d.ts +1546 -0
  35. package/dist/src/config/schema.d.ts.map +1 -0
  36. package/dist/src/config/schema.js +268 -0
  37. package/dist/src/config/schema.js.map +1 -0
  38. package/dist/src/config.d.ts +4 -1
  39. package/dist/src/config.d.ts.map +1 -1
  40. package/dist/src/config.js +8 -12
  41. package/dist/src/config.js.map +1 -1
  42. package/dist/src/core/agent-state-machine.d.ts +131 -0
  43. package/dist/src/core/agent-state-machine.d.ts.map +1 -0
  44. package/dist/src/core/agent-state-machine.js +302 -0
  45. package/dist/src/core/agent-state-machine.js.map +1 -0
  46. package/dist/src/core/base-manager.d.ts +79 -0
  47. package/dist/src/core/base-manager.d.ts.map +1 -0
  48. package/dist/src/core/base-manager.js +170 -0
  49. package/dist/src/core/base-manager.js.map +1 -0
  50. package/dist/src/core/completion-analyzer.d.ts +15 -0
  51. package/dist/src/core/completion-analyzer.d.ts.map +1 -0
  52. package/dist/src/core/completion-analyzer.js +53 -0
  53. package/dist/src/core/completion-analyzer.js.map +1 -0
  54. package/dist/src/core/execution-loop.d.ts +46 -0
  55. package/dist/src/core/execution-loop.d.ts.map +1 -0
  56. package/dist/src/core/execution-loop.js +1258 -0
  57. package/dist/src/core/execution-loop.js.map +1 -0
  58. package/dist/src/core/index.d.ts +7 -0
  59. package/dist/src/core/index.d.ts.map +1 -1
  60. package/dist/src/core/index.js +9 -0
  61. package/dist/src/core/index.js.map +1 -1
  62. package/dist/src/core/process-handlers.d.ts.map +1 -1
  63. package/dist/src/core/process-handlers.js +14 -0
  64. package/dist/src/core/process-handlers.js.map +1 -1
  65. package/dist/src/core/protocol/types.d.ts +4 -4
  66. package/dist/src/core/response-handler.d.ts +16 -0
  67. package/dist/src/core/response-handler.d.ts.map +1 -0
  68. package/dist/src/core/response-handler.js +234 -0
  69. package/dist/src/core/response-handler.js.map +1 -0
  70. package/dist/src/core/subagent-spawner.d.ts +43 -0
  71. package/dist/src/core/subagent-spawner.d.ts.map +1 -0
  72. package/dist/src/core/subagent-spawner.js +966 -0
  73. package/dist/src/core/subagent-spawner.js.map +1 -0
  74. package/dist/src/core/tool-executor.d.ts +59 -0
  75. package/dist/src/core/tool-executor.d.ts.map +1 -0
  76. package/dist/src/core/tool-executor.js +677 -0
  77. package/dist/src/core/tool-executor.js.map +1 -0
  78. package/dist/src/core/types.d.ts +133 -0
  79. package/dist/src/core/types.d.ts.map +1 -0
  80. package/dist/src/core/types.js +12 -0
  81. package/dist/src/core/types.js.map +1 -0
  82. package/dist/src/defaults.d.ts +8 -3
  83. package/dist/src/defaults.d.ts.map +1 -1
  84. package/dist/src/defaults.js +65 -3
  85. package/dist/src/defaults.js.map +1 -1
  86. package/dist/src/integrations/agent-registry.d.ts +11 -0
  87. package/dist/src/integrations/agent-registry.d.ts.map +1 -1
  88. package/dist/src/integrations/agent-registry.js.map +1 -1
  89. package/dist/src/integrations/auto-compaction.d.ts.map +1 -1
  90. package/dist/src/integrations/auto-compaction.js +8 -3
  91. package/dist/src/integrations/auto-compaction.js.map +1 -1
  92. package/dist/src/integrations/bash-policy.d.ts +33 -0
  93. package/dist/src/integrations/bash-policy.d.ts.map +1 -0
  94. package/dist/src/integrations/bash-policy.js +142 -0
  95. package/dist/src/integrations/bash-policy.js.map +1 -0
  96. package/dist/src/integrations/budget-pool.d.ts +7 -0
  97. package/dist/src/integrations/budget-pool.d.ts.map +1 -1
  98. package/dist/src/integrations/budget-pool.js +43 -0
  99. package/dist/src/integrations/budget-pool.js.map +1 -1
  100. package/dist/src/integrations/codebase-ast.d.ts +52 -0
  101. package/dist/src/integrations/codebase-ast.d.ts.map +1 -0
  102. package/dist/src/integrations/codebase-ast.js +457 -0
  103. package/dist/src/integrations/codebase-ast.js.map +1 -0
  104. package/dist/src/integrations/codebase-context.d.ts +23 -0
  105. package/dist/src/integrations/codebase-context.d.ts.map +1 -1
  106. package/dist/src/integrations/codebase-context.js +230 -17
  107. package/dist/src/integrations/codebase-context.js.map +1 -1
  108. package/dist/src/integrations/compaction.d.ts.map +1 -1
  109. package/dist/src/integrations/compaction.js +14 -6
  110. package/dist/src/integrations/compaction.js.map +1 -1
  111. package/dist/src/integrations/context-engineering.d.ts +8 -0
  112. package/dist/src/integrations/context-engineering.d.ts.map +1 -1
  113. package/dist/src/integrations/context-engineering.js +19 -0
  114. package/dist/src/integrations/context-engineering.js.map +1 -1
  115. package/dist/src/integrations/delegation-protocol.js +2 -2
  116. package/dist/src/integrations/delegation-protocol.js.map +1 -1
  117. package/dist/src/integrations/economics.d.ts +67 -1
  118. package/dist/src/integrations/economics.d.ts.map +1 -1
  119. package/dist/src/integrations/economics.js +328 -33
  120. package/dist/src/integrations/economics.js.map +1 -1
  121. package/dist/src/integrations/edit-validator.d.ts +30 -0
  122. package/dist/src/integrations/edit-validator.d.ts.map +1 -0
  123. package/dist/src/integrations/edit-validator.js +85 -0
  124. package/dist/src/integrations/edit-validator.js.map +1 -0
  125. package/dist/src/integrations/file-cache.d.ts +7 -0
  126. package/dist/src/integrations/file-cache.d.ts.map +1 -1
  127. package/dist/src/integrations/file-cache.js +54 -0
  128. package/dist/src/integrations/file-cache.js.map +1 -1
  129. package/dist/src/integrations/health-check.d.ts.map +1 -1
  130. package/dist/src/integrations/health-check.js +3 -2
  131. package/dist/src/integrations/health-check.js.map +1 -1
  132. package/dist/src/integrations/hierarchical-config.d.ts +3 -0
  133. package/dist/src/integrations/hierarchical-config.d.ts.map +1 -1
  134. package/dist/src/integrations/hierarchical-config.js +20 -0
  135. package/dist/src/integrations/hierarchical-config.js.map +1 -1
  136. package/dist/src/integrations/hooks.d.ts +2 -0
  137. package/dist/src/integrations/hooks.d.ts.map +1 -1
  138. package/dist/src/integrations/hooks.js +99 -15
  139. package/dist/src/integrations/hooks.js.map +1 -1
  140. package/dist/src/integrations/index.d.ts +10 -1
  141. package/dist/src/integrations/index.d.ts.map +1 -1
  142. package/dist/src/integrations/index.js +12 -2
  143. package/dist/src/integrations/index.js.map +1 -1
  144. package/dist/src/integrations/logger.d.ts +104 -0
  145. package/dist/src/integrations/logger.d.ts.map +1 -0
  146. package/dist/src/integrations/logger.js +219 -0
  147. package/dist/src/integrations/logger.js.map +1 -0
  148. package/dist/src/integrations/lsp.d.ts.map +1 -1
  149. package/dist/src/integrations/lsp.js +5 -4
  150. package/dist/src/integrations/lsp.js.map +1 -1
  151. package/dist/src/integrations/mcp-client.d.ts.map +1 -1
  152. package/dist/src/integrations/mcp-client.js +8 -7
  153. package/dist/src/integrations/mcp-client.js.map +1 -1
  154. package/dist/src/integrations/observability.d.ts.map +1 -1
  155. package/dist/src/integrations/observability.js +5 -4
  156. package/dist/src/integrations/observability.js.map +1 -1
  157. package/dist/src/integrations/openrouter-pricing.d.ts.map +1 -1
  158. package/dist/src/integrations/openrouter-pricing.js +4 -3
  159. package/dist/src/integrations/openrouter-pricing.js.map +1 -1
  160. package/dist/src/integrations/persistence.d.ts.map +1 -1
  161. package/dist/src/integrations/persistence.js +5 -4
  162. package/dist/src/integrations/persistence.js.map +1 -1
  163. package/dist/src/integrations/planning.d.ts.map +1 -1
  164. package/dist/src/integrations/planning.js +5 -4
  165. package/dist/src/integrations/planning.js.map +1 -1
  166. package/dist/src/integrations/policy-engine.d.ts +55 -0
  167. package/dist/src/integrations/policy-engine.d.ts.map +1 -0
  168. package/dist/src/integrations/policy-engine.js +247 -0
  169. package/dist/src/integrations/policy-engine.js.map +1 -0
  170. package/dist/src/integrations/retry.d.ts +1 -0
  171. package/dist/src/integrations/retry.d.ts.map +1 -1
  172. package/dist/src/integrations/retry.js.map +1 -1
  173. package/dist/src/integrations/routing.d.ts.map +1 -1
  174. package/dist/src/integrations/routing.js +2 -1
  175. package/dist/src/integrations/routing.js.map +1 -1
  176. package/dist/src/integrations/safety.d.ts +5 -4
  177. package/dist/src/integrations/safety.d.ts.map +1 -1
  178. package/dist/src/integrations/safety.js +45 -20
  179. package/dist/src/integrations/safety.js.map +1 -1
  180. package/dist/src/integrations/sandbox/basic.d.ts +7 -0
  181. package/dist/src/integrations/sandbox/basic.d.ts.map +1 -1
  182. package/dist/src/integrations/sandbox/basic.js +27 -2
  183. package/dist/src/integrations/sandbox/basic.js.map +1 -1
  184. package/dist/src/integrations/sandbox/docker.d.ts.map +1 -1
  185. package/dist/src/integrations/sandbox/docker.js +2 -1
  186. package/dist/src/integrations/sandbox/docker.js.map +1 -1
  187. package/dist/src/integrations/sandbox/index.d.ts +6 -0
  188. package/dist/src/integrations/sandbox/index.d.ts.map +1 -1
  189. package/dist/src/integrations/sandbox/index.js +8 -4
  190. package/dist/src/integrations/sandbox/index.js.map +1 -1
  191. package/dist/src/integrations/sandbox/landlock.d.ts.map +1 -1
  192. package/dist/src/integrations/sandbox/landlock.js +3 -0
  193. package/dist/src/integrations/sandbox/landlock.js.map +1 -1
  194. package/dist/src/integrations/self-improvement.d.ts.map +1 -1
  195. package/dist/src/integrations/self-improvement.js +12 -0
  196. package/dist/src/integrations/self-improvement.js.map +1 -1
  197. package/dist/src/integrations/session-store.d.ts +1 -0
  198. package/dist/src/integrations/session-store.d.ts.map +1 -1
  199. package/dist/src/integrations/session-store.js +1 -0
  200. package/dist/src/integrations/session-store.js.map +1 -1
  201. package/dist/src/integrations/shared-blackboard.d.ts +3 -0
  202. package/dist/src/integrations/shared-blackboard.d.ts.map +1 -1
  203. package/dist/src/integrations/shared-blackboard.js +47 -0
  204. package/dist/src/integrations/shared-blackboard.js.map +1 -1
  205. package/dist/src/integrations/smart-decomposer.d.ts +45 -1
  206. package/dist/src/integrations/smart-decomposer.d.ts.map +1 -1
  207. package/dist/src/integrations/smart-decomposer.js +486 -30
  208. package/dist/src/integrations/smart-decomposer.js.map +1 -1
  209. package/dist/src/integrations/sqlite-store.d.ts +2 -0
  210. package/dist/src/integrations/sqlite-store.d.ts.map +1 -1
  211. package/dist/src/integrations/sqlite-store.js +18 -6
  212. package/dist/src/integrations/sqlite-store.js.map +1 -1
  213. package/dist/src/integrations/swarm/failure-classifier.d.ts +11 -0
  214. package/dist/src/integrations/swarm/failure-classifier.d.ts.map +1 -0
  215. package/dist/src/integrations/swarm/failure-classifier.js +95 -0
  216. package/dist/src/integrations/swarm/failure-classifier.js.map +1 -0
  217. package/dist/src/integrations/swarm/index.d.ts +1 -1
  218. package/dist/src/integrations/swarm/index.d.ts.map +1 -1
  219. package/dist/src/integrations/swarm/index.js.map +1 -1
  220. package/dist/src/integrations/swarm/model-selector.d.ts +15 -0
  221. package/dist/src/integrations/swarm/model-selector.d.ts.map +1 -1
  222. package/dist/src/integrations/swarm/model-selector.js +100 -20
  223. package/dist/src/integrations/swarm/model-selector.js.map +1 -1
  224. package/dist/src/integrations/swarm/swarm-budget.d.ts +4 -0
  225. package/dist/src/integrations/swarm/swarm-budget.d.ts.map +1 -1
  226. package/dist/src/integrations/swarm/swarm-budget.js +6 -0
  227. package/dist/src/integrations/swarm/swarm-budget.js.map +1 -1
  228. package/dist/src/integrations/swarm/swarm-config-loader.d.ts +8 -0
  229. package/dist/src/integrations/swarm/swarm-config-loader.d.ts.map +1 -1
  230. package/dist/src/integrations/swarm/swarm-config-loader.js +249 -7
  231. package/dist/src/integrations/swarm/swarm-config-loader.js.map +1 -1
  232. package/dist/src/integrations/swarm/swarm-event-bridge.d.ts +86 -1
  233. package/dist/src/integrations/swarm/swarm-event-bridge.d.ts.map +1 -1
  234. package/dist/src/integrations/swarm/swarm-event-bridge.js +207 -23
  235. package/dist/src/integrations/swarm/swarm-event-bridge.js.map +1 -1
  236. package/dist/src/integrations/swarm/swarm-events.d.ts +58 -1
  237. package/dist/src/integrations/swarm/swarm-events.d.ts.map +1 -1
  238. package/dist/src/integrations/swarm/swarm-events.js +22 -5
  239. package/dist/src/integrations/swarm/swarm-events.js.map +1 -1
  240. package/dist/src/integrations/swarm/swarm-orchestrator.d.ts +147 -8
  241. package/dist/src/integrations/swarm/swarm-orchestrator.d.ts.map +1 -1
  242. package/dist/src/integrations/swarm/swarm-orchestrator.js +2179 -132
  243. package/dist/src/integrations/swarm/swarm-orchestrator.js.map +1 -1
  244. package/dist/src/integrations/swarm/swarm-quality-gate.d.ts +83 -2
  245. package/dist/src/integrations/swarm/swarm-quality-gate.d.ts.map +1 -1
  246. package/dist/src/integrations/swarm/swarm-quality-gate.js +278 -19
  247. package/dist/src/integrations/swarm/swarm-quality-gate.js.map +1 -1
  248. package/dist/src/integrations/swarm/swarm-state-store.d.ts +4 -1
  249. package/dist/src/integrations/swarm/swarm-state-store.d.ts.map +1 -1
  250. package/dist/src/integrations/swarm/swarm-state-store.js +8 -1
  251. package/dist/src/integrations/swarm/swarm-state-store.js.map +1 -1
  252. package/dist/src/integrations/swarm/task-queue.d.ts +54 -0
  253. package/dist/src/integrations/swarm/task-queue.d.ts.map +1 -1
  254. package/dist/src/integrations/swarm/task-queue.js +310 -12
  255. package/dist/src/integrations/swarm/task-queue.js.map +1 -1
  256. package/dist/src/integrations/swarm/types.d.ts +251 -13
  257. package/dist/src/integrations/swarm/types.d.ts.map +1 -1
  258. package/dist/src/integrations/swarm/types.js +70 -8
  259. package/dist/src/integrations/swarm/types.js.map +1 -1
  260. package/dist/src/integrations/swarm/worker-pool.d.ts +21 -4
  261. package/dist/src/integrations/swarm/worker-pool.d.ts.map +1 -1
  262. package/dist/src/integrations/swarm/worker-pool.js +223 -44
  263. package/dist/src/integrations/swarm/worker-pool.js.map +1 -1
  264. package/dist/src/integrations/task-manager.d.ts +33 -1
  265. package/dist/src/integrations/task-manager.d.ts.map +1 -1
  266. package/dist/src/integrations/task-manager.js +78 -4
  267. package/dist/src/integrations/task-manager.js.map +1 -1
  268. package/dist/src/integrations/tool-recommendation.d.ts +7 -4
  269. package/dist/src/integrations/tool-recommendation.d.ts.map +1 -1
  270. package/dist/src/integrations/tool-recommendation.js +58 -5
  271. package/dist/src/integrations/tool-recommendation.js.map +1 -1
  272. package/dist/src/integrations/work-log.js +4 -4
  273. package/dist/src/integrations/work-log.js.map +1 -1
  274. package/dist/src/main.js +106 -30
  275. package/dist/src/main.js.map +1 -1
  276. package/dist/src/modes/repl.d.ts.map +1 -1
  277. package/dist/src/modes/repl.js +50 -12
  278. package/dist/src/modes/repl.js.map +1 -1
  279. package/dist/src/modes/tui.d.ts.map +1 -1
  280. package/dist/src/modes/tui.js +41 -6
  281. package/dist/src/modes/tui.js.map +1 -1
  282. package/dist/src/modes.d.ts.map +1 -1
  283. package/dist/src/modes.js +4 -27
  284. package/dist/src/modes.js.map +1 -1
  285. package/dist/src/observability/tracer.d.ts.map +1 -1
  286. package/dist/src/observability/tracer.js +2 -1
  287. package/dist/src/observability/tracer.js.map +1 -1
  288. package/dist/src/persistence/schema.d.ts.map +1 -1
  289. package/dist/src/persistence/schema.js +11 -0
  290. package/dist/src/persistence/schema.js.map +1 -1
  291. package/dist/src/providers/adapters/anthropic.d.ts.map +1 -1
  292. package/dist/src/providers/adapters/anthropic.js +3 -2
  293. package/dist/src/providers/adapters/anthropic.js.map +1 -1
  294. package/dist/src/providers/adapters/openai.d.ts.map +1 -1
  295. package/dist/src/providers/adapters/openai.js +3 -2
  296. package/dist/src/providers/adapters/openai.js.map +1 -1
  297. package/dist/src/providers/adapters/openrouter.d.ts.map +1 -1
  298. package/dist/src/providers/adapters/openrouter.js +11 -11
  299. package/dist/src/providers/adapters/openrouter.js.map +1 -1
  300. package/dist/src/providers/circuit-breaker.d.ts +1 -0
  301. package/dist/src/providers/circuit-breaker.d.ts.map +1 -1
  302. package/dist/src/providers/circuit-breaker.js.map +1 -1
  303. package/dist/src/providers/provider.d.ts.map +1 -1
  304. package/dist/src/providers/provider.js +2 -1
  305. package/dist/src/providers/provider.js.map +1 -1
  306. package/dist/src/providers/resilient-provider.d.ts.map +1 -1
  307. package/dist/src/providers/resilient-provider.js +2 -1
  308. package/dist/src/providers/resilient-provider.js.map +1 -1
  309. package/dist/src/session-picker.d.ts.map +1 -1
  310. package/dist/src/session-picker.js +40 -5
  311. package/dist/src/session-picker.js.map +1 -1
  312. package/dist/src/shared/budget-tracker.d.ts +65 -0
  313. package/dist/src/shared/budget-tracker.d.ts.map +1 -0
  314. package/dist/src/shared/budget-tracker.js +128 -0
  315. package/dist/src/shared/budget-tracker.js.map +1 -0
  316. package/dist/src/shared/context-engine.d.ts +64 -0
  317. package/dist/src/shared/context-engine.d.ts.map +1 -0
  318. package/dist/src/shared/context-engine.js +117 -0
  319. package/dist/src/shared/context-engine.js.map +1 -0
  320. package/dist/src/shared/index.d.ts +12 -0
  321. package/dist/src/shared/index.d.ts.map +1 -0
  322. package/dist/src/shared/index.js +12 -0
  323. package/dist/src/shared/index.js.map +1 -0
  324. package/dist/src/shared/persistence.d.ts +57 -0
  325. package/dist/src/shared/persistence.d.ts.map +1 -0
  326. package/dist/src/shared/persistence.js +168 -0
  327. package/dist/src/shared/persistence.js.map +1 -0
  328. package/dist/src/shared/shared-context-state.d.ts +89 -0
  329. package/dist/src/shared/shared-context-state.d.ts.map +1 -0
  330. package/dist/src/shared/shared-context-state.js +175 -0
  331. package/dist/src/shared/shared-context-state.js.map +1 -0
  332. package/dist/src/shared/shared-economics-state.d.ts +61 -0
  333. package/dist/src/shared/shared-economics-state.d.ts.map +1 -0
  334. package/dist/src/shared/shared-economics-state.js +100 -0
  335. package/dist/src/shared/shared-economics-state.js.map +1 -0
  336. package/dist/src/tools/agent.d.ts.map +1 -1
  337. package/dist/src/tools/agent.js +11 -2
  338. package/dist/src/tools/agent.js.map +1 -1
  339. package/dist/src/tools/bash.d.ts +1 -1
  340. package/dist/src/tools/bash.d.ts.map +1 -1
  341. package/dist/src/tools/bash.js +2 -1
  342. package/dist/src/tools/bash.js.map +1 -1
  343. package/dist/src/tools/coercion.d.ts +6 -0
  344. package/dist/src/tools/coercion.d.ts.map +1 -1
  345. package/dist/src/tools/coercion.js +13 -0
  346. package/dist/src/tools/coercion.js.map +1 -1
  347. package/dist/src/tools/file.d.ts +5 -5
  348. package/dist/src/tools/file.js +2 -2
  349. package/dist/src/tools/file.js.map +1 -1
  350. package/dist/src/tools/permission.d.ts.map +1 -1
  351. package/dist/src/tools/permission.js +10 -116
  352. package/dist/src/tools/permission.js.map +1 -1
  353. package/dist/src/tools/types.d.ts +1 -0
  354. package/dist/src/tools/types.d.ts.map +1 -1
  355. package/dist/src/tools/types.js.map +1 -1
  356. package/dist/src/tracing/trace-collector.d.ts +292 -0
  357. package/dist/src/tracing/trace-collector.d.ts.map +1 -1
  358. package/dist/src/tracing/trace-collector.js +249 -5
  359. package/dist/src/tracing/trace-collector.js.map +1 -1
  360. package/dist/src/tracing/types.d.ts +200 -1
  361. package/dist/src/tracing/types.d.ts.map +1 -1
  362. package/dist/src/tracing/types.js.map +1 -1
  363. package/dist/src/tricks/failure-evidence.d.ts.map +1 -1
  364. package/dist/src/tricks/failure-evidence.js +2 -1
  365. package/dist/src/tricks/failure-evidence.js.map +1 -1
  366. package/dist/src/tui/app.d.ts +13 -0
  367. package/dist/src/tui/app.d.ts.map +1 -1
  368. package/dist/src/tui/app.js +162 -19
  369. package/dist/src/tui/app.js.map +1 -1
  370. package/dist/src/tui/components/ErrorBoundary.d.ts.map +1 -1
  371. package/dist/src/tui/components/ErrorBoundary.js +3 -2
  372. package/dist/src/tui/components/ErrorBoundary.js.map +1 -1
  373. package/dist/src/tui/event-display.d.ts.map +1 -1
  374. package/dist/src/tui/event-display.js +36 -62
  375. package/dist/src/tui/event-display.js.map +1 -1
  376. package/dist/src/tui/index.d.ts +4 -0
  377. package/dist/src/tui/index.d.ts.map +1 -1
  378. package/dist/src/tui/index.js +17 -0
  379. package/dist/src/tui/index.js.map +1 -1
  380. package/dist/src/types.d.ts +214 -1
  381. package/dist/src/types.d.ts.map +1 -1
  382. package/package.json +18 -3
@@ -0,0 +1,966 @@
1
+ /**
2
+ * Subagent Spawner Module (Phase 2.1)
3
+ *
4
+ * Extracted from ProductionAgent.spawnAgent(), getSubagentBudget(),
5
+ * and spawnAgentsParallel(). Handles the full subagent lifecycle:
6
+ * config, budget, delegation, timeout, cleanup.
7
+ *
8
+ * Uses SubAgentFactory to create subagent instances without importing
9
+ * ProductionAgent directly — avoids circular dependencies.
10
+ */
11
+ import { getSubagentTimeout, getSubagentMaxIterations, } from '../defaults.js';
12
+ import { calculateTaskSimilarity, SUBAGENT_PLAN_MODE_ADDITION, } from '../modes.js';
13
+ import { SUBAGENT_BUDGET, filterToolsForAgent, isCancellationError, createLinkedToken, createGracefulTimeout, race, createDynamicBudgetPool, buildDelegationPrompt, createMinimalDelegationSpec, getSubagentQualityPrompt, ToolRecommendationEngine, createSubagentSupervisor, createSubagentHandle, } from '../integrations/index.js';
14
+ import { mergeApprovalScopeWithProfile, resolvePolicyProfile, } from '../integrations/policy-engine.js';
15
+ /** Duplicate spawn prevention window (60 seconds). */
16
+ const SPAWN_DEDUP_WINDOW_MS = 60000;
17
+ /**
18
+ * Parse a structured closure report from a subagent's text response.
19
+ * The subagent may have produced JSON in response to a TIMEOUT_WRAPUP_PROMPT.
20
+ */
21
+ export function parseStructuredClosureReport(text, defaultExitReason, fallbackTask) {
22
+ if (!text) {
23
+ if (fallbackTask) {
24
+ return {
25
+ findings: [],
26
+ actionsTaken: [],
27
+ failures: ['Timeout before producing structured summary'],
28
+ remainingWork: [fallbackTask],
29
+ exitReason: 'timeout_hard',
30
+ };
31
+ }
32
+ return undefined;
33
+ }
34
+ try {
35
+ const jsonMatch = text.match(/\{[\s\S]*\}/);
36
+ if (jsonMatch) {
37
+ const parsed = JSON.parse(jsonMatch[0]);
38
+ if (parsed.findings || parsed.actionsTaken || parsed.failures || parsed.remainingWork) {
39
+ return {
40
+ findings: Array.isArray(parsed.findings) ? parsed.findings : [],
41
+ actionsTaken: Array.isArray(parsed.actionsTaken) ? parsed.actionsTaken : [],
42
+ failures: Array.isArray(parsed.failures) ? parsed.failures : [],
43
+ remainingWork: Array.isArray(parsed.remainingWork) ? parsed.remainingWork : [],
44
+ exitReason: defaultExitReason,
45
+ suggestedNextSteps: Array.isArray(parsed.suggestedNextSteps) ? parsed.suggestedNextSteps : undefined,
46
+ };
47
+ }
48
+ }
49
+ }
50
+ catch {
51
+ // JSON parse failed — fall through to fallback
52
+ }
53
+ if (defaultExitReason !== 'completed') {
54
+ return {
55
+ findings: [text.slice(0, 500)],
56
+ actionsTaken: [],
57
+ failures: ['Did not produce structured JSON summary'],
58
+ remainingWork: fallbackTask ? [fallbackTask] : [],
59
+ exitReason: defaultExitReason === 'timeout_graceful' ? 'timeout_hard' : defaultExitReason,
60
+ };
61
+ }
62
+ return undefined;
63
+ }
64
+ /**
65
+ * Get budget for a subagent, using the pooled budget when available.
66
+ * Falls back to the static SUBAGENT_BUDGET if no pool is configured.
67
+ */
68
+ export function getSubagentBudget(ctx, agentName, constraints) {
69
+ if (constraints?.maxTokens) {
70
+ return {
71
+ budget: { ...SUBAGENT_BUDGET, maxTokens: constraints.maxTokens },
72
+ allocationId: null,
73
+ };
74
+ }
75
+ if (ctx.budgetPool) {
76
+ const allocationId = `${agentName}-${Date.now()}`;
77
+ const allocation = ctx.budgetPool.reserve(allocationId);
78
+ if (allocation) {
79
+ return {
80
+ budget: {
81
+ ...SUBAGENT_BUDGET,
82
+ maxTokens: allocation.tokenBudget,
83
+ softTokenLimit: Math.floor(allocation.tokenBudget * 0.7),
84
+ maxCost: allocation.costBudget,
85
+ },
86
+ allocationId,
87
+ };
88
+ }
89
+ return {
90
+ budget: {
91
+ ...SUBAGENT_BUDGET,
92
+ maxTokens: 5000,
93
+ softTokenLimit: 3000,
94
+ maxCost: 0.01,
95
+ },
96
+ allocationId: null,
97
+ };
98
+ }
99
+ return { budget: SUBAGENT_BUDGET, allocationId: null };
100
+ }
101
+ /**
102
+ * Spawn a single subagent to handle a delegated task.
103
+ * Extracted from ProductionAgent.spawnAgent().
104
+ */
105
+ export async function spawnAgent(agentName, task, ctx, createSubAgent, constraints) {
106
+ if (!ctx.agentRegistry) {
107
+ return {
108
+ success: false,
109
+ output: 'Agent registry not initialized',
110
+ metrics: { tokens: 0, duration: 0, toolCalls: 0 },
111
+ };
112
+ }
113
+ const agentDef = ctx.agentRegistry.getAgent(agentName);
114
+ if (!agentDef) {
115
+ return {
116
+ success: false,
117
+ output: `Agent not found: ${agentName}`,
118
+ metrics: { tokens: 0, duration: 0, toolCalls: 0 },
119
+ };
120
+ }
121
+ // DUPLICATE SPAWN PREVENTION with SEMANTIC SIMILARITY
122
+ const isSwarmWorker = agentName.startsWith('swarm-');
123
+ const SEMANTIC_SIMILARITY_THRESHOLD = 0.75;
124
+ const taskKey = `${agentName}:${task.slice(0, 150).toLowerCase().replace(/\s+/g, ' ').trim()}`;
125
+ const now = Date.now();
126
+ // Clean up old entries
127
+ for (const [key, entry] of ctx.spawnedTasks.entries()) {
128
+ if (now - entry.timestamp > SPAWN_DEDUP_WINDOW_MS) {
129
+ ctx.spawnedTasks.delete(key);
130
+ }
131
+ }
132
+ let existingMatch;
133
+ let matchType = 'exact';
134
+ if (!isSwarmWorker) {
135
+ existingMatch = ctx.spawnedTasks.get(taskKey);
136
+ if (!existingMatch) {
137
+ for (const [key, entry] of ctx.spawnedTasks.entries()) {
138
+ if (!key.startsWith(`${agentName}:`))
139
+ continue;
140
+ if (now - entry.timestamp >= SPAWN_DEDUP_WINDOW_MS)
141
+ continue;
142
+ const existingTask = key.slice(agentName.length + 1);
143
+ const similarity = calculateTaskSimilarity(task, existingTask);
144
+ if (similarity >= SEMANTIC_SIMILARITY_THRESHOLD) {
145
+ existingMatch = entry;
146
+ matchType = 'semantic';
147
+ ctx.observability?.logger?.debug('Semantic duplicate detected', {
148
+ agent: agentName,
149
+ newTask: task.slice(0, 80),
150
+ existingTask: existingTask.slice(0, 80),
151
+ similarity: (similarity * 100).toFixed(1) + '%',
152
+ });
153
+ break;
154
+ }
155
+ }
156
+ }
157
+ }
158
+ if (existingMatch && now - existingMatch.timestamp < SPAWN_DEDUP_WINDOW_MS) {
159
+ ctx.observability?.logger?.warn('Duplicate spawn prevented', {
160
+ agent: agentName,
161
+ task: task.slice(0, 100),
162
+ matchType,
163
+ originalTimestamp: existingMatch.timestamp,
164
+ elapsedMs: now - existingMatch.timestamp,
165
+ });
166
+ const duplicateMessage = `[DUPLICATE SPAWN PREVENTED${matchType === 'semantic' ? ' - SEMANTIC MATCH' : ''}]\n` +
167
+ `This task was already spawned ${Math.round((now - existingMatch.timestamp) / 1000)}s ago.\n` +
168
+ `${existingMatch.queuedChanges > 0
169
+ ? `The previous spawn queued ${existingMatch.queuedChanges} change(s) to the pending plan.\n` +
170
+ `These changes are already in your plan - do NOT spawn again.\n`
171
+ : ''}Previous result summary:\n${existingMatch.result.slice(0, 500)}`;
172
+ return {
173
+ success: true,
174
+ output: duplicateMessage,
175
+ metrics: { tokens: 0, duration: 0, toolCalls: 0 },
176
+ };
177
+ }
178
+ const agentId = `spawn-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
179
+ ctx.emit({ type: 'agent.spawn', agentId, name: agentName, task });
180
+ ctx.observability?.logger?.info('Spawning agent', { name: agentName, task });
181
+ const startTime = Date.now();
182
+ const childSessionId = `subagent-${agentName}-${Date.now()}`;
183
+ const childTraceId = `trace-${childSessionId}`;
184
+ let workerResultId;
185
+ try {
186
+ // Filter tools for this agent
187
+ let agentTools = filterToolsForAgent(agentDef, Array.from(ctx.tools.values()));
188
+ // Resolve policy profile
189
+ const inferredTaskType = agentDef.taskType ?? ToolRecommendationEngine.inferTaskType(agentName);
190
+ const policyResolution = resolvePolicyProfile({
191
+ policyEngine: ctx.config.policyEngine,
192
+ requestedProfile: agentDef.policyProfile,
193
+ swarmConfig: isSwarmWorker && ctx.config.swarm && typeof ctx.config.swarm === 'object'
194
+ ? ctx.config.swarm
195
+ : undefined,
196
+ taskType: inferredTaskType,
197
+ isSwarmWorker,
198
+ sandboxConfig: ctx.config.sandbox && typeof ctx.config.sandbox === 'object'
199
+ ? ctx.config.sandbox
200
+ : undefined,
201
+ });
202
+ ctx.emit({
203
+ type: 'policy.profile.resolved',
204
+ profile: policyResolution.profileName,
205
+ context: isSwarmWorker ? 'swarm' : 'subagent',
206
+ selectionSource: policyResolution.metadata.selectionSource,
207
+ usedLegacyMappings: policyResolution.metadata.usedLegacyMappings,
208
+ legacySources: policyResolution.metadata.legacyMappingSources,
209
+ });
210
+ if (policyResolution.metadata.usedLegacyMappings) {
211
+ ctx.emit({
212
+ type: 'policy.legacy.fallback.used',
213
+ profile: policyResolution.profileName,
214
+ sources: policyResolution.metadata.legacyMappingSources,
215
+ warnings: policyResolution.metadata.warnings,
216
+ });
217
+ ctx.observability?.logger?.warn('Policy legacy mappings used', {
218
+ agent: agentName,
219
+ profile: policyResolution.profileName,
220
+ sources: policyResolution.metadata.legacyMappingSources,
221
+ });
222
+ }
223
+ // Apply tool recommendations
224
+ if (ctx.toolRecommendation && agentTools.length > 15) {
225
+ const taskType = ToolRecommendationEngine.inferTaskType(agentName);
226
+ const recommendations = ctx.toolRecommendation.recommendTools(task, taskType, agentTools.map(t => t.name));
227
+ if (recommendations.length > 0) {
228
+ const recommendedNames = new Set(recommendations.map(r => r.toolName));
229
+ const alwaysKeep = new Set(['spawn_agent', 'spawn_agents_parallel']);
230
+ if (policyResolution.profile.allowedTools) {
231
+ for (const t of policyResolution.profile.allowedTools)
232
+ alwaysKeep.add(t);
233
+ }
234
+ agentTools = agentTools.filter(t => recommendedNames.has(t.name) || alwaysKeep.has(t.name));
235
+ }
236
+ }
237
+ // Enforce unified tool policy
238
+ if (policyResolution.profile.toolAccessMode === 'whitelist' && policyResolution.profile.allowedTools) {
239
+ const allowed = new Set(policyResolution.profile.allowedTools);
240
+ agentTools = agentTools.filter(t => allowed.has(t.name));
241
+ }
242
+ else if (policyResolution.profile.deniedTools && policyResolution.profile.deniedTools.length > 0) {
243
+ const denied = new Set(policyResolution.profile.deniedTools);
244
+ agentTools = agentTools.filter(t => !denied.has(t.name));
245
+ }
246
+ if (agentTools.length === 0) {
247
+ throw new Error(`Worker '${agentName}' has zero available tools after filtering. Check toolAccessMode and policy profile '${policyResolution.profileName}'.`);
248
+ }
249
+ // Resolve model
250
+ const resolvedModel = (agentDef.model && agentDef.model.includes('/'))
251
+ ? agentDef.model
252
+ : ctx.config.model;
253
+ // Persist subagent task lifecycle
254
+ if (ctx.store?.hasWorkerResultsFeature()) {
255
+ try {
256
+ workerResultId = ctx.store.createWorkerResult(agentId, task.slice(0, 500), resolvedModel || 'default');
257
+ }
258
+ catch (storeErr) {
259
+ ctx.observability?.logger?.warn('Failed to create worker result record', {
260
+ agentId,
261
+ error: storeErr.message,
262
+ });
263
+ }
264
+ }
265
+ // Get subagent config with agent-type-specific timeouts and iteration limits
266
+ const subagentConfig = ctx.config.subagent;
267
+ const hasSubagentConfig = subagentConfig !== false && subagentConfig !== undefined;
268
+ // Timeout precedence
269
+ const agentTypeTimeout = getSubagentTimeout(agentName);
270
+ const rawPerTypeTimeout = hasSubagentConfig
271
+ ? subagentConfig.timeouts?.[agentName]
272
+ : undefined;
273
+ const rawGlobalTimeout = hasSubagentConfig
274
+ ? subagentConfig.defaultTimeout
275
+ : undefined;
276
+ const isValidTimeout = (v) => v !== undefined && Number.isFinite(v) && v > 0;
277
+ const agentDefTimeout = isValidTimeout(agentDef.timeout) ? agentDef.timeout : undefined;
278
+ const perTypeConfigTimeout = isValidTimeout(rawPerTypeTimeout) ? rawPerTypeTimeout : undefined;
279
+ const globalConfigTimeout = isValidTimeout(rawGlobalTimeout) ? rawGlobalTimeout : undefined;
280
+ const subagentTimeout = agentDefTimeout ?? perTypeConfigTimeout ?? agentTypeTimeout ?? globalConfigTimeout ?? 300000;
281
+ // Iteration precedence
282
+ const agentTypeMaxIter = getSubagentMaxIterations(agentName);
283
+ const rawPerTypeMaxIter = hasSubagentConfig
284
+ ? subagentConfig.maxIterations?.[agentName]
285
+ : undefined;
286
+ const rawGlobalMaxIter = hasSubagentConfig
287
+ ? subagentConfig.defaultMaxIterations
288
+ : undefined;
289
+ const isValidIter = (v) => v !== undefined && Number.isFinite(v) && v > 0 && Number.isInteger(v);
290
+ const perTypeConfigMaxIter = isValidIter(rawPerTypeMaxIter) ? rawPerTypeMaxIter : undefined;
291
+ const globalConfigMaxIter = isValidIter(rawGlobalMaxIter) ? rawGlobalMaxIter : undefined;
292
+ const defaultMaxIterations = agentDef.maxIterations ?? perTypeConfigMaxIter ?? agentTypeMaxIter ?? globalConfigMaxIter ?? 15;
293
+ // BLACKBOARD CONTEXT INJECTION
294
+ let blackboardContext = '';
295
+ let blackboardFindingsCount = 0;
296
+ const parentAgentId = `parent-${Date.now()}`;
297
+ if (ctx.blackboard) {
298
+ ctx.blackboard.post(parentAgentId, {
299
+ topic: 'spawn.parent_context',
300
+ content: `Parent spawning ${agentName} for task: ${task.slice(0, 200)}`,
301
+ type: 'progress',
302
+ confidence: 1,
303
+ metadata: { agentName, taskPreview: task.slice(0, 100) },
304
+ });
305
+ const recentFindings = ctx.blackboard.query({
306
+ limit: 5,
307
+ types: ['discovery', 'analysis', 'progress'],
308
+ minConfidence: 0.7,
309
+ });
310
+ blackboardFindingsCount = recentFindings.length;
311
+ if (recentFindings.length > 0) {
312
+ const findingsSummary = recentFindings
313
+ .map(f => `- [${f.agentId}] ${f.topic}: ${f.content.slice(0, 150)}${f.content.length > 150 ? '...' : ''}`)
314
+ .join('\n');
315
+ blackboardContext = `\n\n**BLACKBOARD CONTEXT (from parent/sibling agents):**\n${findingsSummary}\n`;
316
+ }
317
+ }
318
+ // Check for files already in parent's pending plan
319
+ const currentPlan = ctx.pendingPlanManager.getPendingPlan();
320
+ if (currentPlan && currentPlan.proposedChanges.length > 0) {
321
+ const pendingFiles = currentPlan.proposedChanges
322
+ .filter((c) => c.tool === 'write_file' || c.tool === 'edit_file')
323
+ .map((c) => c.args.path || c.args.file_path)
324
+ .filter(Boolean);
325
+ if (pendingFiles.length > 0) {
326
+ blackboardContext += `\n**FILES ALREADY IN PENDING PLAN (do not duplicate):**\n${pendingFiles.slice(0, 10).join('\n')}\n`;
327
+ }
328
+ }
329
+ // CONSTRAINT INJECTION
330
+ const constraintParts = [];
331
+ const subagentBudgetTokens = constraints?.maxTokens ?? SUBAGENT_BUDGET.maxTokens ?? 100000;
332
+ const subagentBudgetMinutes = Math.round((SUBAGENT_BUDGET.maxDuration ?? 240000) / 60000);
333
+ if (isSwarmWorker) {
334
+ constraintParts.push(`**Execution Mode:** You are a focused worker agent.\n` +
335
+ `- Complete your assigned task using tool calls.\n` +
336
+ `- Your FIRST action must be a tool call (read_file, write_file, edit_file, grep, glob, etc.).\n` +
337
+ `- To create files use write_file. To modify files use edit_file. Do NOT use bash for file operations.\n` +
338
+ `- You will receive a system message if you need to wrap up. Until then, work normally.\n` +
339
+ `- Do NOT produce summaries or reports — produce CODE and FILE CHANGES.`);
340
+ }
341
+ else {
342
+ constraintParts.push(`**RESOURCE AWARENESS (CRITICAL):**\n` +
343
+ `- Token budget: ~${(subagentBudgetTokens / 1000).toFixed(0)}k tokens\n` +
344
+ `- Time limit: ~${subagentBudgetMinutes} minutes\n` +
345
+ `- You will receive warnings at 70% usage. When warned, WRAP UP immediately.\n` +
346
+ `- Do not explore indefinitely - be focused and efficient.\n` +
347
+ `- If approaching limits, summarize findings and return.\n` +
348
+ `- **STRUCTURED WRAPUP:** When told to wrap up, respond with ONLY this JSON (no tool calls):\n` +
349
+ ` {"findings":[...], "actionsTaken":[...], "failures":[...], "remainingWork":[...], "suggestedNextSteps":[...]}`);
350
+ }
351
+ if (constraints) {
352
+ if (constraints.focusAreas && constraints.focusAreas.length > 0) {
353
+ constraintParts.push(`**FOCUS AREAS (limit exploration to these paths):**\n${constraints.focusAreas.map(a => ` - ${a}`).join('\n')}`);
354
+ }
355
+ if (constraints.excludeAreas && constraints.excludeAreas.length > 0) {
356
+ constraintParts.push(`**EXCLUDED AREAS (do NOT explore these):**\n${constraints.excludeAreas.map(a => ` - ${a}`).join('\n')}`);
357
+ }
358
+ if (constraints.requiredDeliverables && constraints.requiredDeliverables.length > 0) {
359
+ constraintParts.push(`**REQUIRED DELIVERABLES (you must produce these):**\n${constraints.requiredDeliverables.map(d => ` - ${d}`).join('\n')}`);
360
+ }
361
+ if (constraints.timeboxMinutes) {
362
+ constraintParts.push(`**TIME LIMIT:** ${constraints.timeboxMinutes} minutes (soft limit - wrap up if approaching)`);
363
+ }
364
+ }
365
+ const constraintContext = `\n\n**EXECUTION CONSTRAINTS:**\n${constraintParts.join('\n\n')}\n`;
366
+ // Build delegation-enhanced system prompt
367
+ let delegationContext = '';
368
+ if (ctx.lastComplexityAssessment && ctx.lastComplexityAssessment.tier !== 'simple') {
369
+ const spec = createMinimalDelegationSpec(task, agentName);
370
+ delegationContext = '\n\n' + buildDelegationPrompt(spec);
371
+ }
372
+ const qualityPrompt = '\n\n' + getSubagentQualityPrompt();
373
+ // REPO CONTEXT INJECTION — give subagents a lightweight file structure map
374
+ let repoContextStr = '';
375
+ if (ctx.codebaseContext) {
376
+ const repoMap = ctx.codebaseContext.getRepoMap();
377
+ if (repoMap) {
378
+ // Lightweight repo map: file tree with key symbols (capped at 3000 tokens)
379
+ const { generateLightweightRepoMap } = await import('../integrations/codebase-context.js');
380
+ repoContextStr = '\n\n**REPOSITORY STRUCTURE:**\n' + generateLightweightRepoMap(repoMap, 3000);
381
+ }
382
+ }
383
+ // Inject parent's recently modified files so subagent knows the working context
384
+ let recentFilesStr = '';
385
+ let modifiedFilesList = [];
386
+ if (ctx.economics) {
387
+ const modifiedPaths = ctx.economics.getModifiedFilePaths();
388
+ modifiedFilesList = modifiedPaths.slice(0, 15);
389
+ if (modifiedPaths.length > 0) {
390
+ recentFilesStr = '\n\n**RECENTLY MODIFIED FILES (by parent agent):**\n' +
391
+ modifiedPaths.slice(0, 15).map(f => `- ${f}`).join('\n');
392
+ }
393
+ }
394
+ // Build subagent system prompt
395
+ const parentMode = ctx.modeManager.getMode();
396
+ const subagentSystemPrompt = parentMode === 'plan'
397
+ ? `${agentDef.systemPrompt}\n\n${SUBAGENT_PLAN_MODE_ADDITION}${blackboardContext}${repoContextStr}${recentFilesStr}${constraintContext}${delegationContext}${qualityPrompt}`
398
+ : `${agentDef.systemPrompt}${blackboardContext}${repoContextStr}${recentFilesStr}${constraintContext}${delegationContext}${qualityPrompt}`;
399
+ // Trace context injection for subagent prompt
400
+ ctx.traceCollector?.record({
401
+ type: 'context.injection',
402
+ data: {
403
+ agentId: agentName,
404
+ parentAgentId: ctx.traceCollector.getSessionId() || 'unknown',
405
+ repoMapTokens: Math.ceil(repoContextStr.length / 4),
406
+ blackboardFindings: blackboardFindingsCount,
407
+ modifiedFiles: modifiedFilesList,
408
+ toolCount: agentTools.length,
409
+ model: resolvedModel || 'default',
410
+ },
411
+ });
412
+ // Allocate budget
413
+ const pooledBudget = getSubagentBudget(ctx, agentName, constraints);
414
+ const poolAllocationId = pooledBudget.allocationId;
415
+ const deniedByProfile = new Set(policyResolution.profile.deniedTools ?? []);
416
+ const policyToolPolicies = {};
417
+ for (const toolName of deniedByProfile) {
418
+ policyToolPolicies[toolName] = {
419
+ policy: 'forbidden',
420
+ reason: `Denied by policy profile '${policyResolution.profileName}'`,
421
+ };
422
+ }
423
+ if ((policyResolution.profile.bashMode ?? 'full') === 'disabled') {
424
+ policyToolPolicies.bash = {
425
+ policy: 'forbidden',
426
+ reason: `Bash is disabled by policy profile '${policyResolution.profileName}'`,
427
+ };
428
+ }
429
+ // Create the sub-agent via factory (avoids circular import)
430
+ const subAgent = createSubAgent({
431
+ provider: ctx.provider,
432
+ tools: agentTools,
433
+ toolResolver: ctx.toolResolver || undefined,
434
+ mcpToolSummaries: ctx.config.mcpToolSummaries,
435
+ systemPrompt: subagentSystemPrompt,
436
+ model: resolvedModel,
437
+ maxIterations: agentDef.maxIterations || defaultMaxIterations,
438
+ memory: false,
439
+ planning: false,
440
+ reflection: false,
441
+ compaction: {
442
+ enabled: true,
443
+ mode: 'auto',
444
+ tokenThreshold: 40000,
445
+ preserveRecentCount: 4,
446
+ preserveToolResults: false,
447
+ summaryMaxTokens: 500,
448
+ },
449
+ maxContextTokens: 80000,
450
+ observability: ctx.config.observability,
451
+ sandbox: (() => {
452
+ const swarm = ctx.config.swarm;
453
+ const extraCmds = swarm && typeof swarm === 'object' && swarm.permissions?.additionalAllowedCommands;
454
+ const baseSbx = ctx.config.sandbox;
455
+ if (baseSbx && typeof baseSbx === 'object') {
456
+ const sbx = baseSbx;
457
+ const allowedCommands = extraCmds
458
+ ? [...(sbx.allowedCommands || []), ...extraCmds]
459
+ : sbx.allowedCommands;
460
+ return {
461
+ ...sbx,
462
+ allowedCommands,
463
+ bashMode: policyResolution.profile.bashMode ?? sbx.bashMode,
464
+ bashWriteProtection: policyResolution.profile.bashWriteProtection ?? sbx.bashWriteProtection,
465
+ blockFileCreationViaBash: (policyResolution.profile.bashWriteProtection ?? 'off') === 'block_file_mutation'
466
+ ? true
467
+ : sbx.blockFileCreationViaBash,
468
+ };
469
+ }
470
+ return baseSbx;
471
+ })(),
472
+ // Subagents: raise riskThreshold to 'high' so moderate-risk tools (write_file, edit_file)
473
+ // pass without approval dialogs. High-risk tools (delete_file) still require approval.
474
+ // The scopedApprove paths still constrain WHERE subagents can write.
475
+ humanInLoop: ctx.config.humanInLoop
476
+ ? {
477
+ ...ctx.config.humanInLoop,
478
+ riskThreshold: 'high',
479
+ }
480
+ : ctx.config.humanInLoop,
481
+ executionPolicy: (() => {
482
+ const hasPolicyOverrides = Object.keys(policyToolPolicies).length > 0;
483
+ if (ctx.config.executionPolicy) {
484
+ return {
485
+ ...ctx.config.executionPolicy,
486
+ defaultPolicy: 'allow',
487
+ toolPolicies: {
488
+ ...(ctx.config.executionPolicy.toolPolicies ?? {}),
489
+ ...policyToolPolicies,
490
+ },
491
+ };
492
+ }
493
+ if (hasPolicyOverrides) {
494
+ return {
495
+ enabled: true,
496
+ defaultPolicy: 'allow',
497
+ toolPolicies: policyToolPolicies,
498
+ intentAware: false,
499
+ };
500
+ }
501
+ return { enabled: true, defaultPolicy: 'allow', toolPolicies: {}, intentAware: false };
502
+ })(),
503
+ policyEngine: ctx.config.policyEngine
504
+ ? { ...ctx.config.policyEngine, defaultProfile: policyResolution.profileName }
505
+ : ctx.config.policyEngine,
506
+ threads: false,
507
+ hooks: ctx.config.hooks === false ? false : {
508
+ enabled: true,
509
+ builtIn: { logging: false, timing: false, metrics: false },
510
+ custom: [],
511
+ },
512
+ agentId,
513
+ blackboard: ctx.blackboard || undefined,
514
+ fileCache: ctx.fileCache || undefined,
515
+ budget: agentDef.economicsTuning
516
+ ? { ...pooledBudget.budget, tuning: agentDef.economicsTuning }
517
+ : pooledBudget.budget,
518
+ sharedContextState: ctx.sharedContextState || undefined,
519
+ sharedEconomicsState: ctx.sharedEconomicsState || undefined,
520
+ });
521
+ // Inherit parent's mode
522
+ if (parentMode !== 'build') {
523
+ subAgent.setMode(parentMode);
524
+ }
525
+ // APPROVAL BATCHING
526
+ const swarmPerms = ctx.config.swarm && typeof ctx.config.swarm === 'object'
527
+ ? ctx.config.swarm.permissions : undefined;
528
+ const baseAutoApprove = ['read_file', 'list_files', 'glob', 'grep', 'show_file_history', 'show_session_changes'];
529
+ const baseScopedApprove = isSwarmWorker
530
+ ? {
531
+ write_file: { paths: ['src/', 'tests/', 'tools/'] },
532
+ edit_file: { paths: ['src/', 'tests/', 'tools/'] },
533
+ bash: { paths: ['src/', 'tests/', 'tools/'] },
534
+ }
535
+ : {
536
+ write_file: { paths: ['src/', 'tests/', 'tools/'] },
537
+ edit_file: { paths: ['src/', 'tests/', 'tools/'] },
538
+ };
539
+ const baseRequireApproval = isSwarmWorker ? ['delete_file'] : ['bash', 'delete_file'];
540
+ const mergedScope = mergeApprovalScopeWithProfile({
541
+ autoApprove: swarmPerms?.autoApprove
542
+ ? [...new Set([...baseAutoApprove, ...swarmPerms.autoApprove])]
543
+ : baseAutoApprove,
544
+ scopedApprove: swarmPerms?.scopedApprove
545
+ ? { ...baseScopedApprove, ...swarmPerms.scopedApprove }
546
+ : baseScopedApprove,
547
+ requireApproval: swarmPerms?.requireApproval
548
+ ? swarmPerms.requireApproval
549
+ : baseRequireApproval,
550
+ }, policyResolution.profile);
551
+ subAgent.setApprovalScope(mergedScope);
552
+ subAgent.setParentIterations(ctx.getTotalIterations());
553
+ // UNIFIED TRACING
554
+ if (ctx.traceCollector) {
555
+ const subagentTraceView = ctx.traceCollector.createSubagentView({
556
+ parentSessionId: ctx.traceCollector.getSessionId() || 'unknown',
557
+ agentType: agentName,
558
+ spawnedAtIteration: ctx.state.iteration,
559
+ });
560
+ subAgent.setTraceCollector(subagentTraceView);
561
+ }
562
+ // GRACEFUL TIMEOUT with WRAPUP PHASE
563
+ const IDLE_TIMEOUT = agentDef.idleTimeout ?? 120000;
564
+ let WRAPUP_WINDOW = 30000;
565
+ let IDLE_CHECK_INTERVAL = 5000;
566
+ if (ctx.config.subagent) {
567
+ WRAPUP_WINDOW = ctx.config.subagent.wrapupWindowMs ?? WRAPUP_WINDOW;
568
+ IDLE_CHECK_INTERVAL = ctx.config.subagent.idleCheckIntervalMs ?? IDLE_CHECK_INTERVAL;
569
+ }
570
+ const progressAwareTimeout = createGracefulTimeout(subagentTimeout, IDLE_TIMEOUT, WRAPUP_WINDOW, IDLE_CHECK_INTERVAL);
571
+ progressAwareTimeout.onWrapupWarning(() => {
572
+ ctx.emit({
573
+ type: 'subagent.wrapup.started',
574
+ agentId,
575
+ agentType: agentName,
576
+ reason: 'Timeout approaching - graceful wrapup window opened',
577
+ elapsedMs: Date.now() - startTime,
578
+ });
579
+ subAgent.requestWrapup('Timeout approaching — produce structured summary');
580
+ });
581
+ // Forward events from subagent
582
+ const unsubSubAgent = subAgent.subscribe(event => {
583
+ const taggedEvent = { ...event, subagent: agentName, subagentId: agentId };
584
+ ctx.emit(taggedEvent);
585
+ const progressEvents = ['tool.start', 'tool.complete', 'llm.start', 'llm.complete'];
586
+ if (progressEvents.includes(event.type)) {
587
+ progressAwareTimeout.reportProgress();
588
+ }
589
+ });
590
+ // Link parent's cancellation
591
+ const parentSource = ctx.cancellation?.getSource();
592
+ const effectiveSource = parentSource
593
+ ? createLinkedToken(parentSource, progressAwareTimeout)
594
+ : progressAwareTimeout;
595
+ subAgent.setExternalCancellation(effectiveSource.token);
596
+ // Pause parent's duration timer
597
+ ctx.economics?.pauseDuration();
598
+ try {
599
+ const result = await race(subAgent.run(task), effectiveSource.token);
600
+ const duration = Date.now() - startTime;
601
+ // Extract subagent's pending plan and merge into parent's plan
602
+ let queuedChangeSummary = '';
603
+ let queuedChangesCount = 0;
604
+ if (subAgent.hasPendingPlan()) {
605
+ const subPlan = subAgent.getPendingPlan();
606
+ if (subPlan && subPlan.proposedChanges.length > 0) {
607
+ queuedChangesCount = subPlan.proposedChanges.length;
608
+ ctx.emit({
609
+ type: 'agent.pending_plan',
610
+ agentId: agentName,
611
+ changes: subPlan.proposedChanges,
612
+ });
613
+ const changeSummaries = subPlan.proposedChanges.map(c => {
614
+ if (c.tool === 'write_file' || c.tool === 'edit_file') {
615
+ const path = c.args.path || c.args.file_path || '(unknown file)';
616
+ return ` - [${c.tool}] ${path}: ${c.reason}`;
617
+ }
618
+ else if (c.tool === 'bash') {
619
+ const cmd = String(c.args.command || '').slice(0, 60);
620
+ return ` - [bash] ${cmd}${String(c.args.command || '').length > 60 ? '...' : ''}: ${c.reason}`;
621
+ }
622
+ return ` - [${c.tool}]: ${c.reason}`;
623
+ });
624
+ queuedChangeSummary = `\n\n[PLAN MODE - CHANGES QUEUED TO PARENT]\n` +
625
+ `The following ${subPlan.proposedChanges.length} change(s) have been queued in the parent's pending plan:\n` +
626
+ changeSummaries.join('\n') + '\n' +
627
+ `\nThese changes are now in YOUR pending plan. The task for this subagent is COMPLETE.\n` +
628
+ `Do NOT spawn another agent for the same task - the changes are already queued.\n` +
629
+ `Use /show-plan to see all pending changes, /approve to execute them.`;
630
+ for (const change of subPlan.proposedChanges) {
631
+ ctx.pendingPlanManager.addProposedChange(change.tool, { ...change.args, _fromSubagent: agentName }, `[${agentName}] ${change.reason}`, change.toolCallId);
632
+ }
633
+ }
634
+ if (subPlan?.explorationSummary) {
635
+ ctx.pendingPlanManager.appendExplorationFinding(`[${agentName}] ${subPlan.explorationSummary}`);
636
+ }
637
+ }
638
+ const finalOutput = queuedChangeSummary
639
+ ? (result.response || '') + queuedChangeSummary
640
+ : (result.response || result.error || '');
641
+ const structured = parseStructuredClosureReport(result.response || '', 'completed');
642
+ const subagentFilePaths = subAgent.getModifiedFilePaths();
643
+ const spawnResultFinal = {
644
+ success: result.success,
645
+ output: finalOutput,
646
+ metrics: {
647
+ tokens: result.metrics.totalTokens,
648
+ duration,
649
+ toolCalls: result.metrics.toolCalls,
650
+ },
651
+ structured,
652
+ filesModified: subagentFilePaths,
653
+ };
654
+ // Save to output store
655
+ if (ctx.subagentOutputStore) {
656
+ const outputEntry = {
657
+ id: agentId,
658
+ agentId,
659
+ agentName,
660
+ task,
661
+ fullOutput: finalOutput,
662
+ structured,
663
+ filesModified: subagentFilePaths,
664
+ filesCreated: [],
665
+ timestamp: new Date(),
666
+ tokensUsed: result.metrics.totalTokens,
667
+ durationMs: duration,
668
+ };
669
+ const storeId = ctx.subagentOutputStore.save(outputEntry);
670
+ spawnResultFinal.outputStoreId = storeId;
671
+ }
672
+ if (workerResultId && ctx.store?.hasWorkerResultsFeature()) {
673
+ try {
674
+ ctx.store.completeWorkerResult(workerResultId, {
675
+ fullOutput: finalOutput,
676
+ summary: finalOutput.slice(0, 500),
677
+ artifacts: structured ? [{ type: 'structured_report', data: structured }] : undefined,
678
+ metrics: {
679
+ tokens: result.metrics.totalTokens,
680
+ duration,
681
+ toolCalls: result.metrics.toolCalls,
682
+ },
683
+ });
684
+ }
685
+ catch (storeErr) {
686
+ ctx.observability?.logger?.warn('Failed to persist worker result', {
687
+ agentId,
688
+ error: storeErr.message,
689
+ });
690
+ }
691
+ }
692
+ ctx.emit({
693
+ type: 'agent.complete',
694
+ agentId,
695
+ agentType: agentName,
696
+ success: result.success,
697
+ output: finalOutput.slice(0, 500),
698
+ });
699
+ if (progressAwareTimeout.isInWrapupPhase()) {
700
+ ctx.emit({
701
+ type: 'subagent.wrapup.completed',
702
+ agentId,
703
+ agentType: agentName,
704
+ elapsedMs: Date.now() - startTime,
705
+ });
706
+ }
707
+ // Enhanced tracing
708
+ ctx.traceCollector?.record({
709
+ type: 'subagent.link',
710
+ data: {
711
+ parentSessionId: ctx.traceCollector.getSessionId() || 'unknown',
712
+ childSessionId,
713
+ childTraceId,
714
+ childConfig: {
715
+ agentType: agentName,
716
+ model: resolvedModel || 'default',
717
+ task,
718
+ tools: agentTools.map(t => t.name),
719
+ },
720
+ spawnContext: {
721
+ reason: `Delegated task: ${task.slice(0, 100)}`,
722
+ expectedOutcome: agentDef.description,
723
+ parentIteration: ctx.state.iteration,
724
+ },
725
+ result: {
726
+ success: result.success,
727
+ summary: (result.response || result.error || '').slice(0, 500),
728
+ tokensUsed: result.metrics.totalTokens,
729
+ durationMs: duration,
730
+ },
731
+ },
732
+ });
733
+ unsubSubAgent();
734
+ await subAgent.cleanup();
735
+ ctx.spawnedTasks.set(taskKey, {
736
+ timestamp: Date.now(),
737
+ result: finalOutput,
738
+ queuedChanges: queuedChangesCount,
739
+ });
740
+ return spawnResultFinal;
741
+ }
742
+ catch (err) {
743
+ // Handle cancellation
744
+ if (isCancellationError(err)) {
745
+ const duration = Date.now() - startTime;
746
+ const isUserCancellation = parentSource?.isCancellationRequested;
747
+ const reason = isUserCancellation
748
+ ? 'User cancelled'
749
+ : err.reason || `Timed out after ${subagentTimeout}ms`;
750
+ ctx.emit({ type: 'agent.error', agentId, agentType: agentName, error: reason });
751
+ if (!isUserCancellation) {
752
+ ctx.emit({
753
+ type: 'subagent.timeout.hard_kill',
754
+ agentId,
755
+ agentType: agentName,
756
+ reason,
757
+ elapsedMs: Date.now() - startTime,
758
+ });
759
+ }
760
+ // PRESERVE PARTIAL RESULTS
761
+ const subagentState = subAgent.getState();
762
+ const subagentMetrics = subAgent.getMetrics();
763
+ const assistantMessages = subagentState.messages.filter(m => m.role === 'assistant');
764
+ const lastAssistantMsg = assistantMessages[assistantMessages.length - 1];
765
+ const partialResponse = typeof lastAssistantMsg?.content === 'string'
766
+ ? lastAssistantMsg.content
767
+ : '';
768
+ let cancelledQueuedSummary = '';
769
+ if (subAgent.hasPendingPlan()) {
770
+ const subPlan = subAgent.getPendingPlan();
771
+ if (subPlan && subPlan.proposedChanges.length > 0) {
772
+ ctx.emit({
773
+ type: 'agent.pending_plan',
774
+ agentId: agentName,
775
+ changes: subPlan.proposedChanges,
776
+ });
777
+ const changeSummaries = subPlan.proposedChanges.map(c => {
778
+ if (c.tool === 'write_file' || c.tool === 'edit_file') {
779
+ const path = c.args.path || c.args.file_path || '(unknown file)';
780
+ return ` - [${c.tool}] ${path}: ${c.reason}`;
781
+ }
782
+ else if (c.tool === 'bash') {
783
+ const cmd = String(c.args.command || '').slice(0, 60);
784
+ return ` - [bash] ${cmd}...: ${c.reason}`;
785
+ }
786
+ return ` - [${c.tool}]: ${c.reason}`;
787
+ });
788
+ cancelledQueuedSummary = `\n\n[PLAN MODE - CHANGES QUEUED BEFORE CANCELLATION]\n` +
789
+ `${subPlan.proposedChanges.length} change(s) were queued to the parent plan:\n` +
790
+ changeSummaries.join('\n') + '\n' +
791
+ `These changes are preserved in your pending plan.`;
792
+ for (const change of subPlan.proposedChanges) {
793
+ ctx.pendingPlanManager.addProposedChange(change.tool, { ...change.args, _fromSubagent: agentName }, `[${agentName}] ${change.reason}`, change.toolCallId);
794
+ }
795
+ }
796
+ if (subPlan?.explorationSummary) {
797
+ ctx.pendingPlanManager.appendExplorationFinding(`[${agentName}] ${subPlan.explorationSummary}`);
798
+ }
799
+ }
800
+ const subagentFilePaths = subAgent.getModifiedFilePaths();
801
+ unsubSubAgent();
802
+ try {
803
+ await subAgent.cleanup();
804
+ }
805
+ catch {
806
+ // Ignore cleanup errors on cancellation
807
+ }
808
+ const baseOutput = isUserCancellation
809
+ ? `Subagent '${agentName}' was cancelled by user.`
810
+ : `Subagent '${agentName}' timed out after ${Math.round(subagentTimeout / 1000)}s.`;
811
+ const partialResultSection = partialResponse
812
+ ? `\n\n[PARTIAL RESULTS BEFORE TIMEOUT]\n${partialResponse.slice(0, 2000)}${partialResponse.length > 2000 ? '...(truncated)' : ''}`
813
+ : '';
814
+ ctx.traceCollector?.record({
815
+ type: 'subagent.link',
816
+ data: {
817
+ parentSessionId: ctx.traceCollector.getSessionId() || 'unknown',
818
+ childSessionId,
819
+ childTraceId,
820
+ childConfig: {
821
+ agentType: agentName,
822
+ model: resolvedModel || 'default',
823
+ task,
824
+ tools: agentTools.map(t => t.name),
825
+ },
826
+ spawnContext: {
827
+ reason: `Delegated task: ${task.slice(0, 100)}`,
828
+ expectedOutcome: agentDef.description,
829
+ parentIteration: ctx.state.iteration,
830
+ },
831
+ result: {
832
+ success: false,
833
+ summary: `[TIMEOUT] ${baseOutput}\n${partialResponse.slice(0, 200)}`,
834
+ tokensUsed: subagentMetrics.totalTokens,
835
+ durationMs: duration,
836
+ },
837
+ },
838
+ });
839
+ const exitReason = isUserCancellation ? 'cancelled' : 'timeout_graceful';
840
+ const structured = parseStructuredClosureReport(partialResponse, exitReason, task);
841
+ if (workerResultId && ctx.store?.hasWorkerResultsFeature()) {
842
+ try {
843
+ ctx.store.failWorkerResult(workerResultId, reason);
844
+ }
845
+ catch (storeErr) {
846
+ ctx.observability?.logger?.warn('Failed to mark cancelled worker result as failed', {
847
+ agentId,
848
+ error: storeErr.message,
849
+ });
850
+ }
851
+ }
852
+ return {
853
+ success: false,
854
+ output: baseOutput + partialResultSection + cancelledQueuedSummary,
855
+ metrics: {
856
+ tokens: subagentMetrics.totalTokens,
857
+ duration,
858
+ toolCalls: subagentMetrics.toolCalls,
859
+ },
860
+ structured,
861
+ filesModified: subagentFilePaths,
862
+ };
863
+ }
864
+ throw err;
865
+ }
866
+ finally {
867
+ ctx.economics?.resumeDuration();
868
+ effectiveSource.dispose();
869
+ progressAwareTimeout.dispose();
870
+ if (ctx.budgetPool && poolAllocationId) {
871
+ const subMetrics = subAgent.getMetrics();
872
+ ctx.budgetPool.recordUsage(poolAllocationId, subMetrics.totalTokens, subMetrics.estimatedCost);
873
+ ctx.budgetPool.release(poolAllocationId);
874
+ }
875
+ }
876
+ }
877
+ catch (err) {
878
+ const error = err instanceof Error ? err.message : String(err);
879
+ ctx.emit({ type: 'agent.error', agentId, agentType: agentName, error });
880
+ if (workerResultId && ctx.store?.hasWorkerResultsFeature()) {
881
+ try {
882
+ ctx.store.failWorkerResult(workerResultId, error);
883
+ }
884
+ catch (storeErr) {
885
+ ctx.observability?.logger?.warn('Failed to mark worker result as failed', {
886
+ agentId,
887
+ error: storeErr.message,
888
+ });
889
+ }
890
+ }
891
+ return {
892
+ success: false,
893
+ output: `Agent error: ${error}`,
894
+ metrics: { tokens: 0, duration: Date.now() - startTime, toolCalls: 0 },
895
+ };
896
+ }
897
+ }
898
+ /**
899
+ * Spawn multiple agents in parallel to work on independent tasks.
900
+ * Uses DynamicBudgetPool for parallel spawns and SubagentSupervisor for monitoring.
901
+ * Extracted from ProductionAgent.spawnAgentsParallel().
902
+ */
903
+ export async function spawnAgentsParallel(tasks, ctx, mutators, createSubAgent) {
904
+ ctx.emit({
905
+ type: 'parallel.spawn.start',
906
+ count: tasks.length,
907
+ agents: tasks.map(t => t.agent),
908
+ });
909
+ let settled;
910
+ const originalPool = ctx.budgetPool;
911
+ const supervisor = tasks.length > 1 ? createSubagentSupervisor() : null;
912
+ if (ctx.budgetPool && tasks.length > 1) {
913
+ const poolStats = ctx.budgetPool.getStats();
914
+ const dynamicPool = createDynamicBudgetPool(poolStats.tokensRemaining, 0.1);
915
+ dynamicPool.setExpectedChildren(tasks.length);
916
+ // Temporarily replace the budget pool
917
+ mutators.setBudgetPool(dynamicPool);
918
+ try {
919
+ const promises = tasks.map(({ agent, task }) => {
920
+ const spawnPromise = spawnAgent(agent, task, ctx, createSubAgent);
921
+ if (supervisor) {
922
+ const handle = createSubagentHandle(`parallel-${agent}-${Date.now()}`, agent, task, spawnPromise, {});
923
+ supervisor.add(handle);
924
+ }
925
+ return spawnPromise;
926
+ });
927
+ settled = await Promise.allSettled(promises);
928
+ }
929
+ finally {
930
+ mutators.setBudgetPool(originalPool);
931
+ supervisor?.stop();
932
+ }
933
+ }
934
+ else {
935
+ const promises = tasks.map(({ agent, task }) => spawnAgent(agent, task, ctx, createSubAgent));
936
+ settled = await Promise.allSettled(promises);
937
+ }
938
+ const results = settled.map((result, i) => {
939
+ if (result.status === 'fulfilled') {
940
+ return result.value;
941
+ }
942
+ const error = result.reason instanceof Error ? result.reason.message : String(result.reason);
943
+ ctx.emit({
944
+ type: 'agent.error',
945
+ agentId: tasks[i].agent,
946
+ error: `Unexpected parallel spawn error: ${error}`,
947
+ });
948
+ return {
949
+ success: false,
950
+ output: `Parallel spawn error: ${error}`,
951
+ metrics: { tokens: 0, duration: 0, toolCalls: 0 },
952
+ };
953
+ });
954
+ ctx.emit({
955
+ type: 'parallel.spawn.complete',
956
+ count: tasks.length,
957
+ successCount: results.filter(r => r.success).length,
958
+ results: results.map((r, i) => ({
959
+ agent: tasks[i].agent,
960
+ success: r.success,
961
+ tokens: r.metrics?.tokens || 0,
962
+ })),
963
+ });
964
+ return results;
965
+ }
966
+ //# sourceMappingURL=subagent-spawner.js.map