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
@@ -44,6 +44,13 @@ const DOOM_LOOP_PROMPT = (tool, count) => `[System] You've called ${tool} with t
44
44
  1. Try a DIFFERENT approach or tool
45
45
  2. If blocked, explain what's preventing progress
46
46
  3. If the task is complete, say so explicitly`;
47
+ /**
48
+ * Global doom loop prompt - injected when the same tool call is repeated across multiple workers.
49
+ */
50
+ const GLOBAL_DOOM_LOOP_PROMPT = (tool, workerCount, totalCalls) => `[System] GLOBAL DOOM LOOP: ${totalCalls} calls to ${tool} across ${workerCount} workers. The entire swarm is stuck on this approach.
51
+ 1. Try a fundamentally different strategy
52
+ 2. Do NOT retry the same tool/parameters
53
+ 3. Consider whether the task goal itself needs re-evaluation`;
47
54
  /**
48
55
  * Exploration saturation prompt - gentle nudge to start making edits.
49
56
  */
@@ -62,6 +69,30 @@ Do not retry the same fix. Try a new approach.`;
62
69
  /**
63
70
  * Phase budget exploration exceeded prompt.
64
71
  */
72
+ /** Detect bash commands that are doing file write operations (write/append/redirect/heredoc). */
73
+ const BASH_FILE_WRITE_RE = /^\s*(cat|echo|printf)\b.*(?:>>?|<<)\s*/;
74
+ /** Check whether a bash command is attempting file operations that should use dedicated tools. */
75
+ function isBashFileOperation(command) {
76
+ return BASH_FILE_READ_RE.test(command) || BASH_FILE_WRITE_RE.test(command) || /heredoc|EOF/i.test(command);
77
+ }
78
+ const BASH_FAILURE_CASCADE_PROMPT = (failures, lastCommand) => {
79
+ const isFileOp = lastCommand && isBashFileOperation(lastCommand);
80
+ if (isFileOp) {
81
+ return `[System] ${failures} consecutive bash commands have failed trying to do file operations.
82
+ STOP using bash for file operations. Use the correct tool:
83
+ - To CREATE a file: write_file (not cat/echo with redirect)
84
+ - To MODIFY a file: edit_file (not sed/awk)
85
+ - To READ a file: read_file (not cat/head/tail)
86
+ Switch to the correct tool NOW.`;
87
+ }
88
+ return `[System] ${failures} consecutive bash commands have failed. STOP and:
89
+ 1. Explain what you're trying to accomplish
90
+ 2. Try a DIFFERENT approach or tool
91
+ 3. Do not run another bash command with the same pattern`;
92
+ };
93
+ const SUMMARY_LOOP_PROMPT = `[System] You've produced text-only responses without using tools. You should be DOING work, not summarizing it.
94
+ Pick the most important remaining task and start working on it NOW using your tools (write_file, edit_file, bash, etc.).
95
+ Do NOT output another status summary or task list.`;
65
96
  const EXPLORATION_BUDGET_EXCEEDED_PROMPT = (pct) => `[System] You've spent ${pct}% of your iterations in exploration. Start making edits NOW.
66
97
  Do not read more files. Use what you know to make the fix.`;
67
98
  /**
@@ -69,6 +100,41 @@ Do not read more files. Use what you know to make the fix.`;
69
100
  */
70
101
  const VERIFICATION_RESERVE_PROMPT = `[System] You are running low on iterations. Run your tests NOW to verify your changes.
71
102
  Do not make more edits until you've confirmed whether the current fix works.`;
103
+ const BUDGET_ADVISORY_PROMPT = (reason) => `[System] Budget advisory (${reason}) detected. Continue execution and focus on concrete tool actions to complete the task.`;
104
+ /**
105
+ * Extract success and output from a bash tool result.
106
+ * In production, bash results are objects `{ success, output, metadata }`.
107
+ * Tests may pass strings directly. This normalizes both.
108
+ */
109
+ export function extractBashResult(result) {
110
+ if (result && typeof result === 'object') {
111
+ const obj = result;
112
+ return {
113
+ success: obj.success !== false,
114
+ output: typeof obj.output === 'string' ? obj.output : '',
115
+ };
116
+ }
117
+ if (typeof result === 'string') {
118
+ return { success: true, output: result };
119
+ }
120
+ return { success: true, output: '' };
121
+ }
122
+ /**
123
+ * Regex for common bash file-read commands (simple, no pipes/redirects).
124
+ * Captures the file path for normalized doom loop fingerprinting.
125
+ */
126
+ const BASH_FILE_READ_RE = /^\s*(cat|head|tail|wc|less|more|file|stat|md5sum|sha256sum)\b(?:\s+-[^\s]+)*\s+((?:\/|\.\/|\.\.\/)[\w.\/\-@]+|[\w.\-@][\w.\/\-@]*)\s*$/;
127
+ /**
128
+ * Extract the file target from a simple bash file-read command.
129
+ * Returns null for complex commands (pipes, redirects, non-file-read commands).
130
+ * Used to normalize doom loop fingerprints across cat/head/tail/wc targeting the same file.
131
+ */
132
+ export function extractBashFileTarget(command) {
133
+ if (/[|;&<>]/.test(command))
134
+ return null; // pipes/redirects = complex, skip
135
+ const match = command.match(BASH_FILE_READ_RE);
136
+ return match ? match[2] : null;
137
+ }
72
138
  /**
73
139
  * Primary argument keys that identify the *target* of a tool call.
74
140
  * Used for fuzzy doom loop detection — ignoring secondary/optional args.
@@ -83,6 +149,13 @@ const PRIMARY_KEYS = ['path', 'file_path', 'command', 'pattern', 'query', 'url',
83
149
  export function computeToolFingerprint(toolName, argsStr) {
84
150
  try {
85
151
  const args = JSON.parse(argsStr || '{}');
152
+ // W1: Normalize bash file-read commands so cat/head/tail/wc targeting the same file
153
+ // produce the same fingerprint, triggering doom loop detection.
154
+ if (toolName === 'bash' && typeof args.command === 'string') {
155
+ const fileTarget = extractBashFileTarget(args.command);
156
+ if (fileTarget)
157
+ return `bash:file_read:${fileTarget}`;
158
+ }
86
159
  const primaryArgs = {};
87
160
  for (const key of PRIMARY_KEYS) {
88
161
  if (key in args) {
@@ -115,8 +188,17 @@ export class ExecutionEconomicsManager {
115
188
  pauseStart = null;
116
189
  listeners = [];
117
190
  extensionHandler;
118
- constructor(budget) {
191
+ // Shared economics state for cross-worker doom loop aggregation
192
+ sharedEconomics;
193
+ workerId;
194
+ // Adaptive budget: stores original maxIterations for reversible reduction
195
+ originalMaxIterations = null;
196
+ constructor(budget, sharedEconomics, workerId) {
197
+ this.sharedEconomics = sharedEconomics ?? null;
198
+ this.workerId = workerId ?? 'root';
199
+ const tuning = budget?.tuning;
119
200
  this.budget = {
201
+ enforcementMode: budget?.enforcementMode ?? 'strict',
120
202
  // Hard limits
121
203
  maxTokens: budget?.maxTokens ?? 200000,
122
204
  maxCost: budget?.maxCost ?? 1.00,
@@ -128,6 +210,8 @@ export class ExecutionEconomicsManager {
128
210
  // Iteration guidance
129
211
  targetIterations: budget?.targetIterations ?? 20,
130
212
  maxIterations: budget?.maxIterations ?? 100,
213
+ // Tuning
214
+ tuning,
131
215
  };
132
216
  this.usage = {
133
217
  tokens: 0,
@@ -147,13 +231,13 @@ export class ExecutionEconomicsManager {
147
231
  lastMeaningfulProgress: Date.now(),
148
232
  stuckCount: 0,
149
233
  };
150
- // Initialize doom loop detection state
234
+ // Initialize doom loop detection state (thresholds configurable via tuning)
151
235
  this.loopState = {
152
236
  doomLoopDetected: false,
153
237
  lastTool: null,
154
238
  consecutiveCount: 0,
155
- threshold: 3,
156
- fuzzyThreshold: 4,
239
+ threshold: tuning?.doomLoopThreshold ?? 3,
240
+ fuzzyThreshold: tuning?.doomLoopFuzzyThreshold ?? (tuning?.doomLoopThreshold ? tuning.doomLoopThreshold + 1 : 4),
157
241
  lastWarningTime: 0,
158
242
  };
159
243
  // Initialize phase tracking state
@@ -170,6 +254,8 @@ export class ExecutionEconomicsManager {
170
254
  lastTestPassed: null,
171
255
  consecutiveTestFailures: 0,
172
256
  inTestFixCycle: false,
257
+ consecutiveBashFailures: 0,
258
+ consecutiveTextOnlyTurns: 0,
173
259
  };
174
260
  this.startTime = Date.now();
175
261
  }
@@ -235,12 +321,21 @@ export class ExecutionEconomicsManager {
235
321
  // Update duration
236
322
  this.usage.duration = this.getEffectiveDuration();
237
323
  }
324
+ /**
325
+ * Record a text-only turn (LLM response with no tool calls).
326
+ * Increments the consecutive text-only turn counter for summary-loop detection.
327
+ */
328
+ recordTextOnlyTurn() {
329
+ this.phaseState.consecutiveTextOnlyTurns++;
330
+ }
238
331
  /**
239
332
  * Record a tool call for progress tracking and loop detection.
240
333
  */
241
334
  recordToolCall(toolName, args, _result) {
242
335
  this.usage.toolCalls++;
243
336
  this.usage.iterations++;
337
+ // Any tool call resets the text-only turn counter
338
+ this.phaseState.consecutiveTextOnlyTurns = 0;
244
339
  const now = Date.now();
245
340
  // Track for loop detection (stableStringify ensures consistent ordering for comparison)
246
341
  const argsStr = stableStringify(args);
@@ -253,6 +348,11 @@ export class ExecutionEconomicsManager {
253
348
  // DOOM LOOP DETECTION (OpenCode pattern)
254
349
  // =========================================================================
255
350
  this.updateDoomLoopState(toolName, argsStr);
351
+ // Report to shared economics for cross-worker doom loop aggregation
352
+ if (this.sharedEconomics) {
353
+ const fingerprint = computeToolFingerprint(toolName, argsStr);
354
+ this.sharedEconomics.recordToolCall(this.workerId, fingerprint);
355
+ }
256
356
  // =========================================================================
257
357
  // PHASE TRACKING
258
358
  // =========================================================================
@@ -293,6 +393,17 @@ export class ExecutionEconomicsManager {
293
393
  this.progress.commandsRun.push(command);
294
394
  this.progress.lastMeaningfulProgress = now;
295
395
  this.progress.stuckCount = 0;
396
+ // Extract result from bash tool output (object or string)
397
+ const bashResult = extractBashResult(_result);
398
+ // Track consecutive bash failures (any bash command, not just tests)
399
+ if (_result !== undefined) {
400
+ if (!bashResult.success) {
401
+ this.phaseState.consecutiveBashFailures++;
402
+ }
403
+ else {
404
+ this.phaseState.consecutiveBashFailures = 0;
405
+ }
406
+ }
296
407
  // Detect test runs and track outcomes
297
408
  if (command.includes('test') || command.includes('pytest') || command.includes('npm test') || command.includes('jest')) {
298
409
  this.phaseState.testsRun++;
@@ -300,10 +411,9 @@ export class ExecutionEconomicsManager {
300
411
  if (this.phaseState.phase === 'acting' && this.phaseState.filesModified.size > 0) {
301
412
  this.transitionPhase('verifying', 'Tests run after edits');
302
413
  }
303
- // Track test pass/fail from result if available
304
- if (_result !== undefined) {
305
- const resultStr = typeof _result === 'string' ? _result : '';
306
- this.parseTestOutcome(command, resultStr);
414
+ // Fix: extract output from result object, not treat as string
415
+ if (bashResult.output) {
416
+ this.parseTestOutcome(command, bashResult.output);
307
417
  }
308
418
  }
309
419
  }
@@ -416,8 +526,9 @@ export class ExecutionEconomicsManager {
416
526
  this.phaseState.shouldTransition = false;
417
527
  return;
418
528
  }
419
- // After reading 10+ unique files without edits, suggest transition
420
- if (uniqueFilesRead.size >= 10 && filesModified.size === 0) {
529
+ // After N+ unique files without edits, suggest transition (configurable, default: 10)
530
+ const fileThreshold = this.budget.tuning?.explorationFileThreshold ?? 10;
531
+ if (uniqueFilesRead.size >= fileThreshold && filesModified.size === 0) {
421
532
  this.phaseState.shouldTransition = true;
422
533
  this.emit({
423
534
  type: 'exploration.saturation',
@@ -426,8 +537,9 @@ export class ExecutionEconomicsManager {
426
537
  });
427
538
  return;
428
539
  }
429
- // After 5+ iterations in exploration with diminishing returns (< 2 new files)
430
- if (iterationsInPhase >= 5 && recentNewFiles < 2 && filesModified.size === 0) {
540
+ // After N+ iterations in exploration with diminishing returns (configurable, default: 15)
541
+ const iterThreshold = this.budget.tuning?.explorationIterThreshold ?? 15;
542
+ if (iterationsInPhase >= iterThreshold && recentNewFiles < 2 && filesModified.size === 0) {
431
543
  this.phaseState.shouldTransition = true;
432
544
  this.emit({
433
545
  type: 'exploration.saturation',
@@ -443,9 +555,22 @@ export class ExecutionEconomicsManager {
443
555
  */
444
556
  checkBudget() {
445
557
  this.usage.duration = this.getEffectiveDuration();
558
+ const strictBudgetEnforcement = (this.budget.enforcementMode ?? 'strict') === 'strict';
446
559
  // Check hard limits first
447
560
  if (this.usage.tokens >= this.budget.maxTokens) {
448
561
  this.emit({ type: 'budget.exceeded', budgetType: 'tokens', limit: this.budget.maxTokens, actual: this.usage.tokens });
562
+ if (!strictBudgetEnforcement) {
563
+ return {
564
+ canContinue: true,
565
+ reason: `Token budget exceeded (${this.usage.tokens.toLocaleString()} / ${this.budget.maxTokens.toLocaleString()})`,
566
+ budgetType: 'tokens',
567
+ isHardLimit: false,
568
+ isSoftLimit: true,
569
+ percentUsed: (this.usage.tokens / this.budget.maxTokens) * 100,
570
+ suggestedAction: 'warn',
571
+ injectedPrompt: BUDGET_ADVISORY_PROMPT('tokens'),
572
+ };
573
+ }
449
574
  return {
450
575
  canContinue: false,
451
576
  reason: `Token budget exceeded (${this.usage.tokens.toLocaleString()} / ${this.budget.maxTokens.toLocaleString()})`,
@@ -458,6 +583,18 @@ export class ExecutionEconomicsManager {
458
583
  }
459
584
  if (this.usage.cost >= this.budget.maxCost) {
460
585
  this.emit({ type: 'budget.exceeded', budgetType: 'cost', limit: this.budget.maxCost, actual: this.usage.cost });
586
+ if (!strictBudgetEnforcement) {
587
+ return {
588
+ canContinue: true,
589
+ reason: `Cost budget exceeded ($${this.usage.cost.toFixed(2)} / $${this.budget.maxCost.toFixed(2)})`,
590
+ budgetType: 'cost',
591
+ isHardLimit: false,
592
+ isSoftLimit: true,
593
+ percentUsed: (this.usage.cost / this.budget.maxCost) * 100,
594
+ suggestedAction: 'warn',
595
+ injectedPrompt: BUDGET_ADVISORY_PROMPT('cost'),
596
+ };
597
+ }
461
598
  return {
462
599
  canContinue: false,
463
600
  reason: `Cost budget exceeded ($${this.usage.cost.toFixed(2)} / $${this.budget.maxCost.toFixed(2)})`,
@@ -470,6 +607,18 @@ export class ExecutionEconomicsManager {
470
607
  }
471
608
  if (this.usage.duration >= this.budget.maxDuration) {
472
609
  this.emit({ type: 'budget.exceeded', budgetType: 'duration', limit: this.budget.maxDuration, actual: this.usage.duration });
610
+ if (!strictBudgetEnforcement) {
611
+ return {
612
+ canContinue: true,
613
+ reason: `Duration limit exceeded (${Math.round(this.usage.duration / 1000)}s / ${Math.round(this.budget.maxDuration / 1000)}s)`,
614
+ budgetType: 'duration',
615
+ isHardLimit: false,
616
+ isSoftLimit: true,
617
+ percentUsed: (this.usage.duration / this.budget.maxDuration) * 100,
618
+ suggestedAction: 'warn',
619
+ injectedPrompt: BUDGET_ADVISORY_PROMPT('duration'),
620
+ };
621
+ }
473
622
  return {
474
623
  canContinue: false,
475
624
  reason: `Duration limit exceeded (${Math.round(this.usage.duration / 1000)}s / ${Math.round(this.budget.maxDuration / 1000)}s)`,
@@ -480,10 +629,13 @@ export class ExecutionEconomicsManager {
480
629
  suggestedAction: 'stop',
481
630
  };
482
631
  }
483
- // Max iterations reached - allow one more turn for summary (forceTextOnly)
632
+ // Max iterations reached allow exactly ONE more turn for summary, then terminate.
633
+ // First time at maxIterations: canContinue=true + forceTextOnly for a clean summary.
634
+ // Beyond maxIterations: canContinue=false to stop the loop.
484
635
  if (this.usage.iterations >= this.budget.maxIterations) {
636
+ const isFirstOverage = this.usage.iterations === this.budget.maxIterations;
485
637
  return {
486
- canContinue: true, // Allow one more turn for summary
638
+ canContinue: isFirstOverage, // Only allow one summary turn
487
639
  reason: `Maximum iterations reached (${this.usage.iterations} / ${this.budget.maxIterations})`,
488
640
  budgetType: 'iterations',
489
641
  isHardLimit: true,
@@ -495,6 +647,50 @@ export class ExecutionEconomicsManager {
495
647
  };
496
648
  }
497
649
  // =========================================================================
650
+ // ZERO PROGRESS DETECTION — nudge workers making no tool calls (D1)
651
+ // Raised threshold to 10 (from 5) to give agents more time to plan.
652
+ // No longer forces text-only — instead injects a strong nudge while
653
+ // still allowing tool calls so the agent can recover.
654
+ // =========================================================================
655
+ const zeroProgressThreshold = this.budget.tuning?.zeroProgressThreshold ?? 10;
656
+ if (this.usage.iterations >= zeroProgressThreshold && this.usage.toolCalls === 0) {
657
+ // Only force text-only after 2x the threshold (complete stall)
658
+ const isCompleteStall = this.usage.iterations >= zeroProgressThreshold * 2;
659
+ return {
660
+ canContinue: true,
661
+ reason: `Zero tool calls in ${this.usage.iterations} iterations`,
662
+ budgetType: 'iterations',
663
+ isHardLimit: false,
664
+ isSoftLimit: true,
665
+ percentUsed: (this.usage.iterations / this.budget.maxIterations) * 100,
666
+ suggestedAction: isCompleteStall ? 'stop' : 'warn',
667
+ forceTextOnly: isCompleteStall,
668
+ injectedPrompt: `[System] WARNING: You have completed ${this.usage.iterations} iterations without making a single tool call. ` +
669
+ `You MUST use your tools (read_file, write_file, grep, bash, etc.) to accomplish your task. ` +
670
+ `Start by reading a relevant file or running a command NOW.` +
671
+ (isCompleteStall ? ` This is your LAST chance — respond with a summary if you cannot proceed.` : ''),
672
+ };
673
+ }
674
+ // =========================================================================
675
+ // ADAPTIVE ITERATION BUDGET — reversible reduction at checkpoint (D4)
676
+ // Stores original maxIterations so it can be restored if tools resume.
677
+ // =========================================================================
678
+ const checkpoint = this.budget.tuning?.progressCheckpoint ?? 10;
679
+ if (this.usage.iterations === checkpoint && this.usage.toolCalls === 0) {
680
+ if (!this.originalMaxIterations) {
681
+ this.originalMaxIterations = this.budget.maxIterations;
682
+ }
683
+ const reducedMax = checkpoint + 5; // give 5 more iterations (up from 3)
684
+ if (this.budget.maxIterations > reducedMax) {
685
+ this.budget.maxIterations = reducedMax;
686
+ }
687
+ }
688
+ // Restore original maxIterations if tools start being used after reduction
689
+ if (this.originalMaxIterations && this.usage.toolCalls > 0 && this.budget.maxIterations < this.originalMaxIterations) {
690
+ this.budget.maxIterations = this.originalMaxIterations;
691
+ this.originalMaxIterations = null;
692
+ }
693
+ // =========================================================================
498
694
  // DOOM LOOP DETECTION - Strong intervention
499
695
  // =========================================================================
500
696
  if (this.loopState.doomLoopDetected) {
@@ -510,6 +706,26 @@ export class ExecutionEconomicsManager {
510
706
  };
511
707
  }
512
708
  // =========================================================================
709
+ // GLOBAL DOOM LOOP DETECTION - Cross-worker stuck pattern
710
+ // =========================================================================
711
+ if (this.sharedEconomics && this.progress.recentToolCalls.length > 0) {
712
+ const lastCall = this.progress.recentToolCalls[this.progress.recentToolCalls.length - 1];
713
+ const fingerprint = computeToolFingerprint(lastCall.tool, lastCall.args);
714
+ if (this.sharedEconomics.isGlobalDoomLoop(fingerprint)) {
715
+ const info = this.sharedEconomics.getGlobalLoopInfo(fingerprint);
716
+ return {
717
+ canContinue: true,
718
+ reason: `Global doom loop: ${lastCall.tool} repeated across ${info?.workerCount ?? 0} workers`,
719
+ budgetType: 'iterations',
720
+ isHardLimit: false,
721
+ isSoftLimit: true,
722
+ percentUsed: (this.usage.iterations / this.budget.targetIterations) * 100,
723
+ suggestedAction: 'warn',
724
+ injectedPrompt: GLOBAL_DOOM_LOOP_PROMPT(lastCall.tool, info?.workerCount ?? 0, info?.count ?? 0),
725
+ };
726
+ }
727
+ }
728
+ // =========================================================================
513
729
  // EXPLORATION SATURATION - Gentle nudge
514
730
  // =========================================================================
515
731
  if (this.phaseState.shouldTransition) {
@@ -540,6 +756,54 @@ export class ExecutionEconomicsManager {
540
756
  };
541
757
  }
542
758
  // =========================================================================
759
+ // BASH FAILURE CASCADE - Strong intervention after 3+ consecutive failures
760
+ // =========================================================================
761
+ if (this.phaseState.consecutiveBashFailures >= 3) {
762
+ // Extract last bash command for tool-aware remediation
763
+ let lastBashCommand;
764
+ for (let i = this.progress.recentToolCalls.length - 1; i >= 0; i--) {
765
+ if (this.progress.recentToolCalls[i].tool === 'bash') {
766
+ try {
767
+ const parsed = JSON.parse(this.progress.recentToolCalls[i].args);
768
+ lastBashCommand = parsed.command;
769
+ }
770
+ catch { /* ignore parse errors */ }
771
+ break;
772
+ }
773
+ }
774
+ return {
775
+ canContinue: true,
776
+ reason: `${this.phaseState.consecutiveBashFailures} consecutive bash failures`,
777
+ budgetType: 'iterations',
778
+ isHardLimit: false,
779
+ isSoftLimit: true,
780
+ percentUsed: (this.usage.iterations / this.budget.targetIterations) * 100,
781
+ suggestedAction: 'warn',
782
+ injectedPrompt: BASH_FAILURE_CASCADE_PROMPT(this.phaseState.consecutiveBashFailures, lastBashCommand),
783
+ };
784
+ }
785
+ // =========================================================================
786
+ // SUMMARY LOOP DETECTION - Nudge after 2+ consecutive text-only turns
787
+ // Skip when close to budget limit — the agent can't "start working" if
788
+ // forceTextOnly would be set on the next check (contradictory nudge).
789
+ // =========================================================================
790
+ if (this.phaseState.consecutiveTextOnlyTurns >= 2) {
791
+ const nearBudgetLimit = this.usage.iterations >= this.budget.maxIterations - 1;
792
+ if (!nearBudgetLimit) {
793
+ return {
794
+ canContinue: true,
795
+ reason: `${this.phaseState.consecutiveTextOnlyTurns} consecutive text-only turns (summary loop)`,
796
+ budgetType: 'iterations',
797
+ isHardLimit: false,
798
+ isSoftLimit: true,
799
+ percentUsed: (this.usage.iterations / this.budget.targetIterations) * 100,
800
+ suggestedAction: 'warn',
801
+ injectedPrompt: SUMMARY_LOOP_PROMPT,
802
+ };
803
+ }
804
+ // Near budget limit: skip nudge, let MAX_STEPS_PROMPT handle it next turn
805
+ }
806
+ // =========================================================================
543
807
  // PHASE-AWARE BUDGET ALLOCATION (opt-in, used in eval mode)
544
808
  // =========================================================================
545
809
  if (this.phaseBudget?.enabled) {
@@ -716,7 +980,9 @@ export class ExecutionEconomicsManager {
716
980
  const budget = this.budget;
717
981
  const tokenPct = Math.round((usage.tokens / budget.maxTokens) * 100);
718
982
  const remainingTokens = budget.maxTokens - usage.tokens;
719
- const remainingSec = Math.max(0, Math.round((budget.maxDuration - usage.duration) / 1000));
983
+ const remainingSec = budget.maxDuration === Infinity
984
+ ? Infinity
985
+ : Math.max(0, Math.round((budget.maxDuration - usage.duration) / 1000));
720
986
  // Determine urgency level
721
987
  let urgency = '';
722
988
  if (tokenPct >= 90) {
@@ -725,7 +991,8 @@ export class ExecutionEconomicsManager {
725
991
  else if (tokenPct >= 70) {
726
992
  urgency = '⚡ WARNING: ';
727
993
  }
728
- return `${urgency}Budget: ${usage.tokens.toLocaleString()}/${budget.maxTokens.toLocaleString()} tokens (${tokenPct}%), ~${remainingSec}s remaining. ${tokenPct >= 70 ? 'Wrap up soon!' : ''}`.trim();
994
+ const timeStr = remainingSec === Infinity ? 'no time limit' : `~${remainingSec}s remaining`;
995
+ return `${urgency}Budget: ${usage.tokens.toLocaleString()}/${budget.maxTokens.toLocaleString()} tokens (${tokenPct}%), ${timeStr}. ${tokenPct >= 70 ? 'Wrap up soon!' : ''}`.trim();
729
996
  }
730
997
  /**
731
998
  * Check if approaching budget limit (for proactive warnings).
@@ -755,6 +1022,12 @@ export class ExecutionEconomicsManager {
755
1022
  stuckCount: this.progress.stuckCount,
756
1023
  };
757
1024
  }
1025
+ /**
1026
+ * Get actual file paths modified during this session.
1027
+ */
1028
+ getModifiedFilePaths() {
1029
+ return [...this.progress.filesModified];
1030
+ }
758
1031
  /**
759
1032
  * Get doom loop detection state.
760
1033
  */
@@ -776,6 +1049,7 @@ export class ExecutionEconomicsManager {
776
1049
  lastTestPassed: this.phaseState.lastTestPassed,
777
1050
  consecutiveTestFailures: this.phaseState.consecutiveTestFailures,
778
1051
  inTestFixCycle: this.phaseState.inTestFixCycle,
1052
+ consecutiveBashFailures: this.phaseState.consecutiveBashFailures,
779
1053
  };
780
1054
  }
781
1055
  /**
@@ -811,13 +1085,14 @@ export class ExecutionEconomicsManager {
811
1085
  lastMeaningfulProgress: Date.now(),
812
1086
  stuckCount: 0,
813
1087
  };
814
- // Reset loop detection state
1088
+ // Reset loop detection state (preserve tuning thresholds)
1089
+ const tuning = this.budget.tuning;
815
1090
  this.loopState = {
816
1091
  doomLoopDetected: false,
817
1092
  lastTool: null,
818
1093
  consecutiveCount: 0,
819
- threshold: 3,
820
- fuzzyThreshold: 4,
1094
+ threshold: tuning?.doomLoopThreshold ?? 3,
1095
+ fuzzyThreshold: tuning?.doomLoopFuzzyThreshold ?? (tuning?.doomLoopThreshold ? tuning.doomLoopThreshold + 1 : 4),
821
1096
  lastWarningTime: 0,
822
1097
  };
823
1098
  // Reset phase tracking state
@@ -834,10 +1109,13 @@ export class ExecutionEconomicsManager {
834
1109
  lastTestPassed: null,
835
1110
  consecutiveTestFailures: 0,
836
1111
  inTestFixCycle: false,
1112
+ consecutiveBashFailures: 0,
1113
+ consecutiveTextOnlyTurns: 0,
837
1114
  };
838
1115
  this.startTime = Date.now();
839
1116
  this.pausedDuration = 0;
840
1117
  this.pauseStart = null;
1118
+ this.originalMaxIterations = null;
841
1119
  }
842
1120
  // -------------------------------------------------------------------------
843
1121
  // PRIVATE METHODS
@@ -938,13 +1216,13 @@ export const STANDARD_BUDGET = {
938
1216
  * and other parallel subagents.
939
1217
  */
940
1218
  export const SUBAGENT_BUDGET = {
941
- maxTokens: 150000, // 150k tokens (research agents need more room)
942
- softTokenLimit: 100000, // Warn at 100k
943
- maxCost: 0.50, // Match standard budget
944
- maxDuration: 360000, // 6 minutes
945
- softDurationLimit: 300000, // Warn at 5 minutes
946
- targetIterations: 20,
947
- maxIterations: 40,
1219
+ maxTokens: 250000, // 250k tokens coders need room for explore + code
1220
+ softTokenLimit: 180000, // Warn at 180k
1221
+ maxCost: 0.75, // Increased ceiling for heavier workloads
1222
+ maxDuration: 480000, // 8 minutes
1223
+ softDurationLimit: 420000, // Warn at 7 minutes
1224
+ targetIterations: 30,
1225
+ maxIterations: 60,
948
1226
  };
949
1227
  /**
950
1228
  * Large task budget - for complex multi-step tasks.
@@ -956,6 +1234,23 @@ export const LARGE_BUDGET = {
956
1234
  targetIterations: 50,
957
1235
  maxIterations: 200,
958
1236
  };
1237
+ /**
1238
+ * TUI root agent budget - no time limit, high iteration cap.
1239
+ * The TUI root agent must be able to run as long as needed (swarm tasks,
1240
+ * multi-step workflows). Duration is effectively unlimited; token/cost
1241
+ * limits still apply as a safety net.
1242
+ */
1243
+ export const TUI_ROOT_BUDGET = {
1244
+ enforcementMode: 'doomloop_only',
1245
+ maxTokens: 500000,
1246
+ softTokenLimit: 400000,
1247
+ maxCost: 5.00,
1248
+ softCostLimit: 4.00,
1249
+ maxDuration: Infinity, // No time limit — run as long as tasks remain
1250
+ softDurationLimit: Infinity,
1251
+ targetIterations: 100,
1252
+ maxIterations: 500,
1253
+ };
959
1254
  /**
960
1255
  * Unlimited budget - no limits (use with caution).
961
1256
  */
@@ -971,13 +1266,13 @@ export const UNLIMITED_BUDGET = {
971
1266
  * Each worker gets a small slice of the total swarm budget.
972
1267
  */
973
1268
  export const SWARM_WORKER_BUDGET = {
974
- maxTokens: 20000,
975
- softTokenLimit: 15000,
976
- maxCost: 0.05,
977
- maxDuration: 120000, // 2 minutes
978
- softDurationLimit: 90000, // Warn at 90s
979
- targetIterations: 10,
980
- maxIterations: 15,
1269
+ maxTokens: 30000,
1270
+ softTokenLimit: 25000,
1271
+ maxCost: 0.08,
1272
+ maxDuration: 180000, // 3 minutes
1273
+ softDurationLimit: 150000, // Warn at 2.5 min
1274
+ targetIterations: 15,
1275
+ maxIterations: 25,
981
1276
  };
982
1277
  /**
983
1278
  * Swarm orchestrator budget - moderate budget for decomposition and quality gates.