@iowarp/clio-coder 0.3.3 → 0.3.6

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 (370) hide show
  1. package/CHANGELOG.md +74 -0
  2. package/CONTRIBUTING.md +7 -7
  3. package/README.md +3 -3
  4. package/dist/{acp-P2AQILE2.js → acp-2BEHC4DL.js} +9 -8
  5. package/dist/{agents-72W3BI7I.js → agents-LNNFTM53.js} +29 -24
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-5TWEIYDN.js → auth-KXXFI2VS.js} +14 -10
  8. package/dist/{chunk-GGXXDWE4.js → chunk-22NAGB7X.js} +2 -2
  9. package/dist/{chunk-YCWGATWI.js → chunk-24I7BN55.js} +2 -2
  10. package/dist/{chunk-EKMEHE4H.js → chunk-33YXPOE3.js} +2 -3
  11. package/dist/chunk-3BPUFZDL.js +37 -0
  12. package/dist/chunk-43AOLP7E.js +375 -0
  13. package/dist/{chunk-ZDOOVTXZ.js → chunk-4OC57DA6.js} +27 -4
  14. package/dist/{chunk-6SGHMWE3.js → chunk-5JGRAMKL.js} +5 -5
  15. package/dist/{chunk-V6RTAOC2.js → chunk-6US73PDB.js} +572 -51
  16. package/dist/{chunk-5UFT4SUX.js → chunk-6XXKFVSN.js} +3 -3
  17. package/dist/{chunk-A3CYT5EX.js → chunk-AD2SYQYC.js} +55 -2
  18. package/dist/chunk-AOCYTWAV.js +449 -0
  19. package/dist/chunk-CFGTUFWB.js +67 -0
  20. package/dist/chunk-CJUB2JJ2.js +1478 -0
  21. package/dist/{chunk-FNTMWMX5.js → chunk-CKXWIANG.js} +14 -12
  22. package/dist/{chunk-PIWWS5BL.js → chunk-CYQKWTG3.js} +63 -78
  23. package/dist/{chunk-LZSJBIVT.js → chunk-DJVECN66.js} +271 -762
  24. package/dist/{chunk-CBCAPZAA.js → chunk-E25LMLRW.js} +2 -2
  25. package/dist/{chunk-ZWMF7253.js → chunk-E2ER4LJF.js} +304 -9
  26. package/dist/{chunk-STBPMHSX.js → chunk-EKY57CSP.js} +51 -84
  27. package/dist/{chunk-DUYJ5IO6.js → chunk-EYPA3EGJ.js} +12 -4
  28. package/dist/{chunk-M6SHUN7Q.js → chunk-FO5ZOVUY.js} +2 -2
  29. package/dist/chunk-FYYLNIL5.js +313 -0
  30. package/dist/{chunk-OQ33BKR3.js → chunk-G7MUEIGA.js} +3 -60
  31. package/dist/chunk-GEYXPTRF.js +613 -0
  32. package/dist/chunk-GOXNB3AO.js +261 -0
  33. package/dist/{chunk-G4BMMOKF.js → chunk-HVDIIIQW.js} +2 -2
  34. package/dist/chunk-HWUFFB6L.js +83 -0
  35. package/dist/{chunk-4XUGQOHA.js → chunk-K7T3E2SR.js} +15 -8
  36. package/dist/chunk-K7VKOLQQ.js +15 -0
  37. package/dist/{chunk-UFIIWP2H.js → chunk-KHSFENX2.js} +8 -8
  38. package/dist/{chunk-BMEMKKIT.js → chunk-KOHPCX4K.js} +2 -2
  39. package/dist/chunk-LCGCVYZ4.js +57 -0
  40. package/dist/chunk-LL4KHSZI.js +22 -0
  41. package/dist/{chunk-PAJK6MAQ.js → chunk-LYF7OHWH.js} +42 -15
  42. package/dist/{chunk-POHLU5DW.js → chunk-M6L6IDJG.js} +3 -3
  43. package/dist/{chunk-5UUP6MWO.js → chunk-MV3K5QF2.js} +5 -436
  44. package/dist/{chunk-X4RCMKVQ.js → chunk-NDINPTJ4.js} +2 -2
  45. package/dist/{chunk-TZK7PACC.js → chunk-NILBFAPG.js} +14 -8
  46. package/dist/chunk-ODFEOB4F.js +1082 -0
  47. package/dist/{chunk-AGYYIBLL.js → chunk-OH3TOQTB.js} +6 -2
  48. package/dist/chunk-OZNBF4L3.js +23 -0
  49. package/dist/{chunk-DSELYM6W.js → chunk-PBTHKCPN.js} +30 -10
  50. package/dist/{verify-375KUB3Y.js → chunk-PCZJO5TI.js} +127 -42
  51. package/dist/{chunk-ED4KHGC3.js → chunk-PPAMZ32Z.js} +9 -2
  52. package/dist/{chunk-SRDMMSEP.js → chunk-QM3F2GKX.js} +1063 -1645
  53. package/dist/{chunk-X6IAEBZR.js → chunk-QNQHSOLF.js} +7 -7
  54. package/dist/{chunk-OC7FIQPC.js → chunk-R46L2BIR.js} +10 -7
  55. package/dist/{chunk-2TLUCQVG.js → chunk-RD5U66HV.js} +3 -3
  56. package/dist/{chunk-6N5PTWMY.js → chunk-RY3LY4J5.js} +50 -13
  57. package/dist/{chunk-OKGUZO2U.js → chunk-SPULKLCF.js} +4 -3
  58. package/dist/{chunk-OOJYHWRB.js → chunk-TSHXZTOQ.js} +6 -5
  59. package/dist/chunk-TZSKNMZG.js +434 -0
  60. package/dist/{chunk-7MNJORFF.js → chunk-UL3WSD3F.js} +6 -1
  61. package/dist/{chunk-VJWL6YS5.js → chunk-UUVG37B4.js} +2 -2
  62. package/dist/{chunk-COU2UHX6.js → chunk-VEZEGCGW.js} +170 -2
  63. package/dist/chunk-W6GROXXM.js +69 -0
  64. package/dist/{chunk-OAO4GE4M.js → chunk-WHGPSPT5.js} +2 -2
  65. package/dist/chunk-WHJYKASB.js +677 -0
  66. package/dist/{chunk-ORBHGJC5.js → chunk-WR67VIZY.js} +3 -3
  67. package/dist/{chunk-YHZX5GEU.js → chunk-XAKHZX5N.js} +2 -2
  68. package/dist/{chunk-TZTZS7QK.js → chunk-XE2VEJHX.js} +5 -3
  69. package/dist/{chunk-LM5TQCJZ.js → chunk-XF5N4U5A.js} +8 -7
  70. package/dist/{chunk-LWLEKMDQ.js → chunk-XXQNGV4M.js} +1073 -552
  71. package/dist/{chunk-KZWTDYJF.js → chunk-XYDYPRZI.js} +7 -7
  72. package/dist/chunk-ZGVHUX3M.js +66 -0
  73. package/dist/{chunk-LW6DSM3M.js → chunk-ZRGEBJ4T.js} +1192 -1119
  74. package/dist/{chunk-2DJ2KNFG.js → chunk-ZXF4XRKW.js} +202 -40
  75. package/dist/chunk-ZZMN5OM4.js +122 -0
  76. package/dist/cli/index.js +34 -30
  77. package/dist/{clio-JOU4FXVA.js → clio-M2KGYUFZ.js} +7 -6
  78. package/dist/{code-nav-7AX6FYE6.js → code-nav-GQNL7XA6.js} +8 -6
  79. package/dist/codewiki/build-worker.js +4 -4
  80. package/dist/{components-KELWS457.js → components-5TTYYX6G.js} +3 -3
  81. package/dist/{config-XCDVKR23.js → config-XUUYQIWO.js} +47 -35
  82. package/dist/{configure-4GAP54ZW.js → configure-IHJ7YOMV.js} +18 -15
  83. package/dist/{context-77FM5DV5.js → context-74JLXAWD.js} +18 -10
  84. package/dist/{context-4UOGGLQ5.js → context-75MIWW3U.js} +41 -29
  85. package/dist/{context-5VKGUVJJ.js → context-ZQ7SIFJV.js} +85 -9
  86. package/dist/{context-clear-XXJRLCJJ.js → context-clear-GYKWNUML.js} +41 -29
  87. package/dist/{context-index-BZ4UYMTC.js → context-index-SSR5ECNE.js} +3 -3
  88. package/dist/context-working-set-UX5KEP4J.js +1553 -0
  89. package/dist/{dispatch-runner-QPRDDBDX.js → dispatch-runner-GIJBHNFL.js} +47 -32
  90. package/dist/{docs-2C2LTVT2.js → docs-6FZSCG5B.js} +3 -3
  91. package/dist/{doctor-HR46URBJ.js → doctor-SVJ5BZCW.js} +12 -12
  92. package/dist/{eval-XSSNATB4.js → eval-CG6LLBLD.js} +54 -238
  93. package/dist/{evidence-6HG2PY2B.js → evidence-ZYFIEN42.js} +57 -28
  94. package/dist/{evolve-K7YU3NCY.js → evolve-QGEXEMDW.js} +36 -25
  95. package/dist/{extensions-QVDOHDGJ.js → extensions-ADGNCJJD.js} +3 -3
  96. package/dist/{fleet-VY3HHKN6.js → fleet-S5R4ZOQY.js} +73 -44
  97. package/dist/{fleet-preflight-DDN536IT.js → fleet-preflight-BHSNPBMH.js} +3 -3
  98. package/dist/{init-JYGXI3FK.js → init-5DRU55YR.js} +49 -37
  99. package/dist/memory-7YKKR6UC.js +467 -0
  100. package/dist/{models-I5QWSEOM.js → models-ZPOLRU2C.js} +24 -21
  101. package/dist/{monitor-GE4ID3IA.js → monitor-US5F5YGZ.js} +73 -46
  102. package/dist/{orchestrator-EM5MC3HM.js → orchestrator-E2AL4T5N.js} +1624 -1007
  103. package/dist/{paths-UXLN5YYZ.js → paths-E7KYAQWE.js} +3 -3
  104. package/dist/{reset-L2FQEE3E.js → reset-KZ652EK6.js} +6 -5
  105. package/dist/{run-ZU3QMZPZ.js → run-SRNBKDWD.js} +76 -54
  106. package/dist/{share-S5BZQC5I.js → share-CGZE33UP.js} +7 -6
  107. package/dist/{skills-X5VXCRNQ.js → skills-S2X4DLY5.js} +4 -4
  108. package/dist/{skills-eval-WKIHWTHR.js → skills-eval-W2GGIC4R.js} +40 -29
  109. package/dist/{targets-SNCPI2NR.js → targets-54SWINWB.js} +28 -23
  110. package/dist/{terminal-lease-BNAHVHBS.js → terminal-lease-SAIF2OGY.js} +6 -4
  111. package/dist/{uninstall-FZCQCDKC.js → uninstall-BVLWXKBT.js} +3 -3
  112. package/dist/{upgrade-JQHHPQ4K.js → upgrade-JKAR27XC.js} +20 -19
  113. package/dist/{usage-OR4O5SMZ.js → usage-MSAWCLX4.js} +79 -36
  114. package/dist/verifiers-NCBTHHN2.js +1220 -0
  115. package/dist/verify-X5HDROLA.js +25 -0
  116. package/dist/{wiki-generate-UEXP2ARI.js → wiki-generate-GUSOQ6ZP.js} +50 -37
  117. package/dist/worker/entry.js +90 -70
  118. package/dist/{workspace-G4ZWUIPR.js → workspace-ZJ6BFM3Q.js} +4 -4
  119. package/docs/README.md +8 -7
  120. package/docs/acp.md +1 -1
  121. package/docs/alcf-provider.md +1 -1
  122. package/docs/architecture.md +2 -2
  123. package/docs/artifact-placement.md +1 -2
  124. package/docs/artifact-versions.md +1 -1
  125. package/docs/built-in-agents.md +1 -1
  126. package/docs/capacity-and-scheduling.md +1 -1
  127. package/docs/commands-and-modes.md +60 -26
  128. package/docs/config-knobs-audit.md +1 -2
  129. package/docs/configuration-and-targets.md +26 -1
  130. package/docs/context-engine.md +67 -13
  131. package/docs/context-working-set.md +194 -0
  132. package/docs/development-pipeline.md +1 -1
  133. package/docs/documentation-coverage.md +6 -6
  134. package/docs/documentation-guide.md +7 -6
  135. package/docs/environment-variables.md +2 -1
  136. package/docs/eval-runner.md +1 -1
  137. package/docs/evals-internal.md +4 -32
  138. package/docs/evidence-and-memory.md +139 -7
  139. package/docs/evolution.md +1 -1
  140. package/docs/exit-codes-and-output.md +1 -1
  141. package/docs/extensions-and-sharing.md +2 -2
  142. package/docs/fleet-dispatch.md +49 -8
  143. package/docs/glossary.md +21 -1
  144. package/docs/installation-and-lifecycle.md +2 -2
  145. package/docs/middleware-and-components.md +19 -2
  146. package/docs/model-catalog.md +7 -9
  147. package/docs/observability.md +4 -4
  148. package/docs/proactive-memory.md +26 -16
  149. package/docs/prompt-envelope-and-tools.md +7 -5
  150. package/docs/provider-adapter-cookbook.md +1 -1
  151. package/docs/release-cut-checklist.md +43 -40
  152. package/docs/safety-model.md +49 -8
  153. package/docs/scientific-validation.md +21 -3
  154. package/docs/session-lifecycle.md +3 -3
  155. package/docs/skills-marketplace.md +1 -1
  156. package/docs/tool-usage.md +79 -12
  157. package/docs/trace-store.md +1 -1
  158. package/docs/troubleshooting.md +1 -1
  159. package/docs/tui-design.md +38 -4
  160. package/docs/worker-dispatch-mechanics.md +11 -1
  161. package/package.json +13 -13
  162. package/skills/meta/clio-test/SKILL.md +20 -17
  163. package/skills/meta/clio-test/evals.md +3 -3
  164. package/skills/meta/clio-test/references/harness.md +35 -6
  165. package/skills/meta/clio-test/references/test-map.md +20 -10
  166. package/skills/registry.yaml +2 -2
  167. package/skills/skill-marketplace.json +1 -1
  168. package/src/cli/agents.ts +2 -3
  169. package/src/cli/argv.ts +14 -1
  170. package/src/cli/context-working-set.ts +513 -0
  171. package/src/cli/context.ts +8 -0
  172. package/src/cli/evidence.ts +20 -2
  173. package/src/cli/fleet.ts +15 -0
  174. package/src/cli/index.ts +5 -1
  175. package/src/cli/memory.ts +272 -10
  176. package/src/cli/modes/json-stream.ts +2 -2
  177. package/src/cli/modes/print.ts +12 -1
  178. package/src/cli/run.ts +22 -2
  179. package/src/cli/targets.ts +12 -3
  180. package/src/cli/usage.ts +55 -7
  181. package/src/cli/verifiers.ts +325 -0
  182. package/src/core/bash-exec.ts +39 -14
  183. package/src/core/bus-events.ts +22 -4
  184. package/src/core/config.ts +54 -0
  185. package/src/core/defaults.ts +50 -3
  186. package/src/core/response-model-id.ts +134 -0
  187. package/src/core/toml.ts +62 -0
  188. package/src/core/verification-scripts.ts +6 -0
  189. package/src/core/workspace-files.ts +0 -1
  190. package/src/domains/agents/builtins/architect.md +1 -1
  191. package/src/domains/agents/builtins/verifier.md +3 -0
  192. package/src/domains/agents/catalog.ts +5 -4
  193. package/src/domains/agents/recipe.ts +54 -14
  194. package/src/domains/agents/result-contract.ts +7 -4
  195. package/src/domains/config/classify.ts +1 -0
  196. package/src/domains/context/bootstrap.ts +36 -27
  197. package/src/domains/context/project-metadata.ts +19 -63
  198. package/src/domains/context/prompt-context.ts +8 -0
  199. package/src/domains/context/working-set/contract.ts +161 -0
  200. package/src/domains/context/working-set/defaults.ts +28 -0
  201. package/src/domains/context/working-set/engine.ts +203 -0
  202. package/src/domains/context/working-set/fold.ts +62 -0
  203. package/src/domains/context/working-set/horizon.ts +38 -0
  204. package/src/domains/context/working-set/marker.ts +103 -0
  205. package/src/domains/context/working-set/path-index.ts +436 -0
  206. package/src/domains/context/working-set/payload.ts +152 -0
  207. package/src/domains/context/working-set/policies/age-horizon.ts +55 -0
  208. package/src/domains/context/working-set/policies/index.ts +20 -0
  209. package/src/domains/context/working-set/policies/structural.ts +160 -0
  210. package/src/domains/context/working-set/project.ts +132 -0
  211. package/src/domains/context/working-set/protect.ts +109 -0
  212. package/src/domains/context/working-set/recall.ts +177 -0
  213. package/src/domains/context/working-set/replay/controls.ts +112 -0
  214. package/src/domains/context/working-set/replay/load-clio.ts +199 -0
  215. package/src/domains/context/working-set/replay/metrics.ts +185 -0
  216. package/src/domains/context/working-set/replay/reference-graph.ts +79 -0
  217. package/src/domains/context/working-set/replay/report.ts +139 -0
  218. package/src/domains/context/working-set/replay/runner.ts +325 -0
  219. package/src/domains/context/working-set/replay/synthetic.ts +422 -0
  220. package/src/domains/context/working-set/replay/trace.ts +21 -0
  221. package/src/domains/context/working-set/visible.ts +54 -0
  222. package/src/domains/dispatch/budget-envelope.ts +396 -0
  223. package/src/domains/dispatch/contract.ts +2 -0
  224. package/src/domains/dispatch/extension.ts +81 -27
  225. package/src/domains/dispatch/orphan-recovery.ts +1 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +4 -0
  227. package/src/domains/dispatch/state.ts +1 -0
  228. package/src/domains/dispatch/types.ts +10 -3
  229. package/src/domains/dispatch/validation.ts +14 -0
  230. package/src/domains/dispatch/worker-spawn.ts +14 -3
  231. package/src/domains/eval/metrics/evidence.ts +0 -116
  232. package/src/domains/eval/metrics/invariants.ts +1 -1
  233. package/src/domains/eval/runners/clio-run.ts +1 -10
  234. package/src/domains/eval/runners/external-command.ts +2 -29
  235. package/src/domains/eval/schema/suite.ts +0 -7
  236. package/src/domains/eval/suites/run.ts +1 -7
  237. package/src/domains/evidence/build.ts +112 -45
  238. package/src/domains/evidence/eval.ts +24 -7
  239. package/src/domains/evidence/index.ts +53 -0
  240. package/src/domains/evidence/ordering.ts +12 -0
  241. package/src/domains/evidence/run-trust.ts +221 -0
  242. package/src/domains/evidence/store.ts +46 -6
  243. package/src/domains/evidence/trust-status.ts +854 -0
  244. package/src/domains/evidence/types.ts +26 -0
  245. package/src/domains/memory/index.ts +22 -0
  246. package/src/domains/memory/operations.ts +58 -1
  247. package/src/domains/memory/promotion.ts +281 -0
  248. package/src/domains/memory/prompt-section.ts +25 -5
  249. package/src/domains/memory/proposal.ts +51 -7
  250. package/src/domains/memory/task-bank.ts +3 -2
  251. package/src/domains/memory/task-memory-handoff.ts +181 -24
  252. package/src/domains/memory/task-memory-policy.ts +3 -1
  253. package/src/domains/memory/types.ts +37 -0
  254. package/src/domains/memory/validate.ts +178 -0
  255. package/src/domains/middleware/memory-intervention.ts +38 -25
  256. package/src/domains/middleware/runtime.ts +6 -0
  257. package/src/domains/middleware/skills-reminder.ts +19 -4
  258. package/src/domains/middleware/stalled-turn.ts +208 -5
  259. package/src/domains/middleware/types.ts +10 -0
  260. package/src/domains/observability/contract.ts +6 -1
  261. package/src/domains/observability/cost.ts +20 -4
  262. package/src/domains/observability/extension.ts +2 -2
  263. package/src/domains/providers/index.ts +3 -0
  264. package/src/domains/providers/model-discovery.ts +9 -0
  265. package/src/domains/providers/runtime-resolution.ts +38 -1
  266. package/src/domains/providers/runtimes/common/probe-helpers.ts +97 -16
  267. package/src/domains/providers/types/context-window-slots.ts +18 -0
  268. package/src/domains/providers/types/runtime-descriptor.ts +3 -1
  269. package/src/domains/safety/autonomy.ts +1 -1
  270. package/src/domains/safety/call-target.ts +211 -14
  271. package/src/domains/safety/decision-presentation.ts +268 -0
  272. package/src/domains/safety/default-path-policy.ts +8 -0
  273. package/src/domains/safety/finish-contract.ts +4 -3
  274. package/src/domains/safety/policy-engine.ts +48 -6
  275. package/src/domains/safety/redaction.ts +73 -0
  276. package/src/domains/session/compaction/compact.ts +23 -1
  277. package/src/domains/session/compaction/cut-point.ts +2 -0
  278. package/src/domains/session/compaction/tokens.ts +16 -1
  279. package/src/domains/session/context-ledger.ts +12 -1
  280. package/src/domains/session/decision-board.ts +4 -0
  281. package/src/domains/session/entries.ts +110 -1
  282. package/src/domains/session/history.ts +68 -19
  283. package/src/domains/session/manager.ts +9 -2
  284. package/src/domains/session/migrations/index.ts +22 -3
  285. package/src/domains/session/usage.ts +24 -7
  286. package/src/engine/acp/event-mapper.ts +7 -0
  287. package/src/engine/acp/server.ts +32 -2
  288. package/src/engine/agent.ts +18 -1
  289. package/src/engine/apis/lmstudio.ts +25 -4
  290. package/src/engine/apis/openai-completions.ts +147 -22
  291. package/src/engine/claude/sdk-runtime.ts +8 -2
  292. package/src/engine/claude/tool-safety.ts +13 -0
  293. package/src/engine/loop-guard.ts +27 -3
  294. package/src/engine/session.ts +9 -3
  295. package/src/engine/worker-events.ts +4 -3
  296. package/src/engine/worker-runtime.ts +59 -54
  297. package/src/entry/orchestrator.ts +34 -5
  298. package/src/interactive/chat-loop-messages.ts +40 -6
  299. package/src/interactive/chat-loop.ts +13 -0
  300. package/src/interactive/chat-panel.ts +17 -1
  301. package/src/interactive/chat-renderer.ts +49 -24
  302. package/src/interactive/clio-editor.ts +44 -7
  303. package/src/interactive/context-meter.ts +10 -0
  304. package/src/interactive/context-overlay.ts +120 -7
  305. package/src/interactive/context-recall-command.ts +110 -0
  306. package/src/interactive/cost-overlay.ts +39 -8
  307. package/src/interactive/dispatch-board.ts +212 -35
  308. package/src/interactive/footer/widgets.ts +13 -0
  309. package/src/interactive/interactive-application.ts +6 -1
  310. package/src/interactive/interactive-input-runtime.ts +11 -1
  311. package/src/interactive/interactive-presentation.ts +11 -1
  312. package/src/interactive/interactive-slash-runtime.ts +37 -1
  313. package/src/interactive/memory-overlay.ts +89 -4
  314. package/src/interactive/model-session-replay.ts +21 -0
  315. package/src/interactive/overlay-ask-user-lifecycle.ts +1 -1
  316. package/src/interactive/overlay-frame.ts +5 -2
  317. package/src/interactive/overlay-general-openers.ts +46 -1
  318. package/src/interactive/overlay-key-routing.ts +41 -1
  319. package/src/interactive/overlay-lifecycle.ts +11 -4
  320. package/src/interactive/overlay-permission-lifecycle.ts +23 -8
  321. package/src/interactive/overlay-session-lifecycle.ts +8 -4
  322. package/src/interactive/overlay-transitions.ts +11 -0
  323. package/src/interactive/overlays/ask-user.ts +74 -30
  324. package/src/interactive/overlays/decisions.ts +3 -1
  325. package/src/interactive/permission-hint.ts +35 -0
  326. package/src/interactive/permission-overlay.ts +95 -45
  327. package/src/interactive/renderers/tool-execution.ts +37 -51
  328. package/src/interactive/session-last-turn.ts +8 -1
  329. package/src/interactive/session-transcript.ts +2 -2
  330. package/src/interactive/session-usage-reseed.ts +36 -10
  331. package/src/interactive/slash-commands.ts +31 -4
  332. package/src/interactive/status/summary.ts +5 -0
  333. package/src/interactive/status/types.ts +5 -0
  334. package/src/interactive/terminal-lease.ts +1 -0
  335. package/src/interactive/turn-context.ts +333 -110
  336. package/src/interactive/turn-middleware.ts +7 -6
  337. package/src/interactive/turn-runtime.ts +37 -8
  338. package/src/interactive/turn-state.ts +3 -0
  339. package/src/interactive/worker-progress.ts +440 -0
  340. package/src/interactive/worker-stream.ts +51 -110
  341. package/src/tools/agent-tools.ts +39 -7
  342. package/src/tools/ask-user.ts +21 -1
  343. package/src/tools/bash.ts +144 -82
  344. package/src/tools/builtin-tool-catalog.ts +11 -5
  345. package/src/tools/context/index.ts +107 -5
  346. package/src/tools/context/surface.ts +3 -2
  347. package/src/tools/core-bootstrap.ts +21 -0
  348. package/src/tools/dispatch-arguments.ts +8 -0
  349. package/src/tools/dispatch-event-text.ts +19 -0
  350. package/src/tools/dispatch-runner.ts +9 -7
  351. package/src/tools/dispatch.ts +24 -1
  352. package/src/tools/monitor.ts +43 -20
  353. package/src/tools/registry.ts +72 -10
  354. package/src/tools/result-disposition.ts +706 -0
  355. package/src/tools/result-shaping.ts +321 -20
  356. package/src/tools/safe-exec.ts +2 -0
  357. package/src/tools/verify/authoring.ts +1120 -0
  358. package/src/tools/verify/catalog.ts +346 -0
  359. package/src/tools/verify/index.ts +13 -3
  360. package/src/tools/verify/scripts.ts +135 -37
  361. package/src/tools/verify/surface.ts +9 -5
  362. package/src/tools/worker-evidence.ts +54 -12
  363. package/src/worker/spec-contract.ts +43 -3
  364. package/dist/chunk-J7CWMCQD.js +0 -255
  365. package/dist/chunk-T6YILFSB.js +0 -80
  366. package/dist/chunk-VAKQQHWR.js +0 -434
  367. package/dist/chunk-VPAYEGVX.js +0 -184
  368. package/dist/chunk-XBXAASKX.js +0 -18
  369. package/dist/memory-WFZMGYHX.js +0 -236
  370. package/src/domains/eval/metrics/chaos-stream.ts +0 -93
@@ -0,0 +1,1082 @@
1
+ import { createRequire as __clioCreateRequire } from "node:module"; const require = __clioCreateRequire(import.meta.url);
2
+ import {
3
+ formatSize,
4
+ truncateHead,
5
+ truncateTail
6
+ } from "./chunk-OZNBF4L3.js";
7
+ import {
8
+ createRedactionTally,
9
+ redactSecretsText
10
+ } from "./chunk-4BJ5BYCE.js";
11
+ import {
12
+ byteLength,
13
+ truncateUtf8
14
+ } from "./chunk-6XLNIQDB.js";
15
+ import {
16
+ GUARDRAIL_DEFAULTS,
17
+ GUARDRAIL_ENV_VARS,
18
+ resolveGuardrail
19
+ } from "./chunk-4ZG3XFUR.js";
20
+ import {
21
+ clioStateDir
22
+ } from "./chunk-BNAZZHFG.js";
23
+ import {
24
+ init_esm_shims
25
+ } from "./chunk-3R73A4XB.js";
26
+
27
+ // src/tools/truncate.ts
28
+ init_esm_shims();
29
+ var DEFAULT_MAX_LINES = 2e3;
30
+ var DEFAULT_MAX_BYTES = 16 * 1024;
31
+ function splitLinesForCounting(content) {
32
+ if (content.length === 0) return [];
33
+ const lines = content.split("\n");
34
+ if (content.endsWith("\n")) lines.pop();
35
+ return lines;
36
+ }
37
+ function withClioDefaults(options) {
38
+ return {
39
+ maxLines: options.maxLines ?? DEFAULT_MAX_LINES,
40
+ maxBytes: options.maxBytes ?? DEFAULT_MAX_BYTES
41
+ };
42
+ }
43
+ function truncateHead2(content, options = {}) {
44
+ return truncateHead(content, withClioDefaults(options));
45
+ }
46
+ function truncateTail2(content, options = {}) {
47
+ return truncateTail(content, withClioDefaults(options));
48
+ }
49
+
50
+ // src/tools/result-shaping.ts
51
+ init_esm_shims();
52
+ import { createHash as createHash2 } from "node:crypto";
53
+ import { mkdirSync, readdirSync, rmdirSync, rmSync, statSync, writeFileSync } from "node:fs";
54
+ import { isAbsolute, join, relative, resolve } from "node:path";
55
+
56
+ // src/tools/result-disposition.ts
57
+ init_esm_shims();
58
+ import { createHash } from "node:crypto";
59
+ var TOOL_RESULT_DIGEST_MAX_BYTES = 240;
60
+ var ESSENTIAL_DETAIL_KEYS = /* @__PURE__ */ new Set([
61
+ "aborted",
62
+ "continuation",
63
+ "continuationHint",
64
+ "decision",
65
+ "error",
66
+ "errors",
67
+ "evidence",
68
+ "exitCode",
69
+ "exitStatus",
70
+ "outputBytes",
71
+ "outputCapped",
72
+ "next",
73
+ "outcome",
74
+ "safety",
75
+ "safetyDecision",
76
+ "status",
77
+ "signal",
78
+ "terminate",
79
+ "timedOut",
80
+ "retainedBytes",
81
+ "stderrBytes",
82
+ "stdoutBytes"
83
+ ]);
84
+ function positiveByteCap(value, fallback) {
85
+ return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : fallback;
86
+ }
87
+ function normalizeToolResultDisposition(spec, hardMaxBytes, requested = spec.metadata?.resultDisposition) {
88
+ const declared = requested;
89
+ if (declared === void 0) return null;
90
+ const hardCap = positiveByteCap(hardMaxBytes, 1);
91
+ const presentationCap = Math.min(positiveByteCap(declared.presentation.maxBytes, hardCap), hardCap);
92
+ const contextCap = Math.min(positiveByteCap(declared.context.maxBytes, hardCap), hardCap);
93
+ return {
94
+ presentation: {
95
+ foldDefault: declared.presentation.foldDefault,
96
+ showDiffWhenFolded: declared.presentation.showDiffWhenFolded,
97
+ failureExcerpt: declared.presentation.failureExcerpt,
98
+ maxBytes: presentationCap,
99
+ ...declared.presentation.overflow === void 0 ? {} : { overflow: declared.presentation.overflow }
100
+ },
101
+ context: { ...declared.context, maxBytes: contextCap },
102
+ ...declared.fallback === void 0 ? {} : { fallback: declared.fallback }
103
+ };
104
+ }
105
+ function isRecord(value) {
106
+ return value !== null && typeof value === "object" && !Array.isArray(value);
107
+ }
108
+ function stableValue(value, seen) {
109
+ if (value === null || typeof value !== "object") return value;
110
+ if (seen.has(value)) return "[circular]";
111
+ seen.add(value);
112
+ if (Array.isArray(value)) {
113
+ const items = value.map((item) => stableValue(item, seen));
114
+ seen.delete(value);
115
+ return items;
116
+ }
117
+ const record = value;
118
+ const out = {};
119
+ for (const key of Object.keys(record).sort()) out[key] = stableValue(record[key], seen);
120
+ seen.delete(value);
121
+ return out;
122
+ }
123
+ function stableJson(value) {
124
+ try {
125
+ return JSON.stringify(stableValue(value, /* @__PURE__ */ new Set())) ?? "null";
126
+ } catch {
127
+ return JSON.stringify(String(value));
128
+ }
129
+ }
130
+ function essentialFacts(details) {
131
+ if (details === void 0) return null;
132
+ const facts = {};
133
+ for (const key of Object.keys(details).sort()) {
134
+ if (ESSENTIAL_DETAIL_KEYS.has(key)) facts[key] = details[key];
135
+ }
136
+ const observation = isRecord(details.observation) ? details.observation : null;
137
+ if (observation !== null && observation.next !== void 0) facts.next = observation.next;
138
+ return Object.keys(facts).length > 0 ? facts : null;
139
+ }
140
+ function utf8Prefix(text, maxBytes) {
141
+ if (maxBytes <= 0) return "";
142
+ const buffer = Buffer.from(text, "utf8");
143
+ if (buffer.byteLength <= maxBytes) return text;
144
+ let end = Math.min(maxBytes, buffer.byteLength);
145
+ while (end > 0 && end < buffer.byteLength && (buffer[end] ?? 0) >>> 6 === 2) end -= 1;
146
+ return buffer.subarray(0, end).toString("utf8");
147
+ }
148
+ function utf8Suffix(text, maxBytes) {
149
+ if (maxBytes <= 0) return "";
150
+ const buffer = Buffer.from(text, "utf8");
151
+ if (buffer.byteLength <= maxBytes) return text;
152
+ let start = Math.max(0, buffer.byteLength - maxBytes);
153
+ while (start < buffer.byteLength && (buffer[start] ?? 0) >>> 6 === 2) start += 1;
154
+ return buffer.subarray(start).toString("utf8");
155
+ }
156
+ function capUtf8(text, maxBytes) {
157
+ return byteLength(text) <= maxBytes ? text : utf8Prefix(text, maxBytes);
158
+ }
159
+ function capDigestUtf8(text, maxBytes) {
160
+ if (byteLength(text) <= maxBytes) return text;
161
+ const marker = "\u2026";
162
+ const markerBytes = byteLength(marker);
163
+ if (markerBytes >= maxBytes) return utf8Prefix(text, maxBytes);
164
+ return `${utf8Prefix(text, maxBytes - markerBytes).trimEnd()}${marker}`;
165
+ }
166
+ function boundedToolResultExcerpt(text, maxBytes, bias = "head-tail") {
167
+ if (maxBytes <= 0) return "";
168
+ if (byteLength(text) <= maxBytes) return text;
169
+ if (bias === "tail") return utf8Suffix(text, maxBytes);
170
+ const marker = "\n[\u2026 omitted \u2026]\n";
171
+ const markerBytes = byteLength(marker);
172
+ if (markerBytes >= maxBytes) return utf8Prefix(text, maxBytes);
173
+ const bodyBudget = maxBytes - markerBytes;
174
+ const headBudget = Math.floor(bodyBudget / 2);
175
+ const tailBudget = bodyBudget - headBudget;
176
+ return `${utf8Prefix(text, headBudget)}${marker}${utf8Suffix(text, tailBudget)}`;
177
+ }
178
+ function sourceLineCount(text) {
179
+ if (text.length === 0) return 0;
180
+ return text.replace(/\r\n/gu, "\n").replace(/\r/gu, "\n").split("\n").length;
181
+ }
182
+ function summaryProvenance(text, algorithm = "sha256-head-tail-v1", redactions = 0) {
183
+ return {
184
+ producer: "code",
185
+ algorithm,
186
+ sourceSha256: createHash("sha256").update(text).digest("hex"),
187
+ sourceLines: sourceLineCount(text),
188
+ ...redactions > 0 ? { redactions } : {}
189
+ };
190
+ }
191
+ var ERROR_LIKE_LINE = /(?:\b(?:abort(?:ed)?|assert(?:ion)?|error|exception|fail(?:ed|ure)?|fatal|killed|panic|signal|timed?\s*out|timeout)\b|\bnot ok\b|\bERR!\b)/iu;
192
+ var SUMMARY_LINE_MAX_BYTES = 768;
193
+ function summaryLine(line) {
194
+ return boundedToolResultExcerpt(line, SUMMARY_LINE_MAX_BYTES);
195
+ }
196
+ function normalizeNewlines(text) {
197
+ return text.replace(/\r\n/gu, "\n").replace(/\r/gu, "\n");
198
+ }
199
+ function contentLines(text) {
200
+ return normalizeNewlines(text).split("\n").map((line) => line.trim()).filter((line) => line.length > 0);
201
+ }
202
+ function deterministicHeadTailSummary(text, redact = true) {
203
+ const tally = createRedactionTally();
204
+ const safeText = redact ? redactSecretsText(text, tally) : text;
205
+ return { text: contentLines(safeText).join("\n"), redactions: tally.count, complete: tally.count === 0 };
206
+ }
207
+ function renderSummarySection(label, lines) {
208
+ return lines.length === 0 ? "" : `[${label}]
209
+ ${lines.map(summaryLine).join("\n")}`;
210
+ }
211
+ function deterministicDiagnosticSummary(text, maxBytes, redact = true) {
212
+ if (maxBytes <= 0 || text.length === 0) return { text: "", redactions: 0, complete: text.length === 0 };
213
+ const tally = createRedactionTally();
214
+ const safeText = redact ? redactSecretsText(text, tally) : text;
215
+ const lines = normalizeNewlines(safeText).split("\n");
216
+ const nonempty = lines.map((line, index) => ({ line: line.trim(), index })).filter((entry) => entry.line.length > 0);
217
+ if (nonempty.length === 0) return { text: "", redactions: tally.count, complete: tally.count === 0 };
218
+ if (nonempty.length === 1) {
219
+ const only = nonempty[0]?.line ?? "";
220
+ return {
221
+ text: boundedToolResultExcerpt(only, maxBytes),
222
+ redactions: tally.count,
223
+ complete: tally.count === 0 && byteLength(only) <= maxBytes
224
+ };
225
+ }
226
+ const head = nonempty.slice(0, 4);
227
+ const tail = nonempty.slice(Math.max(head.length, nonempty.length - 6));
228
+ const edgeIndexes = new Set([...head, ...tail].map((entry) => entry.index));
229
+ const diagnostics = nonempty.filter((entry) => !edgeIndexes.has(entry.index) && ERROR_LIKE_LINE.test(entry.line));
230
+ const sections = [
231
+ renderSummarySection(
232
+ "diagnostic head",
233
+ head.map((entry) => entry.line)
234
+ ),
235
+ renderSummarySection(
236
+ "error-like lines",
237
+ diagnostics.map((entry) => entry.line)
238
+ ),
239
+ renderSummarySection(
240
+ "diagnostic tail",
241
+ tail.map((entry) => entry.line)
242
+ )
243
+ ].filter((section) => section.length > 0);
244
+ const selected = [...head, ...diagnostics, ...tail];
245
+ const keepsEveryLine = selected.length === nonempty.length && selected.every((entry) => byteLength(entry.line) <= SUMMARY_LINE_MAX_BYTES);
246
+ const rendered = keepsEveryLine ? selected.map((entry) => summaryLine(entry.line)).join("\n") : sections.join("\n");
247
+ if (byteLength(rendered) <= maxBytes) {
248
+ return { text: rendered, redactions: tally.count, complete: keepsEveryLine && tally.count === 0 };
249
+ }
250
+ const weights = diagnostics.length > 0 ? [0.25, 0.45, 0.3] : [0.4, 0, 0.6];
251
+ const boundedSections = [];
252
+ for (const [index, section] of sections.entries()) {
253
+ const weight = diagnostics.length > 0 ? weights[index] ?? 0 : index === 0 ? 0.4 : 0.6;
254
+ const budget = Math.floor(maxBytes * weight);
255
+ if (budget > 0) boundedSections.push(boundedToolResultExcerpt(section ?? "", budget));
256
+ }
257
+ return { text: capUtf8(boundedSections.join("\n"), maxBytes), redactions: tally.count, complete: false };
258
+ }
259
+ function retrievalLine(offloadPath, followUpHint2) {
260
+ return offloadPath === null ? `retrieve=${JSON.stringify(followUpHint2)}` : `retrieve=${JSON.stringify(`read ${offloadPath} with offset and limit`)}`;
261
+ }
262
+ function contextHeader(input, appliedMode, truncated, provenance) {
263
+ const lines = [
264
+ `[tool-result ${appliedMode}]`,
265
+ `kind=${input.kind} capturedBytes=${input.capturedBytes} displayedBytes=${input.displayedBytes} truncated=${String(truncated)}`,
266
+ retrievalLine(input.offloadPath, input.followUpHint),
267
+ `followUp=${JSON.stringify(input.followUpHint)}`
268
+ ];
269
+ if (provenance !== void 0) {
270
+ lines.push(`summary=code/${provenance.algorithm} sha256=${provenance.sourceSha256} lines=${provenance.sourceLines}`);
271
+ }
272
+ if (input.disposition.fallback !== void 0) {
273
+ lines.push(`fallback=${input.disposition.fallback.reason} ${JSON.stringify(input.disposition.fallback.message)}`);
274
+ }
275
+ const facts = essentialFacts(input.details);
276
+ if (facts !== null) lines.push(`facts=${stableJson(facts)}`);
277
+ return lines.join("\n");
278
+ }
279
+ function joinHeaderAndBody(header, body, maxBytes, bias = "head-tail") {
280
+ if (body.length === 0) return capUtf8(header, maxBytes);
281
+ const separator = "\n";
282
+ const headerBytes = byteLength(header);
283
+ const separatorBytes = byteLength(separator);
284
+ if (headerBytes + separatorBytes >= maxBytes) return capUtf8(header, maxBytes);
285
+ const bodyBudget = maxBytes - headerBytes - separatorBytes;
286
+ return `${header}${separator}${boundedToolResultExcerpt(body, bodyBudget, bias)}`;
287
+ }
288
+ function fullTrailer(input) {
289
+ const facts = essentialFacts(input.details);
290
+ const lines = [];
291
+ if (facts !== null) lines.push(`facts=${stableJson(facts)}`);
292
+ if (input.followUpHint.length > 0) lines.push(`followUp=${JSON.stringify(input.followUpHint)}`);
293
+ return lines.length === 0 ? "" : `[tool-result metadata]
294
+ ${lines.join("\n")}`;
295
+ }
296
+ var NUL = "\0";
297
+ function stripNulForContext(text) {
298
+ const parts = text.split(NUL);
299
+ return parts.length === 1 ? { text, stripped: 0 } : { text: parts.join(""), stripped: parts.length - 1 };
300
+ }
301
+ function projectToolResultContext(input) {
302
+ const requestedMode = input.disposition.context.mode;
303
+ const maxBytes = input.disposition.context.maxBytes;
304
+ const sanitized = stripNulForContext(input.text);
305
+ const body = sanitized.text;
306
+ const capturedTextIsComplete = input.capturedBytes <= byteLength(input.text) && sanitized.stripped === 0;
307
+ if (requestedMode === "full") {
308
+ const trailer = fullTrailer(input);
309
+ const candidate = trailer.length === 0 ? body : `${body}
310
+
311
+ ${trailer}`;
312
+ if (capturedTextIsComplete && byteLength(candidate) <= maxBytes) {
313
+ return { text: candidate, appliedMode: "full", truncated: false };
314
+ }
315
+ const header2 = contextHeader(input, "bounded", true);
316
+ return {
317
+ text: joinHeaderAndBody(header2, body, maxBytes, input.disposition.context.downgradeExcerpt),
318
+ appliedMode: "bounded",
319
+ truncated: true,
320
+ downgrade: { from: "full", to: "bounded", reason: "hard-budget" }
321
+ };
322
+ }
323
+ if (requestedMode === "metadata-only") {
324
+ return {
325
+ text: capUtf8(contextHeader(input, "metadata-only", input.capturedBytes > 0), maxBytes),
326
+ appliedMode: "metadata-only",
327
+ truncated: input.capturedBytes > 0
328
+ };
329
+ }
330
+ if (requestedMode === "summary") {
331
+ const diagnostic = input.disposition.context.strategy === "diagnostic";
332
+ const algorithm = diagnostic ? "sha256-diagnostic-v1" : "sha256-head-tail-v1";
333
+ const redact = input.disposition.context.redact !== false;
334
+ const budgetHeader = contextHeader(input, "summary", true, summaryProvenance(input.text, algorithm));
335
+ const bodyBudget = Math.max(0, maxBytes - byteLength(budgetHeader) - 1);
336
+ const selected = diagnostic ? deterministicDiagnosticSummary(body, bodyBudget, redact) : deterministicHeadTailSummary(body, redact);
337
+ const provenance = summaryProvenance(input.text, algorithm, selected.redactions);
338
+ const completeHeader = contextHeader(input, "summary", false, provenance);
339
+ const fits = byteLength(completeHeader) + 1 + byteLength(selected.text) <= maxBytes;
340
+ const truncated = input.capturedBytes > 0 && !(capturedTextIsComplete && selected.complete && fits);
341
+ const header2 = contextHeader(input, "summary", truncated, provenance);
342
+ return {
343
+ text: joinHeaderAndBody(header2, selected.text, maxBytes),
344
+ appliedMode: "summary",
345
+ truncated,
346
+ summaryProvenance: provenance
347
+ };
348
+ }
349
+ const header = contextHeader(input, "bounded", input.capturedBytes > maxBytes);
350
+ const text = joinHeaderAndBody(header, body, maxBytes, input.disposition.context.excerpt);
351
+ return {
352
+ text,
353
+ appliedMode: "bounded",
354
+ truncated: byteLength(header) + 1 + byteLength(body) > maxBytes || !capturedTextIsComplete
355
+ };
356
+ }
357
+ var DIGEST_FACT_KEYS = [
358
+ "outcome",
359
+ "exitCode",
360
+ "timedOut",
361
+ "aborted",
362
+ "outputCapped",
363
+ "signal",
364
+ "status",
365
+ "error",
366
+ "decision",
367
+ "next"
368
+ ];
369
+ function digestFactText(details) {
370
+ if (details === void 0) return "";
371
+ const facts = [];
372
+ for (const key of DIGEST_FACT_KEYS) {
373
+ if (details[key] !== void 0) facts.push(`${key}=${stableJson(details[key])}`);
374
+ }
375
+ return facts.join(" ");
376
+ }
377
+ function projectionBody(input, projection) {
378
+ if (projection.appliedMode === "metadata-only") return "";
379
+ if (projection.appliedMode === "full") {
380
+ const trailer = fullTrailer(input);
381
+ return trailer.length > 0 && projection.text.endsWith(`
382
+
383
+ ${trailer}`) ? projection.text.slice(0, -(trailer.length + 2)) : projection.text;
384
+ }
385
+ const header = contextHeader(input, projection.appliedMode, projection.truncated, projection.summaryProvenance);
386
+ const prefix = `${header}
387
+ `;
388
+ return projection.text.startsWith(prefix) ? projection.text.slice(prefix.length) : "";
389
+ }
390
+ function digestText(status, facts, body, redactions, maxBytes) {
391
+ const tally = createRedactionTally();
392
+ const safeStatus = redactSecretsText(status, tally);
393
+ const safeFacts = redactSecretsText(facts, tally);
394
+ const statusAndFacts = [safeStatus, safeFacts].filter((value) => value.length > 0).join(" ");
395
+ const bodyBudget = Math.max(0, maxBytes - byteLength(statusAndFacts) - 2);
396
+ const selected = deterministicDiagnosticSummary(body, bodyBudget, true);
397
+ const candidate = [statusAndFacts, selected.text.replace(/\s+/gu, " ").trim()].filter((value) => value.length > 0).join("; ");
398
+ return {
399
+ text: capDigestUtf8(candidate, maxBytes),
400
+ redactions: redactions + tally.count + selected.redactions
401
+ };
402
+ }
403
+ function deterministicToolResultDigest(input, maxBytes = TOOL_RESULT_DIGEST_MAX_BYTES) {
404
+ const projection = projectToolResultContext(input);
405
+ const status = [
406
+ `kind=${input.kind}`,
407
+ `mode=${projection.appliedMode}`,
408
+ `truncated=${String(projection.truncated)}`,
409
+ ...projection.appliedMode === "metadata-only" || projection.truncated ? [`capturedBytes=${input.capturedBytes}`] : []
410
+ ].join(" ");
411
+ const digest = digestText(
412
+ status,
413
+ digestFactText(input.details),
414
+ projectionBody(input, projection),
415
+ projection.summaryProvenance?.redactions ?? 0,
416
+ Math.max(1, Math.floor(maxBytes))
417
+ );
418
+ return {
419
+ text: digest.text,
420
+ provenance: {
421
+ producer: "code",
422
+ source: "canonical-result-disposition",
423
+ algorithm: "redacted-context-digest-v1",
424
+ contextMode: projection.appliedMode,
425
+ ...projection.summaryProvenance === void 0 ? {} : { summaryAlgorithm: projection.summaryProvenance.algorithm },
426
+ ...digest.redactions > 0 ? { redactions: digest.redactions } : {}
427
+ }
428
+ };
429
+ }
430
+ function legacyToolResultDigest(text, options) {
431
+ const maxBytes = Math.max(1, Math.floor(options.maxBytes ?? TOOL_RESULT_DIGEST_MAX_BYTES));
432
+ const fallback = options.outcome === "error" && text.trim().length === 0 ? "an unknown tool error" : text;
433
+ const digest = digestText("", "", fallback, 0, maxBytes);
434
+ return {
435
+ text: digest.text,
436
+ provenance: {
437
+ producer: "code",
438
+ source: "legacy-fallback",
439
+ algorithm: "redacted-legacy-digest-v1",
440
+ ...digest.redactions > 0 ? { redactions: digest.redactions } : {}
441
+ }
442
+ };
443
+ }
444
+ function sanitizeToolResultDigest(digest, maxBytes = TOOL_RESULT_DIGEST_MAX_BYTES) {
445
+ const tally = createRedactionTally();
446
+ const safe = redactSecretsText(digest.text, tally).replace(/\s+/gu, " ").trim();
447
+ const redactions = (digest.provenance.redactions ?? 0) + tally.count;
448
+ return {
449
+ text: capDigestUtf8(safe, Math.max(1, Math.floor(maxBytes))),
450
+ provenance: {
451
+ ...digest.provenance,
452
+ ...redactions > 0 ? { redactions } : {}
453
+ }
454
+ };
455
+ }
456
+ function toolResultContextText(result) {
457
+ if (result.modelContext !== void 0) return result.modelContext;
458
+ return result.kind === "ok" ? result.output : result.message;
459
+ }
460
+ function isDispositionedToolResultError(result) {
461
+ if (!isRecord(result)) return false;
462
+ const details = isRecord(result.details) ? result.details : null;
463
+ const metadata = details !== null && isRecord(details.resultDisposition) ? details.resultDisposition : null;
464
+ const kind = result.kind ?? details?.kind;
465
+ return kind === "error" && metadata?.version === 1 && metadata.applications === 1;
466
+ }
467
+ function toolResultPresentationText(result) {
468
+ if (!isRecord(result)) return null;
469
+ const details = isRecord(result.details) ? result.details : null;
470
+ const metadata = details !== null && isRecord(details.resultDisposition) ? details.resultDisposition : null;
471
+ const presentation = metadata !== null && isRecord(metadata.presentation) ? metadata.presentation : null;
472
+ return presentation !== null && typeof presentation.content === "string" ? presentation.content : null;
473
+ }
474
+ function toolResultPresentationPolicy(result) {
475
+ if (!isRecord(result)) return null;
476
+ const details = isRecord(result.details) ? result.details : null;
477
+ const metadata = details !== null && isRecord(details.resultDisposition) ? details.resultDisposition : null;
478
+ const presentation = metadata !== null && isRecord(metadata.presentation) ? metadata.presentation : null;
479
+ if (presentation === null || presentation.foldDefault !== "folded" && presentation.foldDefault !== "expanded" || typeof presentation.showDiffWhenFolded !== "boolean" || typeof presentation.failureExcerpt !== "boolean") {
480
+ return null;
481
+ }
482
+ return {
483
+ foldDefault: presentation.foldDefault,
484
+ showDiffWhenFolded: presentation.showDiffWhenFolded,
485
+ failureExcerpt: presentation.failureExcerpt
486
+ };
487
+ }
488
+
489
+ // src/tools/result-shaping.ts
490
+ var DEFAULT_TOOL_RESULT_MAX_BYTES = DEFAULT_MAX_BYTES + 2 * 1024;
491
+ var RESULT_TRUNCATION_MARKER = "\n[tool result truncated]";
492
+ var RESULT_OFFLOAD_MAX_BYTES = 10 * 1024 * 1024;
493
+ var TAIL_NOTICE_RESERVE_BYTES = 512;
494
+ var TOOL_OFFLOAD_MAX_AGE_MS = 14 * 24 * 60 * 60 * 1e3;
495
+ function mergeDetails(details, resultSize) {
496
+ return { ...details ?? {}, resultSize };
497
+ }
498
+ function maxBytesFor(spec) {
499
+ const configured = spec.metadata?.resultSizePolicy?.maxBytes;
500
+ return typeof configured === "number" && Number.isFinite(configured) && configured > 0 ? Math.floor(configured) : DEFAULT_TOOL_RESULT_MAX_BYTES;
501
+ }
502
+ function followUpHint(spec) {
503
+ return spec.metadata?.resultSizePolicy?.followUpHint ?? "Use a narrower query, offset/limit arguments, or a more specific tool call to inspect the omitted content.";
504
+ }
505
+ function offloadMaxBytesFor(spec) {
506
+ const configured = spec.metadata?.resultSizePolicy?.offloadMaxBytes;
507
+ return typeof configured === "number" && Number.isFinite(configured) && configured > 0 ? Math.floor(configured) : RESULT_OFFLOAD_MAX_BYTES;
508
+ }
509
+ function toolResultDigestFor(spec, result, requestedDisposition) {
510
+ const text = resultText(result);
511
+ const disposition = normalizeToolResultDisposition(spec, maxBytesFor(spec), requestedDisposition);
512
+ if (disposition === null) {
513
+ const projected = shapeLegacyToolResult(spec, result);
514
+ return legacyToolResultDigest(resultText(projected), { outcome: result.kind });
515
+ }
516
+ const capturedBytes = capturedBytesFor(result, text);
517
+ return deterministicToolResultDigest({
518
+ text,
519
+ kind: result.kind,
520
+ details: result.details,
521
+ disposition,
522
+ capturedBytes,
523
+ displayedBytes: Math.min(capturedBytes, disposition.presentation.maxBytes),
524
+ offloadPath: existingOffloadPath(result.details),
525
+ followUpHint: followUpHint(spec)
526
+ });
527
+ }
528
+ function detailsRecord(details, key) {
529
+ const candidate = details?.[key];
530
+ return candidate !== null && typeof candidate === "object" && !Array.isArray(candidate) ? candidate : null;
531
+ }
532
+ function existingOffloadPath(details) {
533
+ const fromResultSize = detailsRecord(details, "resultSize")?.offloadPath;
534
+ if (typeof fromResultSize === "string" && fromResultSize.length > 0) return fromResultSize;
535
+ const fromObservation = detailsRecord(details, "observation")?.offloadPath;
536
+ return typeof fromObservation === "string" && fromObservation.length > 0 ? fromObservation : null;
537
+ }
538
+ function existingDisposition(details) {
539
+ const disposition = detailsRecord(details, "resultDisposition");
540
+ return disposition?.version === 1 && disposition.applications === 1 ? disposition : null;
541
+ }
542
+ function safePathSegment(value) {
543
+ const safe = value.trim().replace(/[^A-Za-z0-9._-]/g, "_").slice(0, 128);
544
+ return safe.length > 0 ? safe : "unnamed";
545
+ }
546
+ function offloadBody(text, bytes, maxBytes) {
547
+ if (bytes <= maxBytes) return text;
548
+ const notice = `
549
+ [clio-coder scratch output truncated at ${maxBytes} bytes; original size ${bytes} bytes]`;
550
+ const prefixBudget = maxBytes - byteLength(notice);
551
+ return `${truncateUtf8(text, Math.max(0, prefixBudget), "")}${notice}`;
552
+ }
553
+ function sweepExpiredToolOffloads(now = Date.now()) {
554
+ const root = join(clioStateDir(), "scratch");
555
+ const cutoff = now - TOOL_OFFLOAD_MAX_AGE_MS;
556
+ let removed = 0;
557
+ try {
558
+ for (const session of readdirSync(root, { withFileTypes: true })) {
559
+ if (!session.isDirectory()) continue;
560
+ const sessionDir = join(root, session.name);
561
+ for (const entry of readdirSync(sessionDir, { withFileTypes: true })) {
562
+ if (!entry.isFile()) continue;
563
+ const path = join(sessionDir, entry.name);
564
+ try {
565
+ if (statSync(path).mtimeMs >= cutoff) continue;
566
+ rmSync(path, { force: true });
567
+ removed += 1;
568
+ } catch {
569
+ }
570
+ }
571
+ try {
572
+ if (readdirSync(sessionDir).length === 0) rmdirSync(sessionDir);
573
+ } catch {
574
+ }
575
+ }
576
+ } catch {
577
+ }
578
+ return removed;
579
+ }
580
+ function writeToolOffload(text, context, maxBytes = RESULT_OFFLOAD_MAX_BYTES, digest = createHash2("sha256").update(text).digest("hex")) {
581
+ try {
582
+ const bytes = byteLength(text);
583
+ const sessionId = safePathSegment(context?.sessionId ?? "no-session");
584
+ const dir = join(clioStateDir(), "scratch", sessionId);
585
+ const path = join(dir, `${digest}.txt`);
586
+ mkdirSync(dir, { recursive: true });
587
+ writeFileSync(path, offloadBody(text, bytes, maxBytes), "utf8");
588
+ return path;
589
+ } catch {
590
+ return null;
591
+ }
592
+ }
593
+ var OFFLOAD_POINTER_NOTE = "overflow copy, read-only; not the workspace";
594
+ function offloadPointer(offloadPath) {
595
+ return `full: ${offloadPath} (${OFFLOAD_POINTER_NOTE})`;
596
+ }
597
+ function isSessionOffloadPath(filePath, sessionId) {
598
+ const dir = join(clioStateDir(), "scratch", safePathSegment(sessionId ?? "no-session"));
599
+ const rel = relative(dir, resolve(filePath));
600
+ return rel.length > 0 && !rel.startsWith("..") && !isAbsolute(rel);
601
+ }
602
+ function bracketedHint(spec, offloadPath) {
603
+ const hint = followUpHint(spec);
604
+ if (offloadPath === null) return hint;
605
+ return `${hint} ${offloadPointer(offloadPath)}; read it with offset and limit to inspect the rest.`;
606
+ }
607
+ function shapeJsonOverflow(spec, result, text, bytes, maxBytes, context, offloadMaxBytes) {
608
+ const observation = detailsRecord(result.details, "observation");
609
+ const offloadPath = writeToolOffload(text, context, offloadMaxBytes);
610
+ const next = typeof observation?.next === "string" && observation.next.length > 0 ? observation.next : followUpHint(spec);
611
+ const stub = JSON.stringify({
612
+ error: `result exceeded ${maxBytes} bytes`,
613
+ ...offloadPath !== null ? { offloadPath, offloadPathNote: OFFLOAD_POINTER_NOTE } : {},
614
+ next
615
+ });
616
+ const resultSize = {
617
+ bytes,
618
+ shownBytes: byteLength(stub),
619
+ maxBytes,
620
+ truncated: true,
621
+ policy: spec.metadata?.resultSizePolicy?.kind ?? "truncate",
622
+ followUpHint: followUpHint(spec),
623
+ ...offloadPath !== null ? { offloadPath } : {}
624
+ };
625
+ if (result.kind === "ok") {
626
+ return { ...result, output: stub, details: mergeDetails(result.details, resultSize) };
627
+ }
628
+ return { ...result, message: stub, details: mergeDetails(result.details, resultSize) };
629
+ }
630
+ function shapeTailOverflow(spec, result, text, bytes, maxBytes, context, offloadMaxBytes) {
631
+ const truncation = truncateTail2(text, {
632
+ maxLines: DEFAULT_MAX_LINES,
633
+ maxBytes: Math.max(1, maxBytes - TAIL_NOTICE_RESERVE_BYTES)
634
+ });
635
+ const offloadPath = writeToolOffload(text, context, offloadMaxBytes);
636
+ const startLine = truncation.totalLines - truncation.outputLines + 1;
637
+ const scope = truncation.lastLinePartial ? `last ${formatSize(truncation.outputBytes)} of line ${truncation.totalLines} (line is large)` : `lines ${startLine}-${truncation.totalLines} of ${truncation.totalLines}`;
638
+ const location = offloadPath === null ? "" : ` Full output saved to ${offloadPath}; ${OFFLOAD_POINTER_NOTE}; read it with offset/limit.`;
639
+ const note = `[Output tail-truncated: showing ${scope} (${formatSize(maxBytes)} display limit).${location}]`;
640
+ const resultSize = {
641
+ bytes,
642
+ shownBytes: truncation.outputBytes,
643
+ maxBytes,
644
+ truncated: true,
645
+ policy: "tail",
646
+ followUpHint: followUpHint(spec),
647
+ ...offloadPath === null ? {} : { offloadPath }
648
+ };
649
+ const displayed = `${truncation.content}
650
+
651
+ ${note}`;
652
+ if (result.kind === "ok") return { ...result, output: displayed, details: mergeDetails(result.details, resultSize) };
653
+ return { ...result, message: displayed, details: mergeDetails(result.details, resultSize) };
654
+ }
655
+ function shapeLegacyToolResult(spec, result, context, overflow = "head") {
656
+ if (existingOffloadPath(result.details) !== null) return result;
657
+ const maxBytes = maxBytesFor(spec);
658
+ const offloadMaxBytes = offloadMaxBytesFor(spec);
659
+ const text = result.kind === "ok" ? result.output : result.message;
660
+ const bytes = byteLength(text);
661
+ if (bytes <= maxBytes) return result;
662
+ const observation = detailsRecord(result.details, "observation");
663
+ if (observation?.format === "json") {
664
+ return shapeJsonOverflow(spec, result, text, bytes, maxBytes, context, offloadMaxBytes);
665
+ }
666
+ if (overflow === "tail") {
667
+ return shapeTailOverflow(spec, result, text, bytes, maxBytes, context, offloadMaxBytes);
668
+ }
669
+ const truncated = truncateUtf8(text, maxBytes, RESULT_TRUNCATION_MARKER);
670
+ const offloadPath = writeToolOffload(text, context, offloadMaxBytes);
671
+ const resultSize = {
672
+ bytes,
673
+ shownBytes: byteLength(truncated),
674
+ maxBytes,
675
+ truncated: true,
676
+ policy: spec.metadata?.resultSizePolicy?.kind ?? "truncate",
677
+ followUpHint: followUpHint(spec),
678
+ ...offloadPath !== null ? { offloadPath } : {}
679
+ };
680
+ if (result.kind === "ok") {
681
+ return {
682
+ ...result,
683
+ output: `${truncated}
684
+
685
+ [${bracketedHint(spec, offloadPath)}]`,
686
+ details: mergeDetails(result.details, resultSize)
687
+ };
688
+ }
689
+ return {
690
+ ...result,
691
+ message: `${truncated}
692
+
693
+ [${bracketedHint(spec, offloadPath)}]`,
694
+ details: mergeDetails(result.details, resultSize)
695
+ };
696
+ }
697
+ function specWithDisplayCap(spec, maxBytes) {
698
+ const metadata = spec.metadata;
699
+ if (metadata === void 0) return spec;
700
+ return {
701
+ ...spec,
702
+ metadata: {
703
+ ...metadata,
704
+ resultSizePolicy: { ...metadata.resultSizePolicy, maxBytes }
705
+ }
706
+ };
707
+ }
708
+ function resultText(result) {
709
+ return result.kind === "ok" ? result.output : result.message;
710
+ }
711
+ function withFallbackNotice(result, fallback) {
712
+ const note = `
713
+
714
+ [result disposition fell back to metadata-only: ${fallback.reason} (${fallback.message}); the model received facts and retrieval only]`;
715
+ return result.kind === "ok" ? { ...result, output: `${result.output}${note}` } : { ...result, message: `${result.message}${note}` };
716
+ }
717
+ function numberField(record, key) {
718
+ const value = record?.[key];
719
+ return typeof value === "number" && Number.isFinite(value) && value >= 0 ? value : null;
720
+ }
721
+ function capturedBytesFor(result, text) {
722
+ const declared = numberField(detailsRecord(result.details, "resultSize"), "bytes");
723
+ return Math.max(byteLength(text), declared ?? 0);
724
+ }
725
+ function resultWasTruncated(result) {
726
+ return detailsRecord(result.details, "resultSize")?.truncated === true;
727
+ }
728
+ function withOffloadMetadata(result, offloadPath, capturedBytes, displayedBytes, maxBytes, hint) {
729
+ const current = detailsRecord(result.details, "resultSize") ?? {};
730
+ const resultSize = {
731
+ bytes: numberField(current, "bytes") ?? capturedBytes,
732
+ shownBytes: numberField(current, "shownBytes") ?? displayedBytes,
733
+ maxBytes: numberField(current, "maxBytes") ?? maxBytes,
734
+ truncated: current.truncated === true,
735
+ policy: typeof current.policy === "string" ? current.policy : "disposition",
736
+ followUpHint: typeof current.followUpHint === "string" ? current.followUpHint : hint,
737
+ ...current,
738
+ offloadPath
739
+ };
740
+ return { ...result, details: mergeDetails(result.details, resultSize) };
741
+ }
742
+ function shapeToolResult(spec, result, context, requestedDisposition) {
743
+ if (existingDisposition(result.details) !== null) return result;
744
+ const hardMaxBytes = maxBytesFor(spec);
745
+ const disposition = normalizeToolResultDisposition(spec, hardMaxBytes, requestedDisposition);
746
+ if (disposition === null) return shapeLegacyToolResult(spec, result, context);
747
+ const capturedText = resultText(result);
748
+ const capturedBytes = capturedBytesFor(result, capturedText);
749
+ let displayed = shapeLegacyToolResult(
750
+ specWithDisplayCap(spec, disposition.presentation.maxBytes),
751
+ result,
752
+ context,
753
+ disposition.presentation.overflow
754
+ );
755
+ if (disposition.fallback !== void 0) displayed = withFallbackNotice(displayed, disposition.fallback);
756
+ let displayedText = resultText(displayed);
757
+ let displayedBytes = byteLength(displayedText);
758
+ let offloadPath = existingOffloadPath(displayed.details);
759
+ const projectionInput = {
760
+ text: capturedText,
761
+ kind: result.kind,
762
+ details: displayed.details,
763
+ disposition,
764
+ capturedBytes,
765
+ displayedBytes,
766
+ offloadPath,
767
+ followUpHint: followUpHint(spec)
768
+ };
769
+ let projection = projectToolResultContext(projectionInput);
770
+ if (offloadPath === null && projection.truncated) {
771
+ offloadPath = writeToolOffload(
772
+ capturedText,
773
+ context,
774
+ offloadMaxBytesFor(spec),
775
+ projection.summaryProvenance?.sourceSha256
776
+ );
777
+ if (offloadPath !== null) {
778
+ displayed = withOffloadMetadata(
779
+ displayed,
780
+ offloadPath,
781
+ capturedBytes,
782
+ displayedBytes,
783
+ disposition.presentation.maxBytes,
784
+ followUpHint(spec)
785
+ );
786
+ displayedText = resultText(displayed);
787
+ displayedBytes = byteLength(displayedText);
788
+ projection = projectToolResultContext({
789
+ ...projectionInput,
790
+ details: displayed.details,
791
+ displayedBytes,
792
+ offloadPath
793
+ });
794
+ }
795
+ }
796
+ const metadata = {
797
+ version: 1,
798
+ applications: 1,
799
+ presentation: { ...disposition.presentation, content: displayedText },
800
+ context: {
801
+ requestedMode: disposition.context.mode,
802
+ appliedMode: projection.appliedMode,
803
+ maxBytes: disposition.context.maxBytes,
804
+ ...disposition.context.mode === "bounded" && disposition.context.excerpt !== void 0 ? { excerpt: disposition.context.excerpt } : {},
805
+ ...disposition.context.mode === "full" && disposition.context.downgradeExcerpt !== void 0 ? { excerpt: disposition.context.downgradeExcerpt } : {},
806
+ ...disposition.context.mode === "summary" && disposition.context.strategy !== void 0 ? { summaryStrategy: disposition.context.strategy } : {}
807
+ },
808
+ capturedBytes,
809
+ displayedBytes,
810
+ contextBytes: byteLength(projection.text),
811
+ presentationTruncated: resultWasTruncated(displayed),
812
+ contextTruncated: projection.truncated,
813
+ ...projection.downgrade === void 0 ? {} : { downgrade: projection.downgrade },
814
+ ...offloadPath === null ? {} : { offloadPath },
815
+ retrieval: offloadPath === null ? followUpHint(spec) : `read ${offloadPath} with offset and limit to retrieve omitted content`,
816
+ ...projection.summaryProvenance === void 0 ? {} : { summaryProvenance: projection.summaryProvenance },
817
+ ...disposition.fallback === void 0 ? {} : { fallback: disposition.fallback }
818
+ };
819
+ return {
820
+ ...displayed,
821
+ details: { ...displayed.details ?? {}, resultDisposition: metadata },
822
+ modelContext: projection.text
823
+ };
824
+ }
825
+
826
+ // src/tools/observation.ts
827
+ init_esm_shims();
828
+ var OBSERVATION_POLICY_SLACK_BYTES = 2 * 1024;
829
+ var OBSERVE_SELF_CAPS = {
830
+ grepContent: 16 * 1024,
831
+ grepFilesCount: 8 * 1024,
832
+ find: 8 * 1024,
833
+ ls: 8 * 1024,
834
+ codeNav: 16 * 1024,
835
+ contextDocs: 16 * 1024,
836
+ contextSkills: 50 * 1024,
837
+ contextWorkspace: 50 * 1024
838
+ };
839
+ var DEFAULT_OBSERVATION_TURN_BUDGET_BYTES = GUARDRAIL_DEFAULTS.observationTurnBudgetBytes;
840
+ var OBSERVATION_TURN_BUDGET_ENV = GUARDRAIL_ENV_VARS.observationTurnBudgetBytes;
841
+ var MIN_BUDGET_SLICE_BYTES = 1024;
842
+ var BUDGET_TRACK_LIMIT = 256;
843
+ var turnBudgets = /* @__PURE__ */ new Map();
844
+ var MAX_CONTINUATION_CHARS = 200;
845
+ function boundContinuation(next) {
846
+ if (next === void 0 || next.length <= MAX_CONTINUATION_CHARS) return next;
847
+ return `${Array.from(next).slice(0, MAX_CONTINUATION_CHARS).join("")}\u2026`;
848
+ }
849
+ function observationTurnBudgetLimit(env = process.env) {
850
+ return Math.max(MIN_BUDGET_SLICE_BYTES, resolveGuardrail("observationTurnBudgetBytes", env));
851
+ }
852
+ function budgetKey(options) {
853
+ const turnId = options?.turnId?.trim();
854
+ if (!turnId) return null;
855
+ const sessionId = options?.sessionId?.trim() || "no-session";
856
+ return `${sessionId}:${turnId}`;
857
+ }
858
+ function pruneBudgetMap() {
859
+ while (turnBudgets.size > BUDGET_TRACK_LIMIT) {
860
+ let oldestKey = null;
861
+ let oldestSeen = Number.POSITIVE_INFINITY;
862
+ for (const [key, state] of turnBudgets) {
863
+ if (state.lastSeenAt >= oldestSeen) continue;
864
+ oldestKey = key;
865
+ oldestSeen = state.lastSeenAt;
866
+ }
867
+ if (oldestKey === null) break;
868
+ turnBudgets.delete(oldestKey);
869
+ }
870
+ }
871
+ function reserveObservation(selfCapBytes, options) {
872
+ const key = budgetKey(options);
873
+ if (key === null) {
874
+ return {
875
+ key,
876
+ limitBytes: observationTurnBudgetLimit(),
877
+ usedBeforeBytes: 0,
878
+ selfCapBytes,
879
+ callCapBytes: selfCapBytes,
880
+ limited: false,
881
+ exhausted: false,
882
+ committed: false,
883
+ settled: false
884
+ };
885
+ }
886
+ const limitBytes = observationTurnBudgetLimit();
887
+ const state = turnBudgets.get(key) ?? { usedBytes: 0, lastSeenAt: Date.now() };
888
+ state.lastSeenAt = Date.now();
889
+ turnBudgets.set(key, state);
890
+ pruneBudgetMap();
891
+ const remaining = Math.max(0, limitBytes - state.usedBytes);
892
+ if (remaining < MIN_BUDGET_SLICE_BYTES) {
893
+ return {
894
+ key,
895
+ limitBytes,
896
+ usedBeforeBytes: state.usedBytes,
897
+ selfCapBytes,
898
+ callCapBytes: 0,
899
+ limited: true,
900
+ exhausted: true,
901
+ committed: false,
902
+ settled: false
903
+ };
904
+ }
905
+ const callCapBytes = Math.min(selfCapBytes, remaining);
906
+ return {
907
+ key,
908
+ limitBytes,
909
+ usedBeforeBytes: state.usedBytes,
910
+ selfCapBytes,
911
+ callCapBytes,
912
+ limited: callCapBytes < selfCapBytes,
913
+ exhausted: false,
914
+ committed: false,
915
+ settled: false
916
+ };
917
+ }
918
+ function commitObservationReservation(reservation) {
919
+ if (reservation.key === null || reservation.committed || reservation.settled) return;
920
+ if (reservation.callCapBytes <= 0) return;
921
+ reservation.committed = true;
922
+ const state = turnBudgets.get(reservation.key) ?? {
923
+ usedBytes: reservation.usedBeforeBytes,
924
+ lastSeenAt: Date.now()
925
+ };
926
+ state.usedBytes += reservation.callCapBytes;
927
+ state.lastSeenAt = Date.now();
928
+ turnBudgets.set(reservation.key, state);
929
+ }
930
+ function releaseObservation(reservation) {
931
+ if (reservation.key === null || reservation.settled) return;
932
+ reservation.settled = true;
933
+ if (!reservation.committed) return;
934
+ const state = turnBudgets.get(reservation.key);
935
+ if (state === void 0) return;
936
+ state.usedBytes = Math.max(0, state.usedBytes - reservation.callCapBytes);
937
+ state.lastSeenAt = Date.now();
938
+ turnBudgets.set(reservation.key, state);
939
+ }
940
+ function recordSpentBytes(reservation, bytes) {
941
+ if (reservation.key === null || reservation.settled) return;
942
+ reservation.settled = true;
943
+ const committedBytes = reservation.committed ? reservation.callCapBytes : 0;
944
+ const state = turnBudgets.get(reservation.key) ?? {
945
+ usedBytes: reservation.usedBeforeBytes + committedBytes,
946
+ lastSeenAt: Date.now()
947
+ };
948
+ state.usedBytes = Math.max(0, state.usedBytes + bytes - committedBytes);
949
+ state.lastSeenAt = Date.now();
950
+ turnBudgets.set(reservation.key, state);
951
+ }
952
+ function budgetDetails(reservation) {
953
+ if (reservation.key === null) return null;
954
+ return {
955
+ limitBytes: reservation.limitBytes,
956
+ usedBeforeBytes: reservation.usedBeforeBytes,
957
+ exhausted: reservation.exhausted
958
+ };
959
+ }
960
+ function observationBudgetExhausted(input) {
961
+ const { tool, unit, reservation, subject, hint } = input;
962
+ const output = `[observation budget exhausted for this turn before ${tool} ${subject}: ${formatSize(
963
+ reservation.usedBeforeBytes
964
+ )} already returned of ${formatSize(reservation.limitBytes)}. ${hint}]`;
965
+ const shownBytes = byteLength(output);
966
+ recordSpentBytes(reservation, shownBytes);
967
+ const budget = budgetDetails(reservation);
968
+ const observation = {
969
+ tool,
970
+ unit,
971
+ shownCount: 0,
972
+ totalCount: null,
973
+ shownBytes,
974
+ // The notice message is the whole rendering here (the search never ran), so
975
+ // the full size is the message itself; keep totalBytes >= shownBytes.
976
+ totalBytes: shownBytes,
977
+ truncated: true,
978
+ format: "text",
979
+ ...budget !== null ? { budget } : {}
980
+ };
981
+ return { kind: "ok", output, details: { observation } };
982
+ }
983
+ function noticeLine(input, bodyBytes, totalBytes, offloadPath, next) {
984
+ const totalSegment = input.totalCount === null ? `${input.shownCount}+` : String(input.totalCount);
985
+ const parts = [
986
+ `${input.tool}: ${input.shownCount}/${totalSegment} ${input.unit} shown (${formatSize(bodyBytes)} of ${formatSize(totalBytes)})`
987
+ ];
988
+ if (offloadPath !== null) parts.push(offloadPointer(offloadPath));
989
+ if (next !== void 0 && next.length > 0) parts.push(`next: ${next}`);
990
+ return `[${parts.join(" | ")}]`;
991
+ }
992
+ function limitedBudgetNote(reservation) {
993
+ return `[Per-turn observation budget: ${formatSize(reservation.usedBeforeBytes)} already returned of ${formatSize(
994
+ reservation.limitBytes
995
+ )} before this call. Use narrower arguments or continue in a follow-up turn for more content.]`;
996
+ }
997
+ function jsonStubBudgetNote(reservation) {
998
+ return `per-turn observation budget nearly exhausted: ${formatSize(reservation.usedBeforeBytes)} of ${formatSize(reservation.limitBytes)} already returned this turn. Do not retry this call; answer from what you have gathered, or continue in a follow-up turn.`;
999
+ }
1000
+ function finalizeObservation(input) {
1001
+ const format = input.format ?? "text";
1002
+ let output = input.output;
1003
+ let truncated = input.truncated;
1004
+ let shownCount = input.shownCount;
1005
+ let offloadPath = null;
1006
+ const bodyBytes = byteLength(output);
1007
+ const totalBytes = input.totalBytes ?? byteLength(input.fullOutput ?? input.output);
1008
+ const next = boundContinuation(input.next);
1009
+ if (format === "json" && bodyBytes > input.reservation.callCapBytes) {
1010
+ truncated = true;
1011
+ shownCount = 0;
1012
+ offloadPath = writeToolOffload(input.fullOutput ?? output, input.options);
1013
+ const poolBound = input.reservation.limited;
1014
+ output = JSON.stringify({
1015
+ error: `result exceeded ${formatSize(input.reservation.callCapBytes)}`,
1016
+ ...poolBound ? { budget: jsonStubBudgetNote(input.reservation) } : {},
1017
+ ...offloadPath !== null ? { offloadPath } : {},
1018
+ ...!poolBound && next !== void 0 && next.length > 0 ? { next } : {}
1019
+ });
1020
+ } else if (truncated && input.fullOutput !== void 0) {
1021
+ offloadPath = writeToolOffload(input.fullOutput, input.options);
1022
+ }
1023
+ if (format === "text") {
1024
+ if (truncated && input.omitNotice !== true)
1025
+ output += `
1026
+
1027
+ ${noticeLine(input, bodyBytes, totalBytes, offloadPath, next)}`;
1028
+ if (input.reservation.limited && !input.reservation.exhausted) {
1029
+ output += `
1030
+
1031
+ ${limitedBudgetNote(input.reservation)}`;
1032
+ }
1033
+ }
1034
+ const shownBytes = byteLength(output);
1035
+ recordSpentBytes(input.reservation, shownBytes);
1036
+ const budget = budgetDetails(input.reservation);
1037
+ const observation = {
1038
+ tool: input.tool,
1039
+ unit: input.unit,
1040
+ shownCount,
1041
+ totalCount: input.totalCount,
1042
+ shownBytes,
1043
+ // shownBytes counts the appended notice/limited-budget lines; totalBytes
1044
+ // measured only the pre-notice rendering (and equals it when a count-limited
1045
+ // tool like ls offloads nothing). Floor the full-rendering size at the bytes
1046
+ // actually returned so the envelope invariant totalBytes >= shownBytes holds.
1047
+ totalBytes: Math.max(totalBytes, shownBytes),
1048
+ truncated,
1049
+ format,
1050
+ ...next !== void 0 && next.length > 0 ? { next } : {},
1051
+ ...offloadPath !== null ? { offloadPath } : {},
1052
+ ...budget !== null ? { budget } : {}
1053
+ };
1054
+ return { kind: "ok", output, details: { ...input.details ?? {}, observation } };
1055
+ }
1056
+
1057
+ export {
1058
+ deterministicDiagnosticSummary,
1059
+ legacyToolResultDigest,
1060
+ sanitizeToolResultDigest,
1061
+ toolResultContextText,
1062
+ isDispositionedToolResultError,
1063
+ toolResultPresentationText,
1064
+ toolResultPresentationPolicy,
1065
+ DEFAULT_MAX_LINES,
1066
+ splitLinesForCounting,
1067
+ truncateHead2 as truncateHead,
1068
+ truncateTail2 as truncateTail,
1069
+ DEFAULT_TOOL_RESULT_MAX_BYTES,
1070
+ toolResultDigestFor,
1071
+ sweepExpiredToolOffloads,
1072
+ isSessionOffloadPath,
1073
+ shapeToolResult,
1074
+ OBSERVATION_POLICY_SLACK_BYTES,
1075
+ OBSERVE_SELF_CAPS,
1076
+ reserveObservation,
1077
+ commitObservationReservation,
1078
+ releaseObservation,
1079
+ observationBudgetExhausted,
1080
+ finalizeObservation
1081
+ };
1082
+ //# sourceMappingURL=chunk-ODFEOB4F.js.map