@pentoshi/clai 3.6.0 → 3.7.3

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 (322) hide show
  1. package/dist/agent/compaction-summary.d.ts +17 -0
  2. package/dist/agent/compaction-summary.js +64 -0
  3. package/dist/agent/compaction-summary.js.map +1 -0
  4. package/dist/agent/confirm-port.d.ts +3 -1
  5. package/dist/agent/confirm-port.js +5 -1
  6. package/dist/agent/confirm-port.js.map +1 -1
  7. package/dist/agent/context-manager.js +45 -22
  8. package/dist/agent/context-manager.js.map +1 -1
  9. package/dist/agent/events.d.ts +6 -0
  10. package/dist/agent/evidence-governor.d.ts +37 -0
  11. package/dist/agent/evidence-governor.js +70 -0
  12. package/dist/agent/evidence-governor.js.map +1 -0
  13. package/dist/agent/loop-guard.d.ts +29 -11
  14. package/dist/agent/loop-guard.js +93 -39
  15. package/dist/agent/loop-guard.js.map +1 -1
  16. package/dist/agent/must-continue.d.ts +56 -0
  17. package/dist/agent/must-continue.js +240 -0
  18. package/dist/agent/must-continue.js.map +1 -0
  19. package/dist/agent/outcomes.d.ts +101 -0
  20. package/dist/agent/outcomes.js +359 -0
  21. package/dist/agent/outcomes.js.map +1 -0
  22. package/dist/agent/plan-decision.d.ts +33 -0
  23. package/dist/agent/plan-decision.js +104 -0
  24. package/dist/agent/plan-decision.js.map +1 -0
  25. package/dist/agent/plan-tool.d.ts +12 -0
  26. package/dist/agent/plan-tool.js +312 -104
  27. package/dist/agent/plan-tool.js.map +1 -1
  28. package/dist/agent/project-root.js +3 -0
  29. package/dist/agent/project-root.js.map +1 -1
  30. package/dist/agent/prompt-composer.d.ts +21 -0
  31. package/dist/agent/prompt-composer.js +46 -0
  32. package/dist/agent/prompt-composer.js.map +1 -0
  33. package/dist/agent/runner.d.ts +11 -1
  34. package/dist/agent/runner.js +1226 -971
  35. package/dist/agent/runner.js.map +1 -1
  36. package/dist/agent/scope-context.d.ts +3 -0
  37. package/dist/agent/scope-context.js +24 -0
  38. package/dist/agent/scope-context.js.map +1 -0
  39. package/dist/agent/scratch-write.d.ts +4 -0
  40. package/dist/agent/scratch-write.js +54 -0
  41. package/dist/agent/scratch-write.js.map +1 -0
  42. package/dist/agent/session-policy.d.ts +7 -0
  43. package/dist/agent/session-policy.js +61 -0
  44. package/dist/agent/session-policy.js.map +1 -1
  45. package/dist/agent/session-state.d.ts +41 -0
  46. package/dist/agent/session-state.js +107 -0
  47. package/dist/agent/session-state.js.map +1 -0
  48. package/dist/agent/step-budget.d.ts +14 -0
  49. package/dist/agent/step-budget.js +26 -0
  50. package/dist/agent/step-budget.js.map +1 -0
  51. package/dist/agent/task-analyzer.d.ts +12 -3
  52. package/dist/agent/task-analyzer.js +263 -23
  53. package/dist/agent/task-analyzer.js.map +1 -1
  54. package/dist/agent/task-evidence.d.ts +111 -29
  55. package/dist/agent/task-evidence.js +519 -91
  56. package/dist/agent/task-evidence.js.map +1 -1
  57. package/dist/agent/task-plan.d.ts +57 -0
  58. package/dist/agent/task-plan.js +147 -1
  59. package/dist/agent/task-plan.js.map +1 -1
  60. package/dist/agent/tool-call-parser.d.ts +4 -12
  61. package/dist/agent/tool-call-parser.js +34 -67
  62. package/dist/agent/tool-call-parser.js.map +1 -1
  63. package/dist/agent/tool-history.d.ts +7 -0
  64. package/dist/agent/tool-history.js +50 -0
  65. package/dist/agent/tool-history.js.map +1 -1
  66. package/dist/agent/tool-output-formatting.d.ts +13 -1
  67. package/dist/agent/tool-output-formatting.js +75 -22
  68. package/dist/agent/tool-output-formatting.js.map +1 -1
  69. package/dist/agent/turn-outcome.d.ts +11 -0
  70. package/dist/agent/turn-outcome.js +17 -0
  71. package/dist/agent/turn-outcome.js.map +1 -0
  72. package/dist/agent/turn-state.d.ts +11 -0
  73. package/dist/agent/turn-state.js +28 -0
  74. package/dist/agent/turn-state.js.map +1 -0
  75. package/dist/agent/workspace-orient.d.ts +11 -0
  76. package/dist/agent/workspace-orient.js +103 -12
  77. package/dist/agent/workspace-orient.js.map +1 -1
  78. package/dist/app/adapters/agent-event-adapter.d.ts +2 -13
  79. package/dist/app/adapters/agent-event-adapter.js +63 -25
  80. package/dist/app/adapters/agent-event-adapter.js.map +1 -1
  81. package/dist/app/adapters/current-agent-adapter.d.ts +0 -5
  82. package/dist/app/adapters/current-agent-adapter.js +4 -7
  83. package/dist/app/adapters/current-agent-adapter.js.map +1 -1
  84. package/dist/app/adapters/current-jobs-adapter.js +1 -0
  85. package/dist/app/adapters/current-jobs-adapter.js.map +1 -1
  86. package/dist/app/adapters/current-terminal-adapter.d.ts +0 -7
  87. package/dist/app/adapters/current-terminal-adapter.js +0 -7
  88. package/dist/app/adapters/current-terminal-adapter.js.map +1 -1
  89. package/dist/app/adapters/current-updates-adapter.d.ts +0 -5
  90. package/dist/app/adapters/current-updates-adapter.js +0 -5
  91. package/dist/app/adapters/current-updates-adapter.js.map +1 -1
  92. package/dist/app/adapters/in-memory-clipboard-adapter.d.ts +0 -5
  93. package/dist/app/adapters/in-memory-clipboard-adapter.js +0 -5
  94. package/dist/app/adapters/in-memory-clipboard-adapter.js.map +1 -1
  95. package/dist/app/commands/command.d.ts +0 -5
  96. package/dist/app/commands/command.js.map +1 -1
  97. package/dist/app/commands/registry.d.ts +0 -14
  98. package/dist/app/commands/registry.js +0 -20
  99. package/dist/app/commands/registry.js.map +1 -1
  100. package/dist/app/controllers/disposable.d.ts +0 -5
  101. package/dist/app/controllers/disposable.js +0 -5
  102. package/dist/app/controllers/disposable.js.map +1 -1
  103. package/dist/app/controllers/job-controller.d.ts +1 -5
  104. package/dist/app/controllers/job-controller.js +0 -4
  105. package/dist/app/controllers/job-controller.js.map +1 -1
  106. package/dist/app/controllers/plan-controller.d.ts +5 -8
  107. package/dist/app/controllers/plan-controller.js +30 -12
  108. package/dist/app/controllers/plan-controller.js.map +1 -1
  109. package/dist/app/controllers/session-controller.d.ts +17 -32
  110. package/dist/app/controllers/session-controller.js +56 -35
  111. package/dist/app/controllers/session-controller.js.map +1 -1
  112. package/dist/app/controllers/turn-controller.d.ts +2 -6
  113. package/dist/app/controllers/turn-controller.js +8 -8
  114. package/dist/app/controllers/turn-controller.js.map +1 -1
  115. package/dist/app/events/app-event.d.ts +4 -7
  116. package/dist/app/events/app-event.js +0 -6
  117. package/dist/app/events/app-event.js.map +1 -1
  118. package/dist/app/events/event-buffer.d.ts +6 -17
  119. package/dist/app/events/event-buffer.js +27 -24
  120. package/dist/app/events/event-buffer.js.map +1 -1
  121. package/dist/app/events/sequencer.d.ts +0 -9
  122. package/dist/app/events/sequencer.js +0 -4
  123. package/dist/app/events/sequencer.js.map +1 -1
  124. package/dist/app/ports/agent-port.d.ts +13 -3
  125. package/dist/app/ports/clipboard-port.d.ts +0 -5
  126. package/dist/app/ports/confirm-port.d.ts +0 -7
  127. package/dist/app/ports/jobs-port.d.ts +2 -5
  128. package/dist/app/ports/persistence-port.d.ts +0 -4
  129. package/dist/app/ports/secret-port.d.ts +0 -5
  130. package/dist/app/ports/terminal-port.d.ts +0 -6
  131. package/dist/app/ports/updates-port.d.ts +0 -4
  132. package/dist/attachments/service.d.ts +29 -0
  133. package/dist/attachments/service.js +47 -0
  134. package/dist/attachments/service.js.map +1 -0
  135. package/dist/commands/providers.js +0 -3
  136. package/dist/commands/providers.js.map +1 -1
  137. package/dist/commands/search-providers.d.ts +0 -33
  138. package/dist/commands/search-providers.js +0 -33
  139. package/dist/commands/search-providers.js.map +1 -1
  140. package/dist/commands/update.js +1 -9
  141. package/dist/commands/update.js.map +1 -1
  142. package/dist/index.js +22 -42
  143. package/dist/index.js.map +1 -1
  144. package/dist/llm/adapters/ollama-tools.d.ts +0 -4
  145. package/dist/llm/adapters/ollama-tools.js +0 -4
  146. package/dist/llm/adapters/ollama-tools.js.map +1 -1
  147. package/dist/llm/capabilities.d.ts +10 -10
  148. package/dist/llm/capabilities.js +43 -17
  149. package/dist/llm/capabilities.js.map +1 -1
  150. package/dist/llm/groq.js +0 -6
  151. package/dist/llm/groq.js.map +1 -1
  152. package/dist/llm/http.d.ts +0 -17
  153. package/dist/llm/http.js +0 -45
  154. package/dist/llm/http.js.map +1 -1
  155. package/dist/llm/router.d.ts +0 -6
  156. package/dist/llm/router.js +0 -15
  157. package/dist/llm/router.js.map +1 -1
  158. package/dist/llm/tool-protocol.d.ts +0 -6
  159. package/dist/llm/tool-protocol.js +3 -7
  160. package/dist/llm/tool-protocol.js.map +1 -1
  161. package/dist/modes/agent.d.ts +2 -1
  162. package/dist/modes/agent.js +4 -2
  163. package/dist/modes/agent.js.map +1 -1
  164. package/dist/modes/ask.d.ts +0 -18
  165. package/dist/modes/ask.js +0 -49
  166. package/dist/modes/ask.js.map +1 -1
  167. package/dist/os/cwd.d.ts +0 -21
  168. package/dist/os/cwd.js +0 -24
  169. package/dist/os/cwd.js.map +1 -1
  170. package/dist/os/pkgmgr.js +0 -6
  171. package/dist/os/pkgmgr.js.map +1 -1
  172. package/dist/prompts/embedded.d.ts +1 -0
  173. package/dist/prompts/embedded.js +9 -0
  174. package/dist/prompts/embedded.js.map +1 -0
  175. package/dist/prompts/index.d.ts +6 -18
  176. package/dist/prompts/index.js +104 -293
  177. package/dist/prompts/index.js.map +1 -1
  178. package/dist/prompts/system.agent.md +228 -0
  179. package/dist/prompts/system.ask.md +56 -0
  180. package/dist/repl/prompt-line.js +0 -36
  181. package/dist/repl/prompt-line.js.map +1 -1
  182. package/dist/repl/slash-commands.d.ts +0 -9
  183. package/dist/repl/slash-commands.js +2 -23
  184. package/dist/repl/slash-commands.js.map +1 -1
  185. package/dist/repl.d.ts +5 -0
  186. package/dist/repl.js +169 -55
  187. package/dist/repl.js.map +1 -1
  188. package/dist/safety/classifier.js +17 -9
  189. package/dist/safety/classifier.js.map +1 -1
  190. package/dist/safety/engagement-policy.d.ts +46 -0
  191. package/dist/safety/engagement-policy.js +198 -0
  192. package/dist/safety/engagement-policy.js.map +1 -0
  193. package/dist/store/engagement.d.ts +115 -0
  194. package/dist/store/engagement.js +278 -0
  195. package/dist/store/engagement.js.map +1 -0
  196. package/dist/store/logs.d.ts +5 -0
  197. package/dist/store/logs.js +52 -2
  198. package/dist/store/logs.js.map +1 -1
  199. package/dist/store/plan.d.ts +57 -5
  200. package/dist/store/plan.js +182 -8
  201. package/dist/store/plan.js.map +1 -1
  202. package/dist/store/scope.d.ts +4 -1
  203. package/dist/store/scope.js +2 -2
  204. package/dist/store/scope.js.map +1 -1
  205. package/dist/tools/definitions.js +70 -1
  206. package/dist/tools/definitions.js.map +1 -1
  207. package/dist/tools/elevated-shell.d.ts +60 -0
  208. package/dist/tools/elevated-shell.js +233 -0
  209. package/dist/tools/elevated-shell.js.map +1 -0
  210. package/dist/tools/file-diff.d.ts +125 -0
  211. package/dist/tools/file-diff.js +495 -0
  212. package/dist/tools/file-diff.js.map +1 -0
  213. package/dist/tools/fs.d.ts +11 -13
  214. package/dist/tools/fs.js +269 -78
  215. package/dist/tools/fs.js.map +1 -1
  216. package/dist/tools/http.d.ts +15 -0
  217. package/dist/tools/http.js +202 -61
  218. package/dist/tools/http.js.map +1 -1
  219. package/dist/tools/jobs.d.ts +71 -10
  220. package/dist/tools/jobs.js +403 -124
  221. package/dist/tools/jobs.js.map +1 -1
  222. package/dist/tools/nmap-runner.d.ts +11 -0
  223. package/dist/tools/nmap-runner.js +115 -74
  224. package/dist/tools/nmap-runner.js.map +1 -1
  225. package/dist/tools/pentest-workflows.d.ts +8 -0
  226. package/dist/tools/pentest-workflows.js +71 -0
  227. package/dist/tools/pentest-workflows.js.map +1 -0
  228. package/dist/tools/registry.d.ts +9 -0
  229. package/dist/tools/registry.js +244 -57
  230. package/dist/tools/registry.js.map +1 -1
  231. package/dist/tools/shell.d.ts +3 -0
  232. package/dist/tools/shell.js +35 -13
  233. package/dist/tools/shell.js.map +1 -1
  234. package/dist/tools/tool-types.d.ts +11 -0
  235. package/dist/tools/web/fetch-core.d.ts +7 -0
  236. package/dist/tools/web/fetch-core.js +40 -1
  237. package/dist/tools/web/fetch-core.js.map +1 -1
  238. package/dist/tools/web/fetch.js +8 -1
  239. package/dist/tools/web/fetch.js.map +1 -1
  240. package/dist/tui-v2/app/App.js +34 -41
  241. package/dist/tui-v2/app/App.js.map +1 -1
  242. package/dist/tui-v2/app/command-handlers.js +20 -1
  243. package/dist/tui-v2/app/command-handlers.js.map +1 -1
  244. package/dist/tui-v2/app/commands/picker-commands.js +3 -0
  245. package/dist/tui-v2/app/commands/picker-commands.js.map +1 -1
  246. package/dist/tui-v2/app/commands/session-commands.js +5 -0
  247. package/dist/tui-v2/app/commands/session-commands.js.map +1 -1
  248. package/dist/tui-v2/app/plan-lifecycle.d.ts +25 -3
  249. package/dist/tui-v2/app/plan-lifecycle.js +87 -24
  250. package/dist/tui-v2/app/plan-lifecycle.js.map +1 -1
  251. package/dist/tui-v2/bootstrap/patch-opentui-text.d.ts +6 -0
  252. package/dist/tui-v2/bootstrap/patch-opentui-text.js +53 -0
  253. package/dist/tui-v2/bootstrap/patch-opentui-text.js.map +1 -0
  254. package/dist/tui-v2/bootstrap/start-tui-v2.js +7 -0
  255. package/dist/tui-v2/bootstrap/start-tui-v2.js.map +1 -1
  256. package/dist/tui-v2/components/jobs/jobs-panel.js +23 -14
  257. package/dist/tui-v2/components/jobs/jobs-panel.js.map +1 -1
  258. package/dist/tui-v2/components/modal/confirm-modal.d.ts +1 -1
  259. package/dist/tui-v2/components/modal/confirm-modal.js +18 -7
  260. package/dist/tui-v2/components/modal/confirm-modal.js.map +1 -1
  261. package/dist/tui-v2/components/overlay/overlay-host.js +1 -1
  262. package/dist/tui-v2/components/overlay/overlay-host.js.map +1 -1
  263. package/dist/tui-v2/components/pager/pager.d.ts +6 -0
  264. package/dist/tui-v2/components/pager/pager.js +313 -67
  265. package/dist/tui-v2/components/pager/pager.js.map +1 -1
  266. package/dist/tui-v2/components/status/status-line.d.ts +9 -0
  267. package/dist/tui-v2/components/status/status-line.js +17 -3
  268. package/dist/tui-v2/components/status/status-line.js.map +1 -1
  269. package/dist/tui-v2/components/transcript/assistant-message.js +1 -1
  270. package/dist/tui-v2/components/transcript/assistant-message.js.map +1 -1
  271. package/dist/tui-v2/components/transcript/compacted-row.js +1 -1
  272. package/dist/tui-v2/components/transcript/compacted-row.js.map +1 -1
  273. package/dist/tui-v2/components/transcript/tool-card.d.ts +9 -1
  274. package/dist/tui-v2/components/transcript/tool-card.js +114 -9
  275. package/dist/tui-v2/components/transcript/tool-card.js.map +1 -1
  276. package/dist/tui-v2/components/transcript/transcript-row.js +2 -2
  277. package/dist/tui-v2/components/transcript/transcript-row.js.map +1 -1
  278. package/dist/tui-v2/composer/composer-editor.js +16 -0
  279. package/dist/tui-v2/composer/composer-editor.js.map +1 -1
  280. package/dist/tui-v2/controllers/overlay-controller.d.ts +16 -2
  281. package/dist/tui-v2/controllers/overlay-controller.js +92 -12
  282. package/dist/tui-v2/controllers/overlay-controller.js.map +1 -1
  283. package/dist/tui-v2/rendering/artifact-pager-source.d.ts +19 -0
  284. package/dist/tui-v2/rendering/artifact-pager-source.js +103 -0
  285. package/dist/tui-v2/rendering/artifact-pager-source.js.map +1 -0
  286. package/dist/tui-v2/rendering/file-diff-view.d.ts +63 -0
  287. package/dist/tui-v2/rendering/file-diff-view.js +263 -0
  288. package/dist/tui-v2/rendering/file-diff-view.js.map +1 -0
  289. package/dist/tui-v2/rendering/open-tool-output.d.ts +9 -1
  290. package/dist/tui-v2/rendering/open-tool-output.js +65 -12
  291. package/dist/tui-v2/rendering/open-tool-output.js.map +1 -1
  292. package/dist/tui-v2/rendering/pager-chrome.d.ts +12 -0
  293. package/dist/tui-v2/rendering/pager-chrome.js +56 -0
  294. package/dist/tui-v2/rendering/pager-chrome.js.map +1 -0
  295. package/dist/tui-v2/rendering/plan-view.js +1 -1
  296. package/dist/tui-v2/rendering/plan-view.js.map +1 -1
  297. package/dist/tui-v2/rendering/syntax-highlight.d.ts +37 -0
  298. package/dist/tui-v2/rendering/syntax-highlight.js +1303 -0
  299. package/dist/tui-v2/rendering/syntax-highlight.js.map +1 -0
  300. package/dist/tui-v2/rendering/theme.d.ts +28 -0
  301. package/dist/tui-v2/rendering/theme.js +28 -0
  302. package/dist/tui-v2/rendering/theme.js.map +1 -1
  303. package/dist/tui-v2/rendering/tool-presenter.d.ts +5 -0
  304. package/dist/tui-v2/rendering/tool-presenter.js +35 -3
  305. package/dist/tui-v2/rendering/tool-presenter.js.map +1 -1
  306. package/dist/tui-v2/state/transcript-hydrate.js +5 -0
  307. package/dist/tui-v2/state/transcript-hydrate.js.map +1 -1
  308. package/dist/tui-v2/state/transcript-reducer.js +12 -2
  309. package/dist/tui-v2/state/transcript-reducer.js.map +1 -1
  310. package/dist/tui-v2/state/transcript-store.d.ts +7 -0
  311. package/dist/tui-v2/state/transcript-store.js +46 -0
  312. package/dist/tui-v2/state/transcript-store.js.map +1 -1
  313. package/dist/tui-v2/state/transcript-types.d.ts +12 -0
  314. package/dist/tui-v2/state/transcript-types.js +9 -0
  315. package/dist/tui-v2/state/transcript-types.js.map +1 -1
  316. package/dist/types.d.ts +17 -1
  317. package/dist/ui/mentions.d.ts +6 -0
  318. package/dist/ui/mentions.js +50 -12
  319. package/dist/ui/mentions.js.map +1 -1
  320. package/dist/ui/plan-pane.js +1 -1
  321. package/dist/ui/plan-pane.js.map +1 -1
  322. package/package.json +18 -12
@@ -20,14 +20,14 @@ const READ_ONLY_TOOLS = new Set([
20
20
  "image.ocr",
21
21
  "pdf.read",
22
22
  ]);
23
- /**
24
- * Track and detect tool-call repetition patterns so the agent doesn't
25
- * waste steps in loops.
26
- */
27
23
  export class LoopGuard {
28
24
  attempts = [];
29
25
  signatureCount = new Map();
30
26
  signatureSuccess = new Map();
27
+ /** Failed read-only signatures that already used their one free env-change retry. */
28
+ failedReadRetryUsed = new Set();
29
+ lastSuccessfulNonMetaStep = -1;
30
+ constructor(_options = {}) { }
31
31
  /**
32
32
  * Produce a canonical string for a (name, args) pair so that calls
33
33
  * with identical semantics match even if arg order differs or
@@ -38,7 +38,9 @@ export class LoopGuard {
38
38
  for (const key of Object.keys(args).sort()) {
39
39
  let value = args[key];
40
40
  // Normalize command whitespace for shell.exec
41
- if (name === "shell.exec" && key === "command" && typeof value === "string") {
41
+ if ((name === "shell.exec" || name === "shell.start") &&
42
+ key === "command" &&
43
+ typeof value === "string") {
42
44
  value = value.trim().replace(/\s+/g, " ");
43
45
  }
44
46
  sorted[key] = value;
@@ -49,27 +51,36 @@ export class LoopGuard {
49
51
  const sig = this.canonicalize(name, args);
50
52
  this.attempts.push({ step, callName: name, canonicalSignature: sig, ok, exitCode });
51
53
  this.signatureCount.set(sig, (this.signatureCount.get(sig) ?? 0) + 1);
52
- // Remember whether this exact call has EVER succeeded. A call that only
53
- // ever failed should be allowed to retry (e.g. fs.write that hit ENOENT,
54
- // a command that needed installing first) without being flagged as a
55
- // redundant loop.
56
- if (ok)
54
+ // Remember whether this exact call has EVER succeeded.
55
+ if (ok) {
57
56
  this.signatureSuccess.set(sig, true);
58
- else if (!this.signatureSuccess.has(sig))
59
- this.signatureSuccess.set(sig, false);
60
- // X11: after a successful mutate on a path, allow re-reading that path.
61
- if (ok &&
62
- (name === "fs.write" ||
63
- name === "fs.writeMany" ||
64
- name === "fs.edit" ||
65
- name === "fs.replaceLines" ||
66
- name === "fs.append" ||
67
- name === "fs.delete")) {
68
- this.invalidateReadsForMutatedPaths(name, args);
57
+ if (name !== "task.update" && name !== "plan.create") {
58
+ this.lastSuccessfulNonMetaStep = step;
59
+ }
60
+ }
61
+ else {
62
+ if (!this.signatureSuccess.has(sig))
63
+ this.signatureSuccess.set(sig, false);
64
+ }
65
+ // After successful *mutates* (not reads), allow re-list/re-read of those paths.
66
+ // Never invalidate on fs.read/list themselves — that wiped the dedup counter
67
+ // on every successful read and disabled loop detection.
68
+ if (ok && this.isPathMutatingTool(name)) {
69
+ this.invalidateReadsAfterSuccess(name, args);
69
70
  }
70
71
  }
71
- /** Drop successful fs.read signatures that touch the mutated path(s). */
72
- invalidateReadsForMutatedPaths(name, args) {
72
+ isPathMutatingTool(name) {
73
+ return (name === "fs.write" ||
74
+ name === "fs.writeMany" ||
75
+ name === "fs.edit" ||
76
+ name === "fs.replaceLines" ||
77
+ name === "fs.append" ||
78
+ name === "fs.delete" ||
79
+ name === "shell.exec" ||
80
+ name === "shell.start");
81
+ }
82
+ /** Drop list/read signatures that touch paths a successful tool may have created. */
83
+ invalidateReadsAfterSuccess(name, args) {
73
84
  const paths = [];
74
85
  if (typeof args.path === "string")
75
86
  paths.push(args.path);
@@ -80,14 +91,29 @@ export class LoopGuard {
80
91
  }
81
92
  }
82
93
  }
83
- if (paths.length === 0)
94
+ if ((name === "shell.exec" || name === "shell.start") &&
95
+ typeof args.command === "string") {
96
+ const cmd = args.command;
97
+ // mkdir -p path, create-vite name, cd path
98
+ for (const m of cmd.matchAll(/(?:mkdir\s+(?:-p\s+)?|cd\s+|create-[\w@./-]+\s+|vite@\S+\s+)(['"]?)([^\s;'"]+)\1/gi)) {
99
+ if (m[2] && m[2] !== ".")
100
+ paths.push(m[2]);
101
+ }
102
+ if (typeof args.cwd === "string")
103
+ paths.push(args.cwd);
104
+ }
105
+ if (paths.length === 0) {
106
+ // Any successful shell still clears failed fs.list of unknown paths once
107
+ // via the generic read-only retry path in shouldBlock.
84
108
  return;
85
- for (const [sig] of this.signatureCount) {
86
- if (!sig.startsWith("fs.read::"))
109
+ }
110
+ for (const sig of [...this.signatureCount.keys()]) {
111
+ if (!sig.startsWith("fs.read::") && !sig.startsWith("fs.list::"))
87
112
  continue;
88
- if (paths.some((p) => sig.includes(p))) {
113
+ if (paths.some((p) => p.length > 1 && sig.includes(p))) {
89
114
  this.signatureCount.delete(sig);
90
115
  this.signatureSuccess.delete(sig);
116
+ this.failedReadRetryUsed.delete(sig);
91
117
  }
92
118
  }
93
119
  }
@@ -98,16 +124,12 @@ export class LoopGuard {
98
124
  * `{ block: false, reason: "..." }` for a warning (first repeat), or
99
125
  * `{ block: true, reason: "..." }` to force summary (second+ repeat).
100
126
  *
101
- * A call whose every prior attempt FAILED is never blocked — the model is
102
- * expected to fix the cause (install a tool, create a dir) and retry. Only
103
- * calls that already SUCCEEDED are deduped, since re-running them wastes a
104
- * step and risks an infinite summarize loop.
105
- *
106
- * Read-only tools (web.fetch, fs.read, etc.) get a higher threshold (3)
107
- * because they may legitimately need re-calling after context compaction
108
- * removes their results.
127
+ * Failed read-only tools may retry once after any successful intervening
128
+ * non-meta work (e.g. list missing dir scaffold list again). Failed
129
+ * mutates still need structured retry context or a changed path.
130
+ * Successful identical mutates are still deduped.
109
131
  */
110
- shouldBlock(name, args) {
132
+ shouldBlock(name, args, retryContext) {
111
133
  if (name === "task.update" || name === "plan.create") {
112
134
  return { block: false };
113
135
  }
@@ -115,9 +137,41 @@ export class LoopGuard {
115
137
  const count = this.signatureCount.get(sig) ?? 0;
116
138
  if (count === 0)
117
139
  return { block: false };
118
- // Prior attempts all failed allow the retry, no warning.
119
- if (this.signatureSuccess.get(sig) === false)
120
- return { block: false };
140
+ // Previously-failed signature: allow structured retry, or one free retry
141
+ // for read-only tools after environment-changing successful work.
142
+ if (this.signatureSuccess.get(sig) === false) {
143
+ const structuredReason = retryContext?.retryReason;
144
+ const authorized = retryContext?.dependenciesChanged === true ||
145
+ retryContext?.environmentChanged === true ||
146
+ Boolean(structuredReason?.code.trim() && structuredReason.detail.trim());
147
+ if (authorized) {
148
+ return {
149
+ block: false,
150
+ reason: `${name} retry authorized by changed context or structured rationale.`,
151
+ };
152
+ }
153
+ if (READ_ONLY_TOOLS.has(name) && !this.failedReadRetryUsed.has(sig)) {
154
+ // Permit one retry after any successful non-meta tool since the fail.
155
+ const lastFailStep = [...this.attempts]
156
+ .reverse()
157
+ .find((a) => a.canonicalSignature === sig && !a.ok)?.step;
158
+ if (lastFailStep !== undefined &&
159
+ this.lastSuccessfulNonMetaStep > lastFailStep) {
160
+ this.failedReadRetryUsed.add(sig);
161
+ // Reset counters so a successful retry is clean
162
+ this.signatureCount.delete(sig);
163
+ this.signatureSuccess.delete(sig);
164
+ return {
165
+ block: false,
166
+ reason: `${name} retry allowed after successful work changed the environment.`,
167
+ };
168
+ }
169
+ }
170
+ return {
171
+ block: true,
172
+ reason: `${name} previously failed with identical arguments. Change dependencies/environment or provide a structured retry reason.`,
173
+ };
174
+ }
121
175
  // Mutating file tools deserve tool-appropriate wording. Telling a model
122
176
  // that just wrote a file to "use the results you already have" is
123
177
  // nonsensical and has caused models to assume the whole task is done.
@@ -1 +1 @@
1
- {"version":3,"file":"loop-guard.js","sourceRoot":"","sources":["../../src/agent/loop-guard.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"loop-guard.js","sourceRoot":"","sources":["../../src/agent/loop-guard.ts"],"names":[],"mappings":"AAUA;;;;;GAKG;AACH,MAAM,eAAe,GAAG,IAAI,GAAG,CAAC;IAC9B,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,YAAY;IACZ,cAAc;IACd,SAAS;IACT,SAAS;IACT,WAAW;IACX,SAAS;IACT,aAAa;IACb,YAAY;IACZ,eAAe;IACf,WAAW;IACX,UAAU;CACX,CAAC,CAAC;AAyBH,MAAM,OAAO,SAAS;IACZ,QAAQ,GAAkB,EAAE,CAAC;IAC7B,cAAc,GAAG,IAAI,GAAG,EAAkB,CAAC;IAC3C,gBAAgB,GAAG,IAAI,GAAG,EAAmB,CAAC;IACtD,qFAAqF;IAC7E,mBAAmB,GAAG,IAAI,GAAG,EAAU,CAAC;IACxC,yBAAyB,GAAG,CAAC,CAAC,CAAC;IAEvC,YAAY,WAA6B,EAAE,IAAG,CAAC;IAE/C;;;;OAIG;IACH,YAAY,CAAC,IAAY,EAAE,IAA6B;QACtD,MAAM,MAAM,GAA4B,EAAE,CAAC;QAC3C,KAAK,MAAM,GAAG,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC;YAC3C,IAAI,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC;YACtB,8CAA8C;YAC9C,IACE,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,aAAa,CAAC;gBACjD,GAAG,KAAK,SAAS;gBACjB,OAAO,KAAK,KAAK,QAAQ,EACzB,CAAC;gBACD,KAAK,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;YAC5C,CAAC;YACD,MAAM,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC;QACtB,CAAC;QACD,OAAO,GAAG,IAAI,KAAK,IAAI,CAAC,SAAS,CAAC,MAAM,CAAC,EAAE,CAAC;IAC9C,CAAC;IAED,aAAa,CACX,IAAY,EACZ,IAAY,EACZ,IAA6B,EAC7B,EAAW,EACX,QAA6B;QAE7B,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1C,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,kBAAkB,EAAE,GAAG,EAAE,EAAE,EAAE,QAAQ,EAAE,CAAC,CAAC;QACpF,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;QACtE,uDAAuD;QACvD,IAAI,EAAE,EAAE,CAAC;YACP,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACrC,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;gBACrD,IAAI,CAAC,yBAAyB,GAAG,IAAI,CAAC;YACxC,CAAC;QACH,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC;gBAAE,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC;QAC7E,CAAC;QAED,gFAAgF;QAChF,6EAA6E;QAC7E,wDAAwD;QACxD,IAAI,EAAE,IAAI,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,EAAE,CAAC;YACxC,IAAI,CAAC,2BAA2B,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC/C,CAAC;IACH,CAAC;IAEO,kBAAkB,CAAC,IAAY;QACrC,OAAO,CACL,IAAI,KAAK,UAAU;YACnB,IAAI,KAAK,cAAc;YACvB,IAAI,KAAK,SAAS;YAClB,IAAI,KAAK,iBAAiB;YAC1B,IAAI,KAAK,WAAW;YACpB,IAAI,KAAK,WAAW;YACpB,IAAI,KAAK,YAAY;YACrB,IAAI,KAAK,aAAa,CACvB,CAAC;IACJ,CAAC;IAED,qFAAqF;IAC7E,2BAA2B,CACjC,IAAY,EACZ,IAA6B;QAE7B,MAAM,KAAK,GAAa,EAAE,CAAC;QAC3B,IAAI,OAAO,IAAI,CAAC,IAAI,KAAK,QAAQ;YAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,IAAI,IAAI,KAAK,cAAc,IAAI,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YACzD,KAAK,MAAM,CAAC,IAAI,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC3B,IAAI,CAAC,IAAI,OAAO,CAAC,KAAK,QAAQ,IAAI,OAAQ,CAAuB,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;oBACpF,KAAK,CAAC,IAAI,CAAE,CAAsB,CAAC,IAAI,CAAC,CAAC;gBAC3C,CAAC;YACH,CAAC;QACH,CAAC;QACD,IACE,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,aAAa,CAAC;YACjD,OAAO,IAAI,CAAC,OAAO,KAAK,QAAQ,EAChC,CAAC;YACD,MAAM,GAAG,GAAG,IAAI,CAAC,OAAO,CAAC;YACzB,2CAA2C;YAC3C,KAAK,MAAM,CAAC,IAAI,GAAG,CAAC,QAAQ,CAC1B,oFAAoF,CACrF,EAAE,CAAC;gBACF,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,KAAK,GAAG;oBAAE,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;YAC7C,CAAC;YACD,IAAI,OAAO,IAAI,CAAC,GAAG,KAAK,QAAQ;gBAAE,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACvB,yEAAyE;YACzE,uDAAuD;YACvD,OAAO;QACT,CAAC;QACD,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAClD,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,WAAW,CAAC;gBAAE,SAAS;YAC3E,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvD,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAClC,IAAI,CAAC,mBAAmB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACvC,CAAC;QACH,CAAC;IACH,CAAC;IAED;;;;;;;;;;;OAWG;IACH,WAAW,CACT,IAAY,EACZ,IAA6B,EAC7B,YAA2B;QAE3B,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,aAAa,EAAE,CAAC;YACrD,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAC1B,CAAC;QACD,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1C,MAAM,KAAK,GAAG,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAEhD,IAAI,KAAK,KAAK,CAAC;YAAE,OAAO,EAAE,KAAK,EAAE,KAAK,EAAE,CAAC;QAEzC,yEAAyE;QACzE,kEAAkE;QAClE,IAAI,IAAI,CAAC,gBAAgB,CAAC,GAAG,CAAC,GAAG,CAAC,KAAK,KAAK,EAAE,CAAC;YAC7C,MAAM,gBAAgB,GAAG,YAAY,EAAE,WAAW,CAAC;YACnD,MAAM,UAAU,GACd,YAAY,EAAE,mBAAmB,KAAK,IAAI;gBAC1C,YAAY,EAAE,kBAAkB,KAAK,IAAI;gBACzC,OAAO,CAAC,gBAAgB,EAAE,IAAI,CAAC,IAAI,EAAE,IAAI,gBAAgB,CAAC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;YAC3E,IAAI,UAAU,EAAE,CAAC;gBACf,OAAO;oBACL,KAAK,EAAE,KAAK;oBACZ,MAAM,EAAE,GAAG,IAAI,+DAA+D;iBAC/E,CAAC;YACJ,CAAC;YACD,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,CAAC;gBACpE,sEAAsE;gBACtE,MAAM,YAAY,GAAG,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC;qBACpC,OAAO,EAAE;qBACT,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,kBAAkB,KAAK,GAAG,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,IAAI,CAAC;gBAC5D,IACE,YAAY,KAAK,SAAS;oBAC1B,IAAI,CAAC,yBAAyB,GAAG,YAAY,EAC7C,CAAC;oBACD,IAAI,CAAC,mBAAmB,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;oBAClC,gDAAgD;oBAChD,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAChC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;oBAClC,OAAO;wBACL,KAAK,EAAE,KAAK;wBACZ,MAAM,EAAE,GAAG,IAAI,+DAA+D;qBAC/E,CAAC;gBACJ,CAAC;YACH,CAAC;YACD,OAAO;gBACL,KAAK,EAAE,IAAI;gBACX,MAAM,EAAE,GAAG,IAAI,oHAAoH;aACpI,CAAC;QACJ,CAAC;QAED,wEAAwE;QACxE,kEAAkE;QAClE,sEAAsE;QACtE,MAAM,OAAO,GACX,IAAI,KAAK,UAAU;YACnB,IAAI,KAAK,cAAc;YACvB,IAAI,KAAK,SAAS;YAClB,IAAI,KAAK,iBAAiB;YAC1B,IAAI,KAAK,WAAW,CAAC;QAEvB,oEAAoE;QACpE,0DAA0D;QAC1D,MAAM,SAAS,GAAG,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC;QAEpD,IAAI,KAAK,GAAG,SAAS,EAAE,CAAC;YACtB,OAAO;gBACL,KAAK,EAAE,KAAK;gBACZ,MAAM,EAAE,OAAO;oBACb,CAAC,CAAC,GAAG,IAAI,8HAA8H;oBACvI,CAAC,CAAC,IAAI,KAAK,SAAS;wBAClB,CAAC,CAAC,GAAG,IAAI,2KAA2K;wBACpL,CAAC,CAAC,GAAG,IAAI,gHAAgH;aAC9H,CAAC;QACJ,CAAC;QAED,qDAAqD;QACrD,OAAO;YACL,KAAK,EAAE,IAAI;YACX,MAAM,EAAE,OAAO;gBACb,CAAC,CAAC,GAAG,IAAI,uBAAuB,KAAK,gJAAgJ;gBACrL,CAAC,CAAC,IAAI,KAAK,SAAS;oBAClB,CAAC,CAAC,GAAG,IAAI,uBAAuB,KAAK,kJAAkJ;oBACvL,CAAC,CAAC,GAAG,IAAI,uBAAuB,KAAK,0HAA0H;SACpK,CAAC;IACJ,CAAC;IAED,eAAe,CAAC,IAAY,EAAE,IAA6B;QACzD,MAAM,GAAG,GAAG,IAAI,CAAC,YAAY,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;QAC1C,OAAO,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IAC3C,CAAC;IAED;;;OAGG;IACH,mBAAmB,CAAC,SAAS,GAAG,CAAC;QAC/B,IAAI,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,SAAS;YAAE,OAAO,KAAK,CAAC;QACnD,MAAM,MAAM,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,SAAS,CAAC,CAAC;QAC/C,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;IACpC,CAAC;IAED;;;OAGG;IACH,uBAAuB;QACrB,IAAI,KAAK,GAAG,CAAC,CAAC;QACd,KAAK,IAAI,CAAC,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC;YACnD,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,CAAE,CAAC,EAAE;gBAAE,KAAK,EAAE,CAAC;;gBAC9B,MAAM;QACb,CAAC;QACD,OAAO,KAAK,CAAC;IACf,CAAC;IAED;;;;;;;OAOG;IACH,oBAAoB;QAClB,MAAM,mBAAmB,GAAG,IAAI,CAAC,uBAAuB,EAAE,CAAC;QAC3D,IAAI,mBAAmB,GAAG,CAAC;YAAE,OAAO,IAAI,CAAC;QAEzC,6DAA6D;QAC7D,MAAM,WAAW,GAAG,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,CAAC,mBAAmB,CAAC,CAAC;QAC9D,MAAM,WAAW,GAAG,WAAW;aAC5B,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,OAAO,CAAC,CAAC,QAAQ,KAAK,CAAC,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,EAAE,GAAG,CAAC,EAAE,CAAC;aACtE,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,kBAAkB;aAC5B,IAAI,CAAC,IAAI,CAAC,CAAC;QAEd,MAAM,QAAQ,GAAG,mBAAmB,IAAI,CAAC,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC;QAEnE,OAAO,mCAAmC,QAAQ,OAAO,mBAAmB;;;EAG9E,WAAW;;;;;;;;;;;;gHAYmG,CAAC;IAC/G,CAAC;IAED;;;OAGG;IACH,aAAa;QACX,KAAK,MAAM,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,cAAc,CAAC,IAAI,EAAE,CAAC,EAAE,CAAC;YAClD,MAAM,IAAI,GAAG,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;YACtC,IAAI,eAAe,CAAC,GAAG,CAAC,IAAI,CAAC,EAAE,CAAC;gBAC9B,IAAI,CAAC,cAAc,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;gBAChC,IAAI,CAAC,gBAAgB,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC;YACpC,CAAC;QACH,CAAC;QACD,IAAI,CAAC,QAAQ,GAAG,IAAI,CAAC,QAAQ,CAAC,MAAM,CAClC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,eAAe,CAAC,GAAG,CAAC,CAAC,CAAC,QAAQ,CAAC,CACxC,CAAC;IACJ,CAAC;IAED;;OAEG;IACH,IAAI,aAAa;QACf,OAAO,IAAI,CAAC,QAAQ,CAAC,MAAM,CAAC;IAC9B,CAAC;CACF"}
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Completion-time recovery decisions: when a tool-free (or incomplete)
3
+ * final answer must be rejected and the agent forced to act.
4
+ */
5
+ export interface RecoveryBudgets {
6
+ actionIntent: number;
7
+ errorFix: number;
8
+ forcePlan: number;
9
+ featureImpl: number;
10
+ runtimeVerify: number;
11
+ failedProbe: number;
12
+ prematureComplete: number;
13
+ shallowPentest: number;
14
+ freshnessUsed: boolean;
15
+ }
16
+ export declare function createRecoveryBudgets(): RecoveryBudgets;
17
+ export type RecoveryKind = "error_fix" | "narration" | "force_plan" | "feature_impl" | "runtime_verify" | "failed_probe" | "premature_complete" | "freshness" | "shallow_pentest";
18
+ export interface RecoveryAction {
19
+ kind: RecoveryKind;
20
+ /** User/model-facing instruction to append. */
21
+ message: string;
22
+ /** Short terminal notice. */
23
+ notice: string;
24
+ budgetKey: keyof RecoveryBudgets;
25
+ }
26
+ export declare function budgetRemaining(budgets: RecoveryBudgets, key: keyof RecoveryBudgets): boolean;
27
+ export declare function consumeBudget(budgets: RecoveryBudgets, key: keyof RecoveryBudgets): void;
28
+ export declare function recoveryForErrorDiagnosis(nativeTools: boolean): RecoveryAction;
29
+ export declare function recoveryForNarration(nativeTools: boolean, mode: "plan_open" | "pentest" | "web" | "build_plan_prose" | "build" | "generic"): RecoveryAction;
30
+ /** Plan mode only — agent mode must not force plan.create. */
31
+ export declare function recoveryForMissingPlan(nativeTools: boolean): RecoveryAction;
32
+ export declare function recoveryForMissingFeature(projectRoot?: string): RecoveryAction;
33
+ export declare function recoveryForRuntimeVerify(projectRoot?: string): RecoveryAction;
34
+ export declare function recoveryForFailedProbe(): RecoveryAction;
35
+ export declare function recoveryForPrematureComplete(input: {
36
+ unfinished: Array<{
37
+ id: string;
38
+ title: string;
39
+ state: string;
40
+ }>;
41
+ next: {
42
+ id: string;
43
+ title: string;
44
+ state: string;
45
+ };
46
+ pentest: boolean;
47
+ errorFix: boolean;
48
+ }): RecoveryAction;
49
+ export declare function recoveryForFreshness(extra: string): RecoveryAction;
50
+ /** True when a final pentest write-up looks like skim recon without real coverage. */
51
+ export declare function looksLikeShallowPentestReport(text: string, opts: {
52
+ productiveSteps: number;
53
+ sawActiveTest: boolean;
54
+ }): boolean;
55
+ export declare function recoveryForShallowPentest(): RecoveryAction;
56
+ export declare function freestyleClaimsAppReady(text: string): boolean;
@@ -0,0 +1,240 @@
1
+ /**
2
+ * Completion-time recovery decisions: when a tool-free (or incomplete)
3
+ * final answer must be rejected and the agent forced to act.
4
+ */
5
+ export function createRecoveryBudgets() {
6
+ return {
7
+ actionIntent: 0,
8
+ errorFix: 0,
9
+ forcePlan: 0,
10
+ featureImpl: 0,
11
+ runtimeVerify: 0,
12
+ failedProbe: 0,
13
+ prematureComplete: 0,
14
+ shallowPentest: 0,
15
+ freshnessUsed: false,
16
+ };
17
+ }
18
+ const LIMITS = {
19
+ actionIntent: 3,
20
+ errorFix: 3,
21
+ forcePlan: 2,
22
+ featureImpl: 2,
23
+ runtimeVerify: 2,
24
+ failedProbe: 3,
25
+ prematureComplete: 6,
26
+ shallowPentest: 2,
27
+ freshnessUsed: 1,
28
+ };
29
+ export function budgetRemaining(budgets, key) {
30
+ if (key === "freshnessUsed")
31
+ return !budgets.freshnessUsed;
32
+ return budgets[key] < LIMITS[key];
33
+ }
34
+ export function consumeBudget(budgets, key) {
35
+ if (key === "freshnessUsed") {
36
+ budgets.freshnessUsed = true;
37
+ return;
38
+ }
39
+ budgets[key] = budgets[key] + 1;
40
+ }
41
+ export function recoveryForErrorDiagnosis(nativeTools) {
42
+ return {
43
+ kind: "error_fix",
44
+ budgetKey: "errorFix",
45
+ notice: "error diagnosed but not fixed — forcing tool call",
46
+ message: nativeTools
47
+ ? "You diagnosed an error and described the fix but called NO tool. " +
48
+ "Apply the fix now (fs.edit / fs.write / shell.exec), then re-verify. " +
49
+ "Do not stop after identifying the error."
50
+ : "You diagnosed an error and described the fix but emitted NO tool call. " +
51
+ "Apply the fix now, e.g.:\n" +
52
+ '```tool\n{"name":"fs.edit","args":{"path":"<file>","oldText":"...","newText":"..."}}\n```\n' +
53
+ "Then re-run the failing check.",
54
+ };
55
+ }
56
+ export function recoveryForNarration(nativeTools, mode) {
57
+ const base = {
58
+ kind: "narration",
59
+ budgetKey: "actionIntent",
60
+ notice: "described an action but emitted no tool call",
61
+ };
62
+ if (mode === "plan_open") {
63
+ return {
64
+ ...base,
65
+ message: nativeTools
66
+ ? "You wrote a message but called NO tool. Call the next tool now (task.update / fs.write / shell.exec)."
67
+ : "You wrote a message but emitted NO ```tool block. Emit the next tool call now.",
68
+ };
69
+ }
70
+ if (mode === "pentest") {
71
+ return {
72
+ ...base,
73
+ notice: "described a security action but emitted no tool call",
74
+ message: nativeTools
75
+ ? "You described security work but called NO tool. Call a real tool now (net.scan / http.fetch / dns.lookup / shell.exec)."
76
+ : "You described security work but emitted NO ```tool block. Emit a real tool call now (e.g. sysinfo, net.scan, http.fetch).",
77
+ };
78
+ }
79
+ if (mode === "web") {
80
+ return {
81
+ ...base,
82
+ notice: "described a web action but emitted no tool call",
83
+ message: nativeTools
84
+ ? "You claimed a search/fetch but called NO tool. Call web.search or web.fetch now, then answer from results."
85
+ : "You claimed a search/fetch but emitted NO ```tool block. Emit web.search or web.fetch now.",
86
+ };
87
+ }
88
+ if (mode === "build_plan_prose") {
89
+ return {
90
+ ...base,
91
+ notice: "plan was written as text, not created",
92
+ message: nativeTools
93
+ ? 'You wrote the plan as prose but did NOT call plan.create. Call plan.create now with goal, detail, tasks, and kind="coding" or "pentest".'
94
+ : "You wrote the plan as prose but did NOT call plan.create. Emit one plan.create tool block now.",
95
+ };
96
+ }
97
+ if (mode === "build") {
98
+ return {
99
+ ...base,
100
+ message: nativeTools
101
+ ? 'You described work but called NO tool. Call a tool now (e.g. fs.list path="."), then plan.create when ready.'
102
+ : "You described work but emitted NO ```tool block. Explore first, then plan.create when ready.",
103
+ };
104
+ }
105
+ return {
106
+ ...base,
107
+ message: nativeTools
108
+ ? "You described an action but called NO tool. Call the appropriate tool now."
109
+ : "You described an action but emitted NO ```tool block. Emit a real tool call now.",
110
+ };
111
+ }
112
+ /** Plan mode only — agent mode must not force plan.create. */
113
+ export function recoveryForMissingPlan(nativeTools) {
114
+ return {
115
+ kind: "force_plan",
116
+ budgetKey: "forcePlan",
117
+ notice: "plan mode missing plan.create",
118
+ message: nativeTools
119
+ ? "You are in plan mode and tried to finish without a durable plan. Gather any remaining context you need, then call plan.create " +
120
+ "(goal, rich detail with context/approach/risks/verify, all relevant tasks — no artificial cap, kind=coding|pentest|general as appropriate). Do not implement yet."
121
+ : "You are in plan mode and tried to finish without a durable plan. Gather context if needed, then emit plan.create with a comprehensive plan (any relevant task count). Do not implement yet.",
122
+ };
123
+ }
124
+ export function recoveryForMissingFeature(projectRoot) {
125
+ const rootHint = projectRoot
126
+ ? ` Write under "${projectRoot}" with absolute paths.`
127
+ : "";
128
+ return {
129
+ kind: "feature_impl",
130
+ budgetKey: "featureImpl",
131
+ notice: "feature not implemented — scaffold alone is incomplete",
132
+ message: "INCOMPLETE: the user asked for a working product feature, not a blank framework starter. " +
133
+ "Scaffold alone is a failure. Implement the requested feature now (replace starter boilerplate) " +
134
+ "with fs.write / fs.writeMany. Do not shell.start until that feature exists." +
135
+ rootHint,
136
+ };
137
+ }
138
+ export function recoveryForRuntimeVerify(projectRoot) {
139
+ const rootHint = projectRoot ? ` Use cwd "${projectRoot}".` : "";
140
+ return {
141
+ kind: "runtime_verify",
142
+ budgetKey: "runtimeVerify",
143
+ notice: "local app missing runtime proof",
144
+ message: "This is a local app build: do not stop after writing files or only telling the user how to run it. " +
145
+ "Prove the app is running with ANY of: shell.start + shell.tail ready, port LISTEN (lsof/ss), " +
146
+ "or localhost GET (http.fetch or curl). If the server is already listening, do NOT restart it " +
147
+ "just to re-mint evidence — confirm once, leave it running, task.update done, report URL + port + job id." +
148
+ rootHint,
149
+ };
150
+ }
151
+ export function recoveryForFailedProbe() {
152
+ return {
153
+ kind: "failed_probe",
154
+ budgetKey: "failedProbe",
155
+ notice: "localhost probe failed — fix and re-verify",
156
+ message: "The local HTTP probe failed (4xx/5xx or connection refused). Do not stop. " +
157
+ "Diagnose from the error, apply a real fix with fs.edit/fs.write, re-probe, and only then mark verify done. " +
158
+ "Identifying the error without a tool call is incomplete.",
159
+ };
160
+ }
161
+ export function recoveryForPrematureComplete(input) {
162
+ const list = input.unfinished
163
+ .map((t) => `[${t.id}] ${t.title}`)
164
+ .join("; ");
165
+ let instruction = `Resume task ${input.next.id} ("${input.next.title}"): `;
166
+ if (input.errorFix) {
167
+ instruction =
168
+ `Fix the failure with a tool first (fs.edit/fs.write), then continue task ${input.next.id} ("${input.next.title}"): `;
169
+ }
170
+ if (input.pentest) {
171
+ instruction +=
172
+ `task.update in_progress, then recon/test with real tools (dns/http/net.scan — not a local dev server), verify, mark done. `;
173
+ }
174
+ else if (input.next.state === "pending") {
175
+ instruction +=
176
+ `task.update in_progress, do the work, verify, mark done. `;
177
+ }
178
+ else {
179
+ instruction += `finish the work, verify, mark done. `;
180
+ }
181
+ instruction += "Continue until every task is finished.";
182
+ return {
183
+ kind: "premature_complete",
184
+ budgetKey: "prematureComplete",
185
+ notice: `${input.unfinished.length} plan task(s) still unfinished`,
186
+ message: `You have not finished the approved plan: ${input.unfinished.length} task(s) remain (${list}). ` +
187
+ `Do not claim completion without tool evidence. ${instruction}`,
188
+ };
189
+ }
190
+ export function recoveryForFreshness(extra) {
191
+ return {
192
+ kind: "freshness",
193
+ budgetKey: "freshnessUsed",
194
+ notice: "current-info question — search before answering",
195
+ message: extra,
196
+ };
197
+ }
198
+ /** True when a final pentest write-up looks like skim recon without real coverage. */
199
+ export function looksLikeShallowPentestReport(text, opts) {
200
+ if (opts.sawActiveTest)
201
+ return false;
202
+ if (opts.productiveSteps < 3)
203
+ return false;
204
+ const t = text.trim();
205
+ if (t.length < 80)
206
+ return false;
207
+ const lower = t.toLowerCase();
208
+ if (!/\b(finding|vulnerab|assessment|report|recon|open port|security posture|risk rating)\b/.test(lower)) {
209
+ return false;
210
+ }
211
+ const deep = /\b(idor|broken access|injection|xss|csrf|ssrf|rce|sqli|auth.?bypass|privilege|jwt|poc|exploit|confirmed|reproduc|ffuf|gobuster|ferox|directory enum|content discovery|crt\.sh|certificate transparency)\b/i.test(t);
212
+ if (deep)
213
+ return false;
214
+ const shallow = /\b(open ports?|port\s+\d+|server header|missing (?:security )?header|http\/1|tls|banner|robots\.txt|top[- ]?ports?|mature (?:security )?posture|overall risk rating:\s*low)\b/i.test(t);
215
+ const claimsComplete = /\b(no critical|no high|mature|strong security posture|not vulnerable)\b/i.test(t) &&
216
+ !/\b(untested|residual|not (?:tested|enumerated|scanned)|limited scope)\b/i.test(t);
217
+ return shallow || claimsComplete;
218
+ }
219
+ export function recoveryForShallowPentest() {
220
+ return {
221
+ kind: "shallow_pentest",
222
+ budgetKey: "shallowPentest",
223
+ notice: "pentest coverage looks thin — expand surface mapping",
224
+ message: "Coverage looks thin (ports/headers/robots or early closure without residual risk). " +
225
+ "Before finalizing: write a short threat model (top hypotheses for this stack), " +
226
+ "expand attack surface — escalate ports if only top-N was used, " +
227
+ "subdomain strategy beyond a few digs, content/API discovery (ffuf/gobuster + wordlist.find), " +
228
+ "JS harvest, then actively test high-value vectors. " +
229
+ "Background long scans while doing other recon. End with residual/untested honesty — " +
230
+ "do not claim mature posture if major classes were never attempted.",
231
+ };
232
+ }
233
+ export function freestyleClaimsAppReady(text) {
234
+ return (/\b(?:npm|pnpm|yarn|bun)\s+run\s+dev\b/i.test(text) ||
235
+ /\b(?:cargo\s+run|flask\s+run|uvicorn|rails\s+s|python\s+-m\s+http\.server)\b/i.test(text) ||
236
+ /\bopen\s+http:\/\/localhost\b/i.test(text) ||
237
+ /\bhow to run\b/i.test(text) ||
238
+ /\b(?:created|built|ready|complete)\b/i.test(text));
239
+ }
240
+ //# sourceMappingURL=must-continue.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"must-continue.js","sourceRoot":"","sources":["../../src/agent/must-continue.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,101 @@
1
+ export type OutcomeKind = "answer" | "build" | "bugfix" | "operation" | "pentest";
2
+ export type OutcomeStatus = "active" | "succeeded" | "partial" | "blocked" | "failed" | "aborted" | "paused_budget";
3
+ export type CriterionStatus = "unproven" | "supported" | "proven" | "refuted" | "waived";
4
+ export type EvidenceKind = "observation" | "automated-check" | "process-start" | "readiness" | "probe" | "reproduction" | "impact" | "artifact" | "scanner-lead";
5
+ export interface OutcomeCriterion {
6
+ id: string;
7
+ statement: string;
8
+ required: boolean;
9
+ status: CriterionStatus;
10
+ evidenceIds: string[];
11
+ revision: number;
12
+ domain?: "general" | "feature" | "bugfix" | "server" | "pentest-finding" | undefined;
13
+ }
14
+ export interface OutcomeContract {
15
+ schemaVersion: 1;
16
+ id: string;
17
+ sessionId: string;
18
+ userIntent: string;
19
+ kind: OutcomeKind;
20
+ criteria: OutcomeCriterion[];
21
+ assumptions: string[];
22
+ constraints: string[];
23
+ status: OutcomeStatus;
24
+ revision: number;
25
+ createdAt: string;
26
+ updatedAt: string;
27
+ }
28
+ export interface EvidenceRecord {
29
+ schemaVersion: 1;
30
+ id: string;
31
+ outcomeId: string;
32
+ criterionIds: string[];
33
+ taskId?: string | undefined;
34
+ source: {
35
+ tool: string;
36
+ callId: string;
37
+ artifact?: string | undefined;
38
+ };
39
+ kind: EvidenceKind;
40
+ observedAt: string;
41
+ freshness: "current" | "stale";
42
+ strength: "supporting" | "decisive";
43
+ observation: string;
44
+ result: "pass" | "fail" | "inconclusive";
45
+ environment?: Record<string, string> | undefined;
46
+ outcomeRevision: number;
47
+ }
48
+ export interface OutcomeEnvelope {
49
+ schemaVersion: 1;
50
+ outcome: OutcomeContract;
51
+ evidence: EvidenceRecord[];
52
+ failedHypotheses: Array<{
53
+ signature: string;
54
+ premise: string;
55
+ observedAt: string;
56
+ }>;
57
+ }
58
+ export declare function createOutcome(input: {
59
+ sessionId: string;
60
+ userIntent: string;
61
+ kind: OutcomeKind;
62
+ criteria: Array<Pick<OutcomeCriterion, "statement" | "required" | "domain"> & {
63
+ id?: string;
64
+ }>;
65
+ }): OutcomeContract;
66
+ export declare function reviseOutcome(outcome: OutcomeContract, criteria: OutcomeContract["criteria"]): OutcomeContract;
67
+ export declare function linkEvidence(outcome: OutcomeContract, evidence: EvidenceRecord): void;
68
+ export declare function validateCriterionEvidence(criterion: OutcomeCriterion, records: readonly EvidenceRecord[]): {
69
+ ok: boolean;
70
+ reason?: string;
71
+ };
72
+ export declare function deriveOutcomeStatus(outcome: OutcomeContract, records: readonly EvidenceRecord[]): OutcomeStatus;
73
+ export declare function saveOutcomeState(envelope: OutcomeEnvelope): Promise<void>;
74
+ export declare function loadOutcomeState(sessionId: string): Promise<OutcomeEnvelope | undefined>;
75
+ export declare function createEvidence(input: Omit<EvidenceRecord, "schemaVersion" | "id" | "observedAt">): EvidenceRecord;
76
+ export declare function inferOutcomeKind(input: {
77
+ userIntent: string;
78
+ buildLike?: boolean;
79
+ pentestLike?: boolean;
80
+ }): OutcomeKind;
81
+ export declare function defaultOutcomeCriteria(kind: OutcomeKind, userIntent: string): Array<Pick<OutcomeCriterion, "id" | "statement" | "required" | "domain">>;
82
+ export declare function openOutcomeState(input: {
83
+ sessionId: string;
84
+ userIntent: string;
85
+ kind: OutcomeKind;
86
+ continueExisting?: boolean;
87
+ }): Promise<OutcomeEnvelope>;
88
+ export declare function recordFailedHypothesis(envelope: OutcomeEnvelope, input: {
89
+ signature: string;
90
+ premise: string;
91
+ }): void;
92
+ export declare function recordToolEvidence(envelope: OutcomeEnvelope, input: {
93
+ tool: string;
94
+ callId: string;
95
+ ok: boolean;
96
+ output: string;
97
+ artifact?: string | undefined;
98
+ taskId?: string | undefined;
99
+ args?: Record<string, unknown> | undefined;
100
+ }): EvidenceRecord[];
101
+ export declare function recordAnswerEvidence(envelope: OutcomeEnvelope, answer: string): EvidenceRecord | undefined;