@iowarp/clio-coder 0.3.0 → 0.3.1

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 (988) hide show
  1. package/CHANGELOG.md +33 -0
  2. package/README.md +50 -53
  3. package/dist/acp-FPR54DGL.js +138 -0
  4. package/dist/{agents-Q4MYPMUW.js → agents-OGPIHPJH.js} +33 -25
  5. package/dist/assets/codewiki.json +1 -0
  6. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/LICENSE +21 -0
  7. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/cgmanifest.json +16 -0
  8. package/dist/assets/grammars/notices/tree-sitter-wasms/LICENSE +24 -0
  9. package/dist/assets/grammars/tree-sitter-c-sharp.wasm +0 -0
  10. package/dist/assets/grammars/tree-sitter-c.wasm +0 -0
  11. package/dist/assets/grammars/tree-sitter-cpp.wasm +0 -0
  12. package/dist/assets/grammars/tree-sitter-go.wasm +0 -0
  13. package/dist/assets/grammars/tree-sitter-java.wasm +0 -0
  14. package/dist/assets/grammars/tree-sitter-javascript.wasm +0 -0
  15. package/dist/assets/grammars/tree-sitter-python.wasm +0 -0
  16. package/dist/assets/grammars/tree-sitter-ruby.wasm +0 -0
  17. package/dist/assets/grammars/tree-sitter-rust.wasm +0 -0
  18. package/dist/assets/grammars/tree-sitter-tsx.wasm +0 -0
  19. package/dist/assets/grammars/tree-sitter-typescript.wasm +0 -0
  20. package/dist/assets/grammars/tree-sitter.wasm +0 -0
  21. package/dist/{auth-O6HYIJ6J.js → auth-IC3K6NIZ.js} +22 -15
  22. package/dist/{chunk-KKKPTZLM.js → chunk-2STGEDFV.js} +8 -1
  23. package/dist/chunk-3I7MS7N2.js +40 -0
  24. package/dist/chunk-3R73A4XB.js +69 -0
  25. package/dist/{chunk-26BZQOAD.js → chunk-474KN5II.js} +86 -115
  26. package/dist/{chunk-NI4DEJMC.js → chunk-4QKXUHSR.js} +26 -3
  27. package/dist/{chunk-X3BR7HWV.js → chunk-5WIGXA4T.js} +7 -1
  28. package/dist/{chunk-TFSSEXL6.js → chunk-673JJUWJ.js} +14 -4
  29. package/dist/{chunk-GNGDQYDU.js → chunk-7SS2CTV2.js} +27922 -1249
  30. package/dist/{chunk-7RBKDI66.js → chunk-ASND7OZK.js} +104 -12
  31. package/dist/{chunk-X3NE4WVW.js → chunk-BNAZZHFG.js} +7 -1
  32. package/dist/{chunk-RQDWMVRB.js → chunk-BSU2YIWB.js} +9 -3
  33. package/dist/{chunk-CLJ5HLUD.js → chunk-C4PTHK7P.js} +24 -5
  34. package/dist/{chunk-QV47YRF4.js → chunk-CGKSTWHD.js} +7 -1
  35. package/dist/{chunk-BYEU76JP.js → chunk-DKGKUHFA.js} +34 -9
  36. package/dist/chunk-EYOKLTMF.js +170 -0
  37. package/dist/{chunk-PS4PFJQP.js → chunk-FCIH3BIZ.js} +15258 -14130
  38. package/dist/{chunk-2J63S4SF.js → chunk-FST4FYJB.js} +82 -14
  39. package/dist/{chunk-3DANZDGR.js → chunk-G34LV2PF.js} +34 -9
  40. package/dist/{chunk-BBUH4VAA.js → chunk-GAEBEQVI.js} +34 -21
  41. package/dist/chunk-GB6QRBXN.js +8543 -0
  42. package/dist/chunk-GEP36Y4X.js +12796 -0
  43. package/dist/{chunk-TKHQ4DGZ.js → chunk-H6F6BYOH.js} +496 -121
  44. package/dist/{chunk-UGYAX5YI.js → chunk-HQQID6OA.js} +10 -5
  45. package/dist/chunk-IHXBNWMM.js +137 -0
  46. package/dist/{chunk-ME6DNWIU.js → chunk-IS3ONKU3.js} +7 -1
  47. package/dist/{chunk-DXQNI4PC.js → chunk-IWHMRKLL.js} +8 -1
  48. package/dist/chunk-K2ITRMHZ.js +642 -0
  49. package/dist/{chunk-KBR4MZZR.js → chunk-K5XEMXTI.js} +7 -1
  50. package/dist/{chunk-AMFR5YA3.js → chunk-KKNLWXI6.js} +24 -10
  51. package/dist/{chunk-JWHCJDCI.js → chunk-KY56HMHH.js} +145 -61
  52. package/dist/{chunk-E3NYWENM.js → chunk-LU4TK2PR.js} +52 -7
  53. package/dist/{chunk-UWIJNAOB.js → chunk-M5T5VO65.js} +109 -42
  54. package/dist/{chunk-JPOWPFCU.js → chunk-MAR7Y6HW.js} +38 -16
  55. package/dist/chunk-N6F52NLF.js +6951 -0
  56. package/dist/{chunk-UHTSULZS.js → chunk-NMOX6HFD.js} +20 -7
  57. package/dist/{chunk-WD6AJM35.js → chunk-OLBBMFRD.js} +30 -13
  58. package/dist/{chunk-VOO7NYPP.js → chunk-PFEFKVGL.js} +22 -6
  59. package/dist/{chunk-6CWDTGUC.js → chunk-PIUMUEMV.js} +7 -1
  60. package/dist/chunk-PV4JUBVJ.js +462 -0
  61. package/dist/{chunk-527KG6XR.js → chunk-Q3RUPKEJ.js} +22 -4
  62. package/dist/{chunk-D5YD55AR.js → chunk-Q5WJOSJ7.js} +11 -1
  63. package/dist/{chunk-5N2FG33Q.js → chunk-R346GLFC.js} +7 -1
  64. package/dist/{chunk-4UQA7NCT.js → chunk-R5KLMSBV.js} +7 -2
  65. package/dist/{chunk-PIDUD6M2.js → chunk-RDLVBZEO.js} +11 -6
  66. package/dist/{chunk-O4EJEDHO.js → chunk-RPTR2H26.js} +40 -31
  67. package/dist/{chunk-HBU5MTAM.js → chunk-SVNXH4L2.js} +7 -1
  68. package/dist/{chunk-XNISANGE.js → chunk-TEKV33Q5.js} +122 -57
  69. package/dist/chunk-TXOTCRLG.js +15 -0
  70. package/dist/{chunk-VPAWTYLY.js → chunk-WEPFGWHJ.js} +7 -1
  71. package/dist/{chunk-HMYNFFY4.js → chunk-XPLRXC72.js} +7 -2
  72. package/dist/{chunk-UU3R62TT.js → chunk-XYWBQRDM.js} +13 -4
  73. package/dist/{chunk-7BHLZB3A.js → chunk-ZPY3JZ5E.js} +32 -10
  74. package/dist/cli/index.js +39 -33
  75. package/dist/clio-BZVGEUFJ.js +58 -0
  76. package/dist/{components-JVHMUBEB.js → components-DMAOEKFB.js} +26 -9
  77. package/dist/{config-ZFCDBMDC.js → config-IRUQ7SE4.js} +42 -31
  78. package/dist/configure-S7S6F6CL.js +32 -0
  79. package/dist/{context-CDXTP2MP.js → context-3KWFLHJG.js} +17 -11
  80. package/dist/{context-E3KIFVXI.js → context-5RADCKTR.js} +33 -28
  81. package/dist/{context-clear-3F4PLXOS.js → context-clear-7TSNPAAI.js} +36 -28
  82. package/dist/{context-index-Q7YSYTR3.js → context-index-W4RLWOQH.js} +10 -4
  83. package/dist/{docs-YIETIWZI.js → docs-5AWSPS37.js} +16 -10
  84. package/dist/doctor-UC5NAJYQ.js +77 -0
  85. package/dist/{eval-B3KZZESM.js → eval-U6TJHRLX.js} +77 -24
  86. package/dist/{evidence-V67CHM35.js → evidence-YEGUW4L3.js} +34 -26
  87. package/dist/{evolve-YDZSUQYA.js → evolve-TXARCTPG.js} +39 -26
  88. package/dist/{extensions-SRG7XCAH.js → extensions-OZFJ3A3G.js} +13 -7
  89. package/dist/{fleet-CA2CRTVG.js → fleet-6G3DHNYE.js} +45 -37
  90. package/dist/fleet-preflight-DSNT37JK.js +23 -0
  91. package/dist/{init-2OZDJE2D.js → init-KZ5QTF6M.js} +42 -34
  92. package/dist/{memory-3PIQQAKX.js → memory-73ESV5YC.js} +35 -27
  93. package/dist/{models-DY35XI7Y.js → models-A4PVNWJK.js} +34 -23
  94. package/dist/{paths-5OMXW7Z4.js → paths-C4H6IV77.js} +12 -6
  95. package/dist/preload-6WVMHX3A.js +13 -0
  96. package/dist/{reset-PIFYNOS3.js → reset-BGW6OGMV.js} +17 -11
  97. package/dist/{run-3VSPP24F.js → run-YTPEYQOH.js} +60 -48
  98. package/dist/{share-D36RQCXM.js → share-YIFFV4NQ.js} +16 -10
  99. package/dist/{skills-F2MRLELY.js → skills-2V6RA3OQ.js} +18 -11
  100. package/dist/{skills-eval-E2ZTW4PL.js → skills-eval-S2TVJO4F.js} +45 -36
  101. package/dist/{targets-DZMEZAH4.js → targets-TYXLPB23.js} +61 -59
  102. package/dist/{trace-7NYCUI2J.js → trace-GGOJ6Q6Z.js} +9 -3
  103. package/dist/{uninstall-AD3JWHBB.js → uninstall-LLLT4F4W.js} +14 -8
  104. package/dist/{upgrade-WYYBKGDY.js → upgrade-33G2LMM5.js} +45 -23
  105. package/dist/{usage-ULIDAGFF.js → usage-ZAFSXKKG.js} +35 -27
  106. package/dist/version-KGEG7EPO.js +21 -0
  107. package/dist/{wiki-generate-PKFIX6OB.js → wiki-generate-NUQCVOQ3.js} +55 -45
  108. package/dist/worker/entry.js +101 -43
  109. package/docs/README.md +12 -9
  110. package/docs/acp.md +28 -5
  111. package/docs/alcf-provider.md +1 -1
  112. package/docs/architecture.md +23 -2
  113. package/docs/artifact-placement.md +101 -0
  114. package/docs/artifact-versions.md +1 -1
  115. package/docs/built-in-agents.md +4 -2
  116. package/docs/capacity-and-scheduling.md +1 -1
  117. package/docs/commands-and-modes.md +125 -41
  118. package/docs/configuration-and-targets.md +88 -18
  119. package/docs/context-engine.md +6 -2
  120. package/docs/development-pipeline.md +77 -0
  121. package/docs/documentation-coverage.md +4 -4
  122. package/docs/documentation-guide.md +3 -3
  123. package/docs/environment-variables.md +2 -1
  124. package/docs/eval-runner.md +3 -3
  125. package/docs/evals-internal.md +2 -2
  126. package/docs/evidence-and-memory.md +6 -2
  127. package/docs/evolution.md +1 -1
  128. package/docs/exit-codes-and-output.md +1 -1
  129. package/docs/extensions-and-sharing.md +18 -11
  130. package/docs/fleet-demo-runbook.md +22 -23
  131. package/docs/fleet-dispatch.md +111 -12
  132. package/docs/glossary.md +107 -15
  133. package/docs/html/agents_blueprint.html +3 -3
  134. package/docs/html/alcf_blueprint.html +3 -3
  135. package/docs/html/architecture_blueprint.html +3 -3
  136. package/docs/html/commands_blueprint.html +187 -42
  137. package/docs/html/configuration_blueprint.html +7 -7
  138. package/docs/html/context_blueprint.html +3 -3
  139. package/docs/html/documentation_blueprint.html +1 -1
  140. package/docs/html/environment_blueprint.html +3 -3
  141. package/docs/html/eval_blueprint.html +4 -4
  142. package/docs/html/evals_internal_blueprint.html +3 -3
  143. package/docs/html/evolution_blueprint.html +3 -3
  144. package/docs/html/extensions_blueprint.html +3 -3
  145. package/docs/html/fleet_dispatch_blueprint.html +8 -8
  146. package/docs/html/index.html +5 -5
  147. package/docs/html/lifecycle_blueprint.html +4 -4
  148. package/docs/html/memory_blueprint.html +3 -3
  149. package/docs/html/middleware_blueprint.html +3 -3
  150. package/docs/html/models_blueprint.html +2 -2
  151. package/docs/html/observability_blueprint.html +2 -2
  152. package/docs/html/provider_adapter_blueprint.html +3 -3
  153. package/docs/html/safety_blueprint.html +3 -3
  154. package/docs/html/skills_blueprint.html +2 -2
  155. package/docs/html/soak_blueprint.html +3 -3
  156. package/docs/html/tool_usage_blueprint.html +4 -4
  157. package/docs/html/tools_blueprint.html +2 -2
  158. package/docs/html/trace_blueprint.html +3 -3
  159. package/docs/html/tui_design_blueprint.html +100 -40
  160. package/docs/html/validation_blueprint.html +1 -1
  161. package/docs/html/worker_dispatch_blueprint.html +3 -3
  162. package/docs/installation-and-lifecycle.md +62 -11
  163. package/docs/middleware-and-components.md +1 -1
  164. package/docs/model-catalog.md +2 -2
  165. package/docs/observability.md +3 -3
  166. package/docs/proactive-memory.md +12 -12
  167. package/docs/prompt-envelope-and-tools.md +2 -2
  168. package/docs/provider-adapter-cookbook.md +1 -1
  169. package/docs/release-cut-checklist.md +4 -0
  170. package/docs/safety-model.md +21 -5
  171. package/docs/scientific-validation.md +3 -3
  172. package/docs/session-lifecycle.md +2 -2
  173. package/docs/skills-marketplace.md +1 -1
  174. package/docs/time-conventions.md +101 -0
  175. package/docs/tool-usage.md +5 -4
  176. package/docs/trace-store.md +1 -1
  177. package/docs/troubleshooting.md +1 -1
  178. package/docs/tui-design.md +83 -27
  179. package/docs/worker-dispatch-mechanics.md +3 -3
  180. package/package.json +16 -16
  181. package/skills/README.md +5 -6
  182. package/skills/git/file-ticket/SKILL.md +107 -0
  183. package/skills/git/file-ticket/evals.md +54 -0
  184. package/skills/git/fix-issue/SKILL.md +106 -0
  185. package/skills/git/fix-issue/evals.md +71 -0
  186. package/skills/git/ship/SKILL.md +92 -0
  187. package/skills/git/ship/evals.md +72 -0
  188. package/skills/skill-marketplace.json +12 -20
  189. package/src/cli/acp.ts +88 -0
  190. package/src/cli/agents.ts +60 -0
  191. package/src/cli/args.ts +280 -0
  192. package/src/cli/argv.ts +170 -0
  193. package/src/cli/ask.ts +34 -0
  194. package/src/cli/auth.ts +468 -0
  195. package/src/cli/bootstrap-generate.ts +498 -0
  196. package/src/cli/clio.ts +34 -0
  197. package/src/cli/components.ts +195 -0
  198. package/src/cli/config-inspect.ts +330 -0
  199. package/src/cli/config.ts +72 -0
  200. package/src/cli/configure-interop.ts +67 -0
  201. package/src/cli/configure-layout.ts +172 -0
  202. package/src/cli/configure.ts +1487 -0
  203. package/src/cli/context-clear.ts +76 -0
  204. package/src/cli/context-index.ts +102 -0
  205. package/src/cli/context.ts +316 -0
  206. package/src/cli/default-target.ts +63 -0
  207. package/src/cli/docs.ts +340 -0
  208. package/src/cli/doctor.ts +54 -0
  209. package/src/cli/eval.ts +315 -0
  210. package/src/cli/evidence.ts +222 -0
  211. package/src/cli/evolve.ts +219 -0
  212. package/src/cli/extensions.ts +205 -0
  213. package/src/cli/fleet.ts +827 -0
  214. package/src/cli/index.ts +309 -0
  215. package/src/cli/init.ts +219 -0
  216. package/src/cli/initial-message.ts +47 -0
  217. package/src/cli/internal-dispatch.ts +55 -0
  218. package/src/cli/memory.ts +180 -0
  219. package/src/cli/models.ts +257 -0
  220. package/src/cli/modes/json-stream.ts +85 -0
  221. package/src/cli/modes/jsonl.ts +9 -0
  222. package/src/cli/modes/print.ts +589 -0
  223. package/src/cli/oauth-manual-input.ts +72 -0
  224. package/src/cli/oauth-select.ts +36 -0
  225. package/src/cli/output-guard.ts +48 -0
  226. package/src/cli/paths.ts +44 -0
  227. package/src/cli/provider-target.ts +113 -0
  228. package/src/cli/removal.ts +72 -0
  229. package/src/cli/reset.ts +253 -0
  230. package/src/cli/run.ts +497 -0
  231. package/src/cli/share.ts +243 -0
  232. package/src/cli/shared.ts +60 -0
  233. package/src/cli/skills-eval.ts +1225 -0
  234. package/src/cli/skills.ts +470 -0
  235. package/src/cli/steer-channel.ts +86 -0
  236. package/src/cli/targets.ts +1150 -0
  237. package/src/cli/text-layout.ts +102 -0
  238. package/src/cli/trace.ts +274 -0
  239. package/src/cli/uninstall.ts +405 -0
  240. package/src/cli/upgrade.ts +270 -0
  241. package/src/cli/usage.ts +869 -0
  242. package/src/cli/validate-model.ts +28 -0
  243. package/src/cli/version.ts +7 -0
  244. package/src/cli/wiki-generate.ts +509 -0
  245. package/src/core/artifact-paths.ts +43 -0
  246. package/src/core/bash-exec.ts +242 -0
  247. package/src/core/boot-trace.ts +37 -0
  248. package/src/core/bus-events.ts +728 -0
  249. package/src/core/bus-trace.ts +53 -0
  250. package/src/core/c-header-language.ts +265 -0
  251. package/src/core/clio-repo.ts +78 -0
  252. package/src/core/config.ts +1593 -0
  253. package/src/core/context-floor.ts +33 -0
  254. package/src/core/defaults.ts +625 -0
  255. package/src/core/domain-loader.ts +170 -0
  256. package/src/core/event-bus.ts +94 -0
  257. package/src/core/file-references.ts +282 -0
  258. package/src/core/guardrails.ts +185 -0
  259. package/src/core/headless-permission.ts +21 -0
  260. package/src/core/init.ts +223 -0
  261. package/src/core/json-payload.ts +58 -0
  262. package/src/core/package-root.ts +54 -0
  263. package/src/core/path-canonical.ts +37 -0
  264. package/src/core/process-identity.ts +41 -0
  265. package/src/core/recent-models.ts +91 -0
  266. package/src/core/release.ts +2 -0
  267. package/src/core/residency-protection.ts +56 -0
  268. package/src/core/resolve-config-value.ts +88 -0
  269. package/src/core/response-schema.ts +279 -0
  270. package/src/core/run-overrides.ts +77 -0
  271. package/src/core/safe-exec.ts +193 -0
  272. package/src/core/safe-id.ts +37 -0
  273. package/src/core/safe-resource-write.ts +162 -0
  274. package/src/core/session-routing.ts +339 -0
  275. package/src/core/settings-layers.ts +220 -0
  276. package/src/core/shared-bus.ts +8 -0
  277. package/src/core/shell-quote.ts +26 -0
  278. package/src/core/skill-activation.ts +190 -0
  279. package/src/core/startup-timer.ts +37 -0
  280. package/src/core/state-file-lock.ts +207 -0
  281. package/src/core/termination.ts +202 -0
  282. package/src/core/timers.ts +38 -0
  283. package/src/core/tool-names.ts +65 -0
  284. package/src/core/verification-scripts.ts +13 -0
  285. package/src/core/workspace-files.ts +492 -0
  286. package/src/core/xdg.ts +177 -0
  287. package/src/domains/agents/builtins/architect.md +4 -4
  288. package/src/domains/agents/builtins/coder.md +3 -2
  289. package/src/domains/agents/builtins/debugger.md +1 -1
  290. package/src/domains/agents/builtins/documenter.md +1 -1
  291. package/src/domains/agents/builtins/git-master.md +3 -3
  292. package/src/domains/agents/builtins/provenance.md +1 -1
  293. package/src/domains/agents/builtins/researcher.md +1 -1
  294. package/src/domains/agents/builtins/scout.md +1 -1
  295. package/src/domains/agents/builtins/tester.md +1 -1
  296. package/src/domains/agents/builtins/verifier.md +1 -1
  297. package/src/domains/agents/builtins/wiki-writer.md +1 -1
  298. package/src/domains/agents/catalog.ts +172 -0
  299. package/src/domains/agents/contract.ts +16 -0
  300. package/src/domains/agents/extension.ts +110 -0
  301. package/src/domains/agents/fleet-commands.ts +154 -0
  302. package/src/domains/agents/fleet-contract.ts +797 -0
  303. package/src/domains/agents/frontmatter.ts +40 -0
  304. package/src/domains/agents/index.ts +102 -0
  305. package/src/domains/agents/manifest.ts +6 -0
  306. package/src/domains/agents/recipe-schema.ts +202 -0
  307. package/src/domains/agents/recipe.ts +125 -0
  308. package/src/domains/agents/registry.ts +111 -0
  309. package/src/domains/agents/result-contract.ts +1265 -0
  310. package/src/domains/agents/spec.ts +371 -0
  311. package/src/domains/agents/write-boundary.ts +109 -0
  312. package/src/domains/components/diff.ts +99 -0
  313. package/src/domains/components/hash.ts +21 -0
  314. package/src/domains/components/index.ts +3 -0
  315. package/src/domains/components/scan.ts +304 -0
  316. package/src/domains/components/snapshot.ts +108 -0
  317. package/src/domains/components/types.ts +82 -0
  318. package/src/domains/config/agent-namespace.ts +13 -0
  319. package/src/domains/config/classify.ts +94 -0
  320. package/src/domains/config/contract.ts +22 -0
  321. package/src/domains/config/extension.ts +136 -0
  322. package/src/domains/config/index.ts +13 -0
  323. package/src/domains/config/keybindings.ts +164 -0
  324. package/src/domains/config/manifest.ts +6 -0
  325. package/src/domains/config/watcher.ts +41 -0
  326. package/src/domains/context/adoption.ts +880 -0
  327. package/src/domains/context/bootstrap-prompt.ts +273 -0
  328. package/src/domains/context/bootstrap.ts +1409 -0
  329. package/src/domains/context/clear.ts +86 -0
  330. package/src/domains/context/clio-md.ts +327 -0
  331. package/src/domains/context/codewiki/cmake.ts +356 -0
  332. package/src/domains/context/codewiki/cooperative.ts +46 -0
  333. package/src/domains/context/codewiki/digest.ts +135 -0
  334. package/src/domains/context/codewiki/grammar-assets.ts +33 -0
  335. package/src/domains/context/codewiki/indexer.ts +1614 -0
  336. package/src/domains/context/codewiki/tree-sitter.ts +771 -0
  337. package/src/domains/context/contract.ts +62 -0
  338. package/src/domains/context/excluded-dirs.ts +1 -0
  339. package/src/domains/context/extension.ts +407 -0
  340. package/src/domains/context/fingerprint.ts +196 -0
  341. package/src/domains/context/index.ts +164 -0
  342. package/src/domains/context/init-options.ts +69 -0
  343. package/src/domains/context/manifest.ts +6 -0
  344. package/src/domains/context/operator-profile.ts +157 -0
  345. package/src/domains/context/project-metadata.ts +510 -0
  346. package/src/domains/context/project-rules.ts +227 -0
  347. package/src/domains/context/prompt-context.ts +62 -0
  348. package/src/domains/context/refresh.ts +170 -0
  349. package/src/domains/context/sibling-files.ts +10 -0
  350. package/src/domains/context/state.ts +237 -0
  351. package/src/domains/context/wiki/assemble.ts +303 -0
  352. package/src/domains/context/wiki/frontmatter.ts +210 -0
  353. package/src/domains/context/wiki/generate.ts +590 -0
  354. package/src/domains/context/wiki/layout.ts +111 -0
  355. package/src/domains/context/wiki/meta.ts +221 -0
  356. package/src/domains/context/wiki/plan-store.ts +217 -0
  357. package/src/domains/context/wiki/plan.ts +250 -0
  358. package/src/domains/context/wiki/prompts.ts +270 -0
  359. package/src/domains/context/wiki/staleness.ts +198 -0
  360. package/src/domains/dispatch/active-route-planner.ts +168 -0
  361. package/src/domains/dispatch/admission-queue.ts +150 -0
  362. package/src/domains/dispatch/admission.ts +334 -0
  363. package/src/domains/dispatch/agent-candidates.ts +307 -0
  364. package/src/domains/dispatch/agent-ledger-hub.ts +71 -0
  365. package/src/domains/dispatch/agent-ledger-store.ts +257 -0
  366. package/src/domains/dispatch/agent-ledger.ts +212 -0
  367. package/src/domains/dispatch/agent-plan-adapter.ts +85 -0
  368. package/src/domains/dispatch/assignment-events.ts +132 -0
  369. package/src/domains/dispatch/assignment-reconcile.ts +76 -0
  370. package/src/domains/dispatch/assignment-store.ts +162 -0
  371. package/src/domains/dispatch/assignment.ts +278 -0
  372. package/src/domains/dispatch/backoff.ts +59 -0
  373. package/src/domains/dispatch/batch-store.ts +134 -0
  374. package/src/domains/dispatch/batch-tracker.ts +66 -0
  375. package/src/domains/dispatch/capability-match.ts +155 -0
  376. package/src/domains/dispatch/capacity-lease.ts +413 -0
  377. package/src/domains/dispatch/code-step-store.ts +52 -0
  378. package/src/domains/dispatch/code-step.ts +368 -0
  379. package/src/domains/dispatch/contract.ts +278 -0
  380. package/src/domains/dispatch/dedup.ts +133 -0
  381. package/src/domains/dispatch/event-pump.ts +251 -0
  382. package/src/domains/dispatch/execution-handoff.ts +29 -0
  383. package/src/domains/dispatch/execution-plan.ts +328 -0
  384. package/src/domains/dispatch/execution-role.ts +277 -0
  385. package/src/domains/dispatch/execution-scheduler.ts +583 -0
  386. package/src/domains/dispatch/extension.ts +5869 -0
  387. package/src/domains/dispatch/failure-classification.ts +141 -0
  388. package/src/domains/dispatch/fleet-plan.ts +225 -0
  389. package/src/domains/dispatch/fleet-preflight.ts +394 -0
  390. package/src/domains/dispatch/gate-decisions.ts +1040 -0
  391. package/src/domains/dispatch/gate-role-prompts.ts +58 -0
  392. package/src/domains/dispatch/heartbeat.ts +27 -0
  393. package/src/domains/dispatch/index.ts +137 -0
  394. package/src/domains/dispatch/joint-route-adapter.ts +114 -0
  395. package/src/domains/dispatch/joint-route-resolver.ts +283 -0
  396. package/src/domains/dispatch/manifest.ts +6 -0
  397. package/src/domains/dispatch/orphan-recovery.ts +224 -0
  398. package/src/domains/dispatch/outcome.ts +109 -0
  399. package/src/domains/dispatch/phase-timing.ts +47 -0
  400. package/src/domains/dispatch/placement.ts +202 -0
  401. package/src/domains/dispatch/receipt-findings.ts +255 -0
  402. package/src/domains/dispatch/receipt-integrity.ts +378 -0
  403. package/src/domains/dispatch/recovery-candidates.ts +74 -0
  404. package/src/domains/dispatch/reproducibility.ts +48 -0
  405. package/src/domains/dispatch/reservation-store.ts +501 -0
  406. package/src/domains/dispatch/route-approval.ts +177 -0
  407. package/src/domains/dispatch/route-candidates.ts +57 -0
  408. package/src/domains/dispatch/route-decision.ts +1079 -0
  409. package/src/domains/dispatch/route-facts.ts +187 -0
  410. package/src/domains/dispatch/route-history.ts +238 -0
  411. package/src/domains/dispatch/route-observer.ts +488 -0
  412. package/src/domains/dispatch/route-policy.ts +327 -0
  413. package/src/domains/dispatch/route-quality.ts +256 -0
  414. package/src/domains/dispatch/route-readiness.ts +120 -0
  415. package/src/domains/dispatch/routing-intent.ts +287 -0
  416. package/src/domains/dispatch/run-identity.ts +56 -0
  417. package/src/domains/dispatch/scout-transition.ts +130 -0
  418. package/src/domains/dispatch/state.ts +277 -0
  419. package/src/domains/dispatch/tool-stats.ts +132 -0
  420. package/src/domains/dispatch/transport.ts +209 -0
  421. package/src/domains/dispatch/types.ts +785 -0
  422. package/src/domains/dispatch/validation-grounding.ts +154 -0
  423. package/src/domains/dispatch/validation.ts +721 -0
  424. package/src/domains/dispatch/worker-protocol.ts +275 -0
  425. package/src/domains/dispatch/worker-spawn.ts +566 -0
  426. package/src/domains/dispatch/write-boundary-enforcer.ts +97 -0
  427. package/src/domains/dispatch/write-boundary.ts +426 -0
  428. package/src/domains/eval/artifacts/redact.ts +42 -0
  429. package/src/domains/eval/artifacts/store.ts +173 -0
  430. package/src/domains/eval/compare/compare.ts +33 -0
  431. package/src/domains/eval/compare/gates.ts +66 -0
  432. package/src/domains/eval/compare/thresholds.ts +92 -0
  433. package/src/domains/eval/harness-metrics.ts +62 -0
  434. package/src/domains/eval/index.ts +66 -0
  435. package/src/domains/eval/metrics/chaos-stream.ts +93 -0
  436. package/src/domains/eval/metrics/context.ts +34 -0
  437. package/src/domains/eval/metrics/coverage.ts +21 -0
  438. package/src/domains/eval/metrics/evidence.ts +182 -0
  439. package/src/domains/eval/metrics/fleet-loop-stream.ts +196 -0
  440. package/src/domains/eval/metrics/invariants.ts +736 -0
  441. package/src/domains/eval/metrics/latency.ts +4 -0
  442. package/src/domains/eval/metrics/token-stream.ts +139 -0
  443. package/src/domains/eval/metrics/tokens.ts +51 -0
  444. package/src/domains/eval/metrics/tool-calls.ts +7 -0
  445. package/src/domains/eval/proactive-memory.ts +279 -0
  446. package/src/domains/eval/provenance.ts +35 -0
  447. package/src/domains/eval/report.ts +234 -0
  448. package/src/domains/eval/reports/json.ts +5 -0
  449. package/src/domains/eval/reports/junit.ts +23 -0
  450. package/src/domains/eval/reports/markdown.ts +20 -0
  451. package/src/domains/eval/reports/swe-jsonl.ts +16 -0
  452. package/src/domains/eval/reports/text.ts +25 -0
  453. package/src/domains/eval/run-compare.ts +274 -0
  454. package/src/domains/eval/runner.ts +244 -0
  455. package/src/domains/eval/runners/clio-run.ts +148 -0
  456. package/src/domains/eval/runners/context-index.ts +56 -0
  457. package/src/domains/eval/runners/context-init.ts +203 -0
  458. package/src/domains/eval/runners/external-command.ts +350 -0
  459. package/src/domains/eval/runtime-paths.ts +171 -0
  460. package/src/domains/eval/schema/artifact.ts +75 -0
  461. package/src/domains/eval/schema/suite.ts +235 -0
  462. package/src/domains/eval/schema/validate.ts +339 -0
  463. package/src/domains/eval/store.ts +392 -0
  464. package/src/domains/eval/suites/load.ts +74 -0
  465. package/src/domains/eval/suites/matrix.ts +19 -0
  466. package/src/domains/eval/suites/resolve.ts +44 -0
  467. package/src/domains/eval/suites/run.ts +325 -0
  468. package/src/domains/eval/task-file.ts +186 -0
  469. package/src/domains/eval/types.ts +141 -0
  470. package/src/domains/eval/verifiers/command.ts +27 -0
  471. package/src/domains/eval/verifiers/file-exists.ts +6 -0
  472. package/src/domains/eval/verifiers/patch.ts +22 -0
  473. package/src/domains/eval/workspaces/git.ts +41 -0
  474. package/src/domains/eval/workspaces/local.ts +17 -0
  475. package/src/domains/eval/workspaces/temp-copy.ts +29 -0
  476. package/src/domains/evidence/build.ts +1714 -0
  477. package/src/domains/evidence/eval.ts +605 -0
  478. package/src/domains/evidence/failure-attribution.ts +54 -0
  479. package/src/domains/evidence/finish-contract-map.ts +42 -0
  480. package/src/domains/evidence/index.ts +55 -0
  481. package/src/domains/evidence/provenance.ts +200 -0
  482. package/src/domains/evidence/redact.ts +81 -0
  483. package/src/domains/evidence/store.ts +291 -0
  484. package/src/domains/evidence/types.ts +325 -0
  485. package/src/domains/evolution/SELF_EDIT_GATE.md +91 -0
  486. package/src/domains/evolution/index.ts +26 -0
  487. package/src/domains/evolution/manifest.ts +154 -0
  488. package/src/domains/evolution/validate.ts +304 -0
  489. package/src/domains/extensions/contract.ts +22 -0
  490. package/src/domains/extensions/discovery.ts +193 -0
  491. package/src/domains/extensions/extension.ts +46 -0
  492. package/src/domains/extensions/index.ts +34 -0
  493. package/src/domains/extensions/manager.ts +30 -0
  494. package/src/domains/extensions/manifest.ts +6 -0
  495. package/src/domains/extensions/resources.ts +38 -0
  496. package/src/domains/extensions/state.ts +224 -0
  497. package/src/domains/extensions/types.ts +83 -0
  498. package/src/domains/interop/consent.ts +185 -0
  499. package/src/domains/interop/contract.ts +29 -0
  500. package/src/domains/interop/detect.ts +173 -0
  501. package/src/domains/interop/extension.ts +59 -0
  502. package/src/domains/interop/index.ts +34 -0
  503. package/src/domains/interop/manifest.ts +6 -0
  504. package/src/domains/interop/registry.ts +139 -0
  505. package/src/domains/interop/state.ts +92 -0
  506. package/src/domains/interop/types.ts +109 -0
  507. package/src/domains/lifecycle/contract.ts +11 -0
  508. package/src/domains/lifecycle/doctor.ts +536 -0
  509. package/src/domains/lifecycle/extension.ts +23 -0
  510. package/src/domains/lifecycle/index.ts +21 -0
  511. package/src/domains/lifecycle/install-method.ts +51 -0
  512. package/src/domains/lifecycle/manifest.ts +6 -0
  513. package/src/domains/lifecycle/migrations/index.ts +94 -0
  514. package/src/domains/lifecycle/state.ts +93 -0
  515. package/src/domains/lifecycle/upgrade-notice.ts +35 -0
  516. package/src/domains/lifecycle/version.ts +35 -0
  517. package/src/domains/memory/index.ts +128 -0
  518. package/src/domains/memory/operations.ts +143 -0
  519. package/src/domains/memory/prompt-section.ts +86 -0
  520. package/src/domains/memory/proposal.ts +180 -0
  521. package/src/domains/memory/store.ts +163 -0
  522. package/src/domains/memory/task-bank.ts +229 -0
  523. package/src/domains/memory/task-memory-handoff.ts +222 -0
  524. package/src/domains/memory/task-memory-policy.ts +602 -0
  525. package/src/domains/memory/task-memory-status.ts +58 -0
  526. package/src/domains/memory/task-memory-telemetry.ts +346 -0
  527. package/src/domains/memory/task-memory-trace.ts +89 -0
  528. package/src/domains/memory/types.ts +74 -0
  529. package/src/domains/memory/validate.ts +297 -0
  530. package/src/domains/middleware/budget.ts +216 -0
  531. package/src/domains/middleware/contract.ts +35 -0
  532. package/src/domains/middleware/dispatch-nudge.ts +469 -0
  533. package/src/domains/middleware/extension.ts +129 -0
  534. package/src/domains/middleware/hook-receipts.ts +70 -0
  535. package/src/domains/middleware/hooks-io.ts +174 -0
  536. package/src/domains/middleware/hooks.ts +432 -0
  537. package/src/domains/middleware/index.ts +154 -0
  538. package/src/domains/middleware/manifest.ts +6 -0
  539. package/src/domains/middleware/memory-intervention.ts +701 -0
  540. package/src/domains/middleware/rules.ts +42 -0
  541. package/src/domains/middleware/runtime.ts +333 -0
  542. package/src/domains/middleware/skills-reminder.ts +187 -0
  543. package/src/domains/middleware/snapshot.ts +71 -0
  544. package/src/domains/middleware/stalled-turn.ts +71 -0
  545. package/src/domains/middleware/task-board-reminder.ts +87 -0
  546. package/src/domains/middleware/task-nudge.ts +77 -0
  547. package/src/domains/middleware/tool-choice-control.ts +42 -0
  548. package/src/domains/middleware/types.ts +131 -0
  549. package/src/domains/middleware/validate.ts +329 -0
  550. package/src/domains/observability/accountability.ts +67 -0
  551. package/src/domains/observability/contract.ts +168 -0
  552. package/src/domains/observability/cost.ts +206 -0
  553. package/src/domains/observability/evidence-index.ts +123 -0
  554. package/src/domains/observability/extension.ts +281 -0
  555. package/src/domains/observability/index.ts +78 -0
  556. package/src/domains/observability/manifest.ts +10 -0
  557. package/src/domains/observability/metrics.ts +37 -0
  558. package/src/domains/observability/projection.ts +477 -0
  559. package/src/domains/observability/telemetry.ts +89 -0
  560. package/src/domains/observability/trace-store.ts +1454 -0
  561. package/src/domains/prompts/compiler.ts +556 -0
  562. package/src/domains/prompts/contract.ts +30 -0
  563. package/src/domains/prompts/extension.ts +304 -0
  564. package/src/domains/prompts/fragment-loader.ts +139 -0
  565. package/src/domains/prompts/fragments/identity/clio.md +3 -2
  566. package/src/domains/prompts/fragments/identity/self-awareness.md +63 -0
  567. package/src/domains/prompts/fragments/operating/contract.md +10 -1
  568. package/src/domains/prompts/hash.ts +73 -0
  569. package/src/domains/prompts/index.ts +32 -0
  570. package/src/domains/prompts/manifest.ts +8 -0
  571. package/src/domains/prompts/memory-intervention.ts +57 -0
  572. package/src/domains/prompts/preload.ts +82 -0
  573. package/src/domains/providers/auth/api-key.ts +47 -0
  574. package/src/domains/providers/auth/backend-file.ts +69 -0
  575. package/src/domains/providers/auth/backend-memory.ts +17 -0
  576. package/src/domains/providers/auth/index.ts +37 -0
  577. package/src/domains/providers/auth/oauth.ts +36 -0
  578. package/src/domains/providers/auth/storage.ts +667 -0
  579. package/src/domains/providers/capabilities.ts +50 -0
  580. package/src/domains/providers/catalog.ts +162 -0
  581. package/src/domains/providers/contract.ts +151 -0
  582. package/src/domains/providers/credentials.ts +20 -0
  583. package/src/domains/providers/eligibility.ts +24 -0
  584. package/src/domains/providers/errors.ts +64 -0
  585. package/src/domains/providers/extension.ts +536 -0
  586. package/src/domains/providers/index.ts +142 -0
  587. package/src/domains/providers/knowledge-base-path.ts +102 -0
  588. package/src/domains/providers/manifest.ts +6 -0
  589. package/src/domains/providers/model-capabilities.ts +136 -0
  590. package/src/domains/providers/model-discovery.ts +144 -0
  591. package/src/domains/providers/model-family.ts +32 -0
  592. package/src/domains/providers/model-runtime-capabilities.ts +712 -0
  593. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +2 -2
  594. package/src/domains/providers/plugins.ts +59 -0
  595. package/src/domains/providers/probe/fingerprint.ts +44 -0
  596. package/src/domains/providers/probe/http.ts +114 -0
  597. package/src/domains/providers/probe/reasoning.ts +111 -0
  598. package/src/domains/providers/registry.ts +166 -0
  599. package/src/domains/providers/resolver.ts +156 -0
  600. package/src/domains/providers/runtime-resolution.ts +720 -0
  601. package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +90 -0
  602. package/src/domains/providers/runtimes/builtins.ts +78 -0
  603. package/src/domains/providers/runtimes/claude/claude-code.ts +38 -0
  604. package/src/domains/providers/runtimes/claude/claude-sdk.ts +38 -0
  605. package/src/domains/providers/runtimes/claude/common.ts +55 -0
  606. package/src/domains/providers/runtimes/cloud/alcf.ts +171 -0
  607. package/src/domains/providers/runtimes/cloud/anthropic-max.ts +71 -0
  608. package/src/domains/providers/runtimes/cloud/anthropic.ts +43 -0
  609. package/src/domains/providers/runtimes/cloud/bedrock.ts +35 -0
  610. package/src/domains/providers/runtimes/cloud/deepseek.ts +50 -0
  611. package/src/domains/providers/runtimes/cloud/google.ts +41 -0
  612. package/src/domains/providers/runtimes/cloud/groq.ts +46 -0
  613. package/src/domains/providers/runtimes/cloud/mistral.ts +46 -0
  614. package/src/domains/providers/runtimes/cloud/openai-codex.ts +49 -0
  615. package/src/domains/providers/runtimes/cloud/openai.ts +46 -0
  616. package/src/domains/providers/runtimes/cloud/openrouter.ts +111 -0
  617. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +32 -0
  618. package/src/domains/providers/runtimes/common/local-synth.ts +165 -0
  619. package/src/domains/providers/runtimes/common/probe-helpers.ts +474 -0
  620. package/src/domains/providers/runtimes/local-native/lemonade-anthropic.ts +27 -0
  621. package/src/domains/providers/runtimes/local-native/lemonade-openai.ts +26 -0
  622. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +88 -0
  623. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +207 -0
  624. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +180 -0
  625. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +126 -0
  626. package/src/domains/providers/runtimes/local-native/llamacpp.ts +98 -0
  627. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +491 -0
  628. package/src/domains/providers/runtimes/local-native/ollama-native.ts +117 -0
  629. package/src/domains/providers/runtimes/local-native/sglang.ts +26 -0
  630. package/src/domains/providers/runtimes/local-native/vllm.ts +27 -0
  631. package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +104 -0
  632. package/src/domains/providers/runtimes/protocol/anthropic-messages.ts +28 -0
  633. package/src/domains/providers/runtimes/protocol/bedrock.ts +26 -0
  634. package/src/domains/providers/runtimes/protocol/google.ts +27 -0
  635. package/src/domains/providers/runtimes/protocol/openai-compat.ts +145 -0
  636. package/src/domains/providers/support.ts +238 -0
  637. package/src/domains/providers/thinking-control-policy.ts +85 -0
  638. package/src/domains/providers/types/capability-flags.ts +114 -0
  639. package/src/domains/providers/types/cost-provenance.ts +7 -0
  640. package/src/domains/providers/types/inference.ts +41 -0
  641. package/src/domains/providers/types/knowledge-base.ts +156 -0
  642. package/src/domains/providers/types/local-model-quirks.ts +218 -0
  643. package/src/domains/providers/types/runtime-descriptor.ts +170 -0
  644. package/src/domains/providers/types/target-descriptor.ts +38 -0
  645. package/src/domains/resources/collision.ts +92 -0
  646. package/src/domains/resources/common-loader.ts +140 -0
  647. package/src/domains/resources/contract.ts +25 -0
  648. package/src/domains/resources/extension.ts +61 -0
  649. package/src/domains/resources/index.ts +74 -0
  650. package/src/domains/resources/loader.ts +86 -0
  651. package/src/domains/resources/manifest.ts +6 -0
  652. package/src/domains/resources/prompts/loader.ts +232 -0
  653. package/src/domains/resources/prompts/substitute.ts +65 -0
  654. package/src/domains/resources/skills/content-hash.ts +105 -0
  655. package/src/domains/resources/skills/evals.ts +175 -0
  656. package/src/domains/resources/skills/install.ts +410 -0
  657. package/src/domains/resources/skills/loader.ts +978 -0
  658. package/src/domains/resources/skills/marketplace.ts +255 -0
  659. package/src/domains/resources/skills/provenance-pin.ts +115 -0
  660. package/src/domains/safety/action-classifier.ts +268 -0
  661. package/src/domains/safety/approval-axis.ts +23 -0
  662. package/src/domains/safety/audit.ts +487 -0
  663. package/src/domains/safety/autonomy.ts +174 -0
  664. package/src/domains/safety/call-target.ts +59 -0
  665. package/src/domains/safety/contract.ts +65 -0
  666. package/src/domains/safety/damage-control.ts +44 -0
  667. package/src/domains/safety/default-path-policy.ts +117 -0
  668. package/src/domains/safety/extension.ts +383 -0
  669. package/src/domains/safety/finish-contract-registration.ts +128 -0
  670. package/src/domains/safety/finish-contract.ts +554 -0
  671. package/src/domains/safety/index.ts +44 -0
  672. package/src/domains/safety/loop-detector.ts +143 -0
  673. package/src/domains/safety/manifest.ts +6 -0
  674. package/src/domains/safety/path-policy.ts +164 -0
  675. package/src/domains/safety/policy-engine.ts +994 -0
  676. package/src/domains/safety/project-policy.ts +391 -0
  677. package/src/domains/safety/protected-artifacts-registration.ts +189 -0
  678. package/src/domains/safety/protected-artifacts.ts +993 -0
  679. package/src/domains/safety/rejection-feedback.ts +102 -0
  680. package/src/domains/safety/rigor.ts +72 -0
  681. package/src/domains/safety/rule-compiler.ts +48 -0
  682. package/src/domains/safety/rule-pack-loader.ts +92 -0
  683. package/src/domains/safety/run-effects.ts +197 -0
  684. package/src/domains/safety/scope.ts +61 -0
  685. package/src/domains/scheduling/budget.ts +35 -0
  686. package/src/domains/scheduling/cluster.ts +175 -0
  687. package/src/domains/scheduling/contract.ts +30 -0
  688. package/src/domains/scheduling/extension.ts +91 -0
  689. package/src/domains/scheduling/index.ts +12 -0
  690. package/src/domains/scheduling/manifest.ts +6 -0
  691. package/src/domains/session/archive-readers.ts +208 -0
  692. package/src/domains/session/checkpoint.ts +38 -0
  693. package/src/domains/session/compaction/auto.ts +89 -0
  694. package/src/domains/session/compaction/branch-summary.ts +186 -0
  695. package/src/domains/session/compaction/compact.ts +493 -0
  696. package/src/domains/session/compaction/cut-point.ts +171 -0
  697. package/src/domains/session/compaction/defaults.ts +34 -0
  698. package/src/domains/session/compaction/mask-observations.ts +265 -0
  699. package/src/domains/session/compaction/session-entries.ts +18 -0
  700. package/src/domains/session/compaction/tokens.ts +147 -0
  701. package/src/domains/session/context-accounting.ts +583 -0
  702. package/src/domains/session/context-ledger.ts +348 -0
  703. package/src/domains/session/contract.ts +144 -0
  704. package/src/domains/session/cwd-fallback.ts +65 -0
  705. package/src/domains/session/entries.ts +509 -0
  706. package/src/domains/session/extension.ts +322 -0
  707. package/src/domains/session/history.ts +172 -0
  708. package/src/domains/session/index.ts +84 -0
  709. package/src/domains/session/manager.ts +128 -0
  710. package/src/domains/session/manifest.ts +6 -0
  711. package/src/domains/session/migrations/index.ts +27 -0
  712. package/src/domains/session/prompt-manifest.ts +173 -0
  713. package/src/domains/session/protected-artifact-journal.ts +241 -0
  714. package/src/domains/session/protected-artifacts.ts +90 -0
  715. package/src/domains/session/retry.ts +238 -0
  716. package/src/domains/session/task-board.ts +375 -0
  717. package/src/domains/session/tree/active-path.ts +98 -0
  718. package/src/domains/session/tree/fork.ts +160 -0
  719. package/src/domains/session/tree/manager.ts +128 -0
  720. package/src/domains/session/tree/navigator.ts +177 -0
  721. package/src/domains/session/tree/preview.ts +259 -0
  722. package/src/domains/session/usage.ts +148 -0
  723. package/src/domains/session/workspace/git-probe.ts +161 -0
  724. package/src/domains/session/workspace/index.ts +4 -0
  725. package/src/domains/session/workspace/project-type.ts +217 -0
  726. package/src/domains/session/workspace/snapshot.ts +74 -0
  727. package/src/domains/share/archive.ts +684 -0
  728. package/src/domains/share/contract.ts +9 -0
  729. package/src/domains/share/extension.ts +26 -0
  730. package/src/domains/share/index.ts +28 -0
  731. package/src/domains/share/manifest.ts +6 -0
  732. package/src/engine/acp/adapter.ts +397 -0
  733. package/src/engine/acp/errors.ts +32 -0
  734. package/src/engine/acp/event-mapper.ts +154 -0
  735. package/src/engine/acp/server.ts +656 -0
  736. package/src/engine/acp/tool-mediator.ts +686 -0
  737. package/src/engine/acp/transport.ts +654 -0
  738. package/src/engine/acp/types.ts +170 -0
  739. package/src/engine/agent.ts +29 -0
  740. package/src/engine/ai.ts +202 -0
  741. package/src/engine/alcf-oauth.ts +198 -0
  742. package/src/engine/antigravity/subprocess-runtime.ts +205 -0
  743. package/src/engine/apis/degraded-inference.ts +95 -0
  744. package/src/engine/apis/index.ts +20 -0
  745. package/src/engine/apis/llamacpp-residency.ts +252 -0
  746. package/src/engine/apis/lmstudio-native.ts +1438 -0
  747. package/src/engine/apis/lmstudio-residency.ts +92 -0
  748. package/src/engine/apis/ollama-native.ts +507 -0
  749. package/src/engine/apis/openai-completions.ts +716 -0
  750. package/src/engine/apis/output-budget.ts +99 -0
  751. package/src/engine/apis/residency-lock.ts +29 -0
  752. package/src/engine/apis/residency.ts +640 -0
  753. package/src/engine/apis/resident-models.ts +42 -0
  754. package/src/engine/apis/sampling-overrides.ts +38 -0
  755. package/src/engine/apis/thinking-replay.ts +11 -0
  756. package/src/engine/claude/sdk-runtime.ts +685 -0
  757. package/src/engine/claude/session-id.ts +5 -0
  758. package/src/engine/claude/subprocess-runtime.ts +316 -0
  759. package/src/engine/claude/tool-safety.ts +400 -0
  760. package/src/engine/external-subprocess.ts +23 -0
  761. package/src/engine/harmony-response.ts +165 -0
  762. package/src/engine/loop-guard.ts +1127 -0
  763. package/src/engine/oauth.ts +192 -0
  764. package/src/engine/pi-mono-names.ts +13 -0
  765. package/src/engine/provider-payload.ts +315 -0
  766. package/src/engine/select-list.ts +53 -0
  767. package/src/engine/session.ts +834 -0
  768. package/src/engine/strip-tokenizer-sentinels.ts +125 -0
  769. package/src/engine/tui.ts +103 -0
  770. package/src/engine/types.ts +66 -0
  771. package/src/engine/worker-events.ts +100 -0
  772. package/src/engine/worker-runtime.ts +1022 -0
  773. package/src/engine/worker-tools.ts +203 -0
  774. package/src/entry/orchestrator.ts +1873 -0
  775. package/src/interactive/application-controller.ts +346 -0
  776. package/src/interactive/bus-notices.ts +265 -0
  777. package/src/interactive/chat-loop-messages.ts +626 -0
  778. package/src/interactive/chat-loop-policy.ts +18 -0
  779. package/src/interactive/chat-loop.ts +865 -0
  780. package/src/interactive/chat-panel.ts +1694 -0
  781. package/src/interactive/chat-renderer.ts +1038 -0
  782. package/src/interactive/clio-editor.ts +166 -0
  783. package/src/interactive/command-fallbacks.ts +23 -0
  784. package/src/interactive/command-output.ts +85 -0
  785. package/src/interactive/context-activity.ts +203 -0
  786. package/src/interactive/context-meter.ts +223 -0
  787. package/src/interactive/context-overlay.ts +220 -0
  788. package/src/interactive/cost-overlay.ts +279 -0
  789. package/src/interactive/dispatch-board.ts +1319 -0
  790. package/src/interactive/dispatch-steering.ts +86 -0
  791. package/src/interactive/editor-bash.ts +46 -0
  792. package/src/interactive/editor-steer.ts +51 -0
  793. package/src/interactive/editor-submit.ts +303 -0
  794. package/src/interactive/external-editor.ts +67 -0
  795. package/src/interactive/follow-up-queue-panel.ts +75 -0
  796. package/src/interactive/footer/dashboard.ts +534 -0
  797. package/src/interactive/footer/notifications.ts +275 -0
  798. package/src/interactive/footer/widgets.ts +1246 -0
  799. package/src/interactive/footer-panel.ts +187 -0
  800. package/src/interactive/format-time.ts +85 -0
  801. package/src/interactive/index.ts +11 -0
  802. package/src/interactive/interactive-application.ts +755 -0
  803. package/src/interactive/interactive-event-projection.ts +380 -0
  804. package/src/interactive/interactive-input-runtime.ts +261 -0
  805. package/src/interactive/interactive-presentation.ts +452 -0
  806. package/src/interactive/interactive-shell.ts +134 -0
  807. package/src/interactive/interactive-slash-runtime.ts +492 -0
  808. package/src/interactive/interactive-subscriptions.ts +111 -0
  809. package/src/interactive/interactive-tickers.ts +152 -0
  810. package/src/interactive/keybinding-manager.ts +496 -0
  811. package/src/interactive/layout.ts +20 -0
  812. package/src/interactive/leader-key.ts +143 -0
  813. package/src/interactive/loop-guard-interrupt.ts +101 -0
  814. package/src/interactive/memory-overlay.ts +280 -0
  815. package/src/interactive/overlay-ask-user-lifecycle.ts +110 -0
  816. package/src/interactive/overlay-auth-lifecycle.ts +308 -0
  817. package/src/interactive/overlay-frame.ts +502 -0
  818. package/src/interactive/overlay-general-openers.ts +217 -0
  819. package/src/interactive/overlay-key-routing.ts +213 -0
  820. package/src/interactive/overlay-lifecycle.ts +413 -0
  821. package/src/interactive/overlay-model-selectors.ts +127 -0
  822. package/src/interactive/overlay-permission-lifecycle.ts +344 -0
  823. package/src/interactive/overlay-resource-openers.ts +112 -0
  824. package/src/interactive/overlay-session-lifecycle.ts +270 -0
  825. package/src/interactive/overlay-transitions.ts +57 -0
  826. package/src/interactive/overlays/agents.ts +69 -0
  827. package/src/interactive/overlays/ask-user.ts +921 -0
  828. package/src/interactive/overlays/auth-dialog.ts +221 -0
  829. package/src/interactive/overlays/context-reset.ts +108 -0
  830. package/src/interactive/overlays/cwd-fallback.ts +141 -0
  831. package/src/interactive/overlays/extensions.ts +54 -0
  832. package/src/interactive/overlays/help-reference.ts +140 -0
  833. package/src/interactive/overlays/interop.ts +139 -0
  834. package/src/interactive/overlays/keybinding-detail.ts +90 -0
  835. package/src/interactive/overlays/list-overlay.ts +606 -0
  836. package/src/interactive/overlays/message-picker.ts +155 -0
  837. package/src/interactive/overlays/model-selector.ts +1091 -0
  838. package/src/interactive/overlays/prompts.ts +72 -0
  839. package/src/interactive/overlays/session-selector-search.ts +31 -0
  840. package/src/interactive/overlays/session-selector.ts +266 -0
  841. package/src/interactive/overlays/settings.ts +3363 -0
  842. package/src/interactive/overlays/skills-hub.ts +237 -0
  843. package/src/interactive/overlays/tree-selector.ts +387 -0
  844. package/src/interactive/permission-overlay.ts +170 -0
  845. package/src/interactive/render-trace.ts +125 -0
  846. package/src/interactive/renderers/branch-summary.ts +86 -0
  847. package/src/interactive/renderers/code-ink.ts +420 -0
  848. package/src/interactive/renderers/compaction-summary.ts +112 -0
  849. package/src/interactive/renderers/diff.ts +126 -0
  850. package/src/interactive/renderers/notice.ts +28 -0
  851. package/src/interactive/renderers/retry-status.ts +31 -0
  852. package/src/interactive/renderers/structured.ts +89 -0
  853. package/src/interactive/renderers/tool-execution.ts +1104 -0
  854. package/src/interactive/renderers/worker-entry.ts +264 -0
  855. package/src/interactive/session-last-turn.ts +186 -0
  856. package/src/interactive/session-transcript.ts +105 -0
  857. package/src/interactive/session-usage-reseed.ts +74 -0
  858. package/src/interactive/slash-autocomplete.ts +364 -0
  859. package/src/interactive/slash-commands.ts +1319 -0
  860. package/src/interactive/slash-spec.ts +453 -0
  861. package/src/interactive/status/controller.ts +256 -0
  862. package/src/interactive/status/index.ts +23 -0
  863. package/src/interactive/status/state-machine.ts +530 -0
  864. package/src/interactive/status/summary.ts +170 -0
  865. package/src/interactive/status/types.ts +121 -0
  866. package/src/interactive/status/verbs.ts +163 -0
  867. package/src/interactive/status/watchdog.ts +24 -0
  868. package/src/interactive/tasks-overlay.ts +186 -0
  869. package/src/interactive/theme/components.ts +55 -0
  870. package/src/interactive/theme/glyphs.ts +70 -0
  871. package/src/interactive/theme/index.ts +15 -0
  872. package/src/interactive/theme/labels.ts +88 -0
  873. package/src/interactive/theme/rules.ts +138 -0
  874. package/src/interactive/theme/segments.ts +88 -0
  875. package/src/interactive/theme/tokens.ts +121 -0
  876. package/src/interactive/thinking-level-policy.ts +6 -0
  877. package/src/interactive/tool-prose-loop.ts +122 -0
  878. package/src/interactive/tool-prose-registration.ts +48 -0
  879. package/src/interactive/turn-context.ts +854 -0
  880. package/src/interactive/turn-middleware.ts +283 -0
  881. package/src/interactive/turn-persistence.ts +441 -0
  882. package/src/interactive/turn-queues.ts +169 -0
  883. package/src/interactive/turn-recovery.ts +306 -0
  884. package/src/interactive/turn-runtime.ts +802 -0
  885. package/src/interactive/turn-state.ts +123 -0
  886. package/src/interactive/view/artifacts.ts +1342 -0
  887. package/src/interactive/view/view-overlay.ts +732 -0
  888. package/src/interactive/welcome-dashboard.ts +536 -0
  889. package/src/interactive/worker-receipts.ts +94 -0
  890. package/src/interactive/worker-replay.ts +111 -0
  891. package/src/interactive/worker-share.ts +100 -0
  892. package/src/interactive/worker-stream.ts +442 -0
  893. package/src/interactive/workspace-facts.ts +141 -0
  894. package/src/tools/agent-tools.ts +382 -0
  895. package/src/tools/artifact.ts +103 -0
  896. package/src/tools/ask-user.ts +656 -0
  897. package/src/tools/bash.ts +176 -0
  898. package/src/tools/bootstrap.ts +474 -0
  899. package/src/tools/codewiki/code-nav.ts +563 -0
  900. package/src/tools/codewiki/shared.ts +115 -0
  901. package/src/tools/compete-worktrees.ts +898 -0
  902. package/src/tools/context/docs-engine.ts +619 -0
  903. package/src/tools/context/index.ts +435 -0
  904. package/src/tools/credential-present.ts +151 -0
  905. package/src/tools/dispatch-arguments.ts +228 -0
  906. package/src/tools/dispatch-plan.ts +741 -0
  907. package/src/tools/dispatch-scout.ts +461 -0
  908. package/src/tools/dispatch.ts +3338 -0
  909. package/src/tools/edit-diff.ts +534 -0
  910. package/src/tools/edit.ts +128 -0
  911. package/src/tools/executables.ts +22 -0
  912. package/src/tools/file-mutation-queue.ts +35 -0
  913. package/src/tools/find.ts +292 -0
  914. package/src/tools/grep.ts +495 -0
  915. package/src/tools/ignore-policy.ts +169 -0
  916. package/src/tools/ledger.ts +206 -0
  917. package/src/tools/ls.ts +110 -0
  918. package/src/tools/monitor.ts +797 -0
  919. package/src/tools/network-policy.ts +29 -0
  920. package/src/tools/observation.ts +421 -0
  921. package/src/tools/observers.ts +99 -0
  922. package/src/tools/path-utils.ts +79 -0
  923. package/src/tools/policy.ts +154 -0
  924. package/src/tools/profiles.ts +108 -0
  925. package/src/tools/read.ts +173 -0
  926. package/src/tools/registry.ts +1157 -0
  927. package/src/tools/result-shaping.ts +204 -0
  928. package/src/tools/safe-exec.ts +128 -0
  929. package/src/tools/spawn-hygiene.ts +182 -0
  930. package/src/tools/steer.ts +88 -0
  931. package/src/tools/string-enum.ts +15 -0
  932. package/src/tools/tasks.ts +168 -0
  933. package/src/tools/truncate-utf8.ts +17 -0
  934. package/src/tools/truncate.ts +202 -0
  935. package/src/tools/verify/frontend.ts +685 -0
  936. package/src/tools/verify/index.ts +66 -0
  937. package/src/tools/verify/scripts.ts +108 -0
  938. package/src/tools/web-fetch.ts +777 -0
  939. package/src/tools/worker-evidence.ts +215 -0
  940. package/src/tools/write.ts +52 -0
  941. package/src/utils/exif-orientation.ts +192 -0
  942. package/src/utils/git.ts +24 -0
  943. package/src/utils/image-resize.ts +148 -0
  944. package/src/utils/photon.ts +103 -0
  945. package/src/worker/control-lane.ts +22 -0
  946. package/src/worker/entry.ts +257 -0
  947. package/src/worker/event-projection.ts +56 -0
  948. package/src/worker/heartbeat.ts +24 -0
  949. package/src/worker/ledger-mirror.ts +95 -0
  950. package/src/worker/ndjson.ts +40 -0
  951. package/src/worker/protocol.ts +529 -0
  952. package/src/worker/resource-facts.ts +79 -0
  953. package/src/worker/runtime-registry.ts +12 -0
  954. package/src/worker/spec-contract.ts +654 -0
  955. package/src/worker/stdin-demux.ts +316 -0
  956. package/dist/acp-UMLFVA3F.js +0 -92
  957. package/dist/chunk-262G75JS.js +0 -35
  958. package/dist/chunk-5LDRNKX2.js +0 -1063
  959. package/dist/chunk-67MTHP2E.js +0 -135
  960. package/dist/chunk-GOTUR54M.js +0 -9
  961. package/dist/chunk-TPOCL34A.js +0 -2876
  962. package/dist/chunk-XV4ZJ6ZM.js +0 -3177
  963. package/dist/clio-KIQ5SNDS.js +0 -53
  964. package/dist/configure-G4E3A2PG.js +0 -27
  965. package/dist/doctor-M5HJJZOL.js +0 -61
  966. package/dist/domains/agents/builtins/architect.md +0 -33
  967. package/dist/domains/agents/builtins/coder.md +0 -31
  968. package/dist/domains/agents/builtins/context-bootstrap.md +0 -38
  969. package/dist/domains/agents/builtins/debugger.md +0 -30
  970. package/dist/domains/agents/builtins/documenter.md +0 -31
  971. package/dist/domains/agents/builtins/git-master.md +0 -30
  972. package/dist/domains/agents/builtins/provenance.md +0 -30
  973. package/dist/domains/agents/builtins/researcher.md +0 -71
  974. package/dist/domains/agents/builtins/scout.md +0 -42
  975. package/dist/domains/agents/builtins/tester.md +0 -31
  976. package/dist/domains/agents/builtins/verifier.md +0 -30
  977. package/dist/domains/agents/builtins/wiki-writer.md +0 -41
  978. package/dist/fleet-preflight-CLIAX7YR.js +0 -21
  979. package/dist/preload-KZVHET2B.js +0 -11
  980. package/dist/version-ROZ6CZKH.js +0 -16
  981. package/skills/git/commit-crafting/SKILL.md +0 -79
  982. package/skills/git/commit-crafting/evals.md +0 -92
  983. package/skills/git/create-pr/SKILL.md +0 -116
  984. package/skills/git/create-pr/evals.md +0 -114
  985. package/skills/git/investigate-issue/SKILL.md +0 -139
  986. package/skills/git/investigate-issue/evals.md +0 -94
  987. package/skills/git/review-changes/SKILL.md +0 -103
  988. package/skills/git/review-changes/evals.md +0 -85
@@ -0,0 +1,1104 @@
1
+ /**
2
+ * Structured renderer for tool-execution chat segments (Slice A of the
3
+ * pi-coding-agent parity work). pi-coding-agent renders every tool call as
4
+ * a header line plus an optional args body and a result/error block. Clio
5
+ * previously emitted a single inline string per call, which collapsed
6
+ * structure (multi-line outputs vanished) and prevented the live and replay
7
+ * paths from sharing one renderer.
8
+ *
9
+ * Pure functions: no I/O, no console writes, no module-level mutable state.
10
+ * The chat-panel tool segment renderer (live path) and the chat-renderer
11
+ * orphan tool-result fallback (replay path) both consume this module so the
12
+ * two surfaces stay byte-identical.
13
+ */
14
+
15
+ import { sanitizeCallTargetText } from "../../domains/safety/call-target.js";
16
+ import { visibleWidth, wrapTextWithAnsi } from "../../engine/tui.js";
17
+ import { clioTheme, formatCompactMs, GLYPH } from "../theme/index.js";
18
+ import { type DiffRenderInput, renderUnifiedDiff } from "./diff.js";
19
+ import { tryRenderJson, tryRenderXml } from "./structured.js";
20
+
21
+ const theme = clioTheme();
22
+ const dim = (text: string): string => theme.fg("dim", text);
23
+ const red = (text: string): string => theme.fg("error", text);
24
+ const green = (text: string): string => theme.fg("success", text);
25
+ const yellow = (text: string): string => theme.fg("warning", text);
26
+ const cyan = (text: string): string => theme.fg("accent", text);
27
+ const cyanBold = (text: string): string => theme.style("accent", text, { bold: true });
28
+
29
+ // Visible width of the rail prefix is 2 columns (`│ `). Width budgets and
30
+ // diff renderers compute against the visible length, not the styled length,
31
+ // so the constant is kept as the plain-text representation.
32
+ const BODY_INDENT_PLAIN = "│ ";
33
+ const BODY_INDENT_VISIBLE_WIDTH = 2;
34
+ const HEADER_PREFIX_PLAIN = "▸ ";
35
+ const ARG_PREVIEW_LIMIT = 60;
36
+ const WEB_FETCH_ARG_PREVIEW_LIMIT = 140;
37
+ const RESULT_PREVIEW_LIMIT = 4000;
38
+ const FULL_RESULT_PREVIEW_LIMIT = 60_000;
39
+ const FULL_RESULT_ROW_LIMIT = 120;
40
+ const STREAMING_RESULT_ROW_LIMIT = 20;
41
+ const ARGS_BODY_LINE_LIMIT = 24;
42
+ const STATUS_OK_GLYPH = GLYPH.ok;
43
+ const STATUS_ERROR_GLYPH = GLYPH.error;
44
+
45
+ // Hoisted rail prefixes. `indentAndWrap` would otherwise allocate two fresh
46
+ // styled strings per rendered line; by precomputing the dim and error variants
47
+ // once at module scope, repeated rendering of long result blocks stays cheap.
48
+ const RAIL_DIM = dim(BODY_INDENT_PLAIN);
49
+ const RAIL_ERROR = red(BODY_INDENT_PLAIN);
50
+
51
+ export interface ToolExecutionStart {
52
+ toolCallId: string;
53
+ toolName: string;
54
+ args: unknown;
55
+ /** Live elapsed time supplied by the panel for running segments. */
56
+ elapsedMs?: number | undefined;
57
+ }
58
+
59
+ export interface ToolExecutionFinished {
60
+ toolCallId: string;
61
+ toolName: string;
62
+ args?: unknown;
63
+ result: unknown;
64
+ isError: boolean;
65
+ durationMs?: number | undefined;
66
+ /** Persisted summary (bytes, truncated, offloadPath, observation counts). */
67
+ resultSummary?: Record<string, unknown> | undefined;
68
+ /** Honest terminal outcome for synthetic/or permission-blocked calls. */
69
+ outcome?: "blocked" | "aborted" | "orphaned" | undefined;
70
+ /**
71
+ * Why admission refused this call, from the registry verdict. A blocked row
72
+ * that states only that something was refused leaves the operator, and the
73
+ * model reading the same transcript, to guess at the rule.
74
+ */
75
+ blockReason?: string | undefined;
76
+ }
77
+
78
+ export interface ToolBodyRenderOptions {
79
+ /**
80
+ * Render the full tool result body with no middle-elision and no character
81
+ * truncation. The live view keeps bodies bounded so a single tool cannot
82
+ * flood the pane; `/export` sets this so the written transcript reproduces
83
+ * the complete tool output the model actually received.
84
+ */
85
+ unbounded?: boolean;
86
+ }
87
+
88
+ /** Row cap for a tool body: unbounded lifts both the row and char limits. */
89
+ function resultRowLimit(opts: ToolBodyRenderOptions): number {
90
+ return opts.unbounded === true ? Number.POSITIVE_INFINITY : FULL_RESULT_ROW_LIMIT;
91
+ }
92
+
93
+ function resultCharLimit(opts: ToolBodyRenderOptions): number {
94
+ return opts.unbounded === true ? Number.POSITIVE_INFINITY : FULL_RESULT_PREVIEW_LIMIT;
95
+ }
96
+
97
+ // Counts UTF-16 code units; can split a surrogate pair on non-BMP input. Acceptable for ASCII paths/commands.
98
+ function truncate(value: string, limit: number): string {
99
+ if (value.length <= limit) return value;
100
+ const cut = Math.max(0, limit - 3);
101
+ return `${value.slice(0, cut)}...`;
102
+ }
103
+
104
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
105
+ return value !== null && typeof value === "object" && !Array.isArray(value);
106
+ }
107
+
108
+ const SECRET_KEY_RE =
109
+ /(?:api[-_]?key|access[-_]?key|auth(?:orization)?|credential|password|private[-_]?key|secret|token)/iu;
110
+ const ENV_KEY_RE = /^env(?:ironment)?$/iu;
111
+ const SECRET_STRING_RE = /(https?:\/\/[^\s/@]+:)[^\s/@]+@/giu;
112
+ const SECRET_URL_PARAM_RE =
113
+ /([?&](?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[^=\s]*=)[^&#\s]+/giu;
114
+ const SECRET_ASSIGNMENT_RE =
115
+ /(?<![A-Z0-9_])((?:[A-Z0-9_]*(?:ACCESS|API|AUTH|CREDENTIAL|KEY|PASS(?:WORD)?|PRIVATE|SECRET|TOKEN)[A-Z0-9_]*)=)[^\s;&|]+/giu;
116
+ const SECRET_FLAG_RE =
117
+ /(--?(?:[a-z0-9-]*(?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[a-z0-9-]*))(=|\s+)([^\s;&|]+)/giu;
118
+
119
+ function redactSecretString(value: string): string {
120
+ return value
121
+ .replace(SECRET_STRING_RE, "$1[redacted]@")
122
+ .replace(SECRET_URL_PARAM_RE, "$1[redacted]")
123
+ .replace(SECRET_ASSIGNMENT_RE, "$1[redacted]")
124
+ .replace(SECRET_FLAG_RE, "$1$2[redacted]");
125
+ }
126
+
127
+ function redactEnvironmentValue(value: unknown, depth: number): unknown {
128
+ if (depth > 8) return "[redacted nested values]";
129
+ if (typeof value === "string") return "[redacted]";
130
+ if (Array.isArray(value)) return value.map((item) => redactEnvironmentValue(item, depth + 1));
131
+ if (!isPlainObject(value)) return value;
132
+ const out: Record<string, unknown> = {};
133
+ for (const [childKey, childValue] of Object.entries(value)) {
134
+ out[childKey] = redactEnvironmentValue(childValue, depth + 1);
135
+ }
136
+ return out;
137
+ }
138
+
139
+ /** Project tool arguments for display only; execution and receipts retain the original values. */
140
+ export function redactToolArgs(value: unknown, key = "", depth = 0): unknown {
141
+ if (SECRET_KEY_RE.test(key)) return "[redacted]";
142
+ if (ENV_KEY_RE.test(key)) return redactEnvironmentValue(value, depth);
143
+ if (typeof value === "string") return redactSecretString(value);
144
+ if (depth > 8) return "[redacted nested values]";
145
+ if (Array.isArray(value)) return value.map((item) => redactToolArgs(item, key, depth + 1));
146
+ if (!isPlainObject(value)) return value;
147
+ const out: Record<string, unknown> = {};
148
+ for (const [childKey, childValue] of Object.entries(value)) {
149
+ out[childKey] = redactToolArgs(childValue, childKey, depth + 1);
150
+ }
151
+ return out;
152
+ }
153
+
154
+ function readStringField(args: unknown, key: string): string | null {
155
+ if (!isPlainObject(args)) return null;
156
+ const value = args[key];
157
+ return typeof value === "string" ? redactSecretString(value) : null;
158
+ }
159
+
160
+ function isEmptyArgs(args: unknown): boolean {
161
+ if (args === undefined || args === null) return true;
162
+ if (isPlainObject(args) && Object.keys(args).length === 0) return true;
163
+ return false;
164
+ }
165
+
166
+ function jsonStringifySafe(value: unknown): string {
167
+ try {
168
+ const text = JSON.stringify(value);
169
+ return typeof text === "string" ? text : String(value);
170
+ } catch {
171
+ return String(value);
172
+ }
173
+ }
174
+
175
+ function unquoteShellScript(value: string): string {
176
+ const trimmed = value.trim();
177
+ if (trimmed.length < 2) return trimmed;
178
+ const quote = trimmed.charAt(0);
179
+ if ((quote !== "'" && quote !== '"') || trimmed.charAt(trimmed.length - 1) !== quote) return trimmed;
180
+ const inner = trimmed.slice(1, -1);
181
+ if (quote === "'") return inner.replace(/'\\''/g, "'");
182
+ return inner.replace(/\\"/g, '"').replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\\\/g, "\\");
183
+ }
184
+
185
+ function stripShellWrapperForDisplay(command: string): string {
186
+ const trimmed = command.trim();
187
+ const match = /^(?:(?:\/(?:usr\/)?bin\/)?(?:bash|zsh|sh))\s+-lc\s+([\s\S]+)$/u.exec(trimmed);
188
+ if (!match?.[1]) return command;
189
+ return unquoteShellScript(match[1]);
190
+ }
191
+
192
+ function displayArg(toolName: string, value: string): string {
193
+ return toolName === "bash" ? stripShellWrapperForDisplay(value) : value;
194
+ }
195
+
196
+ /**
197
+ * Optional-duration guard around the single duration formatter. formatCompactMs
198
+ * is the one formatter for elapsed time, but these call sites carry a
199
+ * `number | undefined` that may be missing, non-finite, or negative and must
200
+ * then omit the ` · <dur>` segment entirely. Returns null in those cases and
201
+ * delegates every real value to formatCompactMs, so durations render as
202
+ * `860ms`, `4.2s`, `42s`, and `1m36s` with no zero padding on the seconds.
203
+ */
204
+ function optionalCompactMs(durationMs: number | undefined): string | null {
205
+ if (durationMs === undefined || !Number.isFinite(durationMs) || durationMs < 0) return null;
206
+ return formatCompactMs(durationMs);
207
+ }
208
+
209
+ function bashExitCodeFromResult(result: unknown): string | null {
210
+ const unwrapped = unwrapResultEnvelope(result);
211
+ const text = typeof unwrapped === "string" ? unwrapped : jsonStringifySafe(unwrapped);
212
+ const match =
213
+ /\bcommand failed \(exit (?<paren>[^)]+)\)/iu.exec(text) ??
214
+ /\bcommand exited with code (?<code>[0-9?]+)/iu.exec(text) ??
215
+ /\bexit (?<short>[0-9?]+)\b/iu.exec(text);
216
+ return match?.groups?.paren ?? match?.groups?.code ?? match?.groups?.short ?? null;
217
+ }
218
+
219
+ /**
220
+ * Map of known tools to their canonical "primary" arg field. When the arg is
221
+ * a string the header summarises it directly and the args body is suppressed
222
+ * because echoing `{"path": "..."}` next to `tool: read(...)` is duplicate
223
+ * noise. Tools not in this map (or with an unexpected arg shape) fall back
224
+ * to a JSON-dump summary plus the full args body.
225
+ */
226
+ const PRIMARY_ARG_FIELD: Record<string, string> = {
227
+ read: "path",
228
+ edit: "path",
229
+ write: "path",
230
+ ls: "path",
231
+ bash: "command",
232
+ grep: "pattern",
233
+ find: "pattern",
234
+ web_fetch: "url",
235
+ git: "op",
236
+ verify: "check",
237
+ code_nav: "query",
238
+ context: "scope",
239
+ artifact: "kind",
240
+ monitor: "run_id",
241
+ steer: "run_id",
242
+ tasks: "action",
243
+ };
244
+
245
+ /**
246
+ * Returns the captured primary-arg string when the header successfully used a
247
+ * known tool's canonical arg, otherwise null. Drives the args-body suppression
248
+ * so `tool: read(README.md)` does not get followed by `{"path": "README.md"}`.
249
+ */
250
+ function capturedPrimaryArg(toolName: string, args: unknown): string | null {
251
+ const field = PRIMARY_ARG_FIELD[toolName];
252
+ if (field === undefined) return null;
253
+ return readStringField(args, field);
254
+ }
255
+
256
+ /**
257
+ * Pick the most informative single-line summary of a tool's arguments for
258
+ * the header line. Known tools have a canonical "primary" arg (path,
259
+ * command, pattern, url); unknown tools or unexpected shapes fall back to a
260
+ * truncated JSON dump. Returns an empty string when args are absent so the
261
+ * header renders as `tool: <name>()`.
262
+ */
263
+ function summarizeWebFetchArgs(args: unknown): string {
264
+ if (!isPlainObject(args)) return summarizeArgs("", args);
265
+ const compact: Record<string, unknown> = {};
266
+ for (const key of ["url", "format", "max_bytes", "timeout_ms", "method"] as const) {
267
+ if (args[key] !== undefined) compact[key] = args[key];
268
+ }
269
+ return truncate(jsonStringifySafe(Object.keys(compact).length > 0 ? compact : args), WEB_FETCH_ARG_PREVIEW_LIMIT);
270
+ }
271
+
272
+ function summarizeArgs(toolName: string, args: unknown): string {
273
+ if (isEmptyArgs(args)) return "";
274
+ const safeArgs = redactToolArgs(args);
275
+ if (toolName === "web_fetch") return summarizeWebFetchArgs(safeArgs);
276
+ const primary = capturedPrimaryArg(toolName, args);
277
+ if (primary !== null) return truncate(displayArg(toolName, primary), ARG_PREVIEW_LIMIT);
278
+ return truncate(jsonStringifySafe(safeArgs), ARG_PREVIEW_LIMIT);
279
+ }
280
+
281
+ /**
282
+ * Compact resource-read classification. Reads of skill/handbook/agent
283
+ * instruction files and docs pages collapse to one labeled line and never
284
+ * auto-expand; their bodies are reference material, not task output.
285
+ */
286
+ export function classifyResourceRead(toolName: string, args: unknown): string | null {
287
+ if (toolName !== "read") return null;
288
+ const path = readStringField(args, "path");
289
+ if (path === null) return null;
290
+ const normalized = path.replace(/\\/g, "/");
291
+ const base = normalized.split("/").pop() ?? "";
292
+ if (base === "SKILL.md") return "skill";
293
+ if (base === "CLIO-CODER.md") return "handbook";
294
+ if (base === "AGENTS.md") return "agents";
295
+ if (/(^|\/)docs\//.test(normalized)) return "docs";
296
+ return null;
297
+ }
298
+
299
+ function detailsOf(result: unknown): Record<string, unknown> | null {
300
+ if (!isPlainObject(result)) return null;
301
+ return isPlainObject(result.details) ? result.details : null;
302
+ }
303
+
304
+ function observationOf(finished: ToolExecutionFinished): Record<string, unknown> | null {
305
+ const fromDetails = detailsOf(finished.result)?.observation;
306
+ if (isPlainObject(fromDetails)) return fromDetails;
307
+ const fromSummary = finished.resultSummary?.observation;
308
+ return isPlainObject(fromSummary) ? fromSummary : null;
309
+ }
310
+
311
+ function numberField(record: Record<string, unknown> | null, key: string): number | null {
312
+ const value = record?.[key];
313
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
314
+ }
315
+
316
+ function stringField(record: Record<string, unknown> | null, key: string): string | null {
317
+ const value = record?.[key];
318
+ return typeof value === "string" && value.length > 0 ? value : null;
319
+ }
320
+
321
+ function formatBytes(bytes: number): string {
322
+ if (bytes < 1024) return `${bytes}B`;
323
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)}KB`;
324
+ return `${(bytes / (1024 * 1024)).toFixed(1)}MB`;
325
+ }
326
+
327
+ function countSummary(observation: Record<string, unknown>): string | null {
328
+ const unit = stringField(observation, "unit") ?? "results";
329
+ const shown = numberField(observation, "shownCount");
330
+ if (shown === null) return null;
331
+ const total = numberField(observation, "totalCount");
332
+ if (total === null) return `${shown}+ ${unit}`;
333
+ if (total === shown) return `${shown} ${unit}`;
334
+ return `${shown}/${total} ${unit}`;
335
+ }
336
+
337
+ /**
338
+ * Outcome facts for the collapsed ledger line, derived from the observation
339
+ * envelope (OBSERVE plane), the exec record (git/verify), or the dispatch
340
+ * receipt counts. Returns null when the result carries no recognizable facts.
341
+ */
342
+ function outcomeSummary(finished: ToolExecutionFinished): string | null {
343
+ const observation = observationOf(finished);
344
+ if (observation !== null) {
345
+ if (finished.toolName === "read") {
346
+ const shown = numberField(observation, "shownCount");
347
+ const total = numberField(observation, "totalCount");
348
+ if (shown !== null && total !== null) {
349
+ const offsetRaw = isPlainObject(finished.args) ? finished.args.offset : undefined;
350
+ const start = typeof offsetRaw === "number" && offsetRaw > 0 ? Math.floor(offsetRaw) : 1;
351
+ return shown > 0 ? `lines ${start}-${start + shown - 1} of ${total}` : `0 of ${total} lines`;
352
+ }
353
+ }
354
+ return countSummary(observation);
355
+ }
356
+ const details = detailsOf(finished.result);
357
+ if (finished.toolName === "git" || finished.toolName === "verify") {
358
+ const exitCode = numberField(details, "exitCode");
359
+ if (exitCode !== null) return `exit ${exitCode}`;
360
+ const status = stringField(details, "status");
361
+ if (status !== null) return status;
362
+ return null;
363
+ }
364
+ if (finished.toolName === "dispatch") {
365
+ const receipts = numberField(details, "receiptCount");
366
+ const failed = numberField(details, "failedCount") ?? 0;
367
+ if (receipts !== null) return `${receipts} task${receipts === 1 ? "" : "s"} -> ${receipts - failed} ok`;
368
+ return null;
369
+ }
370
+ if (finished.toolName === "tasks") {
371
+ const rawCounts = details?.counts;
372
+ const counts = isPlainObject(rawCounts) ? rawCounts : null;
373
+ const completed = numberField(counts, "completed");
374
+ const total = numberField(counts, "total");
375
+ if (completed !== null && total !== null) {
376
+ const blocked = numberField(counts, "blocked") ?? 0;
377
+ return `${completed}/${total} done${blocked > 0 ? ` · ${blocked} blocked` : ""}`;
378
+ }
379
+ return null;
380
+ }
381
+ return null;
382
+ }
383
+
384
+ function offloadPathOf(finished: ToolExecutionFinished): string | null {
385
+ const observation = observationOf(finished);
386
+ const fromObservation = stringField(observation, "offloadPath");
387
+ if (fromObservation !== null) return fromObservation;
388
+ const summary = finished.resultSummary ?? null;
389
+ const fromSummary = stringField(summary, "offloadPath");
390
+ if (fromSummary !== null) return fromSummary;
391
+ const resultSize = detailsOf(finished.result)?.resultSize;
392
+ return isPlainObject(resultSize) ? stringField(resultSize, "offloadPath") : null;
393
+ }
394
+
395
+ function shownBytesOf(finished: ToolExecutionFinished): number | null {
396
+ const observation = observationOf(finished);
397
+ const fromObservation = numberField(observation, "shownBytes");
398
+ if (fromObservation !== null) return fromObservation;
399
+ return numberField(finished.resultSummary ?? null, "bytes");
400
+ }
401
+
402
+ /**
403
+ * The dim ledger tail appended to a finished collapsed subline: outcome facts,
404
+ * then byte size (duration rides on the status glyph), then the offload path
405
+ * for truncated calls. One line of plain text carries signature and outcome
406
+ * when copied.
407
+ */
408
+ function ledgerTail(finished: ToolExecutionFinished): { facts: string; offload: string } {
409
+ const parts: string[] = [];
410
+ const outcome = outcomeSummary(finished);
411
+ if (outcome !== null) parts.push(outcome);
412
+ const bytes = isNonExecutedOutcome(finished.outcome) ? null : shownBytesOf(finished);
413
+ if (bytes !== null && bytes > 0) parts.push(formatBytes(bytes));
414
+ const offloadPath = offloadPathOf(finished);
415
+ return {
416
+ facts: parts.length > 0 ? dim(` · ${parts.join(" · ")}`) : "",
417
+ offload: offloadPath !== null ? dim(` · full: ${offloadPath}`) : "",
418
+ };
419
+ }
420
+
421
+ /**
422
+ * Marker for a call parked at admission awaiting operator approval. Rendered
423
+ * in place of the elapsed counter so a parked call never reads as executing
424
+ * work; the ⏸ glyph matches the footer's blocked phase.
425
+ */
426
+ const AWAITING_APPROVAL_TAIL = ` ${yellow(GLYPH.phaseBlocked)}${dim(" awaiting approval")}`;
427
+
428
+ /**
429
+ * Subline for an in-flight call whose body is parked at the permission gate.
430
+ * No elapsed counter (nothing is running) and no status glyph (nothing has
431
+ * finished): the awaiting-approval tail is the segment's whole state.
432
+ */
433
+ export function renderToolAwaitingApproval(call: ToolExecutionStart, width: number): string[] {
434
+ const parts = sublineParts({ toolCallId: call.toolCallId, toolName: call.toolName, args: call.args }, undefined, {});
435
+ return wrapSublineWithTail(parts.lead, AWAITING_APPROVAL_TAIL, width);
436
+ }
437
+
438
+ /**
439
+ * Header status: `undefined` when the call is still in flight (no glyph),
440
+ * `"ok"` for success (green check), `"error"` for failure (red cross). The
441
+ * glyph hangs off the right of the header line so the tool name + args read
442
+ * left-to-right without extra punctuation.
443
+ */
444
+ type HeaderStatus = "ok" | "error" | undefined;
445
+
446
+ /** Keeps a refusal reason to one scannable clause on the status tail. */
447
+ const BLOCK_REASON_LIMIT = 72;
448
+
449
+ interface StatusMeta {
450
+ durationMs?: number | undefined;
451
+ exitCode?: string | null;
452
+ outcome?: ToolExecutionFinished["outcome"];
453
+ /** Refusal reason, rendered only alongside a non-executed outcome. */
454
+ blockReason?: string | undefined;
455
+ }
456
+
457
+ function statusGlyph(status: HeaderStatus, meta: StatusMeta = {}): string {
458
+ if (status === undefined) return "";
459
+ const duration = optionalCompactMs(meta.durationMs);
460
+ const durationSuffix = duration ? dim(` · ${duration}`) : "";
461
+ if (status === "ok") return ` ${green(STATUS_OK_GLYPH)}${durationSuffix}`;
462
+ const exitSuffix = meta.exitCode ? dim(` (exit ${meta.exitCode})`) : "";
463
+ const outcomeSuffix = meta.outcome ? dim(` ${meta.outcome}`) : "";
464
+ // A refusal that names no rule tells the operator only that something was
465
+ // stopped. The reason rides the same tail as the outcome word so the
466
+ // collapsed subline and the expanded header state it identically.
467
+ const reason = meta.outcome !== undefined ? meta.blockReason?.trim() : undefined;
468
+ const reasonSuffix = reason ? dim(` · ${truncate(reason, BLOCK_REASON_LIMIT)}`) : "";
469
+ return ` ${red(STATUS_ERROR_GLYPH)}${outcomeSuffix}${reasonSuffix}${exitSuffix}${durationSuffix}`;
470
+ }
471
+
472
+ function headerLine(toolName: string, args: unknown, status: HeaderStatus, meta: StatusMeta = {}): string {
473
+ const summary = summarizeArgs(toolName, args);
474
+ const head = `${dim(HEADER_PREFIX_PLAIN)}${cyanBold(toolName)}${dim("(")}${cyan(summary)}${dim(")")}`;
475
+ return `${head}${statusGlyph(status, meta)}`;
476
+ }
477
+
478
+ function sublineLead(token: string, rest: string): string {
479
+ return `${cyanBold(token)}${rest}`;
480
+ }
481
+
482
+ function styleSublineBody(body: string): string {
483
+ const match = /^(?<lead>[^ (]+)(?<rest>.*)$/u.exec(body);
484
+ if (match?.groups?.lead === undefined || match.groups.rest === undefined) return body;
485
+ return sublineLead(match.groups.lead, match.groups.rest);
486
+ }
487
+
488
+ function buildUnknownToolBody(toolName: string, args: unknown): string {
489
+ return `${toolName}(${summarizeArgs(toolName, args)})`;
490
+ }
491
+
492
+ function buildFieldSublineBody(
493
+ args: unknown,
494
+ key: string,
495
+ lead: string,
496
+ options: { wrapInBackticks?: boolean } = {},
497
+ ): string | null {
498
+ const value = readStringField(args, key);
499
+ if (value === null) return null;
500
+ const preview = truncate(key === "command" ? stripShellWrapperForDisplay(value) : value, ARG_PREVIEW_LIMIT);
501
+ if (options.wrapInBackticks) return `${lead}\`${preview}\``;
502
+ return `${lead}${preview}`;
503
+ }
504
+
505
+ function dispatchSublineBody(args: unknown): string | null {
506
+ if (!isPlainObject(args)) return null;
507
+ if (args.list === true) return "listing fleet agents";
508
+ const sharedAgent =
509
+ (typeof args.agent === "string" && args.agent.trim()) ||
510
+ (typeof args.agent_id === "string" && args.agent_id.trim()) ||
511
+ "coder";
512
+ let rawTasks: unknown = args.tasks;
513
+ if (typeof rawTasks === "string") {
514
+ const trimmed = rawTasks.trim();
515
+ if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
516
+ try {
517
+ rawTasks = JSON.parse(trimmed) as unknown;
518
+ } catch {
519
+ // Keep the string as one plain task; dispatch itself reports malformed JSON.
520
+ }
521
+ }
522
+ }
523
+ const tasks = Array.isArray(rawTasks) ? rawTasks : rawTasks === undefined ? [] : [rawTasks];
524
+ if (tasks.length === 0) return null;
525
+ const first = tasks[0];
526
+ const record = isPlainObject(first) ? first : null;
527
+ const agent =
528
+ (record && typeof record.agent === "string" && record.agent.trim()) ||
529
+ (record && typeof record.agent_id === "string" && record.agent_id.trim()) ||
530
+ sharedAgent;
531
+ const taskText = typeof first === "string" ? first : record && typeof record.task === "string" ? record.task : "";
532
+ const taskPreview = truncate(sanitizeCallTargetText(taskText), ARG_PREVIEW_LIMIT);
533
+ const more = tasks.length > 1 ? ` +${tasks.length - 1} more` : "";
534
+ if (taskPreview.length === 0) return `dispatching ${tasks.length} task${tasks.length === 1 ? "" : "s"}${more}`;
535
+ return `dispatching ${agent}: ${taskPreview}${more}`;
536
+ }
537
+
538
+ const SUBLINE_BODY_BUILDERS: Readonly<Record<string, (args: unknown) => string | null>> = {
539
+ read: (args) => buildFieldSublineBody(args, "path", "reading "),
540
+ edit: (args) => buildFieldSublineBody(args, "path", "editing "),
541
+ write: (args) => buildFieldSublineBody(args, "path", "writing "),
542
+ ls: (args) => buildFieldSublineBody(args, "path", "listing "),
543
+ bash: (args) => buildFieldSublineBody(args, "command", "running ", { wrapInBackticks: true }),
544
+ grep: (args) => buildFieldSublineBody(args, "pattern", "searching for ", { wrapInBackticks: true }),
545
+ find: (args) => buildFieldSublineBody(args, "pattern", "finding ", { wrapInBackticks: true }),
546
+ git: (args) => buildFieldSublineBody(args, "op", "git "),
547
+ verify: (args) => buildFieldSublineBody(args, "check", "verifying "),
548
+ code_nav: (args) => {
549
+ const mode = readStringField(args, "mode");
550
+ const query = readStringField(args, "query")?.trim() ?? "";
551
+ const queryPart = query.length > 0 ? ` \`${truncate(query, ARG_PREVIEW_LIMIT)}\`` : "";
552
+ if (mode !== null && mode.length > 0) return `navigating ${mode}${queryPart}`;
553
+ return queryPart.length > 0 ? `navigating${queryPart}` : null;
554
+ },
555
+ context: (args) => {
556
+ const scope = readStringField(args, "scope");
557
+ if (scope === null || scope.length === 0) return null;
558
+ const query = readStringField(args, "query")?.trim() ?? "";
559
+ const name = readStringField(args, "name")?.trim() ?? "";
560
+ if (scope === "docs" && query.length > 0) return `context docs \`${truncate(query, ARG_PREVIEW_LIMIT)}\``;
561
+ if (scope === "skills" && name.length > 0) return `context skills ${truncate(name, ARG_PREVIEW_LIMIT)}`;
562
+ return `context ${scope}`;
563
+ },
564
+ artifact: (args) => buildFieldSublineBody(args, "kind", "writing "),
565
+ monitor: (args) => buildFieldSublineBody(args, "run_id", "monitoring "),
566
+ steer: (args) => buildFieldSublineBody(args, "run_id", "steering "),
567
+ tasks: (args) => {
568
+ const action = readStringField(args, "action");
569
+ if (action === null) return null;
570
+ if (action === "plan") {
571
+ const title = readStringField(args, "title");
572
+ return title === null ? "tasks plan" : `tasks plan ${truncate(`"${title}"`, ARG_PREVIEW_LIMIT)}`;
573
+ }
574
+ const id = readStringField(args, "id");
575
+ return id === null ? `tasks ${action}` : `tasks ${action} ${id}`;
576
+ },
577
+ dispatch: dispatchSublineBody,
578
+ };
579
+
580
+ /**
581
+ * Per-tool subline templates. Maps a tool name to a function that builds the
582
+ * verb-led subline body without the leading glyph and without the trailing
583
+ * status glyph. Unknown tools fall back to the existing `<name>(<arg>)` form.
584
+ */
585
+ function webFetchMeta(result: unknown): string | null {
586
+ if (!isPlainObject(result) || !isPlainObject(result.details)) return null;
587
+ const status = typeof result.details.status === "number" ? String(result.details.status) : null;
588
+ const format = typeof result.details.format === "string" ? result.details.format : null;
589
+ const bytesRead = typeof result.details.bytesRead === "number" ? result.details.bytesRead : null;
590
+ const truncated = result.details.truncated === true ? "truncated" : null;
591
+ const bytes = bytesRead === null ? null : bytesRead >= 1024 ? `${(bytesRead / 1024).toFixed(1)}KB` : `${bytesRead}B`;
592
+ const parts = [status, format, bytes, truncated].filter(
593
+ (part): part is string => typeof part === "string" && part.length > 0,
594
+ );
595
+ return parts.length > 0 ? parts.join(" · ") : null;
596
+ }
597
+
598
+ /**
599
+ * A call the permission gate blocked never executed, so the collapsed row must
600
+ * not claim it did. `ran \`id\` · 667B ✗ blocked` read as a command that ran and
601
+ * produced 667 bytes, while the expanded header for the same node correctly said
602
+ * `bash(id) ✗ blocked`. Blocked rows use that same call-signature form, and the
603
+ * ledger byte count is suppressed because those bytes are the denial text, not
604
+ * output.
605
+ */
606
+ function isNonExecutedOutcome(outcome: ToolExecutionFinished["outcome"]): boolean {
607
+ return outcome === "blocked";
608
+ }
609
+
610
+ function buildSublineBody(
611
+ toolName: string,
612
+ args: unknown,
613
+ status: HeaderStatus,
614
+ result?: unknown,
615
+ outcome?: ToolExecutionFinished["outcome"],
616
+ ): string {
617
+ if (isNonExecutedOutcome(outcome)) return buildUnknownToolBody(toolName, args);
618
+ if (toolName === "web_fetch") {
619
+ const meta = status === undefined ? null : webFetchMeta(result);
620
+ return `${buildUnknownToolBody(toolName, args)}${meta ? dim(` · ${meta}`) : ""}`;
621
+ }
622
+ if (toolName === "bash") {
623
+ const lead = status === undefined ? "running " : "ran ";
624
+ return (
625
+ buildFieldSublineBody(args, "command", lead, { wrapInBackticks: true }) ?? buildUnknownToolBody(toolName, args)
626
+ );
627
+ }
628
+ const body = SUBLINE_BODY_BUILDERS[toolName]?.(args);
629
+ if (body !== null && body !== undefined) return body;
630
+ return buildUnknownToolBody(toolName, args);
631
+ }
632
+
633
+ interface SublineParts {
634
+ /** Verb, object, and ledger facts. Breakable across wraps. */
635
+ lead: string;
636
+ /**
637
+ * Status glyph, duration, and any offload path, composed as one unit. The
638
+ * caller appends the expand hint here so the whole tail stays atomic: a wrap
639
+ * may fall before the status glyph but never between the glyph, the
640
+ * duration, and the hint. Begins with a joining space so it attaches to the
641
+ * lead's last line when they share a row. Empty for in-flight calls, which
642
+ * carry no status glyph.
643
+ */
644
+ tail: string;
645
+ }
646
+
647
+ function sublineParts(
648
+ call: ToolExecutionStart | ToolExecutionFinished,
649
+ status: HeaderStatus,
650
+ meta: StatusMeta,
651
+ ): SublineParts {
652
+ const finished = "result" in call ? call : null;
653
+ const body = styleSublineBody(buildSublineBody(call.toolName, call.args, status, finished?.result, finished?.outcome));
654
+ const resourceLabel = classifyResourceRead(call.toolName, call.args);
655
+ const resource = resourceLabel !== null ? dim(` · ${resourceLabel}`) : "";
656
+ if (finished !== null) {
657
+ const ledger = ledgerTail(finished);
658
+ return {
659
+ lead: `${dim(HEADER_PREFIX_PLAIN)}${body}${resource}${ledger.facts}`,
660
+ tail: `${statusGlyph(status, meta)}${ledger.offload}`,
661
+ };
662
+ }
663
+ const elapsed = optionalCompactMs("elapsedMs" in call ? call.elapsedMs : undefined);
664
+ const running = elapsed !== null ? dim(` · ${elapsed}`) : "";
665
+ return { lead: `${dim(HEADER_PREFIX_PLAIN)}${body}${resource}${running}`, tail: "" };
666
+ }
667
+
668
+ /**
669
+ * Wrap a collapsed subline while keeping its status tail atomic. The lead wraps
670
+ * normally; the tail (status glyph, duration, offload, and the optional expand
671
+ * hint) is placed as a single unit. When the whole line fits it renders on one
672
+ * row; otherwise the tail joins the lead's last wrapped line if it fits there,
673
+ * and only falls to its own row when it cannot, so the status glyph and
674
+ * duration are never separated by a wrap.
675
+ */
676
+ function wrapSublineWithTail(lead: string, tail: string, width: number): string[] {
677
+ if (tail.length === 0) return wrap(lead, width);
678
+ if (visibleWidth(`${lead}${tail}`) <= width) return [`${lead}${tail}`];
679
+ const leadLines = wrap(lead, width);
680
+ const last = leadLines[leadLines.length - 1];
681
+ if (last !== undefined && visibleWidth(`${last}${tail}`) <= width) {
682
+ leadLines[leadLines.length - 1] = `${last}${tail}`;
683
+ return leadLines;
684
+ }
685
+ // The tail cannot sit beside the lead: give it its own row, dropping the
686
+ // joining leading space so it starts flush at the left.
687
+ return [...leadLines, ...wrap(tail.replace(/^ +/u, ""), width)];
688
+ }
689
+
690
+ function wrap(line: string, width: number): string[] {
691
+ return wrapTextWithAnsi(line, width);
692
+ }
693
+
694
+ /**
695
+ * Apply the body rail to a line and wrap it. The rail (`│ `) is dim by
696
+ * default and red on error so the tool block reads as a single visual unit
697
+ * even when its result spans many lines. Uses the hoisted `RAIL_DIM` /
698
+ * `RAIL_ERROR` constants so we do not allocate a fresh styled prefix per
699
+ * wrapped line.
700
+ */
701
+ function indentAndWrap(line: string, width: number, isError: boolean): string[] {
702
+ const rail = isError ? RAIL_ERROR : RAIL_DIM;
703
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
704
+ const out: string[] = [];
705
+ for (const wrapped of wrap(line, bodyWidth)) {
706
+ out.push(`${rail}${wrapped}`);
707
+ }
708
+ return out;
709
+ }
710
+
711
+ /**
712
+ * Render the pretty-printed JSON args body. Splits on `\n` first and then
713
+ * applies a line cap so the cut never lands inside an open string or before
714
+ * a closing brace; the previous codepoint-level `truncate` could leave a
715
+ * malformed JSON snippet that broke copy-paste. Mirrors the line-cap strategy
716
+ * `renderResultBlock` already uses for tool output.
717
+ */
718
+ function renderArgsBody(args: unknown, width: number, isError: boolean): string[] {
719
+ if (isEmptyArgs(args)) return [];
720
+ const out: string[] = [];
721
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
722
+ const lines = tryRenderJson(redactToolArgs(args), bodyWidth, { lineLimit: ARGS_BODY_LINE_LIMIT });
723
+ if (!lines) return [];
724
+ for (const raw of lines) {
725
+ out.push(...indentAndWrap(raw, width, isError));
726
+ }
727
+ return out;
728
+ }
729
+
730
+ /**
731
+ * pi-agent-core wraps tool results in `{ content: [{ type: "text", text }, ...] }`
732
+ * envelopes. Rendering that JSON verbatim hides the actual tool output behind
733
+ * a sea of escaped quotes. When the envelope shape matches, concatenate the
734
+ * text segments and treat the join as the real result; otherwise return the
735
+ * value untouched so callers stringify it normally.
736
+ */
737
+ export function unwrapResultEnvelope(result: unknown): unknown {
738
+ if (typeof result === "string" || result === null || result === undefined) return result;
739
+ const blocks = Array.isArray(result)
740
+ ? result
741
+ : isPlainObject(result) && Array.isArray(result.content)
742
+ ? result.content
743
+ : null;
744
+ if (blocks === null) return result;
745
+ const parts: string[] = [];
746
+ for (const block of blocks) {
747
+ if (!isPlainObject(block)) return result;
748
+ if (block.type !== "text" || typeof block.text !== "string") return result;
749
+ parts.push(block.text);
750
+ }
751
+ if (parts.length === 0) return result;
752
+ return parts.join("");
753
+ }
754
+
755
+ export function previewResult(result: unknown): string {
756
+ if (typeof result === "string") return truncate(result, RESULT_PREVIEW_LIMIT);
757
+ return truncate(jsonStringifySafe(result), RESULT_PREVIEW_LIMIT);
758
+ }
759
+
760
+ function isEmptyResult(result: unknown): boolean {
761
+ if (result === null || result === undefined) return true;
762
+ if (typeof result === "string" && result.length === 0) return true;
763
+ return false;
764
+ }
765
+
766
+ function resultText(result: unknown, limit = FULL_RESULT_PREVIEW_LIMIT): string {
767
+ if (typeof result === "string") return truncate(result, limit);
768
+ return truncate(jsonStringifySafe(result), limit);
769
+ }
770
+
771
+ function truncateRowsMiddle(rows: ReadonlyArray<string>, rowLimit: number, isError: boolean): string[] {
772
+ if (rows.length <= rowLimit) return [...rows];
773
+ if (rowLimit <= 1) return [`${isError ? RAIL_ERROR : RAIL_DIM}${dim(`... ${rows.length} lines hidden`)}`];
774
+ const available = rowLimit - 1;
775
+ const head = Math.floor(available / 2);
776
+ const tail = available - head;
777
+ const hidden = Math.max(0, rows.length - head - tail);
778
+ return [
779
+ ...rows.slice(0, head),
780
+ `${isError ? RAIL_ERROR : RAIL_DIM}${dim(`... ${hidden} lines hidden`)}`,
781
+ ...rows.slice(-tail),
782
+ ];
783
+ }
784
+
785
+ function renderOutputRows(text: string, width: number, isError: boolean, rowLimit: number): string[] {
786
+ const rows: string[] = [];
787
+ for (const raw of text.split("\n")) {
788
+ rows.push(...indentAndWrap(raw, width, isError));
789
+ }
790
+ return truncateRowsMiddle(rows, rowLimit, isError);
791
+ }
792
+
793
+ function renderStructuredOutputRows(
794
+ value: unknown,
795
+ width: number,
796
+ isError: boolean,
797
+ rowLimit: number,
798
+ ): string[] | null {
799
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
800
+ const unwrapped = unwrapResultEnvelope(value);
801
+ const structured =
802
+ typeof unwrapped === "string"
803
+ ? (tryRenderJson(unwrapped, bodyWidth, { lineLimit: rowLimit }) ??
804
+ tryRenderXml(unwrapped, bodyWidth, { lineLimit: rowLimit }))
805
+ : tryRenderJson(unwrapped, bodyWidth, { lineLimit: rowLimit });
806
+ if (!structured) return null;
807
+ const out: string[] = [];
808
+ for (const row of structured) out.push(...indentAndWrap(row, width, isError));
809
+ return out;
810
+ }
811
+
812
+ function highlightBashCommand(command: string): string {
813
+ const tokens = command.match(/'[^']*'|"[^"]*"|\|\||&&|[|;()<>]|[^\s|;&()<>]+|\s+/gu) ?? [command];
814
+ return tokens
815
+ .map((token) => {
816
+ if (/^\s+$/u.test(token)) return token;
817
+ if (/^'[^']*'$|^"[^"]*"$/u.test(token)) return green(token);
818
+ if (/^(?:\|\||&&|[|;()<>])$/u.test(token)) return dim(token);
819
+ if (/^-{1,2}[\w-]+/u.test(token)) return yellow(token);
820
+ return token;
821
+ })
822
+ .join("");
823
+ }
824
+
825
+ interface EditDiffArgs {
826
+ path?: string;
827
+ old_string: string;
828
+ new_string: string;
829
+ }
830
+
831
+ /**
832
+ * Defensive shape check: edit-tool args must carry both `old_string` and
833
+ * `new_string` strings before we can render a diff. `path` is optional; the
834
+ * diff renderer falls back to `"file"` when absent. Anything else falls
835
+ * through to the standard result block so the dispatch is opportunistic and
836
+ * never throws.
837
+ */
838
+ function asEditDiffArgs(args: unknown): EditDiffArgs | null {
839
+ if (!isPlainObject(args)) return null;
840
+ const oldString = args.old_string;
841
+ const newString = args.new_string;
842
+ if (typeof oldString !== "string" || typeof newString !== "string") return null;
843
+ const out: EditDiffArgs = { old_string: oldString, new_string: newString };
844
+ if (typeof args.path === "string") out.path = args.path;
845
+ return out;
846
+ }
847
+
848
+ // The `diff` library appends a `` sentinel row when a
849
+ // side of the comparison lacks a trailing newline. It is transcript noise, so
850
+ // the edit diff block drops it. The marker text carries no ANSI, so a substring
851
+ // check against the styled row is reliable and keeps this module free of raw
852
+ // escape literals.
853
+ const NO_NEWLINE_MARKER = "\";
854
+
855
+ function isNoNewlineMarkerRow(row: string): boolean {
856
+ return row.includes(NO_NEWLINE_MARKER);
857
+ }
858
+
859
+ function renderEditDiffBlock(args: EditDiffArgs, width: number): string[] {
860
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
861
+ const input: DiffRenderInput = { oldText: args.old_string, newText: args.new_string };
862
+ if (args.path !== undefined) input.filename = args.path;
863
+ const out: string[] = [];
864
+ for (const line of renderUnifiedDiff(input, bodyWidth)) {
865
+ if (isNoNewlineMarkerRow(line)) continue;
866
+ out.push(`${RAIL_DIM}${line}`);
867
+ }
868
+ return out;
869
+ }
870
+
871
+ interface BashArgs {
872
+ command: string;
873
+ }
874
+
875
+ /**
876
+ * Defensive shape check: bash-tool args must carry a string `command` for the
877
+ * `$ <cmd>` echo line to render. Anything else falls through to the standard
878
+ * result block so the dispatch is opportunistic and never throws.
879
+ */
880
+ function asBashArgs(args: unknown): BashArgs | null {
881
+ if (!isPlainObject(args)) return null;
882
+ const command = args.command;
883
+ if (typeof command !== "string") return null;
884
+ return { command: redactSecretString(command) };
885
+ }
886
+
887
+ /**
888
+ * Bash subrenderer: emits `$ <cmd>` (full command) on its own line under the
889
+ * rail, then the unwrapped output via the same chain as `renderResultBlock`.
890
+ * Mirrors pi-coding-agent's bash component shape so users see exactly what
891
+ * was executed before the output. Failures use the same command and output
892
+ * body while the caller selects the red rail and error status.
893
+ */
894
+ function renderBashResultBlock(
895
+ args: BashArgs,
896
+ result: unknown,
897
+ width: number,
898
+ isError: boolean,
899
+ opts: ToolBodyRenderOptions = {},
900
+ ): string[] {
901
+ const out: string[] = [];
902
+ const commandLine = `${cyanBold("$")} ${highlightBashCommand(stripShellWrapperForDisplay(args.command))}`;
903
+ out.push(...indentAndWrap(commandLine, width, isError));
904
+ const unwrapped = unwrapResultEnvelope(result);
905
+ if (isEmptyResult(unwrapped)) {
906
+ out.push(...indentAndWrap(dim("(no output)"), width, isError));
907
+ return out;
908
+ }
909
+ out.push(...renderOutputRows(resultText(unwrapped, resultCharLimit(opts)), width, isError, resultRowLimit(opts)));
910
+ return out;
911
+ }
912
+
913
+ function renderResultBlock(
914
+ result: unknown,
915
+ isError: boolean,
916
+ width: number,
917
+ opts: ToolBodyRenderOptions = {},
918
+ ): string[] {
919
+ const unwrapped = unwrapResultEnvelope(result);
920
+ if (isEmptyResult(unwrapped)) {
921
+ return indentAndWrap(dim("(no output)"), width, isError);
922
+ }
923
+ const structured = renderStructuredOutputRows(unwrapped, width, isError, resultRowLimit(opts));
924
+ if (structured) return structured;
925
+ return renderOutputRows(resultText(unwrapped, resultCharLimit(opts)), width, isError, resultRowLimit(opts));
926
+ }
927
+
928
+ /**
929
+ * Header-only render for a tool call that has not yet finished. Used by the
930
+ * live chat panel between `tool_execution_start` and `tool_execution_end`.
931
+ * No status glyph: the absence of the glyph signals "still running".
932
+ */
933
+ export function renderToolCallHeader(call: ToolExecutionStart, width: number): string[] {
934
+ return wrap(headerLine(call.toolName, call.args, undefined), width);
935
+ }
936
+
937
+ /** Running-only footer used when an operator pauses live output; execution continues. */
938
+ export function renderToolRunningStatus(call: ToolExecutionStart, width: number): string[] {
939
+ const elapsed = optionalCompactMs(call.elapsedMs);
940
+ return [
941
+ ...renderToolCallHeader(call, width),
942
+ ...indentAndWrap(
943
+ dim(elapsed ? `(running... ${elapsed}; live output hidden)` : "(running; live output hidden)"),
944
+ width,
945
+ false,
946
+ ),
947
+ ];
948
+ }
949
+
950
+ function sublineStatus(call: ToolExecutionStart | ToolExecutionFinished): HeaderStatus {
951
+ // Discriminate on `result` rather than `isError`: only `ToolExecutionFinished`
952
+ // carries a `result` field, so a `ToolExecutionStart` with a stray
953
+ // `isError: false` (e.g. from a future event-shape change) cannot trip the
954
+ // finished path. `result` is the type's load-bearing field.
955
+ if (!("result" in call)) return undefined;
956
+ return call.isError ? "error" : "ok";
957
+ }
958
+
959
+ /**
960
+ * One-line subline form of a tool call. Format:
961
+ * ▸ <body><status>
962
+ * `status` is "" for in-flight, " ✓" green for success, " ✗" red for error.
963
+ * Output is width-wrapped via wrapTextWithAnsi.
964
+ *
965
+ * When `expandKey` is supplied AND the call has finished, a dim ` (<key>)`
966
+ * discoverability hint rides at the very end of the atomic status tail so users
967
+ * see how to expand the collapsed block. Composing the full line (facts, status
968
+ * glyph, duration, offload, and hint) before wrapping keeps the status glyph
969
+ * and duration together on one row. The hint is suppressed for in-flight calls
970
+ * (still running, no useful body to expand yet) and when `expandKey` is
971
+ * empty/undefined (no key bound, hint would be misleading). The renderer never
972
+ * imports the keybindings manager directly; the caller resolves the key string
973
+ * and passes it in to keep this module pure.
974
+ */
975
+ export function renderToolSubline(
976
+ call: ToolExecutionStart | ToolExecutionFinished,
977
+ width: number,
978
+ expandKey?: string,
979
+ ): string[] {
980
+ const status = sublineStatus(call);
981
+ const meta: StatusMeta =
982
+ "result" in call
983
+ ? {
984
+ durationMs: call.durationMs,
985
+ exitCode: call.toolName === "bash" && call.isError ? bashExitCodeFromResult(call.result) : null,
986
+ outcome: call.outcome,
987
+ blockReason: call.blockReason,
988
+ }
989
+ : {};
990
+ const parts = sublineParts(call, status, meta);
991
+ const showHint = status !== undefined && expandKey !== undefined && expandKey.length > 0;
992
+ const tail = showHint ? `${parts.tail}${dim(` (${expandKey})`)}` : parts.tail;
993
+ return wrapSublineWithTail(parts.lead, tail, width);
994
+ }
995
+
996
+ /**
997
+ * Full render: header + args body (if non-empty) + result block. Used by
998
+ * the live chat panel on `tool_execution_end` and by the replay path when a
999
+ * tool result can be paired with its prior call's args. Header carries a
1000
+ * green check on success and a red cross on error so the user can scan tool
1001
+ * outcomes without reading the body.
1002
+ */
1003
+ export function renderToolExecution(
1004
+ finished: ToolExecutionFinished,
1005
+ width: number,
1006
+ opts: ToolBodyRenderOptions = {},
1007
+ ): string[] {
1008
+ const status: HeaderStatus = finished.isError ? "error" : "ok";
1009
+ const statusMeta: StatusMeta = {
1010
+ durationMs: finished.durationMs,
1011
+ exitCode: finished.toolName === "bash" && finished.isError ? bashExitCodeFromResult(finished.result) : null,
1012
+ outcome: finished.outcome,
1013
+ blockReason: finished.blockReason,
1014
+ };
1015
+ const out: string[] = [];
1016
+ out.push(...wrap(headerLine(finished.toolName, finished.args, status, statusMeta), width));
1017
+
1018
+ // Edit-tool dispatch: when the tool succeeded and `args` carries the
1019
+ // expected `{ old_string, new_string }` strings, swap the args body and
1020
+ // result block for a unified diff. The header still renders so the user
1021
+ // sees `▸ edit(<path>)`, and the args body is suppressed because echoing
1022
+ // both strings would just duplicate what the diff already shows.
1023
+ if (finished.toolName === "edit" && finished.isError === false) {
1024
+ const editArgs = asEditDiffArgs(redactToolArgs(finished.args));
1025
+ if (editArgs !== null) {
1026
+ out.push(...renderEditDiffBlock(editArgs, width));
1027
+ return out;
1028
+ }
1029
+ }
1030
+
1031
+ // Bash-tool dispatch: when `args.command` is a string, prefix the result
1032
+ // body with `$ <cmd>` on its own line so the user sees the display command
1033
+ // above its output. Failures use the red rail and expose the parsed exit
1034
+ // code in the header when the result includes one.
1035
+ if (finished.toolName === "bash") {
1036
+ const bashArgs = asBashArgs(redactToolArgs(finished.args));
1037
+ if (bashArgs !== null) {
1038
+ out.push(...renderBashResultBlock(bashArgs, finished.result, width, finished.isError, opts));
1039
+ return out;
1040
+ }
1041
+ }
1042
+
1043
+ // Suppress the args body when the header already encodes the salient arg
1044
+ // (e.g. `▸ read(README.md)` already shows the path; rendering
1045
+ // `{"path": "README.md"}` underneath is duplicate noise). For tools without
1046
+ // a known primary arg the body still renders so users see what the model
1047
+ // actually invoked.
1048
+ if (capturedPrimaryArg(finished.toolName, finished.args) === null) {
1049
+ out.push(...renderArgsBody(finished.args, width, finished.isError));
1050
+ }
1051
+ out.push(...renderResultBlock(finished.result, finished.isError, width, opts));
1052
+ return out;
1053
+ }
1054
+
1055
+ /**
1056
+ * Result-only render for replayed tool results that arrived without a
1057
+ * matching prior tool-call entry (orphan results in the session log).
1058
+ * Identical to `renderToolExecution` minus the args body.
1059
+ */
1060
+ export function renderToolResultOnly(
1061
+ finished: Omit<ToolExecutionFinished, "args">,
1062
+ width: number,
1063
+ opts: ToolBodyRenderOptions = {},
1064
+ ): string[] {
1065
+ const status: HeaderStatus = finished.isError ? "error" : "ok";
1066
+ const statusMeta: StatusMeta = {
1067
+ durationMs: finished.durationMs,
1068
+ exitCode: finished.toolName === "bash" && finished.isError ? bashExitCodeFromResult(finished.result) : null,
1069
+ outcome: finished.outcome,
1070
+ blockReason: finished.blockReason,
1071
+ };
1072
+ const out: string[] = [];
1073
+ out.push(...wrap(headerLine(finished.toolName, undefined, status, statusMeta), width));
1074
+ out.push(...renderResultBlock(finished.result, finished.isError, width, opts));
1075
+ return out;
1076
+ }
1077
+
1078
+ /**
1079
+ * Streaming render for an in-flight tool call whose expanded block should
1080
+ * surface the latest partial output. Used by the chat panel between
1081
+ * `tool_execution_start` and `tool_execution_end` when the user has expanded
1082
+ * the tool segment. The header carries no status glyph (still running), the
1083
+ * args body is suppressed when the header captures the primary arg, the
1084
+ * partial output renders under the rail capped at `RESULT_LINE_LIMIT` lines,
1085
+ * and a dim `(running...)` marker on the trailing line communicates that the
1086
+ * block is still being written. An empty `partialOutput` renders
1087
+ * `(no output yet)` so the user can distinguish a slow start from a stalled
1088
+ * call.
1089
+ */
1090
+ export function renderToolStreamingExecution(call: ToolExecutionStart, width: number, partialOutput: string): string[] {
1091
+ const out: string[] = [];
1092
+ out.push(...wrap(headerLine(call.toolName, call.args, undefined), width));
1093
+ if (capturedPrimaryArg(call.toolName, call.args) === null) {
1094
+ out.push(...renderArgsBody(call.args, width, false));
1095
+ }
1096
+ if (partialOutput.length === 0) {
1097
+ out.push(...indentAndWrap(dim("(no output yet)"), width, false));
1098
+ } else {
1099
+ out.push(...renderOutputRows(partialOutput, width, false, STREAMING_RESULT_ROW_LIMIT));
1100
+ }
1101
+ const elapsed = optionalCompactMs(call.elapsedMs);
1102
+ out.push(...indentAndWrap(dim(elapsed !== null ? `(running... ${elapsed})` : "(running...)"), width, false));
1103
+ return out;
1104
+ }