attocode 0.2.4 → 0.2.5

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 (577) hide show
  1. package/CHANGELOG.md +56 -1
  2. package/dist/src/adapters.d.ts +2 -1
  3. package/dist/src/adapters.d.ts.map +1 -1
  4. package/dist/src/adapters.js +60 -2
  5. package/dist/src/adapters.js.map +1 -1
  6. package/dist/src/agent/agent-builder.d.ts +117 -0
  7. package/dist/src/agent/agent-builder.d.ts.map +1 -0
  8. package/dist/src/agent/agent-builder.js +204 -0
  9. package/dist/src/agent/agent-builder.js.map +1 -0
  10. package/dist/src/agent/feature-initializer.d.ts +80 -0
  11. package/dist/src/agent/feature-initializer.d.ts.map +1 -0
  12. package/dist/src/agent/feature-initializer.js +677 -0
  13. package/dist/src/agent/feature-initializer.js.map +1 -0
  14. package/dist/src/agent/index.d.ts +13 -0
  15. package/dist/src/agent/index.d.ts.map +1 -0
  16. package/dist/src/agent/index.js +13 -0
  17. package/dist/src/agent/index.js.map +1 -0
  18. package/dist/src/agent/message-builder.d.ts +50 -0
  19. package/dist/src/agent/message-builder.d.ts.map +1 -0
  20. package/dist/src/agent/message-builder.js +173 -0
  21. package/dist/src/agent/message-builder.js.map +1 -0
  22. package/dist/src/agent/session-api.d.ts +94 -0
  23. package/dist/src/agent/session-api.d.ts.map +1 -0
  24. package/dist/src/agent/session-api.js +262 -0
  25. package/dist/src/agent/session-api.js.map +1 -0
  26. package/dist/src/agent-tools/lsp-file-tools.d.ts +1 -1
  27. package/dist/src/agent-tools/lsp-file-tools.d.ts.map +1 -1
  28. package/dist/src/agent.d.ts +14 -115
  29. package/dist/src/agent.d.ts.map +1 -1
  30. package/dist/src/agent.js +36 -1177
  31. package/dist/src/agent.js.map +1 -1
  32. package/dist/src/cli.js +1 -1
  33. package/dist/src/cli.js.map +1 -1
  34. package/dist/src/commands/handler.d.ts.map +1 -1
  35. package/dist/src/commands/handler.js +8 -7
  36. package/dist/src/commands/handler.js.map +1 -1
  37. package/dist/src/commands/init.js +1 -1
  38. package/dist/src/commands/init.js.map +1 -1
  39. package/dist/src/config/schema.d.ts +6 -6
  40. package/dist/src/core/execution-loop.d.ts.map +1 -1
  41. package/dist/src/core/execution-loop.js +155 -16
  42. package/dist/src/core/execution-loop.js.map +1 -1
  43. package/dist/src/core/response-handler.d.ts.map +1 -1
  44. package/dist/src/core/response-handler.js +3 -2
  45. package/dist/src/core/response-handler.js.map +1 -1
  46. package/dist/src/core/subagent-spawner.d.ts.map +1 -1
  47. package/dist/src/core/subagent-spawner.js +13 -6
  48. package/dist/src/core/subagent-spawner.js.map +1 -1
  49. package/dist/src/core/tool-executor.d.ts.map +1 -1
  50. package/dist/src/core/tool-executor.js +7 -2
  51. package/dist/src/core/tool-executor.js.map +1 -1
  52. package/dist/src/core/types.d.ts +1 -0
  53. package/dist/src/core/types.d.ts.map +1 -1
  54. package/dist/src/core/types.js.map +1 -1
  55. package/dist/src/integrations/agents/agent-registry.d.ts +262 -0
  56. package/dist/src/integrations/agents/agent-registry.d.ts.map +1 -0
  57. package/dist/src/integrations/agents/agent-registry.js +686 -0
  58. package/dist/src/integrations/agents/agent-registry.js.map +1 -0
  59. package/dist/src/integrations/agents/async-subagent.d.ts +135 -0
  60. package/dist/src/integrations/agents/async-subagent.d.ts.map +1 -0
  61. package/dist/src/integrations/agents/async-subagent.js +213 -0
  62. package/dist/src/integrations/agents/async-subagent.js.map +1 -0
  63. package/dist/src/integrations/agents/complexity-classifier.d.ts +86 -0
  64. package/dist/src/integrations/agents/complexity-classifier.d.ts.map +1 -0
  65. package/dist/src/integrations/agents/complexity-classifier.js +233 -0
  66. package/dist/src/integrations/agents/complexity-classifier.js.map +1 -0
  67. package/dist/src/integrations/agents/delegation-protocol.d.ts +86 -0
  68. package/dist/src/integrations/agents/delegation-protocol.d.ts.map +1 -0
  69. package/dist/src/integrations/agents/delegation-protocol.js +127 -0
  70. package/dist/src/integrations/agents/delegation-protocol.js.map +1 -0
  71. package/dist/src/integrations/agents/multi-agent.d.ts +150 -0
  72. package/dist/src/integrations/agents/multi-agent.d.ts.map +1 -0
  73. package/dist/src/integrations/agents/multi-agent.js +306 -0
  74. package/dist/src/integrations/agents/multi-agent.js.map +1 -0
  75. package/dist/src/integrations/agents/result-synthesizer.d.ts +389 -0
  76. package/dist/src/integrations/agents/result-synthesizer.d.ts.map +1 -0
  77. package/dist/src/integrations/agents/result-synthesizer.js +951 -0
  78. package/dist/src/integrations/agents/result-synthesizer.js.map +1 -0
  79. package/dist/src/integrations/agents/shared-blackboard.d.ts +406 -0
  80. package/dist/src/integrations/agents/shared-blackboard.d.ts.map +1 -0
  81. package/dist/src/integrations/agents/shared-blackboard.js +757 -0
  82. package/dist/src/integrations/agents/shared-blackboard.js.map +1 -0
  83. package/dist/src/integrations/agents/subagent-output-store.d.ts +91 -0
  84. package/dist/src/integrations/agents/subagent-output-store.d.ts.map +1 -0
  85. package/dist/src/integrations/agents/subagent-output-store.js +257 -0
  86. package/dist/src/integrations/agents/subagent-output-store.js.map +1 -0
  87. package/dist/src/integrations/budget/budget-pool.d.ts +115 -0
  88. package/dist/src/integrations/budget/budget-pool.d.ts.map +1 -0
  89. package/dist/src/integrations/budget/budget-pool.js +205 -0
  90. package/dist/src/integrations/budget/budget-pool.js.map +1 -0
  91. package/dist/src/integrations/budget/cancellation.d.ts +229 -0
  92. package/dist/src/integrations/budget/cancellation.d.ts.map +1 -0
  93. package/dist/src/integrations/budget/cancellation.js +520 -0
  94. package/dist/src/integrations/budget/cancellation.js.map +1 -0
  95. package/dist/src/integrations/budget/dynamic-budget.d.ts +81 -0
  96. package/dist/src/integrations/budget/dynamic-budget.d.ts.map +1 -0
  97. package/dist/src/integrations/budget/dynamic-budget.js +151 -0
  98. package/dist/src/integrations/budget/dynamic-budget.js.map +1 -0
  99. package/dist/src/integrations/budget/economics.d.ts +435 -0
  100. package/dist/src/integrations/budget/economics.d.ts.map +1 -0
  101. package/dist/src/integrations/budget/economics.js +1007 -0
  102. package/dist/src/integrations/budget/economics.js.map +1 -0
  103. package/dist/src/integrations/budget/injection-budget.d.ts +71 -0
  104. package/dist/src/integrations/budget/injection-budget.d.ts.map +1 -0
  105. package/dist/src/integrations/budget/injection-budget.js +137 -0
  106. package/dist/src/integrations/budget/injection-budget.js.map +1 -0
  107. package/dist/src/integrations/budget/loop-detector.d.ts +105 -0
  108. package/dist/src/integrations/budget/loop-detector.d.ts.map +1 -0
  109. package/dist/src/integrations/budget/loop-detector.js +287 -0
  110. package/dist/src/integrations/budget/loop-detector.js.map +1 -0
  111. package/dist/src/integrations/budget/phase-tracker.d.ts +114 -0
  112. package/dist/src/integrations/budget/phase-tracker.d.ts.map +1 -0
  113. package/dist/src/integrations/budget/phase-tracker.js +262 -0
  114. package/dist/src/integrations/budget/phase-tracker.js.map +1 -0
  115. package/dist/src/integrations/budget/resources.d.ts +182 -0
  116. package/dist/src/integrations/budget/resources.d.ts.map +1 -0
  117. package/dist/src/integrations/budget/resources.js +318 -0
  118. package/dist/src/integrations/budget/resources.js.map +1 -0
  119. package/dist/src/integrations/context/auto-compaction.d.ts +210 -0
  120. package/dist/src/integrations/context/auto-compaction.d.ts.map +1 -0
  121. package/dist/src/integrations/context/auto-compaction.js +477 -0
  122. package/dist/src/integrations/context/auto-compaction.js.map +1 -0
  123. package/dist/src/integrations/context/code-analyzer.d.ts +71 -0
  124. package/dist/src/integrations/context/code-analyzer.d.ts.map +1 -0
  125. package/dist/src/integrations/context/code-analyzer.js +448 -0
  126. package/dist/src/integrations/context/code-analyzer.js.map +1 -0
  127. package/dist/src/integrations/context/code-selector.d.ts +78 -0
  128. package/dist/src/integrations/context/code-selector.d.ts.map +1 -0
  129. package/dist/src/integrations/context/code-selector.js +649 -0
  130. package/dist/src/integrations/context/code-selector.js.map +1 -0
  131. package/dist/src/integrations/context/codebase-ast.d.ts +138 -0
  132. package/dist/src/integrations/context/codebase-ast.d.ts.map +1 -0
  133. package/dist/src/integrations/context/codebase-ast.js +818 -0
  134. package/dist/src/integrations/context/codebase-ast.js.map +1 -0
  135. package/dist/src/integrations/context/codebase-context.d.ts +473 -0
  136. package/dist/src/integrations/context/codebase-context.d.ts.map +1 -0
  137. package/dist/src/integrations/context/codebase-context.js +685 -0
  138. package/dist/src/integrations/context/codebase-context.js.map +1 -0
  139. package/dist/src/integrations/context/compaction.d.ts +191 -0
  140. package/dist/src/integrations/context/compaction.d.ts.map +1 -0
  141. package/dist/src/integrations/context/compaction.js +384 -0
  142. package/dist/src/integrations/context/compaction.js.map +1 -0
  143. package/dist/src/integrations/context/context-engineering.d.ts +274 -0
  144. package/dist/src/integrations/context/context-engineering.d.ts.map +1 -0
  145. package/dist/src/integrations/context/context-engineering.js +437 -0
  146. package/dist/src/integrations/context/context-engineering.js.map +1 -0
  147. package/dist/src/integrations/context/file-cache.d.ts +97 -0
  148. package/dist/src/integrations/context/file-cache.d.ts.map +1 -0
  149. package/dist/src/integrations/context/file-cache.js +218 -0
  150. package/dist/src/integrations/context/file-cache.js.map +1 -0
  151. package/dist/src/integrations/context/semantic-cache.d.ts +178 -0
  152. package/dist/src/integrations/context/semantic-cache.d.ts.map +1 -0
  153. package/dist/src/integrations/context/semantic-cache.js +372 -0
  154. package/dist/src/integrations/context/semantic-cache.js.map +1 -0
  155. package/dist/src/integrations/index.d.ts +72 -68
  156. package/dist/src/integrations/index.d.ts.map +1 -1
  157. package/dist/src/integrations/index.js +76 -68
  158. package/dist/src/integrations/index.js.map +1 -1
  159. package/dist/src/integrations/lsp/lsp.d.ts +196 -0
  160. package/dist/src/integrations/lsp/lsp.d.ts.map +1 -0
  161. package/dist/src/integrations/lsp/lsp.js +583 -0
  162. package/dist/src/integrations/lsp/lsp.js.map +1 -0
  163. package/dist/src/integrations/mcp/mcp-client.d.ts +279 -0
  164. package/dist/src/integrations/mcp/mcp-client.d.ts.map +1 -0
  165. package/dist/src/integrations/mcp/mcp-client.js +755 -0
  166. package/dist/src/integrations/mcp/mcp-client.js.map +1 -0
  167. package/dist/src/integrations/mcp/mcp-custom-tools.d.ts +102 -0
  168. package/dist/src/integrations/mcp/mcp-custom-tools.d.ts.map +1 -0
  169. package/dist/src/integrations/mcp/mcp-custom-tools.js +232 -0
  170. package/dist/src/integrations/mcp/mcp-custom-tools.js.map +1 -0
  171. package/dist/src/integrations/mcp/mcp-tool-search.d.ts +77 -0
  172. package/dist/src/integrations/mcp/mcp-tool-search.d.ts.map +1 -0
  173. package/dist/src/integrations/mcp/mcp-tool-search.js +220 -0
  174. package/dist/src/integrations/mcp/mcp-tool-search.js.map +1 -0
  175. package/dist/src/integrations/mcp/mcp-tool-validator.d.ts +60 -0
  176. package/dist/src/integrations/mcp/mcp-tool-validator.d.ts.map +1 -0
  177. package/dist/src/integrations/mcp/mcp-tool-validator.js +141 -0
  178. package/dist/src/integrations/mcp/mcp-tool-validator.js.map +1 -0
  179. package/dist/src/integrations/persistence/codebase-repository.d.ts +45 -0
  180. package/dist/src/integrations/persistence/codebase-repository.d.ts.map +1 -0
  181. package/dist/src/integrations/persistence/codebase-repository.js +81 -0
  182. package/dist/src/integrations/persistence/codebase-repository.js.map +1 -0
  183. package/dist/src/integrations/persistence/goal-repository.d.ts +71 -0
  184. package/dist/src/integrations/persistence/goal-repository.d.ts.map +1 -0
  185. package/dist/src/integrations/persistence/goal-repository.js +184 -0
  186. package/dist/src/integrations/persistence/goal-repository.js.map +1 -0
  187. package/dist/src/integrations/persistence/history.d.ts +72 -0
  188. package/dist/src/integrations/persistence/history.d.ts.map +1 -0
  189. package/dist/src/integrations/persistence/history.js +165 -0
  190. package/dist/src/integrations/persistence/history.js.map +1 -0
  191. package/dist/src/integrations/persistence/persistence.d.ts +49 -0
  192. package/dist/src/integrations/persistence/persistence.d.ts.map +1 -0
  193. package/dist/src/integrations/persistence/persistence.js +197 -0
  194. package/dist/src/integrations/persistence/persistence.js.map +1 -0
  195. package/dist/src/integrations/persistence/session-repository.d.ts +212 -0
  196. package/dist/src/integrations/persistence/session-repository.d.ts.map +1 -0
  197. package/dist/src/integrations/persistence/session-repository.js +770 -0
  198. package/dist/src/integrations/persistence/session-repository.js.map +1 -0
  199. package/dist/src/integrations/persistence/session-store.d.ts +184 -0
  200. package/dist/src/integrations/persistence/session-store.d.ts.map +1 -0
  201. package/dist/src/integrations/persistence/session-store.js +346 -0
  202. package/dist/src/integrations/persistence/session-store.js.map +1 -0
  203. package/dist/src/integrations/persistence/sqlite-store.d.ts +453 -0
  204. package/dist/src/integrations/persistence/sqlite-store.d.ts.map +1 -0
  205. package/dist/src/integrations/persistence/sqlite-store.js +676 -0
  206. package/dist/src/integrations/persistence/sqlite-store.js.map +1 -0
  207. package/dist/src/integrations/persistence/worker-repository.d.ts +65 -0
  208. package/dist/src/integrations/persistence/worker-repository.d.ts.map +1 -0
  209. package/dist/src/integrations/persistence/worker-repository.js +183 -0
  210. package/dist/src/integrations/persistence/worker-repository.js.map +1 -0
  211. package/dist/src/integrations/quality/auto-checkpoint.d.ts +98 -0
  212. package/dist/src/integrations/quality/auto-checkpoint.d.ts.map +1 -0
  213. package/dist/src/integrations/quality/auto-checkpoint.js +252 -0
  214. package/dist/src/integrations/quality/auto-checkpoint.js.map +1 -0
  215. package/dist/src/integrations/quality/dead-letter-queue.d.ts +233 -0
  216. package/dist/src/integrations/quality/dead-letter-queue.d.ts.map +1 -0
  217. package/dist/src/integrations/quality/dead-letter-queue.js +543 -0
  218. package/dist/src/integrations/quality/dead-letter-queue.js.map +1 -0
  219. package/dist/src/integrations/quality/health-check.d.ts +218 -0
  220. package/dist/src/integrations/quality/health-check.d.ts.map +1 -0
  221. package/dist/src/integrations/quality/health-check.js +415 -0
  222. package/dist/src/integrations/quality/health-check.js.map +1 -0
  223. package/dist/src/integrations/quality/learning-store.d.ts +291 -0
  224. package/dist/src/integrations/quality/learning-store.d.ts.map +1 -0
  225. package/dist/src/integrations/quality/learning-store.js +646 -0
  226. package/dist/src/integrations/quality/learning-store.js.map +1 -0
  227. package/dist/src/integrations/quality/self-improvement.d.ts +90 -0
  228. package/dist/src/integrations/quality/self-improvement.d.ts.map +1 -0
  229. package/dist/src/integrations/quality/self-improvement.js +229 -0
  230. package/dist/src/integrations/quality/self-improvement.js.map +1 -0
  231. package/dist/src/integrations/quality/tool-recommendation.d.ts +61 -0
  232. package/dist/src/integrations/quality/tool-recommendation.d.ts.map +1 -0
  233. package/dist/src/integrations/quality/tool-recommendation.js +268 -0
  234. package/dist/src/integrations/quality/tool-recommendation.js.map +1 -0
  235. package/dist/src/integrations/safety/bash-policy.d.ts +33 -0
  236. package/dist/src/integrations/safety/bash-policy.d.ts.map +1 -0
  237. package/dist/src/integrations/safety/bash-policy.js +144 -0
  238. package/dist/src/integrations/safety/bash-policy.js.map +1 -0
  239. package/dist/src/integrations/safety/edit-validator.d.ts +30 -0
  240. package/dist/src/integrations/safety/edit-validator.d.ts.map +1 -0
  241. package/dist/src/integrations/safety/edit-validator.js +87 -0
  242. package/dist/src/integrations/safety/edit-validator.js.map +1 -0
  243. package/dist/src/integrations/safety/execution-policy.d.ts +189 -0
  244. package/dist/src/integrations/safety/execution-policy.d.ts.map +1 -0
  245. package/dist/src/integrations/safety/execution-policy.js +352 -0
  246. package/dist/src/integrations/safety/execution-policy.js.map +1 -0
  247. package/dist/src/integrations/safety/policy-engine.d.ts +55 -0
  248. package/dist/src/integrations/safety/policy-engine.d.ts.map +1 -0
  249. package/dist/src/integrations/safety/policy-engine.js +247 -0
  250. package/dist/src/integrations/safety/policy-engine.js.map +1 -0
  251. package/dist/src/integrations/safety/safety.d.ts +174 -0
  252. package/dist/src/integrations/safety/safety.d.ts.map +1 -0
  253. package/dist/src/integrations/safety/safety.js +470 -0
  254. package/dist/src/integrations/safety/safety.js.map +1 -0
  255. package/dist/src/integrations/safety/sandbox/basic.d.ts +81 -0
  256. package/dist/src/integrations/safety/sandbox/basic.d.ts.map +1 -0
  257. package/dist/src/integrations/safety/sandbox/basic.js +335 -0
  258. package/dist/src/integrations/safety/sandbox/basic.js.map +1 -0
  259. package/dist/src/integrations/safety/sandbox/docker.d.ts +94 -0
  260. package/dist/src/integrations/safety/sandbox/docker.d.ts.map +1 -0
  261. package/dist/src/integrations/safety/sandbox/docker.js +294 -0
  262. package/dist/src/integrations/safety/sandbox/docker.js.map +1 -0
  263. package/dist/src/integrations/safety/sandbox/index.d.ts +188 -0
  264. package/dist/src/integrations/safety/sandbox/index.d.ts.map +1 -0
  265. package/dist/src/integrations/safety/sandbox/index.js +386 -0
  266. package/dist/src/integrations/safety/sandbox/index.js.map +1 -0
  267. package/dist/src/integrations/safety/sandbox/landlock.d.ts +59 -0
  268. package/dist/src/integrations/safety/sandbox/landlock.d.ts.map +1 -0
  269. package/dist/src/integrations/safety/sandbox/landlock.js +329 -0
  270. package/dist/src/integrations/safety/sandbox/landlock.js.map +1 -0
  271. package/dist/src/integrations/safety/sandbox/seatbelt.d.ts +68 -0
  272. package/dist/src/integrations/safety/sandbox/seatbelt.d.ts.map +1 -0
  273. package/dist/src/integrations/safety/sandbox/seatbelt.js +298 -0
  274. package/dist/src/integrations/safety/sandbox/seatbelt.js.map +1 -0
  275. package/dist/src/integrations/safety/type-checker.d.ts +53 -0
  276. package/dist/src/integrations/safety/type-checker.d.ts.map +1 -0
  277. package/dist/src/integrations/safety/type-checker.js +142 -0
  278. package/dist/src/integrations/safety/type-checker.js.map +1 -0
  279. package/dist/src/integrations/skills/skill-executor.d.ts +113 -0
  280. package/dist/src/integrations/skills/skill-executor.d.ts.map +1 -0
  281. package/dist/src/integrations/skills/skill-executor.js +270 -0
  282. package/dist/src/integrations/skills/skill-executor.js.map +1 -0
  283. package/dist/src/integrations/skills/skills.d.ts +262 -0
  284. package/dist/src/integrations/skills/skills.d.ts.map +1 -0
  285. package/dist/src/integrations/skills/skills.js +602 -0
  286. package/dist/src/integrations/skills/skills.js.map +1 -0
  287. package/dist/src/integrations/streaming/pty-shell.d.ts +169 -0
  288. package/dist/src/integrations/streaming/pty-shell.d.ts.map +1 -0
  289. package/dist/src/integrations/streaming/pty-shell.js +367 -0
  290. package/dist/src/integrations/streaming/pty-shell.js.map +1 -0
  291. package/dist/src/integrations/streaming/streaming.d.ts +102 -0
  292. package/dist/src/integrations/streaming/streaming.d.ts.map +1 -0
  293. package/dist/src/integrations/streaming/streaming.js +362 -0
  294. package/dist/src/integrations/streaming/streaming.js.map +1 -0
  295. package/dist/src/integrations/swarm/index.d.ts +2 -1
  296. package/dist/src/integrations/swarm/index.d.ts.map +1 -1
  297. package/dist/src/integrations/swarm/index.js +2 -0
  298. package/dist/src/integrations/swarm/index.js.map +1 -1
  299. package/dist/src/integrations/swarm/model-selector.js +1 -1
  300. package/dist/src/integrations/swarm/model-selector.js.map +1 -1
  301. package/dist/src/integrations/swarm/swarm-budget.d.ts +1 -1
  302. package/dist/src/integrations/swarm/swarm-budget.d.ts.map +1 -1
  303. package/dist/src/integrations/swarm/swarm-budget.js +1 -1
  304. package/dist/src/integrations/swarm/swarm-budget.js.map +1 -1
  305. package/dist/src/integrations/swarm/swarm-config-loader.d.ts.map +1 -1
  306. package/dist/src/integrations/swarm/swarm-config-loader.js +7 -0
  307. package/dist/src/integrations/swarm/swarm-config-loader.js.map +1 -1
  308. package/dist/src/integrations/swarm/swarm-events.d.ts +1 -1
  309. package/dist/src/integrations/swarm/swarm-events.d.ts.map +1 -1
  310. package/dist/src/integrations/swarm/swarm-execution.d.ts +27 -0
  311. package/dist/src/integrations/swarm/swarm-execution.d.ts.map +1 -0
  312. package/dist/src/integrations/swarm/swarm-execution.js +1021 -0
  313. package/dist/src/integrations/swarm/swarm-execution.js.map +1 -0
  314. package/dist/src/integrations/swarm/swarm-helpers.d.ts +26 -0
  315. package/dist/src/integrations/swarm/swarm-helpers.d.ts.map +1 -0
  316. package/dist/src/integrations/swarm/swarm-helpers.js +95 -0
  317. package/dist/src/integrations/swarm/swarm-helpers.js.map +1 -0
  318. package/dist/src/integrations/swarm/swarm-lifecycle.d.ts +100 -0
  319. package/dist/src/integrations/swarm/swarm-lifecycle.d.ts.map +1 -0
  320. package/dist/src/integrations/swarm/swarm-lifecycle.js +922 -0
  321. package/dist/src/integrations/swarm/swarm-lifecycle.js.map +1 -0
  322. package/dist/src/integrations/swarm/swarm-orchestrator.d.ts +84 -203
  323. package/dist/src/integrations/swarm/swarm-orchestrator.d.ts.map +1 -1
  324. package/dist/src/integrations/swarm/swarm-orchestrator.js +251 -2870
  325. package/dist/src/integrations/swarm/swarm-orchestrator.js.map +1 -1
  326. package/dist/src/integrations/swarm/swarm-quality-gate.js +1 -1
  327. package/dist/src/integrations/swarm/swarm-quality-gate.js.map +1 -1
  328. package/dist/src/integrations/swarm/swarm-recovery.d.ts +75 -0
  329. package/dist/src/integrations/swarm/swarm-recovery.d.ts.map +1 -0
  330. package/dist/src/integrations/swarm/swarm-recovery.js +550 -0
  331. package/dist/src/integrations/swarm/swarm-recovery.js.map +1 -0
  332. package/dist/src/integrations/swarm/swarm-state-store.d.ts.map +1 -1
  333. package/dist/src/integrations/swarm/swarm-state-store.js +6 -0
  334. package/dist/src/integrations/swarm/swarm-state-store.js.map +1 -1
  335. package/dist/src/integrations/swarm/task-queue.d.ts +1 -1
  336. package/dist/src/integrations/swarm/task-queue.d.ts.map +1 -1
  337. package/dist/src/integrations/swarm/task-queue.js +28 -1
  338. package/dist/src/integrations/swarm/task-queue.js.map +1 -1
  339. package/dist/src/integrations/swarm/types.d.ts +17 -5
  340. package/dist/src/integrations/swarm/types.d.ts.map +1 -1
  341. package/dist/src/integrations/swarm/types.js.map +1 -1
  342. package/dist/src/integrations/swarm/worker-pool.d.ts +1 -1
  343. package/dist/src/integrations/swarm/worker-pool.d.ts.map +1 -1
  344. package/dist/src/integrations/swarm/worker-pool.js +13 -9
  345. package/dist/src/integrations/swarm/worker-pool.js.map +1 -1
  346. package/dist/src/integrations/tasks/dependency-analyzer.d.ts +34 -0
  347. package/dist/src/integrations/tasks/dependency-analyzer.d.ts.map +1 -0
  348. package/dist/src/integrations/tasks/dependency-analyzer.js +232 -0
  349. package/dist/src/integrations/tasks/dependency-analyzer.js.map +1 -0
  350. package/dist/src/integrations/tasks/interactive-planning.d.ts +322 -0
  351. package/dist/src/integrations/tasks/interactive-planning.d.ts.map +1 -0
  352. package/dist/src/integrations/tasks/interactive-planning.js +655 -0
  353. package/dist/src/integrations/tasks/interactive-planning.js.map +1 -0
  354. package/dist/src/integrations/tasks/pending-plan.d.ts +196 -0
  355. package/dist/src/integrations/tasks/pending-plan.d.ts.map +1 -0
  356. package/dist/src/integrations/tasks/pending-plan.js +431 -0
  357. package/dist/src/integrations/tasks/pending-plan.js.map +1 -0
  358. package/dist/src/integrations/tasks/planning.d.ts +115 -0
  359. package/dist/src/integrations/tasks/planning.d.ts.map +1 -0
  360. package/dist/src/integrations/tasks/planning.js +413 -0
  361. package/dist/src/integrations/tasks/planning.js.map +1 -0
  362. package/dist/src/integrations/tasks/smart-decomposer.d.ts +316 -0
  363. package/dist/src/integrations/tasks/smart-decomposer.d.ts.map +1 -0
  364. package/dist/src/integrations/tasks/smart-decomposer.js +661 -0
  365. package/dist/src/integrations/tasks/smart-decomposer.js.map +1 -0
  366. package/dist/src/integrations/tasks/task-manager.d.ts +164 -0
  367. package/dist/src/integrations/tasks/task-manager.d.ts.map +1 -0
  368. package/dist/src/integrations/tasks/task-manager.js +383 -0
  369. package/dist/src/integrations/tasks/task-manager.js.map +1 -0
  370. package/dist/src/integrations/tasks/task-splitter.d.ts +56 -0
  371. package/dist/src/integrations/tasks/task-splitter.d.ts.map +1 -0
  372. package/dist/src/integrations/tasks/task-splitter.js +537 -0
  373. package/dist/src/integrations/tasks/task-splitter.js.map +1 -0
  374. package/dist/src/integrations/tasks/verification-gate.d.ts +103 -0
  375. package/dist/src/integrations/tasks/verification-gate.d.ts.map +1 -0
  376. package/dist/src/integrations/tasks/verification-gate.js +193 -0
  377. package/dist/src/integrations/tasks/verification-gate.js.map +1 -0
  378. package/dist/src/integrations/tasks/work-log.d.ts +87 -0
  379. package/dist/src/integrations/tasks/work-log.d.ts.map +1 -0
  380. package/dist/src/integrations/tasks/work-log.js +275 -0
  381. package/dist/src/integrations/tasks/work-log.js.map +1 -0
  382. package/dist/src/integrations/utilities/capabilities.d.ts +160 -0
  383. package/dist/src/integrations/utilities/capabilities.d.ts.map +1 -0
  384. package/dist/src/integrations/utilities/capabilities.js +426 -0
  385. package/dist/src/integrations/utilities/capabilities.js.map +1 -0
  386. package/dist/src/integrations/utilities/diff-utils.d.ts +105 -0
  387. package/dist/src/integrations/utilities/diff-utils.d.ts.map +1 -0
  388. package/dist/src/integrations/utilities/diff-utils.js +497 -0
  389. package/dist/src/integrations/utilities/diff-utils.js.map +1 -0
  390. package/dist/src/integrations/utilities/environment-facts.d.ts +52 -0
  391. package/dist/src/integrations/utilities/environment-facts.d.ts.map +1 -0
  392. package/dist/src/integrations/utilities/environment-facts.js +84 -0
  393. package/dist/src/integrations/utilities/environment-facts.js.map +1 -0
  394. package/dist/src/integrations/utilities/file-change-tracker.d.ts +162 -0
  395. package/dist/src/integrations/utilities/file-change-tracker.d.ts.map +1 -0
  396. package/dist/src/integrations/utilities/file-change-tracker.js +538 -0
  397. package/dist/src/integrations/utilities/file-change-tracker.js.map +1 -0
  398. package/dist/src/integrations/utilities/graph-visualization.d.ts +72 -0
  399. package/dist/src/integrations/utilities/graph-visualization.d.ts.map +1 -0
  400. package/dist/src/integrations/utilities/graph-visualization.js +383 -0
  401. package/dist/src/integrations/utilities/graph-visualization.js.map +1 -0
  402. package/dist/src/integrations/utilities/hierarchical-config.d.ts +215 -0
  403. package/dist/src/integrations/utilities/hierarchical-config.d.ts.map +1 -0
  404. package/dist/src/integrations/utilities/hierarchical-config.js +504 -0
  405. package/dist/src/integrations/utilities/hierarchical-config.js.map +1 -0
  406. package/dist/src/integrations/utilities/hooks.d.ts +116 -0
  407. package/dist/src/integrations/utilities/hooks.d.ts.map +1 -0
  408. package/dist/src/integrations/utilities/hooks.js +410 -0
  409. package/dist/src/integrations/utilities/hooks.js.map +1 -0
  410. package/dist/src/integrations/utilities/ignore.d.ts +143 -0
  411. package/dist/src/integrations/utilities/ignore.d.ts.map +1 -0
  412. package/dist/src/integrations/utilities/ignore.js +417 -0
  413. package/dist/src/integrations/utilities/ignore.js.map +1 -0
  414. package/dist/src/integrations/utilities/image-renderer.d.ts +119 -0
  415. package/dist/src/integrations/utilities/image-renderer.d.ts.map +1 -0
  416. package/dist/src/integrations/utilities/image-renderer.js +306 -0
  417. package/dist/src/integrations/utilities/image-renderer.js.map +1 -0
  418. package/dist/src/integrations/utilities/logger.d.ts +104 -0
  419. package/dist/src/integrations/utilities/logger.d.ts.map +1 -0
  420. package/dist/src/integrations/utilities/logger.js +219 -0
  421. package/dist/src/integrations/utilities/logger.js.map +1 -0
  422. package/dist/src/integrations/utilities/memory.d.ts +116 -0
  423. package/dist/src/integrations/utilities/memory.d.ts.map +1 -0
  424. package/dist/src/integrations/utilities/memory.js +311 -0
  425. package/dist/src/integrations/utilities/memory.js.map +1 -0
  426. package/dist/src/integrations/utilities/observability.d.ts +162 -0
  427. package/dist/src/integrations/utilities/observability.d.ts.map +1 -0
  428. package/dist/src/integrations/utilities/observability.js +407 -0
  429. package/dist/src/integrations/utilities/observability.js.map +1 -0
  430. package/dist/src/integrations/utilities/openrouter-pricing.d.ts +67 -0
  431. package/dist/src/integrations/utilities/openrouter-pricing.d.ts.map +1 -0
  432. package/dist/src/integrations/utilities/openrouter-pricing.js +166 -0
  433. package/dist/src/integrations/utilities/openrouter-pricing.js.map +1 -0
  434. package/dist/src/integrations/utilities/react.d.ts +139 -0
  435. package/dist/src/integrations/utilities/react.d.ts.map +1 -0
  436. package/dist/src/integrations/utilities/react.js +273 -0
  437. package/dist/src/integrations/utilities/react.js.map +1 -0
  438. package/dist/src/integrations/utilities/retry.d.ts +132 -0
  439. package/dist/src/integrations/utilities/retry.d.ts.map +1 -0
  440. package/dist/src/integrations/utilities/retry.js +233 -0
  441. package/dist/src/integrations/utilities/retry.js.map +1 -0
  442. package/dist/src/integrations/utilities/routing.d.ts +118 -0
  443. package/dist/src/integrations/utilities/routing.d.ts.map +1 -0
  444. package/dist/src/integrations/utilities/routing.js +348 -0
  445. package/dist/src/integrations/utilities/routing.js.map +1 -0
  446. package/dist/src/integrations/utilities/rules.d.ts +131 -0
  447. package/dist/src/integrations/utilities/rules.d.ts.map +1 -0
  448. package/dist/src/integrations/utilities/rules.js +284 -0
  449. package/dist/src/integrations/utilities/rules.js.map +1 -0
  450. package/dist/src/integrations/utilities/sourcegraph.d.ts +169 -0
  451. package/dist/src/integrations/utilities/sourcegraph.d.ts.map +1 -0
  452. package/dist/src/integrations/utilities/sourcegraph.js +379 -0
  453. package/dist/src/integrations/utilities/sourcegraph.js.map +1 -0
  454. package/dist/src/integrations/utilities/thinking-strategy.d.ts +52 -0
  455. package/dist/src/integrations/utilities/thinking-strategy.d.ts.map +1 -0
  456. package/dist/src/integrations/utilities/thinking-strategy.js +129 -0
  457. package/dist/src/integrations/utilities/thinking-strategy.js.map +1 -0
  458. package/dist/src/integrations/utilities/thread-manager.d.ts +199 -0
  459. package/dist/src/integrations/utilities/thread-manager.d.ts.map +1 -0
  460. package/dist/src/integrations/utilities/thread-manager.js +357 -0
  461. package/dist/src/integrations/utilities/thread-manager.js.map +1 -0
  462. package/dist/src/integrations/utilities/token-estimate.d.ts +11 -0
  463. package/dist/src/integrations/utilities/token-estimate.d.ts.map +1 -0
  464. package/dist/src/integrations/utilities/token-estimate.js +14 -0
  465. package/dist/src/integrations/utilities/token-estimate.js.map +1 -0
  466. package/dist/src/main.js +10 -4
  467. package/dist/src/main.js.map +1 -1
  468. package/dist/src/modes/repl.d.ts.map +1 -1
  469. package/dist/src/modes/repl.js +22 -5
  470. package/dist/src/modes/repl.js.map +1 -1
  471. package/dist/src/modes/tui.d.ts.map +1 -1
  472. package/dist/src/modes/tui.js +23 -6
  473. package/dist/src/modes/tui.js.map +1 -1
  474. package/dist/src/modes.js +1 -1
  475. package/dist/src/modes.js.map +1 -1
  476. package/dist/src/observability/tracer.js +1 -1
  477. package/dist/src/observability/tracer.js.map +1 -1
  478. package/dist/src/persistence/schema.d.ts +2 -0
  479. package/dist/src/persistence/schema.d.ts.map +1 -1
  480. package/dist/src/persistence/schema.js +31 -0
  481. package/dist/src/persistence/schema.js.map +1 -1
  482. package/dist/src/providers/adapters/anthropic.d.ts +6 -0
  483. package/dist/src/providers/adapters/anthropic.d.ts.map +1 -1
  484. package/dist/src/providers/adapters/anthropic.js +99 -15
  485. package/dist/src/providers/adapters/anthropic.js.map +1 -1
  486. package/dist/src/providers/adapters/azure.d.ts +74 -0
  487. package/dist/src/providers/adapters/azure.d.ts.map +1 -0
  488. package/dist/src/providers/adapters/azure.js +354 -0
  489. package/dist/src/providers/adapters/azure.js.map +1 -0
  490. package/dist/src/providers/adapters/mock.d.ts +16 -2
  491. package/dist/src/providers/adapters/mock.d.ts.map +1 -1
  492. package/dist/src/providers/adapters/mock.js +44 -3
  493. package/dist/src/providers/adapters/mock.js.map +1 -1
  494. package/dist/src/providers/adapters/openai.d.ts +6 -1
  495. package/dist/src/providers/adapters/openai.d.ts.map +1 -1
  496. package/dist/src/providers/adapters/openai.js +39 -8
  497. package/dist/src/providers/adapters/openai.js.map +1 -1
  498. package/dist/src/providers/adapters/openrouter.d.ts +6 -0
  499. package/dist/src/providers/adapters/openrouter.d.ts.map +1 -1
  500. package/dist/src/providers/adapters/openrouter.js +73 -3
  501. package/dist/src/providers/adapters/openrouter.js.map +1 -1
  502. package/dist/src/providers/provider.js +1 -1
  503. package/dist/src/providers/provider.js.map +1 -1
  504. package/dist/src/providers/resilient-provider.js +1 -1
  505. package/dist/src/providers/resilient-provider.js.map +1 -1
  506. package/dist/src/providers/types.d.ts +23 -2
  507. package/dist/src/providers/types.d.ts.map +1 -1
  508. package/dist/src/session-picker.d.ts +1 -1
  509. package/dist/src/session-picker.d.ts.map +1 -1
  510. package/dist/src/session-picker.js +1 -1
  511. package/dist/src/session-picker.js.map +1 -1
  512. package/dist/src/shared/budget-tracker.js +1 -1
  513. package/dist/src/shared/budget-tracker.js.map +1 -1
  514. package/dist/src/tools/agent.d.ts +1 -1
  515. package/dist/src/tools/agent.d.ts.map +1 -1
  516. package/dist/src/tools/bash.js +1 -1
  517. package/dist/src/tools/bash.js.map +1 -1
  518. package/dist/src/tools/file.js +1 -1
  519. package/dist/src/tools/file.js.map +1 -1
  520. package/dist/src/tools/permission.js +2 -2
  521. package/dist/src/tools/permission.js.map +1 -1
  522. package/dist/src/tools/registry.d.ts +1 -1
  523. package/dist/src/tools/registry.d.ts.map +1 -1
  524. package/dist/src/tools/registry.js +1 -1
  525. package/dist/src/tools/registry.js.map +1 -1
  526. package/dist/src/tools/tasks.d.ts +1 -1
  527. package/dist/src/tools/tasks.d.ts.map +1 -1
  528. package/dist/src/tools/undo.d.ts +1 -1
  529. package/dist/src/tools/undo.d.ts.map +1 -1
  530. package/dist/src/tracing/cache-boundary-tracker.d.ts.map +1 -1
  531. package/dist/src/tracing/cache-boundary-tracker.js +2 -2
  532. package/dist/src/tracing/cache-boundary-tracker.js.map +1 -1
  533. package/dist/src/tracing/trace-collector.d.ts +22 -0
  534. package/dist/src/tracing/trace-collector.d.ts.map +1 -1
  535. package/dist/src/tracing/trace-collector.js +27 -3
  536. package/dist/src/tracing/trace-collector.js.map +1 -1
  537. package/dist/src/tracing/types.d.ts +17 -1
  538. package/dist/src/tracing/types.d.ts.map +1 -1
  539. package/dist/src/tracing/types.js.map +1 -1
  540. package/dist/src/tricks/failure-evidence.js +1 -1
  541. package/dist/src/tricks/failure-evidence.js.map +1 -1
  542. package/dist/src/tricks/recitation.d.ts.map +1 -1
  543. package/dist/src/tricks/recitation.js +2 -1
  544. package/dist/src/tricks/recitation.js.map +1 -1
  545. package/dist/src/tricks/recursive-context.d.ts.map +1 -1
  546. package/dist/src/tricks/recursive-context.js +2 -2
  547. package/dist/src/tricks/recursive-context.js.map +1 -1
  548. package/dist/src/tricks/reversible-compaction.d.ts.map +1 -1
  549. package/dist/src/tricks/reversible-compaction.js +6 -2
  550. package/dist/src/tricks/reversible-compaction.js.map +1 -1
  551. package/dist/src/tui/app.d.ts +3 -3
  552. package/dist/src/tui/app.d.ts.map +1 -1
  553. package/dist/src/tui/app.js +86 -14
  554. package/dist/src/tui/app.js.map +1 -1
  555. package/dist/src/tui/components/CollapsibleDiffView.d.ts +1 -1
  556. package/dist/src/tui/components/CollapsibleDiffView.d.ts.map +1 -1
  557. package/dist/src/tui/components/DiagnosticsPanel.d.ts +24 -0
  558. package/dist/src/tui/components/DiagnosticsPanel.d.ts.map +1 -0
  559. package/dist/src/tui/components/DiagnosticsPanel.js +47 -0
  560. package/dist/src/tui/components/DiagnosticsPanel.js.map +1 -0
  561. package/dist/src/tui/components/DiffView.d.ts +1 -1
  562. package/dist/src/tui/components/DiffView.d.ts.map +1 -1
  563. package/dist/src/tui/components/ErrorBoundary.js +1 -1
  564. package/dist/src/tui/components/ErrorBoundary.js.map +1 -1
  565. package/dist/src/tui/components/TasksPanel.d.ts +1 -1
  566. package/dist/src/tui/components/TasksPanel.d.ts.map +1 -1
  567. package/dist/src/tui/event-display.js +1 -1
  568. package/dist/src/tui/event-display.js.map +1 -1
  569. package/dist/src/tui/index.js +1 -1
  570. package/dist/src/tui/index.js.map +1 -1
  571. package/dist/src/tui/transparency-aggregator.d.ts +13 -0
  572. package/dist/src/tui/transparency-aggregator.d.ts.map +1 -1
  573. package/dist/src/tui/transparency-aggregator.js +21 -0
  574. package/dist/src/tui/transparency-aggregator.js.map +1 -1
  575. package/dist/src/types.d.ts +27 -2
  576. package/dist/src/types.d.ts.map +1 -1
  577. package/package.json +1 -1
@@ -0,0 +1,1021 @@
1
+ /**
2
+ * Swarm Execution — Task dispatch loop, wave management, and completion handling.
3
+ *
4
+ * Extracted from swarm-orchestrator.ts (Phase 3a).
5
+ * Contains: executeWaves, executeWave, dispatchTask, handleTaskCompletion.
6
+ */
7
+ import { getTaskTypeConfig } from './types.js';
8
+ import { selectAlternativeModel } from './model-selector.js';
9
+ import { evaluateWorkerOutput, runPreFlightChecks, checkArtifacts, checkArtifactsEnhanced, runConcreteChecks } from './swarm-quality-gate.js';
10
+ import { classifySwarmFailure } from './failure-classifier.js';
11
+ import { isHollowCompletion, FAILURE_INDICATORS, hasFutureIntentLanguage } from './swarm-helpers.js';
12
+ import { reviewWave, saveCheckpoint, emitBudgetUpdate, getEffectiveRetries, getSwarmProgressSummary, getModelHealthSummary, extractFileArtifacts, } from './swarm-lifecycle.js';
13
+ import { tryResilienceRecovery, rescueCascadeSkipped, assessAndAdapt, shouldAutoSplit, judgeSplit, recordRateLimit, isCircuitBreakerActive, decreaseStagger, getStaggerMs, } from './swarm-recovery.js';
14
+ // ─── Wave Execution ─────────────────────────────────────────────────────
15
+ /**
16
+ * Execute all waves in sequence, with review after each.
17
+ */
18
+ export async function executeWaves(ctx, recoveryState, getStatus) {
19
+ let waveIndex = ctx.taskQueue.getCurrentWave();
20
+ const totalWaves = ctx.taskQueue.getTotalWaves();
21
+ const dispatchLeaseStaleMs = ctx.config.dispatchLeaseStaleMs ?? 5 * 60 * 1000;
22
+ while (waveIndex < totalWaves && !ctx.cancelled) {
23
+ const activeTaskIds = new Set(ctx.workerPool.getActiveWorkerStatus().map(w => w.taskId));
24
+ const recovered = ctx.taskQueue.reconcileStaleDispatched({
25
+ staleAfterMs: dispatchLeaseStaleMs,
26
+ activeTaskIds,
27
+ });
28
+ if (recovered.length > 0) {
29
+ ctx.logDecision('lease-recovery', `Recovered ${recovered.length} stale dispatched task(s)`, recovered.join(', '));
30
+ }
31
+ const readyTasks = ctx.taskQueue.getReadyTasks();
32
+ const queueStats = ctx.taskQueue.getStats();
33
+ // F18: Skip empty waves
34
+ if (readyTasks.length === 0 && queueStats.running === 0 && queueStats.ready === 0) {
35
+ ctx.logDecision('wave-skip', `Skipping waves ${waveIndex + 1}-${totalWaves}: no dispatchable tasks remain`, `Stats: ${queueStats.completed} completed, ${queueStats.failed} failed, ${queueStats.skipped} skipped`);
36
+ break;
37
+ }
38
+ ctx.emit({
39
+ type: 'swarm.wave.start',
40
+ wave: waveIndex + 1,
41
+ totalWaves,
42
+ taskCount: readyTasks.length,
43
+ });
44
+ // Dispatch tasks up to concurrency limit
45
+ await executeWave(ctx, recoveryState, readyTasks, getStatus);
46
+ // Wave complete stats
47
+ const afterStats = ctx.taskQueue.getStats();
48
+ const waveCompleted = afterStats.completed - (queueStats.completed);
49
+ const waveFailed = afterStats.failed - (queueStats.failed);
50
+ const waveSkipped = afterStats.skipped - (queueStats.skipped);
51
+ ctx.emit({
52
+ type: 'swarm.wave.complete',
53
+ wave: waveIndex + 1,
54
+ totalWaves,
55
+ completed: waveCompleted,
56
+ failed: waveFailed,
57
+ skipped: waveSkipped,
58
+ });
59
+ // Wave failure recovery: if ALL tasks in a wave failed, retry with adapted context
60
+ if (waveCompleted === 0 && waveFailed > 0 && readyTasks.length > 0) {
61
+ ctx.emit({ type: 'swarm.wave.allFailed', wave: waveIndex + 1 });
62
+ ctx.logDecision('wave-recovery', `Entire wave ${waveIndex + 1} failed (${waveFailed} tasks)`, 'Checking if budget allows retry with adapted strategy');
63
+ const budgetRemaining = ctx.budgetPool.hasCapacity();
64
+ const failedWaveTasks = readyTasks.filter(t => {
65
+ const task = ctx.taskQueue.getTask(t.id);
66
+ return task && task.status === 'failed' && task.attempts < (ctx.config.workerRetries + 1);
67
+ });
68
+ if (budgetRemaining && failedWaveTasks.length > 0) {
69
+ for (const t of failedWaveTasks) {
70
+ const task = ctx.taskQueue.getTask(t.id);
71
+ if (!task)
72
+ continue;
73
+ task.status = 'ready';
74
+ task.retryContext = {
75
+ previousFeedback: 'All tasks in this batch failed. Try a fundamentally different approach — the previous strategy did not work.',
76
+ previousScore: 0,
77
+ attempt: task.attempts,
78
+ previousModel: task.assignedModel,
79
+ swarmProgress: getSwarmProgressSummary(ctx),
80
+ };
81
+ }
82
+ ctx.logDecision('wave-recovery', `Re-queued ${failedWaveTasks.length} tasks with adapted retry context`, 'Budget allows retry');
83
+ await executeWave(ctx, recoveryState, failedWaveTasks.map(t => ctx.taskQueue.getTask(t.id)).filter(t => t.status === 'ready'), getStatus);
84
+ }
85
+ }
86
+ // F5: Adaptive re-decomposition signal
87
+ const waveTotal = waveCompleted + waveFailed + waveSkipped;
88
+ const waveSuccessRate = waveTotal > 0 ? waveCompleted / waveTotal : 0;
89
+ if (waveSuccessRate < 0.5 && waveTotal >= 2) {
90
+ ctx.logDecision('decomposition-quality', `Wave ${waveIndex + 1} success rate ${(waveSuccessRate * 100).toFixed(0)}% (${waveCompleted}/${waveTotal})`, 'Low success rate may indicate decomposition quality issues');
91
+ }
92
+ // V2: Review wave outputs
93
+ const review = await reviewWave(ctx, waveIndex);
94
+ if (review && review.fixupTasks.length > 0) {
95
+ await executeWave(ctx, recoveryState, review.fixupTasks, getStatus);
96
+ }
97
+ // Rescue cascade-skipped tasks that can still run
98
+ const rescued = rescueCascadeSkipped(ctx);
99
+ if (rescued.length > 0) {
100
+ ctx.logDecision('cascade-rescue', `Rescued ${rescued.length} cascade-skipped tasks after wave ${waveIndex + 1}`, rescued.map(t => t.id).join(', '));
101
+ await executeWave(ctx, recoveryState, rescued, getStatus);
102
+ }
103
+ // Reset quality circuit breaker at wave boundary
104
+ if (recoveryState.qualityGateDisabledModels.size > 0) {
105
+ recoveryState.qualityGateDisabledModels.clear();
106
+ recoveryState.perModelQualityRejections.clear();
107
+ ctx.logDecision('quality-circuit-breaker', `Re-enabled quality gates for all models at wave ${waveIndex + 1} boundary`, 'Each wave gets a fresh quality evaluation window');
108
+ }
109
+ // F3: Log budget reallocation after wave completion
110
+ const budgetStats = ctx.budgetPool.getStats();
111
+ ctx.logDecision('budget-reallocation', `After wave ${waveIndex + 1}: ${budgetStats.tokensRemaining} tokens remaining (${(budgetStats.utilization * 100).toFixed(0)}% utilized)`, '');
112
+ ctx.budgetPool.reallocateUnused(budgetStats.tokensRemaining);
113
+ // F21: Mid-swarm situational assessment
114
+ await assessAndAdapt(ctx, recoveryState, waveIndex);
115
+ // V2: Checkpoint after each wave
116
+ saveCheckpoint(ctx, `wave-${waveIndex}`);
117
+ // Advance to next wave
118
+ if (!ctx.taskQueue.advanceWave())
119
+ break;
120
+ waveIndex++;
121
+ }
122
+ }
123
+ /**
124
+ * Execute a single wave's tasks with concurrency control.
125
+ */
126
+ export async function executeWave(ctx, recoveryState, tasks, getStatus) {
127
+ // Dispatch initial batch with stagger
128
+ let taskIndex = 0;
129
+ while (taskIndex < tasks.length && ctx.workerPool.availableSlots > 0 && !ctx.cancelled) {
130
+ if (isCircuitBreakerActive(recoveryState, ctx)) {
131
+ const waitMs = recoveryState.circuitBreakerUntil - Date.now();
132
+ if (waitMs > 0)
133
+ await new Promise(resolve => setTimeout(resolve, waitMs));
134
+ continue;
135
+ }
136
+ const task = tasks[taskIndex];
137
+ await dispatchTask(ctx, recoveryState, task, getStatus);
138
+ taskIndex++;
139
+ if (taskIndex < tasks.length && ctx.workerPool.availableSlots > 0) {
140
+ await new Promise(resolve => setTimeout(resolve, getStaggerMs(recoveryState)));
141
+ }
142
+ }
143
+ // Process completions and dispatch more tasks as slots open
144
+ while (ctx.workerPool.activeCount > 0 && !ctx.cancelled) {
145
+ const completed = await ctx.workerPool.waitForAny();
146
+ if (!completed)
147
+ break;
148
+ await handleTaskCompletion(ctx, recoveryState, completed.taskId, completed.result, completed.startedAt, getStatus);
149
+ emitBudgetUpdate(ctx);
150
+ ctx.emit({ type: 'swarm.status', status: getStatus() });
151
+ // Dispatch more tasks if slots available and tasks remain
152
+ while (taskIndex < tasks.length && ctx.workerPool.availableSlots > 0 && !ctx.cancelled) {
153
+ const task = tasks[taskIndex];
154
+ if (task.status === 'ready') {
155
+ await dispatchTask(ctx, recoveryState, task, getStatus);
156
+ if (taskIndex + 1 < tasks.length && ctx.workerPool.availableSlots > 0) {
157
+ await new Promise(resolve => setTimeout(resolve, getStaggerMs(recoveryState)));
158
+ }
159
+ }
160
+ taskIndex++;
161
+ }
162
+ // Also check for cross-wave ready tasks to fill slots
163
+ if (ctx.workerPool.availableSlots > 0 && !isCircuitBreakerActive(recoveryState, ctx)) {
164
+ const moreReady = ctx.taskQueue.getAllReadyTasks()
165
+ .filter(t => !ctx.workerPool.getActiveWorkerStatus().some(w => w.taskId === t.id));
166
+ for (let i = 0; i < moreReady.length; i++) {
167
+ if (ctx.workerPool.availableSlots <= 0)
168
+ break;
169
+ await dispatchTask(ctx, recoveryState, moreReady[i], getStatus);
170
+ if (i + 1 < moreReady.length && ctx.workerPool.availableSlots > 0) {
171
+ await new Promise(resolve => setTimeout(resolve, getStaggerMs(recoveryState)));
172
+ }
173
+ }
174
+ }
175
+ }
176
+ // F20: Re-dispatch pass — after all workers finish, budget may have been freed
177
+ if (!ctx.cancelled && ctx.budgetPool.hasCapacity()) {
178
+ const stillReady = ctx.taskQueue.getAllReadyTasks()
179
+ .filter(t => !ctx.workerPool.getActiveWorkerStatus().some(w => w.taskId === t.id));
180
+ if (stillReady.length > 0) {
181
+ ctx.logDecision('budget-redispatch', `Budget freed after wave — re-dispatching ${stillReady.length} ready task(s)`, `Budget: ${JSON.stringify(ctx.budgetPool.getStats())}`);
182
+ for (const task of stillReady) {
183
+ if (ctx.workerPool.availableSlots <= 0 || !ctx.budgetPool.hasCapacity())
184
+ break;
185
+ await dispatchTask(ctx, recoveryState, task, getStatus);
186
+ if (ctx.workerPool.availableSlots > 0) {
187
+ await new Promise(resolve => setTimeout(resolve, getStaggerMs(recoveryState)));
188
+ }
189
+ }
190
+ while (ctx.workerPool.activeCount > 0 && !ctx.cancelled) {
191
+ const completed = await ctx.workerPool.waitForAny();
192
+ if (!completed)
193
+ break;
194
+ await handleTaskCompletion(ctx, recoveryState, completed.taskId, completed.result, completed.startedAt, getStatus);
195
+ emitBudgetUpdate(ctx);
196
+ ctx.emit({ type: 'swarm.status', status: getStatus() });
197
+ }
198
+ }
199
+ }
200
+ }
201
+ // ─── Task Dispatch ──────────────────────────────────────────────────────
202
+ /**
203
+ * Dispatch a single task to a worker.
204
+ */
205
+ export async function dispatchTask(ctx, recoveryState, task, _getStatus) {
206
+ const worker = ctx.workerPool.selectWorker(task);
207
+ if (!worker) {
208
+ ctx.logDecision('no-worker', `${task.id}: no worker for type ${task.type}`, '');
209
+ if (task.attempts > 0) {
210
+ const syntheticTaskResult = { success: false, output: '', tokensUsed: 0, costUsed: 0, durationMs: 0, model: 'none' };
211
+ const syntheticSpawn = { success: false, output: '', metrics: { tokens: 0, duration: 0, toolCalls: 0 } };
212
+ if (await tryResilienceRecovery(ctx, recoveryState, task, task.id, syntheticTaskResult, syntheticSpawn)) {
213
+ return;
214
+ }
215
+ }
216
+ ctx.taskQueue.markFailedWithoutCascade(task.id, 0);
217
+ ctx.taskQueue.triggerCascadeSkip(task.id);
218
+ ctx.emit({
219
+ type: 'swarm.task.failed',
220
+ taskId: task.id,
221
+ error: `No worker available for task type: ${task.type}`,
222
+ attempt: task.attempts,
223
+ maxAttempts: 0,
224
+ willRetry: false,
225
+ failureMode: 'error',
226
+ });
227
+ return;
228
+ }
229
+ try {
230
+ // Pre-dispatch auto-split for critical-path bottlenecks
231
+ if (shouldAutoSplit(ctx, task)) {
232
+ try {
233
+ const splitResult = await judgeSplit(ctx, task);
234
+ if (splitResult.shouldSplit && splitResult.subtasks) {
235
+ task.status = 'dispatched';
236
+ ctx.taskQueue.replaceWithSubtasks(task.id, splitResult.subtasks);
237
+ ctx.emit({
238
+ type: 'swarm.task.resilience',
239
+ taskId: task.id,
240
+ strategy: 'auto-split',
241
+ succeeded: true,
242
+ reason: `Pre-dispatch split into ${splitResult.subtasks.length} parallel subtasks`,
243
+ artifactsFound: 0,
244
+ toolCalls: 0,
245
+ });
246
+ return;
247
+ }
248
+ }
249
+ catch (err) {
250
+ ctx.logDecision('auto-split', `${task.id}: split judge failed — ${err.message}`, '');
251
+ }
252
+ }
253
+ ctx.totalDispatches++;
254
+ const dispatchedModel = task.assignedModel ?? worker.model;
255
+ ctx.taskQueue.markDispatched(task.id, dispatchedModel);
256
+ if (task.assignedModel && task.assignedModel !== worker.model) {
257
+ ctx.logDecision('failover', `Dispatching ${task.id} with failover model ${task.assignedModel} (worker default: ${worker.model})`, 'Retry model override is active');
258
+ }
259
+ await ctx.workerPool.dispatch(task, worker);
260
+ ctx.emit({
261
+ type: 'swarm.task.dispatched',
262
+ taskId: task.id,
263
+ description: task.description,
264
+ model: dispatchedModel,
265
+ workerName: worker.name,
266
+ toolCount: worker.allowedTools?.length ?? -1,
267
+ tools: worker.allowedTools,
268
+ retryContext: task.retryContext,
269
+ fromModel: task.retryContext ? task.retryContext.previousModel : undefined,
270
+ attempts: task.attempts,
271
+ });
272
+ }
273
+ catch (error) {
274
+ const errorMsg = error.message;
275
+ // F20: Budget exhaustion is NOT a task failure
276
+ if (errorMsg.includes('Budget pool exhausted')) {
277
+ task.status = 'ready';
278
+ ctx.logDecision('budget-pause', `Cannot dispatch ${task.id}: budget exhausted — task kept ready for potential re-dispatch`, `Budget stats: ${JSON.stringify(ctx.budgetPool.getStats())}`);
279
+ return;
280
+ }
281
+ ctx.errors.push({
282
+ taskId: task.id,
283
+ phase: 'dispatch',
284
+ message: errorMsg,
285
+ recovered: false,
286
+ });
287
+ ctx.logDecision('dispatch-error', `${task.id}: dispatch failed: ${errorMsg.slice(0, 100)}`, `attempts: ${task.attempts}`);
288
+ if (task.attempts > 0) {
289
+ const syntheticTaskResult = { success: false, output: '', tokensUsed: 0, costUsed: 0, durationMs: 0, model: 'none' };
290
+ const syntheticSpawn = { success: false, output: '', metrics: { tokens: 0, duration: 0, toolCalls: 0 } };
291
+ if (await tryResilienceRecovery(ctx, recoveryState, task, task.id, syntheticTaskResult, syntheticSpawn)) {
292
+ ctx.errors[ctx.errors.length - 1].recovered = true;
293
+ return;
294
+ }
295
+ }
296
+ ctx.taskQueue.markFailedWithoutCascade(task.id, 0);
297
+ ctx.taskQueue.triggerCascadeSkip(task.id);
298
+ ctx.emit({
299
+ type: 'swarm.task.failed',
300
+ taskId: task.id,
301
+ error: errorMsg,
302
+ attempt: task.attempts,
303
+ maxAttempts: 1 + ctx.config.workerRetries,
304
+ willRetry: false,
305
+ failureMode: 'error',
306
+ });
307
+ }
308
+ }
309
+ // ─── Task Completion Handling ───────────────────────────────────────────
310
+ /**
311
+ * Handle a completed task: quality gate, bookkeeping, retry logic, model health, failover.
312
+ */
313
+ export async function handleTaskCompletion(ctx, recoveryState, taskId, spawnResult, startedAt, _getStatus) {
314
+ const task = ctx.taskQueue.getTask(taskId);
315
+ if (!task)
316
+ return;
317
+ // Guard: task was terminally resolved while its worker was running
318
+ if ((task.status === 'skipped' || task.status === 'failed') && !task.pendingCascadeSkip)
319
+ return;
320
+ // V7: Global dispatch cap
321
+ const maxDispatches = ctx.config.maxDispatchesPerTask ?? 5;
322
+ if (task.attempts >= maxDispatches) {
323
+ const durationMs = Date.now() - startedAt;
324
+ const taskResult = ctx.workerPool.toTaskResult(spawnResult, task, durationMs);
325
+ ctx.totalTokens += taskResult.tokensUsed;
326
+ ctx.totalCost += taskResult.costUsed;
327
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
328
+ return;
329
+ }
330
+ ctx.taskQueue.markFailedWithoutCascade(taskId, 0);
331
+ ctx.taskQueue.triggerCascadeSkip(taskId);
332
+ ctx.emit({
333
+ type: 'swarm.task.failed',
334
+ taskId,
335
+ error: `Dispatch cap reached (${maxDispatches} attempts)`,
336
+ attempt: task.attempts,
337
+ maxAttempts: maxDispatches,
338
+ willRetry: false,
339
+ failureMode: task.failureMode,
340
+ });
341
+ ctx.logDecision('dispatch-cap', `${taskId}: hard cap reached (${task.attempts}/${maxDispatches})`, 'No more retries — resilience recovery also failed');
342
+ return;
343
+ }
344
+ const durationMs = Date.now() - startedAt;
345
+ const taskResult = ctx.workerPool.toTaskResult(spawnResult, task, durationMs);
346
+ // Track model usage
347
+ const model = task.assignedModel ?? 'unknown';
348
+ const usage = ctx.modelUsage.get(model) ?? { tasks: 0, tokens: 0, cost: 0 };
349
+ usage.tasks++;
350
+ usage.tokens += taskResult.tokensUsed;
351
+ usage.cost += taskResult.costUsed;
352
+ ctx.modelUsage.set(model, usage);
353
+ ctx.totalTokens += taskResult.tokensUsed;
354
+ ctx.totalCost += taskResult.costUsed;
355
+ if (taskResult.budgetUtilization) {
356
+ ctx.logDecision('budget-utilization', `${taskId}: token ${taskResult.budgetUtilization.tokenPercent}%, iter ${taskResult.budgetUtilization.iterationPercent}%`, `model=${model}, tokens=${taskResult.tokensUsed}, duration=${durationMs}ms`);
357
+ }
358
+ // V10: Emit per-attempt event
359
+ ctx.emit({
360
+ type: 'swarm.task.attempt',
361
+ taskId,
362
+ attempt: task.attempts,
363
+ model,
364
+ success: spawnResult.success,
365
+ durationMs,
366
+ toolCalls: spawnResult.metrics.toolCalls ?? 0,
367
+ failureMode: !spawnResult.success ? task.failureMode : undefined,
368
+ qualityScore: taskResult.qualityScore,
369
+ output: taskResult.output.slice(0, 500),
370
+ });
371
+ if (!spawnResult.success) {
372
+ return handleFailedCompletion(ctx, recoveryState, task, taskId, spawnResult, taskResult, model, durationMs, startedAt, maxDispatches);
373
+ }
374
+ // V6: Hollow completion detection
375
+ if (isHollowCompletion(spawnResult, task.type, ctx.config)) {
376
+ return handleHollowCompletion(ctx, recoveryState, task, taskId, spawnResult, taskResult, model, maxDispatches);
377
+ }
378
+ // F4: Task had pendingCascadeSkip but produced non-hollow results
379
+ if (task.pendingCascadeSkip) {
380
+ const cachedReport = checkArtifacts(task);
381
+ const preFlight = runPreFlightChecks(task, taskResult, ctx.config, cachedReport);
382
+ if (preFlight && !preFlight.passed) {
383
+ task.pendingCascadeSkip = undefined;
384
+ task.status = 'skipped';
385
+ ctx.logDecision('cascade-skip', `${taskId}: pending cascade skip honored (pre-flight failed: ${preFlight.feedback})`, '');
386
+ ctx.emit({ type: 'swarm.task.skipped', taskId, reason: `cascade skip honored — output failed pre-flight: ${preFlight.feedback}` });
387
+ return;
388
+ }
389
+ task.pendingCascadeSkip = undefined;
390
+ task.status = 'dispatched';
391
+ ctx.logDecision('cascade-skip', `${taskId}: pending cascade skip overridden — worker produced valid output`, '');
392
+ }
393
+ // Record model health on success
394
+ ctx.healthTracker.recordSuccess(model, durationMs);
395
+ decreaseStagger(recoveryState);
396
+ // Run quality gate if enabled
397
+ const effectiveRetries = getEffectiveRetries(ctx, task);
398
+ const recentRLCount = recoveryState.recentRateLimits.filter(t => t > Date.now() - 30_000).length;
399
+ const isLastAttempt = task.attempts >= (effectiveRetries + 1);
400
+ const shouldRunQualityGate = ctx.config.qualityGates
401
+ && !recoveryState.qualityGateDisabledModels.has(model)
402
+ && !isLastAttempt
403
+ && Date.now() >= recoveryState.circuitBreakerUntil
404
+ && recentRLCount < 2;
405
+ const cachedArtifactReport = checkArtifacts(task);
406
+ if (shouldRunQualityGate) {
407
+ const rejected = await runQualityGate(ctx, recoveryState, task, taskId, spawnResult, taskResult, model, effectiveRetries, cachedArtifactReport);
408
+ if (rejected)
409
+ return;
410
+ }
411
+ // F7: When quality gate was skipped, still run pre-flight + concrete checks
412
+ if (!shouldRunQualityGate && ctx.config.qualityGates) {
413
+ const preFlight = runPreFlightChecks(task, taskResult, ctx.config, cachedArtifactReport);
414
+ if (preFlight && !preFlight.passed) {
415
+ taskResult.qualityScore = preFlight.score;
416
+ taskResult.qualityFeedback = preFlight.feedback;
417
+ ctx.qualityRejections++;
418
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, effectiveRetries);
419
+ if (canRetry) {
420
+ ctx.retries++;
421
+ }
422
+ else {
423
+ ctx.logDecision('preflight-reject', `${taskId}: pre-flight failed: ${preFlight.feedback}`, '');
424
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
425
+ return;
426
+ }
427
+ ctx.taskQueue.triggerCascadeSkip(taskId);
428
+ }
429
+ ctx.emit({
430
+ type: 'swarm.quality.rejected',
431
+ taskId,
432
+ score: preFlight.score,
433
+ feedback: preFlight.feedback,
434
+ artifactCount: 0,
435
+ outputLength: taskResult.output.length,
436
+ preFlightReject: true,
437
+ });
438
+ return;
439
+ }
440
+ // F2: Run concrete validation when pre-flight passes but gate was skipped
441
+ if (ctx.config.enableConcreteValidation !== false) {
442
+ const concreteResult = runConcreteChecks(task, taskResult);
443
+ if (!concreteResult.passed) {
444
+ taskResult.qualityScore = 2;
445
+ taskResult.qualityFeedback = `Concrete validation failed: ${concreteResult.issues.join('; ')}`;
446
+ ctx.qualityRejections++;
447
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, effectiveRetries);
448
+ if (canRetry) {
449
+ ctx.retries++;
450
+ }
451
+ else {
452
+ ctx.logDecision('concrete-reject', `${taskId}: concrete validation failed: ${concreteResult.issues.join('; ')}`, '');
453
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
454
+ return;
455
+ }
456
+ ctx.taskQueue.triggerCascadeSkip(taskId);
457
+ }
458
+ ctx.emit({
459
+ type: 'swarm.quality.rejected',
460
+ taskId,
461
+ score: 2,
462
+ feedback: taskResult.qualityFeedback,
463
+ artifactCount: 0,
464
+ outputLength: taskResult.output.length,
465
+ preFlightReject: false,
466
+ });
467
+ return;
468
+ }
469
+ }
470
+ }
471
+ // Final completion guard: block "narrative success" for action tasks
472
+ const completionGuard = ctx.config.completionGuard ?? {};
473
+ const rejectFutureIntentOutputs = completionGuard.rejectFutureIntentOutputs ?? true;
474
+ const requireConcreteArtifactsForActionTasks = completionGuard.requireConcreteArtifactsForActionTasks ?? true;
475
+ const typeConfig = getTaskTypeConfig(task.type, ctx.config);
476
+ const artifactReport = checkArtifactsEnhanced(task, taskResult);
477
+ const filesOnDisk = artifactReport.files.filter(f => f.exists && f.sizeBytes > 0).length;
478
+ const hasConcreteArtifacts = filesOnDisk > 0 || (taskResult.filesModified?.length ?? 0) > 0;
479
+ const isActionTask = !!typeConfig.requiresToolCalls;
480
+ if (rejectFutureIntentOutputs && hasFutureIntentLanguage(taskResult.output ?? '')) {
481
+ taskResult.qualityScore = 1;
482
+ taskResult.qualityFeedback = 'Completion rejected: output indicates pending, unexecuted work';
483
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, effectiveRetries);
484
+ if (canRetry) {
485
+ ctx.retries++;
486
+ }
487
+ else {
488
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
489
+ return;
490
+ }
491
+ ctx.taskQueue.triggerCascadeSkip(taskId);
492
+ }
493
+ ctx.emit({
494
+ type: 'swarm.quality.rejected',
495
+ taskId,
496
+ score: 1,
497
+ feedback: taskResult.qualityFeedback,
498
+ artifactCount: filesOnDisk,
499
+ outputLength: taskResult.output.length,
500
+ preFlightReject: true,
501
+ filesOnDisk,
502
+ });
503
+ return;
504
+ }
505
+ if (requireConcreteArtifactsForActionTasks && isActionTask && !hasConcreteArtifacts) {
506
+ taskResult.qualityScore = 1;
507
+ taskResult.qualityFeedback = 'Completion rejected: action task produced no concrete artifacts';
508
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, effectiveRetries);
509
+ if (canRetry) {
510
+ ctx.retries++;
511
+ }
512
+ else {
513
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
514
+ return;
515
+ }
516
+ ctx.taskQueue.triggerCascadeSkip(taskId);
517
+ }
518
+ ctx.emit({
519
+ type: 'swarm.quality.rejected',
520
+ taskId,
521
+ score: 1,
522
+ feedback: taskResult.qualityFeedback,
523
+ artifactCount: filesOnDisk,
524
+ outputLength: taskResult.output.length,
525
+ preFlightReject: true,
526
+ filesOnDisk,
527
+ });
528
+ return;
529
+ }
530
+ // Task passed — mark completed
531
+ ctx.taskQueue.markCompleted(taskId, taskResult);
532
+ ctx.hollowStreak = 0;
533
+ recoveryState.taskTimeoutCounts.delete(taskId);
534
+ // H6: Post findings to blackboard
535
+ if (ctx.blackboard && taskResult.findings) {
536
+ try {
537
+ for (const finding of taskResult.findings) {
538
+ ctx.blackboard.post(`swarm-worker-${taskId}`, {
539
+ topic: `swarm.task.${task.type}`,
540
+ content: finding,
541
+ type: 'progress',
542
+ confidence: (taskResult.qualityScore ?? 3) / 5,
543
+ tags: ['swarm', task.type],
544
+ relatedFiles: task.targetFiles,
545
+ });
546
+ }
547
+ }
548
+ catch {
549
+ ctx.errors.push({
550
+ taskId,
551
+ phase: 'execution',
552
+ message: 'Failed to post findings to blackboard',
553
+ recovered: true,
554
+ });
555
+ }
556
+ }
557
+ ctx.emit({
558
+ type: 'swarm.task.completed',
559
+ taskId,
560
+ success: true,
561
+ tokensUsed: taskResult.tokensUsed,
562
+ costUsed: taskResult.costUsed,
563
+ durationMs: taskResult.durationMs,
564
+ qualityScore: taskResult.qualityScore,
565
+ qualityFeedback: taskResult.qualityFeedback,
566
+ output: taskResult.output,
567
+ closureReport: taskResult.closureReport,
568
+ toolCalls: spawnResult.metrics.toolCalls,
569
+ });
570
+ }
571
+ // ─── Internal Helpers ───────────────────────────────────────────────────
572
+ /**
573
+ * Handle the case where a worker fails (spawnResult.success === false).
574
+ */
575
+ async function handleFailedCompletion(ctx, recoveryState, task, taskId, spawnResult, taskResult, model, durationMs, startedAt, maxDispatches) {
576
+ const failure = classifySwarmFailure(spawnResult.output, spawnResult.metrics.toolCalls);
577
+ const { failureClass, retryable, errorType, failureMode, reason } = failure;
578
+ const isTimeout = failureMode === 'timeout';
579
+ const isRateLimited = failureClass === 'rate_limited';
580
+ const isSpendLimit = failureClass === 'provider_spend_limit';
581
+ const isNonRetryable = !retryable;
582
+ ctx.healthTracker.recordFailure(model, errorType);
583
+ ctx.emit({ type: 'swarm.model.health', record: { model, ...getModelHealthSummary(ctx, model) } });
584
+ task.failureMode = failureMode;
585
+ if (isRateLimited) {
586
+ recordRateLimit(recoveryState, ctx);
587
+ }
588
+ // F25a: Consecutive timeout tracking
589
+ if (isTimeout) {
590
+ const count = (recoveryState.taskTimeoutCounts.get(taskId) ?? 0) + 1;
591
+ recoveryState.taskTimeoutCounts.set(taskId, count);
592
+ const timeoutLimit = ctx.config.consecutiveTimeoutLimit ?? 3;
593
+ ctx.logDecision('timeout-tracking', `${taskId}: consecutive timeout ${count}/${timeoutLimit}`, '');
594
+ if (count >= timeoutLimit) {
595
+ let failoverSucceeded = false;
596
+ if (ctx.config.enableModelFailover) {
597
+ const capability = getTaskTypeConfig(task.type, ctx.config).capability ?? 'code';
598
+ const alternative = selectAlternativeModel(ctx.config.workers, model, capability, ctx.healthTracker);
599
+ if (alternative) {
600
+ ctx.emit({
601
+ type: 'swarm.model.failover',
602
+ taskId,
603
+ fromModel: model,
604
+ toModel: alternative.model,
605
+ reason: 'consecutive-timeouts',
606
+ });
607
+ task.assignedModel = alternative.model;
608
+ recoveryState.taskTimeoutCounts.set(taskId, 0);
609
+ ctx.logDecision('failover', `Timeout failover ${taskId}: ${model} → ${alternative.model}`, `${count} consecutive timeouts`);
610
+ failoverSucceeded = true;
611
+ }
612
+ }
613
+ if (!failoverSucceeded) {
614
+ task.failureMode = 'timeout';
615
+ const timeoutTaskResult = ctx.workerPool.toTaskResult(spawnResult, task, Date.now() - startedAt);
616
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, timeoutTaskResult, spawnResult)) {
617
+ recoveryState.taskTimeoutCounts.delete(taskId);
618
+ return;
619
+ }
620
+ ctx.taskQueue.markFailedWithoutCascade(taskId, 0);
621
+ ctx.taskQueue.triggerCascadeSkip(taskId);
622
+ ctx.emit({
623
+ type: 'swarm.task.failed',
624
+ taskId,
625
+ error: `${count} consecutive timeouts — no alternative model available`,
626
+ attempt: task.attempts,
627
+ maxAttempts: maxDispatches,
628
+ willRetry: false,
629
+ failureMode: 'timeout',
630
+ failureClass: 'timeout',
631
+ retrySuppressed: true,
632
+ retryReason: 'Consecutive timeout limit reached with no alternative model',
633
+ });
634
+ ctx.logDecision('timeout-early-fail', `${taskId}: ${count} consecutive timeouts, no alt model — resilience recovery also failed`, '');
635
+ recoveryState.taskTimeoutCounts.delete(taskId);
636
+ return;
637
+ }
638
+ }
639
+ }
640
+ else {
641
+ recoveryState.taskTimeoutCounts.delete(taskId);
642
+ }
643
+ // V2: Model failover on retryable rate limits
644
+ if (isRateLimited && ctx.config.enableModelFailover) {
645
+ const capability = getTaskTypeConfig(task.type, ctx.config).capability ?? 'code';
646
+ const alternative = selectAlternativeModel(ctx.config.workers, model, capability, ctx.healthTracker);
647
+ if (alternative) {
648
+ ctx.emit({
649
+ type: 'swarm.model.failover',
650
+ taskId,
651
+ fromModel: model,
652
+ toModel: alternative.model,
653
+ reason: errorType,
654
+ });
655
+ task.assignedModel = alternative.model;
656
+ ctx.logDecision('failover', `Switched ${taskId} from ${model} to ${alternative.model}`, `${errorType} error`);
657
+ }
658
+ }
659
+ // V5/V7: Store error context so retry gets different prompt
660
+ if (!(isRateLimited || isSpendLimit)) {
661
+ const timeoutSeconds = isTimeout ? Math.round(durationMs / 1000) : 0;
662
+ task.retryContext = {
663
+ previousFeedback: isTimeout
664
+ ? `Previous attempt timed out after ${timeoutSeconds}s. You must complete this task more efficiently — work faster, use fewer tool calls, and produce your result sooner.`
665
+ : spawnResult.output.slice(0, 2000),
666
+ previousScore: 0,
667
+ attempt: task.attempts,
668
+ previousModel: model,
669
+ previousFiles: taskResult.filesModified,
670
+ swarmProgress: getSwarmProgressSummary(ctx),
671
+ };
672
+ ctx.sharedContextEngine.reportFailure(taskId, {
673
+ action: task.description.slice(0, 200),
674
+ error: spawnResult.output.slice(0, 500),
675
+ });
676
+ }
677
+ // V7: Reset hollow streak on non-hollow failure
678
+ ctx.hollowStreak = 0;
679
+ // Worker failed — use higher retry limit for rate limit errors
680
+ const baseRetries = getEffectiveRetries(ctx, task);
681
+ const retryLimit = isNonRetryable
682
+ ? 0
683
+ : isRateLimited
684
+ ? Math.min(ctx.config.rateLimitRetries ?? 3, baseRetries + 1)
685
+ : baseRetries;
686
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, retryLimit);
687
+ if (isNonRetryable) {
688
+ ctx.logDecision('retry-suppressed', `${taskId}: ${failureClass}`, reason);
689
+ }
690
+ if (canRetry) {
691
+ ctx.retries++;
692
+ if (isRateLimited) {
693
+ const baseDelay = ctx.config.retryBaseDelayMs ?? 5000;
694
+ const cooldownMs = Math.min(baseDelay * Math.pow(2, task.attempts - 1), 30000);
695
+ ctx.taskQueue.setRetryAfter(taskId, cooldownMs);
696
+ ctx.logDecision('rate-limit-cooldown', `${taskId}: ${errorType} cooldown ${cooldownMs}ms, model ${model}`, '');
697
+ }
698
+ }
699
+ else if (!isRateLimited) {
700
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
701
+ return;
702
+ }
703
+ ctx.taskQueue.triggerCascadeSkip(taskId);
704
+ }
705
+ else {
706
+ ctx.taskQueue.triggerCascadeSkip(taskId);
707
+ }
708
+ ctx.emit({
709
+ type: 'swarm.task.failed',
710
+ taskId,
711
+ error: spawnResult.output.slice(0, 200),
712
+ attempt: task.attempts,
713
+ maxAttempts: 1 + ctx.config.workerRetries,
714
+ willRetry: canRetry,
715
+ toolCalls: spawnResult.metrics.toolCalls,
716
+ failoverModel: task.assignedModel !== model ? task.assignedModel : undefined,
717
+ failureMode: task.failureMode,
718
+ failureClass,
719
+ retrySuppressed: isNonRetryable,
720
+ retryReason: reason,
721
+ });
722
+ }
723
+ /**
724
+ * Handle hollow completion — workers that "succeed" without doing any work.
725
+ */
726
+ async function handleHollowCompletion(ctx, recoveryState, task, taskId, spawnResult, taskResult, model, maxDispatches) {
727
+ // F4: Hollow result + pendingCascadeSkip
728
+ if (task.pendingCascadeSkip) {
729
+ task.pendingCascadeSkip = undefined;
730
+ task.status = 'skipped';
731
+ ctx.totalHollows++;
732
+ ctx.logDecision('cascade-skip', `${taskId}: pending cascade skip honored (hollow completion)`, '');
733
+ ctx.emit({ type: 'swarm.task.skipped', taskId, reason: 'cascade skip honored — hollow completion' });
734
+ return;
735
+ }
736
+ task.failureMode = 'hollow';
737
+ ctx.healthTracker.recordHollow(model);
738
+ const admitsFailure = spawnResult.success && FAILURE_INDICATORS.some(f => (spawnResult.output ?? '').toLowerCase().includes(f));
739
+ task.retryContext = {
740
+ previousFeedback: admitsFailure
741
+ ? 'Previous attempt reported success but admitted failure (e.g., "budget exhausted", "unable to complete"). You MUST execute tool calls and produce concrete output this time.'
742
+ : 'Previous attempt produced no meaningful output. Try again with a concrete approach.',
743
+ previousScore: 1,
744
+ attempt: task.attempts,
745
+ previousModel: model,
746
+ previousFiles: taskResult.filesModified,
747
+ swarmProgress: getSwarmProgressSummary(ctx),
748
+ };
749
+ ctx.sharedContextEngine.reportFailure(taskId, {
750
+ action: task.description.slice(0, 200),
751
+ error: 'Hollow completion: worker produced no meaningful output',
752
+ });
753
+ // Model failover for hollow completions
754
+ if (ctx.config.enableModelFailover) {
755
+ const capability = getTaskTypeConfig(task.type, ctx.config).capability ?? 'code';
756
+ const alternative = selectAlternativeModel(ctx.config.workers, model, capability, ctx.healthTracker);
757
+ if (alternative) {
758
+ ctx.emit({
759
+ type: 'swarm.model.failover',
760
+ taskId,
761
+ fromModel: model,
762
+ toModel: alternative.model,
763
+ reason: 'hollow-completion',
764
+ });
765
+ task.assignedModel = alternative.model;
766
+ ctx.logDecision('failover', `Hollow failover ${taskId}: ${model} → ${alternative.model}`, 'Model produced hollow completion');
767
+ }
768
+ }
769
+ const hollowRetries = getEffectiveRetries(ctx, task);
770
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, hollowRetries);
771
+ if (canRetry) {
772
+ ctx.retries++;
773
+ }
774
+ else {
775
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
776
+ return;
777
+ }
778
+ ctx.taskQueue.triggerCascadeSkip(taskId);
779
+ }
780
+ ctx.emit({
781
+ type: 'swarm.task.failed',
782
+ taskId,
783
+ error: 'Hollow completion: worker used no tools',
784
+ attempt: task.attempts,
785
+ maxAttempts: 1 + ctx.config.workerRetries,
786
+ willRetry: canRetry,
787
+ toolCalls: spawnResult.metrics.toolCalls,
788
+ failoverModel: task.assignedModel !== model ? task.assignedModel : undefined,
789
+ failureMode: 'hollow',
790
+ });
791
+ ctx.hollowStreak++;
792
+ ctx.totalHollows++;
793
+ ctx.logDecision('hollow-completion', `${taskId}: worker completed with 0 tool calls (streak: ${ctx.hollowStreak}, total hollows: ${ctx.totalHollows}/${ctx.totalDispatches})`, canRetry ? 'Marking as failed for retry' : 'Retries exhausted — hard fail');
794
+ // B2: Hollow streak handling
795
+ const HOLLOW_STREAK_THRESHOLD = 3;
796
+ if (ctx.hollowStreak >= HOLLOW_STREAK_THRESHOLD) {
797
+ const uniqueModels = new Set(ctx.config.workers.map(w => w.model));
798
+ const singleModel = uniqueModels.size === 1;
799
+ const onlyModel = [...uniqueModels][0];
800
+ const modelUnhealthy = singleModel && !ctx.healthTracker.getAllRecords().find(r => r.model === onlyModel)?.healthy;
801
+ if (singleModel && modelUnhealthy) {
802
+ if (ctx.config.enableHollowTermination) {
803
+ ctx.logDecision('early-termination', `Terminating swarm: ${ctx.hollowStreak} consecutive hollow completions on sole model ${onlyModel}`, 'Single-model swarm with unhealthy model — enableHollowTermination is on');
804
+ skipRemainingTasksInternal(ctx, `Single-model hollow streak (${ctx.hollowStreak}x on ${onlyModel})`);
805
+ }
806
+ else {
807
+ ctx.logDecision('stall-mode', `${ctx.hollowStreak} consecutive hollows on sole model ${onlyModel} — entering stall mode`, 'Will attempt model failover or simplified retry on next dispatch');
808
+ ctx.hollowStreak = 0;
809
+ }
810
+ }
811
+ }
812
+ // V7: Multi-model hollow ratio
813
+ const minDispatches = ctx.config.hollowTerminationMinDispatches ?? 8;
814
+ const threshold = ctx.config.hollowTerminationRatio ?? 0.55;
815
+ if (ctx.totalDispatches >= minDispatches) {
816
+ const ratio = ctx.totalHollows / ctx.totalDispatches;
817
+ if (ratio > threshold) {
818
+ if (ctx.config.enableHollowTermination) {
819
+ ctx.logDecision('early-termination', `Terminating swarm: hollow ratio ${(ratio * 100).toFixed(0)}% (${ctx.totalHollows}/${ctx.totalDispatches})`, `Exceeds threshold ${(threshold * 100).toFixed(0)}% after ${minDispatches}+ dispatches — enableHollowTermination is on`);
820
+ skipRemainingTasksInternal(ctx, `Hollow ratio ${(ratio * 100).toFixed(0)}% — models cannot execute tasks`);
821
+ }
822
+ else if (!recoveryState.hollowRatioWarned) {
823
+ recoveryState.hollowRatioWarned = true;
824
+ ctx.logDecision('stall-warning', `Hollow ratio ${(ratio * 100).toFixed(0)}% (${ctx.totalHollows}/${ctx.totalDispatches})`, 'High hollow rate but continuing — tasks may still recover via resilience');
825
+ }
826
+ }
827
+ }
828
+ }
829
+ /**
830
+ * Run the quality gate (LLM judge) on a task completion.
831
+ * Returns true if the task was rejected (caller should return), false if it passed.
832
+ */
833
+ async function runQualityGate(ctx, recoveryState, task, taskId, spawnResult, taskResult, model, effectiveRetries, cachedArtifactReport) {
834
+ const judgeModel = ctx.config.hierarchy?.judge?.model
835
+ ?? ctx.config.qualityGateModel ?? ctx.config.orchestratorModel;
836
+ const judgeConfig = {
837
+ model: judgeModel,
838
+ persona: ctx.config.hierarchy?.judge?.persona,
839
+ };
840
+ ctx.emit({ type: 'swarm.role.action', role: 'judge', action: 'quality-gate', model: judgeModel, taskId });
841
+ const fileArtifacts = extractFileArtifacts(ctx, task, taskResult);
842
+ const baseThreshold = ctx.config.qualityThreshold ?? 3;
843
+ const qualityThreshold = task.isFoundation ? Math.max(2, baseThreshold - 1) : baseThreshold;
844
+ const quality = await evaluateWorkerOutput(ctx.provider, judgeModel, task, taskResult, judgeConfig, qualityThreshold, (resp, purpose) => ctx.trackOrchestratorUsage(resp, purpose), fileArtifacts, ctx.config, cachedArtifactReport);
845
+ taskResult.qualityScore = quality.score;
846
+ taskResult.qualityFeedback = quality.feedback;
847
+ // F11: Foundation tasks that barely pass
848
+ if (quality.passed && task.isFoundation && quality.score <= baseThreshold - 1) {
849
+ const concreteResult = runConcreteChecks(task, taskResult);
850
+ if (!concreteResult.passed) {
851
+ quality.passed = false;
852
+ quality.feedback += ` [F11: foundation task barely passed (${quality.score}/${baseThreshold}) but concrete validation failed: ${concreteResult.issues.join('; ')}]`;
853
+ ctx.logDecision('foundation-concrete-gate', `${taskId}: foundation task scored ${quality.score} (relaxed threshold ${qualityThreshold}) but concrete checks failed — rejecting`, concreteResult.issues.join('; '));
854
+ }
855
+ }
856
+ if (!quality.passed) {
857
+ // F7: Gate error fallback
858
+ if (quality.gateError && (ctx.config.enableConcreteValidation !== false)) {
859
+ const concreteResult = runConcreteChecks(task, taskResult);
860
+ if (concreteResult.passed) {
861
+ ctx.logDecision('gate-error-fallback', `${taskId}: gate error but concrete checks passed — tentatively accepting`, quality.gateErrorMessage ?? 'unknown');
862
+ taskResult.qualityScore = quality.score;
863
+ taskResult.qualityFeedback = `${quality.feedback} [concrete validation passed — tentative accept]`;
864
+ recoveryState.perModelQualityRejections.delete(model);
865
+ return false; // passed
866
+ }
867
+ else {
868
+ ctx.logDecision('gate-error-fallback', `${taskId}: gate error AND concrete checks failed — rejecting`, `Concrete issues: ${concreteResult.issues.join('; ')}`);
869
+ ctx.qualityRejections++;
870
+ task.failureMode = 'quality';
871
+ ctx.healthTracker.recordQualityRejection(model, quality.score);
872
+ ctx.emit({ type: 'swarm.model.health', record: { model, ...getModelHealthSummary(ctx, model) } });
873
+ ctx.hollowStreak = 0;
874
+ task.retryContext = {
875
+ previousFeedback: `Gate error + concrete validation failed: ${concreteResult.issues.join('; ')}`,
876
+ previousScore: quality.score,
877
+ attempt: task.attempts,
878
+ previousModel: model,
879
+ previousFiles: taskResult.filesModified,
880
+ swarmProgress: getSwarmProgressSummary(ctx),
881
+ };
882
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, effectiveRetries);
883
+ if (canRetry) {
884
+ ctx.retries++;
885
+ }
886
+ else {
887
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
888
+ return true;
889
+ }
890
+ ctx.taskQueue.triggerCascadeSkip(taskId);
891
+ }
892
+ ctx.emit({
893
+ type: 'swarm.quality.rejected',
894
+ taskId,
895
+ score: quality.score,
896
+ feedback: quality.feedback,
897
+ artifactCount: fileArtifacts.length,
898
+ outputLength: taskResult.output.length,
899
+ preFlightReject: false,
900
+ filesOnDisk: checkArtifactsEnhanced(task, taskResult).files.filter(f => f.exists && f.sizeBytes > 0).length,
901
+ });
902
+ return true;
903
+ }
904
+ }
905
+ else if (!quality.gateError) {
906
+ // Normal quality rejection
907
+ ctx.qualityRejections++;
908
+ task.failureMode = 'quality';
909
+ ctx.healthTracker.recordQualityRejection(model, quality.score);
910
+ ctx.emit({ type: 'swarm.model.health', record: { model, ...getModelHealthSummary(ctx, model) } });
911
+ ctx.hollowStreak = 0;
912
+ // F7: Per-model circuit breaker
913
+ if (!quality.preFlightReject) {
914
+ const QUALITY_CIRCUIT_BREAKER_THRESHOLD = 5;
915
+ const modelRejections = (recoveryState.perModelQualityRejections.get(model) ?? 0) + 1;
916
+ recoveryState.perModelQualityRejections.set(model, modelRejections);
917
+ if (modelRejections >= QUALITY_CIRCUIT_BREAKER_THRESHOLD) {
918
+ recoveryState.qualityGateDisabledModels.add(model);
919
+ ctx.logDecision('quality-circuit-breaker', `Switched model ${model} to pre-flight-only mode after ${modelRejections} rejections`, 'Skipping LLM judge but keeping pre-flight checks mandatory');
920
+ }
921
+ }
922
+ task.retryContext = {
923
+ previousFeedback: quality.feedback,
924
+ previousScore: quality.score,
925
+ attempt: task.attempts,
926
+ previousModel: model,
927
+ previousFiles: taskResult.filesModified,
928
+ swarmProgress: getSwarmProgressSummary(ctx),
929
+ };
930
+ ctx.sharedContextEngine.reportFailure(taskId, {
931
+ action: task.description.slice(0, 200),
932
+ error: `Quality gate rejection (score ${quality.score}): ${quality.feedback.slice(0, 300)}`,
933
+ });
934
+ // V5: Model failover on quality rejection
935
+ if (quality.score < qualityThreshold && ctx.config.enableModelFailover && !quality.artifactAutoFail) {
936
+ const capability = getTaskTypeConfig(task.type, ctx.config).capability ?? 'code';
937
+ const alternative = selectAlternativeModel(ctx.config.workers, model, capability, ctx.healthTracker);
938
+ if (alternative) {
939
+ ctx.emit({
940
+ type: 'swarm.model.failover',
941
+ taskId,
942
+ fromModel: model,
943
+ toModel: alternative.model,
944
+ reason: `quality-score-${quality.score}`,
945
+ });
946
+ task.assignedModel = alternative.model;
947
+ ctx.logDecision('failover', `Quality failover ${taskId}: ${model} → ${alternative.model}`, `Score ${quality.score}/5`);
948
+ }
949
+ }
950
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, effectiveRetries);
951
+ if (canRetry) {
952
+ ctx.retries++;
953
+ }
954
+ else {
955
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
956
+ return true;
957
+ }
958
+ ctx.taskQueue.triggerCascadeSkip(taskId);
959
+ }
960
+ ctx.emit({
961
+ type: 'swarm.quality.rejected',
962
+ taskId,
963
+ score: quality.score,
964
+ feedback: quality.feedback,
965
+ artifactCount: fileArtifacts.length,
966
+ outputLength: taskResult.output.length,
967
+ preFlightReject: quality.preFlightReject,
968
+ filesOnDisk: checkArtifactsEnhanced(task, taskResult).files.filter(f => f.exists && f.sizeBytes > 0).length,
969
+ });
970
+ return true;
971
+ }
972
+ else {
973
+ // gateError=true but concrete validation disabled
974
+ ctx.qualityRejections++;
975
+ task.failureMode = 'quality';
976
+ ctx.hollowStreak = 0;
977
+ task.retryContext = {
978
+ previousFeedback: quality.feedback,
979
+ previousScore: quality.score,
980
+ attempt: task.attempts,
981
+ previousModel: model,
982
+ previousFiles: taskResult.filesModified,
983
+ swarmProgress: getSwarmProgressSummary(ctx),
984
+ };
985
+ const canRetry = ctx.taskQueue.markFailedWithoutCascade(taskId, effectiveRetries);
986
+ if (canRetry) {
987
+ ctx.retries++;
988
+ }
989
+ else {
990
+ if (await tryResilienceRecovery(ctx, recoveryState, task, taskId, taskResult, spawnResult)) {
991
+ return true;
992
+ }
993
+ ctx.taskQueue.triggerCascadeSkip(taskId);
994
+ }
995
+ ctx.emit({
996
+ type: 'swarm.quality.rejected',
997
+ taskId,
998
+ score: quality.score,
999
+ feedback: quality.feedback,
1000
+ artifactCount: fileArtifacts.length,
1001
+ outputLength: taskResult.output.length,
1002
+ preFlightReject: false,
1003
+ filesOnDisk: checkArtifactsEnhanced(task, taskResult).files.filter(f => f.exists && f.sizeBytes > 0).length,
1004
+ });
1005
+ return true;
1006
+ }
1007
+ }
1008
+ // Quality passed — reset per-model rejection counter
1009
+ recoveryState.perModelQualityRejections.delete(model);
1010
+ return false; // passed
1011
+ }
1012
+ /** Internal helper for skipRemainingTasks within execution context */
1013
+ function skipRemainingTasksInternal(ctx, reason) {
1014
+ for (const task of ctx.taskQueue.getAllTasks()) {
1015
+ if (task.status === 'pending' || task.status === 'ready') {
1016
+ task.status = 'skipped';
1017
+ ctx.emit({ type: 'swarm.task.skipped', taskId: task.id, reason });
1018
+ }
1019
+ }
1020
+ }
1021
+ //# sourceMappingURL=swarm-execution.js.map