@iowarp/clio-coder 0.3.0 → 0.3.2

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 (1187) hide show
  1. package/CHANGELOG.md +123 -2
  2. package/CONTRIBUTING.md +23 -23
  3. package/README.md +295 -627
  4. package/dist/acp-BIYHVZIM.js +128 -0
  5. package/dist/{agents-Q4MYPMUW.js → agents-YT6SSRIT.js} +52 -27
  6. package/dist/assets/codewiki.json +1 -0
  7. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/LICENSE +21 -0
  8. package/dist/assets/grammars/notices/@vscode__tree-sitter-wasm/cgmanifest.json +16 -0
  9. package/dist/assets/grammars/notices/tree-sitter-wasms/LICENSE +24 -0
  10. package/dist/assets/grammars/tree-sitter-c-sharp.wasm +0 -0
  11. package/dist/assets/grammars/tree-sitter-c.wasm +0 -0
  12. package/dist/assets/grammars/tree-sitter-cpp.wasm +0 -0
  13. package/dist/assets/grammars/tree-sitter-go.wasm +0 -0
  14. package/dist/assets/grammars/tree-sitter-java.wasm +0 -0
  15. package/dist/assets/grammars/tree-sitter-javascript.wasm +0 -0
  16. package/dist/assets/grammars/tree-sitter-python.wasm +0 -0
  17. package/dist/assets/grammars/tree-sitter-ruby.wasm +0 -0
  18. package/dist/assets/grammars/tree-sitter-rust.wasm +0 -0
  19. package/dist/assets/grammars/tree-sitter-tsx.wasm +0 -0
  20. package/dist/assets/grammars/tree-sitter-typescript.wasm +0 -0
  21. package/dist/assets/grammars/tree-sitter.wasm +0 -0
  22. package/dist/{auth-O6HYIJ6J.js → auth-5TWEIYDN.js} +30 -15
  23. package/dist/chunk-2EHAIA3X.js +481 -0
  24. package/dist/{chunk-ME6DNWIU.js → chunk-2IR2NMPA.js} +12 -4
  25. package/dist/chunk-2SFS6XQE.js +122 -0
  26. package/dist/{chunk-KKKPTZLM.js → chunk-2STGEDFV.js} +8 -1
  27. package/dist/chunk-2VTFPG5O.js +48 -0
  28. package/dist/chunk-3I7MS7N2.js +40 -0
  29. package/dist/chunk-3R73A4XB.js +69 -0
  30. package/dist/{chunk-JPOWPFCU.js → chunk-3ZXDFGR5.js} +52 -23
  31. package/dist/chunk-4BJ5BYCE.js +61 -0
  32. package/dist/{chunk-26BZQOAD.js → chunk-4BPJXDWC.js} +161 -260
  33. package/dist/chunk-4KLWL3UC.js +18 -0
  34. package/dist/{chunk-5LDRNKX2.js → chunk-4VP4KH3K.js} +161 -262
  35. package/dist/chunk-4ZG3XFUR.js +77 -0
  36. package/dist/chunk-5B2AEOW5.js +5407 -0
  37. package/dist/chunk-5TSRNF4G.js +510 -0
  38. package/dist/{chunk-WD6AJM35.js → chunk-5UUP6MWO.js} +48 -69
  39. package/dist/{chunk-X3BR7HWV.js → chunk-5WIGXA4T.js} +7 -1
  40. package/dist/chunk-65DEGPJ6.js +52 -0
  41. package/dist/chunk-6EJMN2Y3.js +17 -0
  42. package/dist/chunk-6EJV5X2W.js +16405 -0
  43. package/dist/chunk-6N5PTWMY.js +136 -0
  44. package/dist/chunk-6XLNIQDB.js +27 -0
  45. package/dist/{chunk-XNISANGE.js → chunk-77VKQEHF.js} +171 -74
  46. package/dist/chunk-7CR24IG7.js +242 -0
  47. package/dist/{chunk-UWIJNAOB.js → chunk-7EYHLWU7.js} +907 -638
  48. package/dist/chunk-7MNJORFF.js +22 -0
  49. package/dist/{chunk-JWHCJDCI.js → chunk-A3CYT5EX.js} +257 -79
  50. package/dist/chunk-AGYYIBLL.js +1069 -0
  51. package/dist/chunk-AO4RKG4M.js +277 -0
  52. package/dist/chunk-APJ265NV.js +7410 -0
  53. package/dist/chunk-ARBGF5F7.js +174 -0
  54. package/dist/{chunk-TFSSEXL6.js → chunk-BMEMKKIT.js} +14 -4
  55. package/dist/{chunk-X3NE4WVW.js → chunk-BNAZZHFG.js} +7 -1
  56. package/dist/chunk-CBCAPZAA.js +229 -0
  57. package/dist/{chunk-QV47YRF4.js → chunk-CGKSTWHD.js} +7 -1
  58. package/dist/chunk-CMZWFGD2.js +352 -0
  59. package/dist/chunk-ECH6PKUQ.js +39 -0
  60. package/dist/{chunk-67MTHP2E.js → chunk-ED4KHGC3.js} +13 -5
  61. package/dist/chunk-EKMEHE4H.js +340 -0
  62. package/dist/{chunk-O4EJEDHO.js → chunk-EPVUXGXG.js} +50 -35
  63. package/dist/chunk-FCSXB6T2.js +338 -0
  64. package/dist/chunk-FJ3H4MN5.js +48 -0
  65. package/dist/chunk-FQ4SKYE4.js +29 -0
  66. package/dist/chunk-G2DE3C7R.js +644 -0
  67. package/dist/chunk-G4BMMOKF.js +182 -0
  68. package/dist/{chunk-7BHLZB3A.js → chunk-GGXXDWE4.js} +190 -1218
  69. package/dist/chunk-HC4CLZ2Y.js +68 -0
  70. package/dist/{chunk-E3NYWENM.js → chunk-HFSBBKSQ.js} +55 -61
  71. package/dist/chunk-HKIYEGME.js +30 -0
  72. package/dist/chunk-I4HZDVNP.js +73 -0
  73. package/dist/chunk-IGLFWIYI.js +161 -0
  74. package/dist/chunk-IHXBNWMM.js +137 -0
  75. package/dist/chunk-IKCO5N3L.js +162 -0
  76. package/dist/chunk-IR4CFBFN.js +56 -0
  77. package/dist/{chunk-DXQNI4PC.js → chunk-IWHMRKLL.js} +8 -1
  78. package/dist/{chunk-VOO7NYPP.js → chunk-J5HN4RYU.js} +27 -9
  79. package/dist/{chunk-4UQA7NCT.js → chunk-J5Q24KAG.js} +7 -2
  80. package/dist/{chunk-KBR4MZZR.js → chunk-JVCV3ICN.js} +7 -1
  81. package/dist/chunk-KJ5LWLOE.js +1077 -0
  82. package/dist/chunk-LBMZMYH2.js +285 -0
  83. package/dist/{chunk-3DANZDGR.js → chunk-LBNRH5WM.js} +100 -161
  84. package/dist/{chunk-TKHQ4DGZ.js → chunk-LZSJBIVT.js} +7358 -7414
  85. package/dist/{chunk-UGYAX5YI.js → chunk-M6SHUN7Q.js} +13 -8
  86. package/dist/chunk-MAW544W2.js +1882 -0
  87. package/dist/chunk-MBS4V7ZP.js +217 -0
  88. package/dist/{chunk-2J63S4SF.js → chunk-MFFY33HR.js} +167 -140
  89. package/dist/chunk-MNA4JGU4.js +255 -0
  90. package/dist/chunk-MQSRRFWA.js +3428 -0
  91. package/dist/{chunk-RQDWMVRB.js → chunk-MVVUPGPW.js} +138 -137
  92. package/dist/chunk-OAO4GE4M.js +619 -0
  93. package/dist/chunk-OHHN2SO4.js +5135 -0
  94. package/dist/chunk-OKGUZO2U.js +34 -0
  95. package/dist/{chunk-BBUH4VAA.js → chunk-OOJYHWRB.js} +60 -361
  96. package/dist/{chunk-D5YD55AR.js → chunk-OQ33BKR3.js} +12 -1
  97. package/dist/chunk-OQE5J4C6.js +73 -0
  98. package/dist/{chunk-AMFR5YA3.js → chunk-ORBHGJC5.js} +26 -12
  99. package/dist/chunk-POHLU5DW.js +1186 -0
  100. package/dist/chunk-QKMUKYO7.js +4961 -0
  101. package/dist/{chunk-7RBKDI66.js → chunk-QTYWRVRA.js} +104 -12
  102. package/dist/{chunk-5N2FG33Q.js → chunk-R346GLFC.js} +7 -1
  103. package/dist/chunk-SRF2PJNW.js +184 -0
  104. package/dist/chunk-SST6Z5JA.js +80 -0
  105. package/dist/{chunk-XV4ZJ6ZM.js → chunk-STBPMHSX.js} +473 -1194
  106. package/dist/{chunk-HBU5MTAM.js → chunk-SVNXH4L2.js} +7 -1
  107. package/dist/chunk-T6YILFSB.js +80 -0
  108. package/dist/chunk-TXOTCRLG.js +15 -0
  109. package/dist/chunk-TZTZS7QK.js +227 -0
  110. package/dist/chunk-UOV2BYIW.js +107 -0
  111. package/dist/{chunk-527KG6XR.js → chunk-V4RXGQ5Q.js} +72 -185
  112. package/dist/chunk-VAKQQHWR.js +434 -0
  113. package/dist/chunk-VG7TBQIY.js +128 -0
  114. package/dist/chunk-VJWL6YS5.js +244 -0
  115. package/dist/chunk-WEH5XRJQ.js +32 -0
  116. package/dist/{chunk-VPAWTYLY.js → chunk-WEPFGWHJ.js} +7 -1
  117. package/dist/chunk-WMSVI4G2.js +2095 -0
  118. package/dist/chunk-WVO7V2QY.js +797 -0
  119. package/dist/chunk-X4RCMKVQ.js +641 -0
  120. package/dist/chunk-X75S7HFS.js +374 -0
  121. package/dist/chunk-XN3L4EYL.js +46 -0
  122. package/dist/{chunk-HMYNFFY4.js → chunk-XPLRXC72.js} +7 -2
  123. package/dist/{chunk-PIDUD6M2.js → chunk-YCWGATWI.js} +12 -5
  124. package/dist/chunk-YHZX5GEU.js +193 -0
  125. package/dist/chunk-YXLYO42X.js +91 -0
  126. package/dist/{chunk-UHTSULZS.js → chunk-ZDOOVTXZ.js} +38 -73
  127. package/dist/chunk-ZI647VB5.js +37 -0
  128. package/dist/{chunk-CLJ5HLUD.js → chunk-ZWLZP4ZT.js} +25 -6
  129. package/dist/cli/index.js +70 -56
  130. package/dist/clio-4LY5K2AC.js +25 -0
  131. package/dist/code-nav-7AX6FYE6.js +600 -0
  132. package/dist/codewiki/build-worker.js +66 -0
  133. package/dist/compile-cache-CVJMMODC.js +18 -0
  134. package/dist/{components-JVHMUBEB.js → components-KELWS457.js} +31 -9
  135. package/dist/{config-ZFCDBMDC.js → config-GTLUW2PR.js} +104 -56
  136. package/dist/configure-R6A64DHX.js +42 -0
  137. package/dist/context-5VKGUVJJ.js +866 -0
  138. package/dist/{context-CDXTP2MP.js → context-JFZEJ7W5.js} +21 -13
  139. package/dist/{context-E3KIFVXI.js → context-RW5HC47S.js} +77 -36
  140. package/dist/{context-clear-3F4PLXOS.js → context-clear-6ZHBAZZT.js} +64 -30
  141. package/dist/{context-index-Q7YSYTR3.js → context-index-BZ4UYMTC.js} +36 -24
  142. package/dist/dispatch-runner-VKBRCWQC.js +1997 -0
  143. package/dist/{docs-YIETIWZI.js → docs-2C2LTVT2.js} +32 -13
  144. package/dist/doctor-KI767GSN.js +87 -0
  145. package/dist/{eval-B3KZZESM.js → eval-XSSNATB4.js} +93 -27
  146. package/dist/{evidence-V67CHM35.js → evidence-UA6AWDQQ.js} +55 -27
  147. package/dist/{evolve-YDZSUQYA.js → evolve-QNTFGV6Z.js} +59 -26
  148. package/dist/{extensions-SRG7XCAH.js → extensions-QVDOHDGJ.js} +23 -8
  149. package/dist/{fleet-CA2CRTVG.js → fleet-Q7UOMUSG.js} +173 -56
  150. package/dist/fleet-preflight-DDN536IT.js +26 -0
  151. package/dist/{init-2OZDJE2D.js → init-WBB65ZHQ.js} +79 -34
  152. package/dist/{memory-3PIQQAKX.js → memory-MD3O64RI.js} +57 -28
  153. package/dist/{models-DY35XI7Y.js → models-BZU34YWD.js} +49 -24
  154. package/dist/monitor-MEQA5C3I.js +661 -0
  155. package/dist/{chunk-PS4PFJQP.js → orchestrator-CGFKEP27.js} +22837 -18564
  156. package/dist/{paths-5OMXW7Z4.js → paths-UXLN5YYZ.js} +17 -6
  157. package/dist/preload-P6DGH2PZ.js +13 -0
  158. package/dist/{reset-PIFYNOS3.js → reset-L2FQEE3E.js} +25 -13
  159. package/dist/{run-3VSPP24F.js → run-IV4Q6RLN.js} +115 -63
  160. package/dist/{share-D36RQCXM.js → share-S5BZQC5I.js} +23 -10
  161. package/dist/{skills-F2MRLELY.js → skills-LQEKRDTN.js} +42 -15
  162. package/dist/{skills-eval-E2ZTW4PL.js → skills-eval-3DC4HEWS.js} +90 -45
  163. package/dist/steer-GGWFUJUD.js +77 -0
  164. package/dist/{targets-DZMEZAH4.js → targets-C4SSGQOB.js} +78 -60
  165. package/dist/terminal-lease-IT5JW2NR.js +395 -0
  166. package/dist/{trace-7NYCUI2J.js → trace-PNCASAXC.js} +48 -17
  167. package/dist/tree-sitter-HGKH6LG4.js +4673 -0
  168. package/dist/{uninstall-AD3JWHBB.js → uninstall-FZCQCDKC.js} +19 -8
  169. package/dist/{upgrade-WYYBKGDY.js → upgrade-7TT7SQ3G.js} +66 -24
  170. package/dist/{usage-ULIDAGFF.js → usage-GV4PKT3M.js} +71 -32
  171. package/dist/verify-G6V4D2G7.js +716 -0
  172. package/dist/version-KGEG7EPO.js +21 -0
  173. package/dist/web-fetch-2YHJ3KTG.js +638 -0
  174. package/dist/{wiki-generate-PKFIX6OB.js → wiki-generate-DQF6Z66B.js} +98 -48
  175. package/dist/worker/entry.js +297 -54
  176. package/dist/workspace-G4ZWUIPR.js +22 -0
  177. package/docs/README.md +29 -21
  178. package/docs/acp.md +191 -16
  179. package/docs/alcf-provider.md +1 -1
  180. package/docs/architecture.md +157 -7
  181. package/docs/artifact-placement.md +101 -0
  182. package/docs/artifact-versions.md +1 -1
  183. package/docs/built-in-agents.md +4 -2
  184. package/docs/capacity-and-scheduling.md +1 -1
  185. package/docs/commands-and-modes.md +224 -97
  186. package/docs/config-knobs-audit.md +1 -3
  187. package/docs/configuration-and-targets.md +236 -38
  188. package/docs/context-engine.md +34 -7
  189. package/docs/development-pipeline.md +102 -0
  190. package/docs/dispatch-architecture-rationale.md +1 -1
  191. package/docs/documentation-coverage.md +4 -4
  192. package/docs/documentation-guide.md +3 -3
  193. package/docs/environment-variables.md +15 -6
  194. package/docs/eval-runner.md +3 -3
  195. package/docs/evals-internal.md +2 -2
  196. package/docs/evidence-and-memory.md +10 -2
  197. package/docs/evolution.md +2 -2
  198. package/docs/exit-codes-and-output.md +15 -9
  199. package/docs/extensions-and-sharing.md +25 -18
  200. package/docs/fleet-demo-runbook.md +22 -23
  201. package/docs/fleet-dispatch.md +117 -16
  202. package/docs/git-commit-provenance.md +120 -0
  203. package/docs/glossary.md +107 -15
  204. package/docs/installation-and-lifecycle.md +75 -17
  205. package/docs/middleware-and-components.md +1 -1
  206. package/docs/model-catalog.md +46 -15
  207. package/docs/observability.md +8 -5
  208. package/docs/performance-methodology.md +491 -0
  209. package/docs/pi-boundary.md +72 -0
  210. package/docs/proactive-memory.md +14 -14
  211. package/docs/prompt-envelope-and-tools.md +25 -4
  212. package/docs/provider-adapter-cookbook.md +57 -4
  213. package/docs/release-cut-checklist.md +129 -111
  214. package/docs/safety-model.md +28 -8
  215. package/docs/scientific-validation.md +3 -3
  216. package/docs/session-lifecycle.md +55 -12
  217. package/docs/skills-marketplace.md +12 -8
  218. package/docs/time-conventions.md +101 -0
  219. package/docs/tool-usage.md +6 -5
  220. package/docs/trace-store.md +1 -1
  221. package/docs/troubleshooting.md +10 -7
  222. package/docs/tui-design.md +121 -28
  223. package/docs/worker-dispatch-mechanics.md +3 -3
  224. package/package.json +33 -36
  225. package/skills/README.md +5 -6
  226. package/skills/coding/ast-grep/SKILL.md +136 -0
  227. package/skills/coding/ast-grep/evals.md +56 -0
  228. package/skills/coding/ast-grep/references/rule_reference.md +297 -0
  229. package/skills/coding/coding-standards/SKILL.md +113 -0
  230. package/skills/coding/coding-standards/evals.md +34 -0
  231. package/skills/coding/prototype/SKILL.md +86 -0
  232. package/skills/coding/prototype/evals.md +42 -0
  233. package/skills/coding/prototype/references/LOGIC.md +67 -0
  234. package/skills/coding/prototype/references/UI.md +112 -0
  235. package/skills/coding/tdd/SKILL.md +101 -0
  236. package/skills/coding/tdd/evals.md +41 -0
  237. package/skills/coding/tdd/references/mocking.md +59 -0
  238. package/skills/coding/tdd/references/tests.md +77 -0
  239. package/skills/context/context-handoff/SKILL.md +126 -0
  240. package/skills/context/context-handoff/evals.md +57 -0
  241. package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
  242. package/skills/context/context-prime/SKILL.md +95 -0
  243. package/skills/context/context-prime/evals.md +54 -0
  244. package/skills/git/file-ticket/SKILL.md +107 -0
  245. package/skills/git/file-ticket/evals.md +54 -0
  246. package/skills/git/fix-issue/SKILL.md +106 -0
  247. package/skills/git/fix-issue/evals.md +71 -0
  248. package/skills/git/ship/SKILL.md +92 -0
  249. package/skills/git/ship/evals.md +72 -0
  250. package/skills/meta/clio-dev/SKILL.md +91 -0
  251. package/skills/meta/clio-dev/evals.md +45 -0
  252. package/skills/meta/clio-test/SKILL.md +130 -0
  253. package/skills/meta/clio-test/evals.md +43 -0
  254. package/skills/meta/clio-test/references/harness.md +97 -0
  255. package/skills/meta/clio-test/references/test-map.md +59 -0
  256. package/skills/meta/credentials/SKILL.md +125 -0
  257. package/skills/meta/credentials/evals.md +104 -0
  258. package/skills/meta/find-skills/SKILL.md +72 -0
  259. package/skills/meta/find-skills/evals.md +47 -0
  260. package/skills/meta/herdr/SKILL.md +127 -0
  261. package/skills/meta/herdr/evals.md +38 -0
  262. package/skills/meta/skill-craft/SKILL.md +102 -0
  263. package/skills/meta/skill-craft/evals.md +41 -0
  264. package/skills/planning/architecture/SKILL.md +129 -0
  265. package/skills/planning/architecture/evals.md +36 -0
  266. package/skills/planning/backlog/SKILL.md +90 -0
  267. package/skills/planning/backlog/evals.md +43 -0
  268. package/skills/planning/prd/SKILL.md +82 -0
  269. package/skills/planning/prd/evals.md +49 -0
  270. package/skills/planning/product-intent/SKILL.md +112 -0
  271. package/skills/planning/product-intent/evals.md +36 -0
  272. package/skills/planning/tech-spec/SKILL.md +115 -0
  273. package/skills/planning/tech-spec/evals.md +47 -0
  274. package/skills/registry.yaml +136 -0
  275. package/skills/research/arxiv-literature/SKILL.md +104 -0
  276. package/skills/research/arxiv-literature/evals.md +58 -0
  277. package/skills/research/experiment-protocol/SKILL.md +122 -0
  278. package/skills/research/experiment-protocol/evals.md +91 -0
  279. package/skills/research/scientific-debugging/SKILL.md +119 -0
  280. package/skills/research/scientific-debugging/evals.md +138 -0
  281. package/skills/research/scientific-modernization/SKILL.md +138 -0
  282. package/skills/research/scientific-modernization/evals.md +84 -0
  283. package/skills/skill-marketplace.json +12 -20
  284. package/skills/workflow/design-council/SKILL.md +139 -0
  285. package/skills/workflow/design-council/evals.md +97 -0
  286. package/skills/workflow/grill-me/SKILL.md +186 -0
  287. package/skills/workflow/grill-me/evals.md +78 -0
  288. package/skills/workflow/workflow-distiller/SKILL.md +136 -0
  289. package/skills/workflow/workflow-distiller/evals.md +107 -0
  290. package/src/cli/acp.ts +115 -0
  291. package/src/cli/agents.ts +60 -0
  292. package/src/cli/args.ts +280 -0
  293. package/src/cli/argv.ts +170 -0
  294. package/src/cli/ask.ts +34 -0
  295. package/src/cli/auth.ts +468 -0
  296. package/src/cli/bootstrap-generate.ts +498 -0
  297. package/src/cli/clio.ts +96 -0
  298. package/src/cli/components.ts +195 -0
  299. package/src/cli/config-inspect.ts +336 -0
  300. package/src/cli/config.ts +72 -0
  301. package/src/cli/configure-interop.ts +67 -0
  302. package/src/cli/configure-layout.ts +172 -0
  303. package/src/cli/configure.ts +1525 -0
  304. package/src/cli/context-clear.ts +76 -0
  305. package/src/cli/context-index.ts +100 -0
  306. package/src/cli/context.ts +321 -0
  307. package/src/cli/default-target.ts +55 -0
  308. package/src/cli/docs.ts +346 -0
  309. package/src/cli/doctor.ts +54 -0
  310. package/src/cli/eval.ts +315 -0
  311. package/src/cli/evidence.ts +225 -0
  312. package/src/cli/evolve.ts +219 -0
  313. package/src/cli/extensions.ts +214 -0
  314. package/src/cli/fleet.ts +868 -0
  315. package/src/cli/index.ts +338 -0
  316. package/src/cli/init.ts +219 -0
  317. package/src/cli/initial-message.ts +47 -0
  318. package/src/cli/internal-dispatch.ts +55 -0
  319. package/src/cli/memory.ts +182 -0
  320. package/src/cli/models.ts +257 -0
  321. package/src/cli/modes/json-stream.ts +121 -0
  322. package/src/cli/modes/jsonl.ts +9 -0
  323. package/src/cli/modes/print.ts +604 -0
  324. package/src/cli/oauth-manual-input.ts +72 -0
  325. package/src/cli/oauth-select.ts +36 -0
  326. package/src/cli/output-guard.ts +48 -0
  327. package/src/cli/paths.ts +44 -0
  328. package/src/cli/provider-target.ts +113 -0
  329. package/src/cli/removal.ts +72 -0
  330. package/src/cli/reset.ts +253 -0
  331. package/src/cli/run.ts +497 -0
  332. package/src/cli/share.ts +243 -0
  333. package/src/cli/shared.ts +60 -0
  334. package/src/cli/skills-eval.ts +1240 -0
  335. package/src/cli/skills.ts +485 -0
  336. package/src/cli/steer-channel.ts +86 -0
  337. package/src/cli/targets.ts +1154 -0
  338. package/src/cli/text-layout.ts +112 -0
  339. package/src/cli/trace.ts +322 -0
  340. package/src/cli/uninstall.ts +405 -0
  341. package/src/cli/upgrade.ts +286 -0
  342. package/src/cli/usage.ts +876 -0
  343. package/src/cli/validate-model.ts +28 -0
  344. package/src/cli/version.ts +7 -0
  345. package/src/cli/wiki-generate.ts +510 -0
  346. package/src/core/agent-environment.ts +7 -0
  347. package/src/core/artifact-paths.ts +43 -0
  348. package/src/core/bash-exec.ts +313 -0
  349. package/src/core/boot-trace.ts +42 -0
  350. package/src/core/bus-events.ts +744 -0
  351. package/src/core/bus-trace.ts +53 -0
  352. package/src/core/c-header-language.ts +265 -0
  353. package/src/core/clio-repo.ts +78 -0
  354. package/src/core/commit-attribution.ts +157 -0
  355. package/src/core/compile-cache.ts +159 -0
  356. package/src/core/config.ts +1722 -0
  357. package/src/core/context-floor.ts +33 -0
  358. package/src/core/defaults.ts +659 -0
  359. package/src/core/domain-loader.ts +177 -0
  360. package/src/core/event-bus.ts +94 -0
  361. package/src/core/file-references.ts +282 -0
  362. package/src/core/git-commit-attribution.ts +362 -0
  363. package/src/core/guardrails.ts +185 -0
  364. package/src/core/headless-permission.ts +21 -0
  365. package/src/core/incomplete-installation.ts +45 -0
  366. package/src/core/init.ts +223 -0
  367. package/src/core/json-payload.ts +58 -0
  368. package/src/core/package-root.ts +54 -0
  369. package/src/core/path-canonical.ts +37 -0
  370. package/src/core/process-identity.ts +41 -0
  371. package/src/core/recent-models.ts +91 -0
  372. package/src/core/residency-protection.ts +56 -0
  373. package/src/core/resolve-config-value.ts +88 -0
  374. package/src/core/response-schema.ts +279 -0
  375. package/src/core/run-overrides.ts +77 -0
  376. package/src/core/safe-exec.ts +205 -0
  377. package/src/core/safe-id.ts +37 -0
  378. package/src/core/safe-resource-write.ts +162 -0
  379. package/src/core/session-routing.ts +339 -0
  380. package/src/core/settings-layers.ts +354 -0
  381. package/src/core/shared-bus.ts +8 -0
  382. package/src/core/shell-quote.ts +26 -0
  383. package/src/core/skill-activation.ts +190 -0
  384. package/src/core/startup-timer.ts +37 -0
  385. package/src/core/state-file-lock.ts +219 -0
  386. package/src/core/termination.ts +275 -0
  387. package/src/core/timers.ts +38 -0
  388. package/src/core/tool-names.ts +65 -0
  389. package/src/core/verification-scripts.ts +13 -0
  390. package/src/core/workspace-files.ts +492 -0
  391. package/src/core/xdg.ts +177 -0
  392. package/src/domains/agents/builtins/architect.md +4 -4
  393. package/src/domains/agents/builtins/coder.md +3 -2
  394. package/src/domains/agents/builtins/debugger.md +1 -1
  395. package/src/domains/agents/builtins/documenter.md +1 -1
  396. package/src/domains/agents/builtins/git-master.md +3 -3
  397. package/src/domains/agents/builtins/provenance.md +1 -1
  398. package/src/domains/agents/builtins/researcher.md +1 -1
  399. package/src/domains/agents/builtins/scout.md +1 -1
  400. package/src/domains/agents/builtins/tester.md +1 -1
  401. package/src/domains/agents/builtins/verifier.md +1 -1
  402. package/src/domains/agents/builtins/wiki-writer.md +1 -1
  403. package/src/domains/agents/catalog.ts +172 -0
  404. package/src/domains/agents/contract.ts +16 -0
  405. package/src/domains/agents/extension.ts +110 -0
  406. package/src/domains/agents/fleet-commands.ts +154 -0
  407. package/src/domains/agents/fleet-contract.ts +797 -0
  408. package/src/domains/agents/frontmatter.ts +40 -0
  409. package/src/domains/agents/index.ts +102 -0
  410. package/src/domains/agents/manifest.ts +6 -0
  411. package/src/domains/agents/recipe-schema.ts +202 -0
  412. package/src/domains/agents/recipe.ts +125 -0
  413. package/src/domains/agents/registry.ts +111 -0
  414. package/src/domains/agents/result-contract.ts +1265 -0
  415. package/src/domains/agents/spec.ts +371 -0
  416. package/src/domains/agents/write-boundary.ts +109 -0
  417. package/src/domains/components/diff.ts +99 -0
  418. package/src/domains/components/hash.ts +21 -0
  419. package/src/domains/components/index.ts +3 -0
  420. package/src/domains/components/scan.ts +304 -0
  421. package/src/domains/components/snapshot.ts +108 -0
  422. package/src/domains/components/types.ts +82 -0
  423. package/src/domains/config/agent-namespace.ts +13 -0
  424. package/src/domains/config/classify.ts +106 -0
  425. package/src/domains/config/contract.ts +22 -0
  426. package/src/domains/config/extension.ts +142 -0
  427. package/src/domains/config/index.ts +23 -0
  428. package/src/domains/config/keybindings.ts +200 -0
  429. package/src/domains/config/manifest.ts +6 -0
  430. package/src/domains/config/watcher.ts +41 -0
  431. package/src/domains/context/adoption.ts +880 -0
  432. package/src/domains/context/bootstrap-prompt.ts +273 -0
  433. package/src/domains/context/bootstrap.ts +1502 -0
  434. package/src/domains/context/clear.ts +91 -0
  435. package/src/domains/context/clio-md.ts +429 -0
  436. package/src/domains/context/codewiki/artifact.ts +400 -0
  437. package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
  438. package/src/domains/context/codewiki/build-worker.ts +54 -0
  439. package/src/domains/context/codewiki/cmake.ts +356 -0
  440. package/src/domains/context/codewiki/cooperative.ts +46 -0
  441. package/src/domains/context/codewiki/coordinator.ts +182 -0
  442. package/src/domains/context/codewiki/digest.ts +135 -0
  443. package/src/domains/context/codewiki/grammar-assets.ts +33 -0
  444. package/src/domains/context/codewiki/indexer.ts +1529 -0
  445. package/src/domains/context/codewiki/paths.ts +67 -0
  446. package/src/domains/context/codewiki/schema.ts +80 -0
  447. package/src/domains/context/codewiki/tree-sitter.ts +771 -0
  448. package/src/domains/context/contract.ts +68 -0
  449. package/src/domains/context/excluded-dirs.ts +1 -0
  450. package/src/domains/context/extension.ts +358 -0
  451. package/src/domains/context/fingerprint.ts +198 -0
  452. package/src/domains/context/index.ts +154 -0
  453. package/src/domains/context/init-options.ts +69 -0
  454. package/src/domains/context/manifest.ts +6 -0
  455. package/src/domains/context/operator-profile.ts +157 -0
  456. package/src/domains/context/project-metadata.ts +529 -0
  457. package/src/domains/context/project-rules.ts +227 -0
  458. package/src/domains/context/prompt-context.ts +61 -0
  459. package/src/domains/context/refresh.ts +178 -0
  460. package/src/domains/context/runtime.ts +17 -0
  461. package/src/domains/context/sibling-files.ts +10 -0
  462. package/src/domains/context/state.ts +237 -0
  463. package/src/domains/context/wiki/assemble.ts +303 -0
  464. package/src/domains/context/wiki/frontmatter.ts +210 -0
  465. package/src/domains/context/wiki/generate.ts +595 -0
  466. package/src/domains/context/wiki/layout.ts +111 -0
  467. package/src/domains/context/wiki/meta.ts +221 -0
  468. package/src/domains/context/wiki/plan-store.ts +217 -0
  469. package/src/domains/context/wiki/plan.ts +250 -0
  470. package/src/domains/context/wiki/prompts.ts +283 -0
  471. package/src/domains/context/wiki/staleness.ts +198 -0
  472. package/src/domains/dispatch/active-route-planner.ts +168 -0
  473. package/src/domains/dispatch/admission-queue.ts +150 -0
  474. package/src/domains/dispatch/admission.ts +334 -0
  475. package/src/domains/dispatch/agent-candidates.ts +307 -0
  476. package/src/domains/dispatch/agent-ledger-hub.ts +71 -0
  477. package/src/domains/dispatch/agent-ledger-store.ts +257 -0
  478. package/src/domains/dispatch/agent-ledger.ts +212 -0
  479. package/src/domains/dispatch/agent-plan-adapter.ts +85 -0
  480. package/src/domains/dispatch/assignment-events.ts +132 -0
  481. package/src/domains/dispatch/assignment-reconcile.ts +76 -0
  482. package/src/domains/dispatch/assignment-store.ts +162 -0
  483. package/src/domains/dispatch/assignment.ts +278 -0
  484. package/src/domains/dispatch/backoff.ts +59 -0
  485. package/src/domains/dispatch/batch-store.ts +134 -0
  486. package/src/domains/dispatch/batch-tracker.ts +66 -0
  487. package/src/domains/dispatch/capability-match.ts +155 -0
  488. package/src/domains/dispatch/capacity-lease.ts +413 -0
  489. package/src/domains/dispatch/code-step-store.ts +52 -0
  490. package/src/domains/dispatch/code-step.ts +387 -0
  491. package/src/domains/dispatch/contract.ts +278 -0
  492. package/src/domains/dispatch/dedup.ts +133 -0
  493. package/src/domains/dispatch/event-pump.ts +251 -0
  494. package/src/domains/dispatch/execution-handoff.ts +29 -0
  495. package/src/domains/dispatch/execution-plan.ts +328 -0
  496. package/src/domains/dispatch/execution-role.ts +277 -0
  497. package/src/domains/dispatch/execution-scheduler.ts +583 -0
  498. package/src/domains/dispatch/extension.ts +6006 -0
  499. package/src/domains/dispatch/failure-classification.ts +147 -0
  500. package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
  501. package/src/domains/dispatch/fleet-plan.ts +225 -0
  502. package/src/domains/dispatch/fleet-preflight.ts +394 -0
  503. package/src/domains/dispatch/gate-decisions.ts +1040 -0
  504. package/src/domains/dispatch/gate-role-prompts.ts +58 -0
  505. package/src/domains/dispatch/heartbeat.ts +27 -0
  506. package/src/domains/dispatch/index.ts +137 -0
  507. package/src/domains/dispatch/joint-route-adapter.ts +114 -0
  508. package/src/domains/dispatch/joint-route-resolver.ts +283 -0
  509. package/src/domains/dispatch/manifest.ts +6 -0
  510. package/src/domains/dispatch/orphan-recovery.ts +266 -0
  511. package/src/domains/dispatch/outcome.ts +109 -0
  512. package/src/domains/dispatch/phase-timing.ts +47 -0
  513. package/src/domains/dispatch/placement.ts +202 -0
  514. package/src/domains/dispatch/receipt-findings.ts +255 -0
  515. package/src/domains/dispatch/receipt-integrity.ts +383 -0
  516. package/src/domains/dispatch/recovery-candidates.ts +74 -0
  517. package/src/domains/dispatch/reproducibility.ts +48 -0
  518. package/src/domains/dispatch/reservation-store.ts +501 -0
  519. package/src/domains/dispatch/route-approval.ts +177 -0
  520. package/src/domains/dispatch/route-candidates.ts +57 -0
  521. package/src/domains/dispatch/route-decision.ts +1079 -0
  522. package/src/domains/dispatch/route-facts.ts +187 -0
  523. package/src/domains/dispatch/route-history.ts +238 -0
  524. package/src/domains/dispatch/route-observer.ts +488 -0
  525. package/src/domains/dispatch/route-policy.ts +327 -0
  526. package/src/domains/dispatch/route-quality.ts +256 -0
  527. package/src/domains/dispatch/route-readiness.ts +120 -0
  528. package/src/domains/dispatch/routing-intent.ts +287 -0
  529. package/src/domains/dispatch/run-identity.ts +56 -0
  530. package/src/domains/dispatch/scout-transition.ts +130 -0
  531. package/src/domains/dispatch/state.ts +302 -0
  532. package/src/domains/dispatch/tool-stats.ts +132 -0
  533. package/src/domains/dispatch/transport.ts +210 -0
  534. package/src/domains/dispatch/types.ts +799 -0
  535. package/src/domains/dispatch/validation-grounding.ts +154 -0
  536. package/src/domains/dispatch/validation.ts +721 -0
  537. package/src/domains/dispatch/worker-protocol.ts +275 -0
  538. package/src/domains/dispatch/worker-spawn.ts +585 -0
  539. package/src/domains/dispatch/write-boundary-enforcer.ts +97 -0
  540. package/src/domains/dispatch/write-boundary.ts +426 -0
  541. package/src/domains/eval/artifacts/redact.ts +42 -0
  542. package/src/domains/eval/artifacts/store.ts +173 -0
  543. package/src/domains/eval/compare/compare.ts +33 -0
  544. package/src/domains/eval/compare/gates.ts +66 -0
  545. package/src/domains/eval/compare/thresholds.ts +92 -0
  546. package/src/domains/eval/harness-metrics.ts +62 -0
  547. package/src/domains/eval/index.ts +66 -0
  548. package/src/domains/eval/metrics/chaos-stream.ts +93 -0
  549. package/src/domains/eval/metrics/context.ts +34 -0
  550. package/src/domains/eval/metrics/coverage.ts +21 -0
  551. package/src/domains/eval/metrics/evidence.ts +182 -0
  552. package/src/domains/eval/metrics/fleet-loop-stream.ts +196 -0
  553. package/src/domains/eval/metrics/invariants.ts +736 -0
  554. package/src/domains/eval/metrics/latency.ts +4 -0
  555. package/src/domains/eval/metrics/token-stream.ts +139 -0
  556. package/src/domains/eval/metrics/tokens.ts +51 -0
  557. package/src/domains/eval/metrics/tool-calls.ts +7 -0
  558. package/src/domains/eval/proactive-memory.ts +279 -0
  559. package/src/domains/eval/provenance.ts +35 -0
  560. package/src/domains/eval/report.ts +234 -0
  561. package/src/domains/eval/reports/json.ts +5 -0
  562. package/src/domains/eval/reports/junit.ts +23 -0
  563. package/src/domains/eval/reports/markdown.ts +20 -0
  564. package/src/domains/eval/reports/swe-jsonl.ts +16 -0
  565. package/src/domains/eval/reports/text.ts +25 -0
  566. package/src/domains/eval/run-compare.ts +274 -0
  567. package/src/domains/eval/runner.ts +244 -0
  568. package/src/domains/eval/runners/clio-run.ts +148 -0
  569. package/src/domains/eval/runners/context-index.ts +56 -0
  570. package/src/domains/eval/runners/context-init.ts +203 -0
  571. package/src/domains/eval/runners/external-command.ts +350 -0
  572. package/src/domains/eval/runtime-paths.ts +171 -0
  573. package/src/domains/eval/schema/artifact.ts +75 -0
  574. package/src/domains/eval/schema/suite.ts +235 -0
  575. package/src/domains/eval/schema/validate.ts +339 -0
  576. package/src/domains/eval/store.ts +392 -0
  577. package/src/domains/eval/suites/load.ts +74 -0
  578. package/src/domains/eval/suites/matrix.ts +19 -0
  579. package/src/domains/eval/suites/resolve.ts +44 -0
  580. package/src/domains/eval/suites/run.ts +325 -0
  581. package/src/domains/eval/task-file.ts +186 -0
  582. package/src/domains/eval/types.ts +140 -0
  583. package/src/domains/eval/verifiers/command.ts +27 -0
  584. package/src/domains/eval/verifiers/file-exists.ts +6 -0
  585. package/src/domains/eval/verifiers/patch.ts +22 -0
  586. package/src/domains/eval/workspaces/git.ts +41 -0
  587. package/src/domains/eval/workspaces/local.ts +17 -0
  588. package/src/domains/eval/workspaces/temp-copy.ts +29 -0
  589. package/src/domains/evidence/build.ts +1754 -0
  590. package/src/domains/evidence/eval.ts +605 -0
  591. package/src/domains/evidence/failure-attribution.ts +54 -0
  592. package/src/domains/evidence/finish-contract-map.ts +42 -0
  593. package/src/domains/evidence/index.ts +55 -0
  594. package/src/domains/evidence/provenance.ts +200 -0
  595. package/src/domains/evidence/redact.ts +81 -0
  596. package/src/domains/evidence/store.ts +291 -0
  597. package/src/domains/evidence/types.ts +325 -0
  598. package/src/domains/evolution/SELF_EDIT_GATE.md +91 -0
  599. package/src/domains/evolution/index.ts +26 -0
  600. package/src/domains/evolution/manifest.ts +154 -0
  601. package/src/domains/evolution/validate.ts +304 -0
  602. package/src/domains/extensions/contract.ts +22 -0
  603. package/src/domains/extensions/discovery.ts +193 -0
  604. package/src/domains/extensions/extension.ts +46 -0
  605. package/src/domains/extensions/index.ts +34 -0
  606. package/src/domains/extensions/manager.ts +30 -0
  607. package/src/domains/extensions/manifest.ts +6 -0
  608. package/src/domains/extensions/resources.ts +38 -0
  609. package/src/domains/extensions/state.ts +224 -0
  610. package/src/domains/extensions/types.ts +83 -0
  611. package/src/domains/interop/consent.ts +185 -0
  612. package/src/domains/interop/contract.ts +29 -0
  613. package/src/domains/interop/detect.ts +173 -0
  614. package/src/domains/interop/extension.ts +59 -0
  615. package/src/domains/interop/index.ts +34 -0
  616. package/src/domains/interop/manifest.ts +6 -0
  617. package/src/domains/interop/registry.ts +139 -0
  618. package/src/domains/interop/state.ts +92 -0
  619. package/src/domains/interop/types.ts +109 -0
  620. package/src/domains/lifecycle/contract.ts +11 -0
  621. package/src/domains/lifecycle/doctor.ts +536 -0
  622. package/src/domains/lifecycle/extension.ts +23 -0
  623. package/src/domains/lifecycle/index.ts +21 -0
  624. package/src/domains/lifecycle/install-method.ts +51 -0
  625. package/src/domains/lifecycle/manifest.ts +6 -0
  626. package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
  627. package/src/domains/lifecycle/migrations/index.ts +114 -0
  628. package/src/domains/lifecycle/state.ts +93 -0
  629. package/src/domains/lifecycle/upgrade-notice.ts +35 -0
  630. package/src/domains/lifecycle/version.ts +35 -0
  631. package/src/domains/memory/index.ts +128 -0
  632. package/src/domains/memory/operations.ts +143 -0
  633. package/src/domains/memory/prompt-section.ts +86 -0
  634. package/src/domains/memory/proposal.ts +180 -0
  635. package/src/domains/memory/store.ts +163 -0
  636. package/src/domains/memory/task-bank.ts +229 -0
  637. package/src/domains/memory/task-memory-handoff.ts +222 -0
  638. package/src/domains/memory/task-memory-policy.ts +602 -0
  639. package/src/domains/memory/task-memory-status.ts +58 -0
  640. package/src/domains/memory/task-memory-telemetry.ts +346 -0
  641. package/src/domains/memory/task-memory-trace.ts +89 -0
  642. package/src/domains/memory/types.ts +74 -0
  643. package/src/domains/memory/validate.ts +297 -0
  644. package/src/domains/middleware/budget.ts +216 -0
  645. package/src/domains/middleware/contract.ts +35 -0
  646. package/src/domains/middleware/dispatch-nudge.ts +469 -0
  647. package/src/domains/middleware/extension.ts +129 -0
  648. package/src/domains/middleware/hook-receipts.ts +70 -0
  649. package/src/domains/middleware/hooks-io.ts +186 -0
  650. package/src/domains/middleware/hooks.ts +432 -0
  651. package/src/domains/middleware/index.ts +154 -0
  652. package/src/domains/middleware/manifest.ts +6 -0
  653. package/src/domains/middleware/memory-intervention.ts +701 -0
  654. package/src/domains/middleware/rules.ts +42 -0
  655. package/src/domains/middleware/runtime.ts +333 -0
  656. package/src/domains/middleware/skills-reminder.ts +202 -0
  657. package/src/domains/middleware/snapshot.ts +71 -0
  658. package/src/domains/middleware/stalled-turn.ts +71 -0
  659. package/src/domains/middleware/task-board-reminder.ts +87 -0
  660. package/src/domains/middleware/task-nudge.ts +77 -0
  661. package/src/domains/middleware/tool-choice-control.ts +42 -0
  662. package/src/domains/middleware/types.ts +131 -0
  663. package/src/domains/middleware/validate.ts +329 -0
  664. package/src/domains/observability/accountability.ts +67 -0
  665. package/src/domains/observability/contract.ts +168 -0
  666. package/src/domains/observability/cost.ts +206 -0
  667. package/src/domains/observability/evidence-index.ts +123 -0
  668. package/src/domains/observability/extension.ts +281 -0
  669. package/src/domains/observability/index.ts +78 -0
  670. package/src/domains/observability/manifest.ts +10 -0
  671. package/src/domains/observability/metrics.ts +37 -0
  672. package/src/domains/observability/projection.ts +477 -0
  673. package/src/domains/observability/telemetry.ts +89 -0
  674. package/src/domains/observability/trace-store.ts +1454 -0
  675. package/src/domains/prompts/compiler.ts +614 -0
  676. package/src/domains/prompts/contract.ts +46 -0
  677. package/src/domains/prompts/extension.ts +336 -0
  678. package/src/domains/prompts/fragment-loader.ts +138 -0
  679. package/src/domains/prompts/fragments/identity/clio.md +5 -6
  680. package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
  681. package/src/domains/prompts/fragments/identity/self-awareness.md +19 -0
  682. package/src/domains/prompts/fragments/operating/contract.md +4 -41
  683. package/src/domains/prompts/fragments/operating/delegation.md +42 -0
  684. package/src/domains/prompts/fragments/operating/skills.md +26 -0
  685. package/src/domains/prompts/fragments/operating/worker.md +16 -0
  686. package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
  687. package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
  688. package/src/domains/prompts/fragments/safety/read-only.md +4 -4
  689. package/src/domains/prompts/fragments/safety/suggest.md +2 -2
  690. package/src/domains/prompts/fragments/wiki/page.md +10 -0
  691. package/src/domains/prompts/fragments/wiki/plan.md +10 -0
  692. package/src/domains/prompts/hash.ts +73 -0
  693. package/src/domains/prompts/index.ts +32 -0
  694. package/src/domains/prompts/manifest.ts +8 -0
  695. package/src/domains/prompts/memory-intervention.ts +57 -0
  696. package/src/domains/prompts/preload.ts +82 -0
  697. package/src/domains/providers/auth/api-key.ts +47 -0
  698. package/src/domains/providers/auth/backend-file.ts +79 -0
  699. package/src/domains/providers/auth/backend-memory.ts +72 -0
  700. package/src/domains/providers/auth/boot-status.ts +65 -0
  701. package/src/domains/providers/auth/index.ts +37 -0
  702. package/src/domains/providers/auth/oauth.ts +37 -0
  703. package/src/domains/providers/auth/storage.ts +726 -0
  704. package/src/domains/providers/capabilities.ts +58 -0
  705. package/src/domains/providers/catalog.ts +162 -0
  706. package/src/domains/providers/contract.ts +162 -0
  707. package/src/domains/providers/credentials.ts +20 -0
  708. package/src/domains/providers/eligibility.ts +24 -0
  709. package/src/domains/providers/errors.ts +64 -0
  710. package/src/domains/providers/extension.ts +548 -0
  711. package/src/domains/providers/index.ts +142 -0
  712. package/src/domains/providers/knowledge-base-path.ts +102 -0
  713. package/src/domains/providers/manifest.ts +6 -0
  714. package/src/domains/providers/model-capabilities.ts +136 -0
  715. package/src/domains/providers/model-discovery.ts +144 -0
  716. package/src/domains/providers/model-family.ts +32 -0
  717. package/src/domains/providers/model-runtime-capabilities.ts +723 -0
  718. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +120 -37
  719. package/src/domains/providers/plugins.ts +61 -0
  720. package/src/domains/providers/probe/fingerprint.ts +64 -0
  721. package/src/domains/providers/probe/http.ts +114 -0
  722. package/src/domains/providers/probe/reasoning.ts +111 -0
  723. package/src/domains/providers/registry.ts +187 -0
  724. package/src/domains/providers/resolver.ts +156 -0
  725. package/src/domains/providers/runtime-resolution.ts +720 -0
  726. package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +90 -0
  727. package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
  728. package/src/domains/providers/runtimes/builtins.ts +78 -0
  729. package/src/domains/providers/runtimes/claude/claude-code.ts +38 -0
  730. package/src/domains/providers/runtimes/claude/claude-sdk.ts +38 -0
  731. package/src/domains/providers/runtimes/claude/common.ts +55 -0
  732. package/src/domains/providers/runtimes/cloud/alcf.ts +171 -0
  733. package/src/domains/providers/runtimes/cloud/anthropic-max.ts +71 -0
  734. package/src/domains/providers/runtimes/cloud/anthropic.ts +43 -0
  735. package/src/domains/providers/runtimes/cloud/bedrock.ts +35 -0
  736. package/src/domains/providers/runtimes/cloud/deepseek.ts +50 -0
  737. package/src/domains/providers/runtimes/cloud/google.ts +41 -0
  738. package/src/domains/providers/runtimes/cloud/groq.ts +46 -0
  739. package/src/domains/providers/runtimes/cloud/mistral.ts +46 -0
  740. package/src/domains/providers/runtimes/cloud/openai-codex.ts +49 -0
  741. package/src/domains/providers/runtimes/cloud/openai.ts +46 -0
  742. package/src/domains/providers/runtimes/cloud/openrouter.ts +111 -0
  743. package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
  744. package/src/domains/providers/runtimes/common/local-synth.ts +164 -0
  745. package/src/domains/providers/runtimes/common/probe-helpers.ts +474 -0
  746. package/src/domains/providers/runtimes/local-native/lemonade-anthropic.ts +27 -0
  747. package/src/domains/providers/runtimes/local-native/lemonade-openai.ts +26 -0
  748. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +88 -0
  749. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +207 -0
  750. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +180 -0
  751. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +126 -0
  752. package/src/domains/providers/runtimes/local-native/llamacpp.ts +98 -0
  753. package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
  754. package/src/domains/providers/runtimes/local-native/ollama-native.ts +117 -0
  755. package/src/domains/providers/runtimes/local-native/sglang.ts +26 -0
  756. package/src/domains/providers/runtimes/local-native/vllm.ts +27 -0
  757. package/src/domains/providers/runtimes/protocol/anthropic-compat.ts +104 -0
  758. package/src/domains/providers/runtimes/protocol/anthropic-messages.ts +28 -0
  759. package/src/domains/providers/runtimes/protocol/bedrock.ts +26 -0
  760. package/src/domains/providers/runtimes/protocol/google.ts +27 -0
  761. package/src/domains/providers/runtimes/protocol/openai-compat.ts +145 -0
  762. package/src/domains/providers/support.ts +241 -0
  763. package/src/domains/providers/thinking-control-policy.ts +85 -0
  764. package/src/domains/providers/types/capability-flags.ts +114 -0
  765. package/src/domains/providers/types/cost-provenance.ts +7 -0
  766. package/src/domains/providers/types/inference.ts +41 -0
  767. package/src/domains/providers/types/knowledge-base.ts +156 -0
  768. package/src/domains/providers/types/local-model-quirks.ts +216 -0
  769. package/src/domains/providers/types/runtime-descriptor.ts +181 -0
  770. package/src/domains/providers/types/target-descriptor.ts +60 -0
  771. package/src/domains/resources/collision.ts +92 -0
  772. package/src/domains/resources/common-loader.ts +140 -0
  773. package/src/domains/resources/contract.ts +24 -0
  774. package/src/domains/resources/extension.ts +59 -0
  775. package/src/domains/resources/index.ts +74 -0
  776. package/src/domains/resources/loader.ts +85 -0
  777. package/src/domains/resources/manifest.ts +6 -0
  778. package/src/domains/resources/prompts/loader.ts +246 -0
  779. package/src/domains/resources/prompts/substitute.ts +1 -0
  780. package/src/domains/resources/skills/content-hash.ts +107 -0
  781. package/src/domains/resources/skills/evals.ts +175 -0
  782. package/src/domains/resources/skills/install.ts +427 -0
  783. package/src/domains/resources/skills/loader.ts +985 -0
  784. package/src/domains/resources/skills/marketplace.ts +301 -0
  785. package/src/domains/resources/skills/provenance-pin.ts +115 -0
  786. package/src/domains/safety/action-classifier.ts +270 -0
  787. package/src/domains/safety/approval-axis.ts +23 -0
  788. package/src/domains/safety/audit.ts +493 -0
  789. package/src/domains/safety/autonomy.ts +174 -0
  790. package/src/domains/safety/call-target.ts +59 -0
  791. package/src/domains/safety/contract.ts +65 -0
  792. package/src/domains/safety/damage-control.ts +44 -0
  793. package/src/domains/safety/default-path-policy.ts +117 -0
  794. package/src/domains/safety/extension.ts +383 -0
  795. package/src/domains/safety/finish-contract-registration.ts +128 -0
  796. package/src/domains/safety/finish-contract.ts +554 -0
  797. package/src/domains/safety/index.ts +44 -0
  798. package/src/domains/safety/loop-detector.ts +143 -0
  799. package/src/domains/safety/manifest.ts +6 -0
  800. package/src/domains/safety/path-policy.ts +164 -0
  801. package/src/domains/safety/policy-engine.ts +994 -0
  802. package/src/domains/safety/project-policy.ts +391 -0
  803. package/src/domains/safety/protected-artifacts-registration.ts +189 -0
  804. package/src/domains/safety/protected-artifacts.ts +993 -0
  805. package/src/domains/safety/rejection-feedback.ts +102 -0
  806. package/src/domains/safety/rigor.ts +72 -0
  807. package/src/domains/safety/rule-compiler.ts +48 -0
  808. package/src/domains/safety/rule-pack-loader.ts +92 -0
  809. package/src/domains/safety/run-effects.ts +197 -0
  810. package/src/domains/safety/scope.ts +61 -0
  811. package/src/domains/scheduling/budget.ts +35 -0
  812. package/src/domains/scheduling/cluster.ts +175 -0
  813. package/src/domains/scheduling/contract.ts +30 -0
  814. package/src/domains/scheduling/extension.ts +91 -0
  815. package/src/domains/scheduling/index.ts +12 -0
  816. package/src/domains/scheduling/manifest.ts +6 -0
  817. package/src/domains/session/archive-readers.ts +208 -0
  818. package/src/domains/session/checkpoint.ts +38 -0
  819. package/src/domains/session/compaction/auto.ts +89 -0
  820. package/src/domains/session/compaction/branch-summary.ts +187 -0
  821. package/src/domains/session/compaction/compact.ts +493 -0
  822. package/src/domains/session/compaction/cut-point.ts +172 -0
  823. package/src/domains/session/compaction/defaults.ts +34 -0
  824. package/src/domains/session/compaction/mask-observations.ts +265 -0
  825. package/src/domains/session/compaction/session-entries.ts +18 -0
  826. package/src/domains/session/compaction/tokens.ts +148 -0
  827. package/src/domains/session/context-accounting.ts +583 -0
  828. package/src/domains/session/context-ledger.ts +362 -0
  829. package/src/domains/session/contract.ts +159 -0
  830. package/src/domains/session/cwd-fallback.ts +65 -0
  831. package/src/domains/session/decision-board.ts +190 -0
  832. package/src/domains/session/entries.ts +572 -0
  833. package/src/domains/session/extension.ts +403 -0
  834. package/src/domains/session/history.ts +172 -0
  835. package/src/domains/session/index.ts +84 -0
  836. package/src/domains/session/manager.ts +128 -0
  837. package/src/domains/session/manifest.ts +6 -0
  838. package/src/domains/session/migrations/index.ts +27 -0
  839. package/src/domains/session/prompt-manifest.ts +173 -0
  840. package/src/domains/session/protected-artifact-journal.ts +241 -0
  841. package/src/domains/session/protected-artifacts.ts +90 -0
  842. package/src/domains/session/retry.ts +230 -0
  843. package/src/domains/session/session-artifacts.ts +107 -0
  844. package/src/domains/session/task-board.ts +569 -0
  845. package/src/domains/session/tree/active-path.ts +137 -0
  846. package/src/domains/session/tree/fork.ts +159 -0
  847. package/src/domains/session/tree/manager.ts +128 -0
  848. package/src/domains/session/tree/navigator.ts +177 -0
  849. package/src/domains/session/tree/preview.ts +259 -0
  850. package/src/domains/session/usage.ts +148 -0
  851. package/src/domains/session/workspace/git-probe.ts +167 -0
  852. package/src/domains/session/workspace/index.ts +4 -0
  853. package/src/domains/session/workspace/project-type.ts +217 -0
  854. package/src/domains/session/workspace/snapshot.ts +74 -0
  855. package/src/domains/share/archive.ts +684 -0
  856. package/src/domains/share/contract.ts +9 -0
  857. package/src/domains/share/extension.ts +26 -0
  858. package/src/domains/share/index.ts +28 -0
  859. package/src/domains/share/manifest.ts +6 -0
  860. package/src/domains/user-tasks/store.ts +297 -0
  861. package/src/engine/acp/adapter.ts +397 -0
  862. package/src/engine/acp/errors.ts +128 -0
  863. package/src/engine/acp/event-mapper.ts +154 -0
  864. package/src/engine/acp/server.ts +2238 -0
  865. package/src/engine/acp/tool-mediator.ts +686 -0
  866. package/src/engine/acp/transport.ts +775 -0
  867. package/src/engine/acp/types.ts +196 -0
  868. package/src/engine/agent.ts +29 -0
  869. package/src/engine/ai.ts +207 -0
  870. package/src/engine/alcf-oauth.ts +205 -0
  871. package/src/engine/antigravity/subprocess-runtime.ts +205 -0
  872. package/src/engine/api-registry.ts +223 -0
  873. package/src/engine/apis/degraded-inference.ts +95 -0
  874. package/src/engine/apis/index.ts +16 -0
  875. package/src/engine/apis/llamacpp-residency.ts +292 -0
  876. package/src/engine/apis/lmstudio-residency.ts +76 -0
  877. package/src/engine/apis/lmstudio.ts +243 -0
  878. package/src/engine/apis/ollama-native.ts +528 -0
  879. package/src/engine/apis/openai-completions.ts +795 -0
  880. package/src/engine/apis/output-budget.ts +99 -0
  881. package/src/engine/apis/residency-lock.ts +29 -0
  882. package/src/engine/apis/residency.ts +776 -0
  883. package/src/engine/apis/resident-models.ts +42 -0
  884. package/src/engine/apis/sampling-overrides.ts +38 -0
  885. package/src/engine/apis/types.ts +16 -0
  886. package/src/engine/claude/sdk-runtime.ts +685 -0
  887. package/src/engine/claude/session-id.ts +5 -0
  888. package/src/engine/claude/subprocess-runtime.ts +316 -0
  889. package/src/engine/claude/tool-safety.ts +400 -0
  890. package/src/engine/env-api-keys.ts +98 -0
  891. package/src/engine/external-subprocess.ts +23 -0
  892. package/src/engine/gemma-channel-filter.ts +223 -0
  893. package/src/engine/harmony-response.ts +165 -0
  894. package/src/engine/instrumented-tui.ts +192 -0
  895. package/src/engine/loop-guard.ts +1127 -0
  896. package/src/engine/messages.ts +14 -0
  897. package/src/engine/models.ts +42 -0
  898. package/src/engine/oauth.ts +196 -0
  899. package/src/engine/pi-mono-names.ts +13 -0
  900. package/src/engine/prompt-templates.ts +1 -0
  901. package/src/engine/provider-payload.ts +272 -0
  902. package/src/engine/select-list.ts +53 -0
  903. package/src/engine/session.ts +834 -0
  904. package/src/engine/strip-tokenizer-sentinels.ts +125 -0
  905. package/src/engine/truncate.ts +9 -0
  906. package/src/engine/tui.ts +111 -0
  907. package/src/engine/types.ts +63 -0
  908. package/src/engine/worker-events.ts +100 -0
  909. package/src/engine/worker-runtime-capabilities.ts +5 -0
  910. package/src/engine/worker-runtime.ts +1022 -0
  911. package/src/engine/worker-tools.ts +208 -0
  912. package/src/entry/boot-options.ts +50 -0
  913. package/src/entry/orchestrator.ts +2011 -0
  914. package/src/interactive/application-controller.ts +433 -0
  915. package/src/interactive/bus-notices.ts +265 -0
  916. package/src/interactive/chat-loop-messages.ts +626 -0
  917. package/src/interactive/chat-loop-policy.ts +18 -0
  918. package/src/interactive/chat-loop.ts +1090 -0
  919. package/src/interactive/chat-panel.ts +1820 -0
  920. package/src/interactive/chat-renderer.ts +1228 -0
  921. package/src/interactive/clio-editor.ts +161 -0
  922. package/src/interactive/command-fallbacks.ts +23 -0
  923. package/src/interactive/command-output.ts +85 -0
  924. package/src/interactive/context-activity.ts +203 -0
  925. package/src/interactive/context-meter.ts +223 -0
  926. package/src/interactive/context-overlay.ts +246 -0
  927. package/src/interactive/cost-overlay.ts +279 -0
  928. package/src/interactive/dispatch-board.ts +1319 -0
  929. package/src/interactive/dispatch-steering.ts +86 -0
  930. package/src/interactive/editor-bash.ts +46 -0
  931. package/src/interactive/editor-steer.ts +51 -0
  932. package/src/interactive/editor-submit.ts +507 -0
  933. package/src/interactive/export-html/ansi-to-html.ts +161 -0
  934. package/src/interactive/export-html/index.ts +51 -0
  935. package/src/interactive/export-html/template.ts +45 -0
  936. package/src/interactive/export-html/tool-renderer.ts +54 -0
  937. package/src/interactive/external-editor.ts +67 -0
  938. package/src/interactive/follow-up-queue-panel.ts +75 -0
  939. package/src/interactive/footer/dashboard.ts +538 -0
  940. package/src/interactive/footer/notifications.ts +275 -0
  941. package/src/interactive/footer/widgets.ts +1264 -0
  942. package/src/interactive/footer-panel.ts +187 -0
  943. package/src/interactive/format-time.ts +97 -0
  944. package/src/interactive/index.ts +11 -0
  945. package/src/interactive/interactive-application.ts +939 -0
  946. package/src/interactive/interactive-event-projection.ts +385 -0
  947. package/src/interactive/interactive-input-runtime.ts +307 -0
  948. package/src/interactive/interactive-presentation.ts +584 -0
  949. package/src/interactive/interactive-shell.ts +388 -0
  950. package/src/interactive/interactive-slash-runtime.ts +554 -0
  951. package/src/interactive/interactive-subscriptions.ts +111 -0
  952. package/src/interactive/interactive-tickers.ts +183 -0
  953. package/src/interactive/keybinding-manager.ts +496 -0
  954. package/src/interactive/layout.ts +57 -0
  955. package/src/interactive/leader-key.ts +143 -0
  956. package/src/interactive/loop-guard-interrupt.ts +101 -0
  957. package/src/interactive/memory-overlay.ts +280 -0
  958. package/src/interactive/overlay-ask-user-lifecycle.ts +110 -0
  959. package/src/interactive/overlay-auth-lifecycle.ts +308 -0
  960. package/src/interactive/overlay-frame.ts +502 -0
  961. package/src/interactive/overlay-general-openers.ts +274 -0
  962. package/src/interactive/overlay-key-routing.ts +216 -0
  963. package/src/interactive/overlay-lifecycle.ts +426 -0
  964. package/src/interactive/overlay-model-selectors.ts +127 -0
  965. package/src/interactive/overlay-permission-lifecycle.ts +345 -0
  966. package/src/interactive/overlay-resource-openers.ts +112 -0
  967. package/src/interactive/overlay-session-lifecycle.ts +327 -0
  968. package/src/interactive/overlay-transitions.ts +57 -0
  969. package/src/interactive/overlays/agents.ts +69 -0
  970. package/src/interactive/overlays/ask-user.ts +921 -0
  971. package/src/interactive/overlays/auth-dialog.ts +221 -0
  972. package/src/interactive/overlays/context-reset.ts +108 -0
  973. package/src/interactive/overlays/cwd-fallback.ts +141 -0
  974. package/src/interactive/overlays/decisions.ts +300 -0
  975. package/src/interactive/overlays/extensions.ts +54 -0
  976. package/src/interactive/overlays/help-reference.ts +145 -0
  977. package/src/interactive/overlays/interop.ts +139 -0
  978. package/src/interactive/overlays/keybinding-detail.ts +90 -0
  979. package/src/interactive/overlays/list-overlay.ts +606 -0
  980. package/src/interactive/overlays/message-picker.ts +155 -0
  981. package/src/interactive/overlays/model-selector.ts +1109 -0
  982. package/src/interactive/overlays/prompts.ts +72 -0
  983. package/src/interactive/overlays/session-selector-search.ts +31 -0
  984. package/src/interactive/overlays/session-selector.ts +284 -0
  985. package/src/interactive/overlays/settings.ts +3451 -0
  986. package/src/interactive/overlays/skills-hub.ts +237 -0
  987. package/src/interactive/overlays/tree-selector.ts +422 -0
  988. package/src/interactive/permission-overlay.ts +170 -0
  989. package/src/interactive/render-trace.ts +534 -0
  990. package/src/interactive/renderers/branch-summary.ts +86 -0
  991. package/src/interactive/renderers/code-ink.ts +420 -0
  992. package/src/interactive/renderers/compaction-summary.ts +112 -0
  993. package/src/interactive/renderers/diff.ts +137 -0
  994. package/src/interactive/renderers/mermaid.ts +53 -0
  995. package/src/interactive/renderers/notice.ts +28 -0
  996. package/src/interactive/renderers/retry-status.ts +31 -0
  997. package/src/interactive/renderers/structured.ts +89 -0
  998. package/src/interactive/renderers/tool-execution.ts +1357 -0
  999. package/src/interactive/renderers/worker-entry.ts +280 -0
  1000. package/src/interactive/session-last-turn.ts +186 -0
  1001. package/src/interactive/session-switch-settlement.ts +10 -0
  1002. package/src/interactive/session-transcript.ts +105 -0
  1003. package/src/interactive/session-usage-reseed.ts +74 -0
  1004. package/src/interactive/slash-autocomplete.ts +256 -0
  1005. package/src/interactive/slash-commands.ts +1407 -0
  1006. package/src/interactive/slash-spec.ts +424 -0
  1007. package/src/interactive/status/controller.ts +260 -0
  1008. package/src/interactive/status/index.ts +23 -0
  1009. package/src/interactive/status/state-machine.ts +530 -0
  1010. package/src/interactive/status/summary.ts +170 -0
  1011. package/src/interactive/status/types.ts +121 -0
  1012. package/src/interactive/status/verbs.ts +163 -0
  1013. package/src/interactive/status/watchdog.ts +24 -0
  1014. package/src/interactive/stdout-backpressure.ts +99 -0
  1015. package/src/interactive/stream-pacer.ts +530 -0
  1016. package/src/interactive/stream-pacing-policy.ts +66 -0
  1017. package/src/interactive/tasks-overlay.ts +540 -0
  1018. package/src/interactive/terminal-lease.ts +485 -0
  1019. package/src/interactive/theme/components.ts +55 -0
  1020. package/src/interactive/theme/glyphs.ts +70 -0
  1021. package/src/interactive/theme/index.ts +15 -0
  1022. package/src/interactive/theme/labels.ts +88 -0
  1023. package/src/interactive/theme/rules.ts +138 -0
  1024. package/src/interactive/theme/segments.ts +88 -0
  1025. package/src/interactive/theme/tokens.ts +121 -0
  1026. package/src/interactive/thinking-level-policy.ts +6 -0
  1027. package/src/interactive/tool-prose-loop.ts +122 -0
  1028. package/src/interactive/tool-prose-registration.ts +48 -0
  1029. package/src/interactive/turn-context.ts +855 -0
  1030. package/src/interactive/turn-middleware.ts +283 -0
  1031. package/src/interactive/turn-persistence.ts +458 -0
  1032. package/src/interactive/turn-queues.ts +181 -0
  1033. package/src/interactive/turn-recovery.ts +323 -0
  1034. package/src/interactive/turn-runtime.ts +869 -0
  1035. package/src/interactive/turn-state.ts +133 -0
  1036. package/src/interactive/view/artifacts.ts +1452 -0
  1037. package/src/interactive/view/view-overlay.ts +735 -0
  1038. package/src/interactive/welcome-dashboard.ts +537 -0
  1039. package/src/interactive/worker-receipts.ts +143 -0
  1040. package/src/interactive/worker-replay.ts +111 -0
  1041. package/src/interactive/worker-share.ts +100 -0
  1042. package/src/interactive/worker-stream.ts +446 -0
  1043. package/src/interactive/workspace-facts.ts +141 -0
  1044. package/src/tools/agent-tools.ts +402 -0
  1045. package/src/tools/artifact.ts +103 -0
  1046. package/src/tools/ask-user.ts +666 -0
  1047. package/src/tools/bash.ts +204 -0
  1048. package/src/tools/bootstrap.ts +77 -0
  1049. package/src/tools/builtin-tool-catalog.ts +265 -0
  1050. package/src/tools/codewiki/code-nav-surface.ts +29 -0
  1051. package/src/tools/codewiki/code-nav.ts +549 -0
  1052. package/src/tools/codewiki/shared.ts +118 -0
  1053. package/src/tools/compete-worktrees.ts +898 -0
  1054. package/src/tools/context/docs-engine.ts +630 -0
  1055. package/src/tools/context/index.ts +514 -0
  1056. package/src/tools/context/surface.ts +19 -0
  1057. package/src/tools/core-bootstrap.ts +168 -0
  1058. package/src/tools/credential-present.ts +151 -0
  1059. package/src/tools/dispatch-admission.ts +533 -0
  1060. package/src/tools/dispatch-arguments.ts +228 -0
  1061. package/src/tools/dispatch-background.ts +54 -0
  1062. package/src/tools/dispatch-event-text.ts +6 -0
  1063. package/src/tools/dispatch-plan.ts +746 -0
  1064. package/src/tools/dispatch-run-events.ts +238 -0
  1065. package/src/tools/dispatch-runner.ts +2370 -0
  1066. package/src/tools/dispatch-scout-admission.ts +295 -0
  1067. package/src/tools/dispatch-scout.ts +461 -0
  1068. package/src/tools/dispatch-types.ts +77 -0
  1069. package/src/tools/dispatch.ts +244 -0
  1070. package/src/tools/edit-diff.ts +534 -0
  1071. package/src/tools/edit.ts +128 -0
  1072. package/src/tools/executables.ts +22 -0
  1073. package/src/tools/file-mutation-queue.ts +35 -0
  1074. package/src/tools/find.ts +294 -0
  1075. package/src/tools/grep.ts +495 -0
  1076. package/src/tools/ignore-policy.ts +169 -0
  1077. package/src/tools/lazy-tool.ts +60 -0
  1078. package/src/tools/ledger.ts +206 -0
  1079. package/src/tools/ls.ts +110 -0
  1080. package/src/tools/monitor-surface.ts +36 -0
  1081. package/src/tools/monitor.ts +767 -0
  1082. package/src/tools/network-policy.ts +29 -0
  1083. package/src/tools/observation.ts +421 -0
  1084. package/src/tools/observers.ts +99 -0
  1085. package/src/tools/path-utils.ts +79 -0
  1086. package/src/tools/policy.ts +154 -0
  1087. package/src/tools/profiles.ts +108 -0
  1088. package/src/tools/read.ts +173 -0
  1089. package/src/tools/registry.ts +1169 -0
  1090. package/src/tools/result-shaping.ts +204 -0
  1091. package/src/tools/safe-exec.ts +128 -0
  1092. package/src/tools/spawn-hygiene.ts +182 -0
  1093. package/src/tools/steer-surface.ts +17 -0
  1094. package/src/tools/steer.ts +77 -0
  1095. package/src/tools/tasks.ts +265 -0
  1096. package/src/tools/truncate-utf8.ts +17 -0
  1097. package/src/tools/truncate.ts +43 -0
  1098. package/src/tools/verify/frontend.ts +687 -0
  1099. package/src/tools/verify/index.ts +31 -0
  1100. package/src/tools/verify/scripts.ts +108 -0
  1101. package/src/tools/verify/surface.ts +46 -0
  1102. package/src/tools/web-fetch-surface.ts +23 -0
  1103. package/src/tools/web-fetch.ts +759 -0
  1104. package/src/tools/worker-evidence.ts +215 -0
  1105. package/src/tools/write.ts +57 -0
  1106. package/src/utils/exif-orientation.ts +192 -0
  1107. package/src/utils/git.ts +24 -0
  1108. package/src/utils/image-resize.ts +148 -0
  1109. package/src/utils/photon.ts +103 -0
  1110. package/src/worker/control-lane.ts +22 -0
  1111. package/src/worker/entry.ts +294 -0
  1112. package/src/worker/event-projection.ts +56 -0
  1113. package/src/worker/heartbeat.ts +24 -0
  1114. package/src/worker/ledger-mirror.ts +95 -0
  1115. package/src/worker/ndjson.ts +40 -0
  1116. package/src/worker/protocol.ts +529 -0
  1117. package/src/worker/resource-facts.ts +79 -0
  1118. package/src/worker/runtime-registry.ts +12 -0
  1119. package/src/worker/spec-contract.ts +675 -0
  1120. package/src/worker/stdin-demux.ts +316 -0
  1121. package/dist/acp-UMLFVA3F.js +0 -92
  1122. package/dist/chunk-262G75JS.js +0 -35
  1123. package/dist/chunk-6CWDTGUC.js +0 -20
  1124. package/dist/chunk-BYEU76JP.js +0 -899
  1125. package/dist/chunk-GNGDQYDU.js +0 -34688
  1126. package/dist/chunk-GOTUR54M.js +0 -9
  1127. package/dist/chunk-NI4DEJMC.js +0 -88
  1128. package/dist/chunk-TPOCL34A.js +0 -2876
  1129. package/dist/chunk-UU3R62TT.js +0 -128
  1130. package/dist/clio-KIQ5SNDS.js +0 -53
  1131. package/dist/configure-G4E3A2PG.js +0 -27
  1132. package/dist/doctor-M5HJJZOL.js +0 -61
  1133. package/dist/domains/agents/builtins/architect.md +0 -33
  1134. package/dist/domains/agents/builtins/coder.md +0 -31
  1135. package/dist/domains/agents/builtins/context-bootstrap.md +0 -38
  1136. package/dist/domains/agents/builtins/debugger.md +0 -30
  1137. package/dist/domains/agents/builtins/documenter.md +0 -31
  1138. package/dist/domains/agents/builtins/git-master.md +0 -30
  1139. package/dist/domains/agents/builtins/provenance.md +0 -30
  1140. package/dist/domains/agents/builtins/researcher.md +0 -71
  1141. package/dist/domains/agents/builtins/scout.md +0 -42
  1142. package/dist/domains/agents/builtins/tester.md +0 -31
  1143. package/dist/domains/agents/builtins/verifier.md +0 -30
  1144. package/dist/domains/agents/builtins/wiki-writer.md +0 -41
  1145. package/dist/fleet-preflight-CLIAX7YR.js +0 -21
  1146. package/dist/preload-KZVHET2B.js +0 -11
  1147. package/dist/version-ROZ6CZKH.js +0 -16
  1148. package/docs/html/agents_blueprint.html +0 -936
  1149. package/docs/html/alcf_blueprint.html +0 -324
  1150. package/docs/html/architecture_blueprint.html +0 -850
  1151. package/docs/html/commands_blueprint.html +0 -794
  1152. package/docs/html/config_knobs_audit_blueprint.html +0 -178
  1153. package/docs/html/configuration_blueprint.html +0 -1080
  1154. package/docs/html/context_blueprint.html +0 -603
  1155. package/docs/html/documentation_blueprint.html +0 -832
  1156. package/docs/html/environment_blueprint.html +0 -404
  1157. package/docs/html/eval_blueprint.html +0 -743
  1158. package/docs/html/evals_internal_blueprint.html +0 -190
  1159. package/docs/html/evolution_blueprint.html +0 -674
  1160. package/docs/html/extensions_blueprint.html +0 -2065
  1161. package/docs/html/fleet_dispatch_blueprint.html +0 -286
  1162. package/docs/html/index.html +0 -919
  1163. package/docs/html/lifecycle_blueprint.html +0 -723
  1164. package/docs/html/memory_blueprint.html +0 -699
  1165. package/docs/html/middleware_blueprint.html +0 -664
  1166. package/docs/html/models_blueprint.html +0 -2366
  1167. package/docs/html/observability_blueprint.html +0 -683
  1168. package/docs/html/provider_adapter_blueprint.html +0 -245
  1169. package/docs/html/safety_blueprint.html +0 -1386
  1170. package/docs/html/shared.css +0 -571
  1171. package/docs/html/shared.js +0 -143
  1172. package/docs/html/skills_blueprint.html +0 -671
  1173. package/docs/html/soak_blueprint.html +0 -182
  1174. package/docs/html/tool_usage_blueprint.html +0 -350
  1175. package/docs/html/tools_blueprint.html +0 -2249
  1176. package/docs/html/trace_blueprint.html +0 -235
  1177. package/docs/html/tui_design_blueprint.html +0 -314
  1178. package/docs/html/validation_blueprint.html +0 -961
  1179. package/docs/html/worker_dispatch_blueprint.html +0 -231
  1180. package/skills/git/commit-crafting/SKILL.md +0 -79
  1181. package/skills/git/commit-crafting/evals.md +0 -92
  1182. package/skills/git/create-pr/SKILL.md +0 -116
  1183. package/skills/git/create-pr/evals.md +0 -114
  1184. package/skills/git/investigate-issue/SKILL.md +0 -139
  1185. package/skills/git/investigate-issue/evals.md +0 -94
  1186. package/skills/git/review-changes/SKILL.md +0 -103
  1187. package/skills/git/review-changes/evals.md +0 -85
@@ -0,0 +1,1357 @@
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 { formatSize } from "../../engine/truncate.js";
17
+ import { visibleWidth, wrapTextWithAnsi } from "../../engine/tui.js";
18
+ import type { ApprovalRequestView } from "../permission-overlay.js";
19
+ import { clioTheme, formatCompactMs, GLYPH } from "../theme/index.js";
20
+ import { renderDiffLines } from "./diff.js";
21
+ import { tryRenderJson, tryRenderXml } from "./structured.js";
22
+
23
+ const theme = clioTheme();
24
+ const dim = (text: string): string => theme.fg("dim", text);
25
+ const red = (text: string): string => theme.fg("error", text);
26
+ const green = (text: string): string => theme.fg("success", text);
27
+ const yellow = (text: string): string => theme.fg("warning", text);
28
+ const cyan = (text: string): string => theme.fg("accent", text);
29
+ const cyanBold = (text: string): string => theme.style("accent", text, { bold: true });
30
+
31
+ // Visible width of the rail prefix is 2 columns (`│ `). Width budgets and
32
+ // diff renderers compute against the visible length, not the styled length,
33
+ // so the constant is kept as the plain-text representation.
34
+ const BODY_INDENT_PLAIN = "│ ";
35
+ const BODY_INDENT_VISIBLE_WIDTH = 2;
36
+ const HEADER_PREFIX_PLAIN = "▸ ";
37
+ const ARG_PREVIEW_LIMIT = 60;
38
+ const WEB_FETCH_ARG_PREVIEW_LIMIT = 140;
39
+ const FULL_RESULT_PREVIEW_LIMIT = 60_000;
40
+ const FULL_RESULT_ROW_LIMIT = 120;
41
+ const STREAMING_RESULT_ROW_LIMIT = 20;
42
+ const ARGS_BODY_LINE_LIMIT = 24;
43
+ const STATUS_OK_GLYPH = GLYPH.ok;
44
+ const STATUS_ERROR_GLYPH = GLYPH.error;
45
+
46
+ // Hoisted rail prefixes. `indentAndWrap` would otherwise allocate two fresh
47
+ // styled strings per rendered line; by precomputing the dim and error variants
48
+ // once at module scope, repeated rendering of long result blocks stays cheap.
49
+ const RAIL_DIM = dim(BODY_INDENT_PLAIN);
50
+ const RAIL_ERROR = red(BODY_INDENT_PLAIN);
51
+
52
+ export interface ToolExecutionStart {
53
+ toolCallId: string;
54
+ toolName: string;
55
+ args: unknown;
56
+ /** Live elapsed time supplied by the panel for running segments. */
57
+ elapsedMs?: number | undefined;
58
+ /** Pi may stream a tool call's arguments before execution starts. */
59
+ phase?: "forming" | "ready" | "running" | undefined;
60
+ }
61
+
62
+ export interface ToolExecutionFinished {
63
+ toolCallId: string;
64
+ toolName: string;
65
+ args?: unknown;
66
+ result: unknown;
67
+ isError: boolean;
68
+ durationMs?: number | undefined;
69
+ /** Persisted summary (bytes, truncated, offloadPath, observation counts). */
70
+ resultSummary?: Record<string, unknown> | undefined;
71
+ /** Honest terminal outcome for synthetic/or permission-blocked calls. */
72
+ outcome?: "blocked" | "aborted" | "orphaned" | undefined;
73
+ /**
74
+ * Why admission refused this call, from the registry verdict. A blocked row
75
+ * that states only that something was refused leaves the operator, and the
76
+ * model reading the same transcript, to guess at the rule.
77
+ */
78
+ blockReason?: string | undefined;
79
+ /** Structured exit status when the caller has one; text parsing is legacy fallback only. */
80
+ exitCode?: number | string | null | undefined;
81
+ /** Local `!!` bash output is visible to the operator but excluded from model context. */
82
+ excludeFromContext?: boolean | undefined;
83
+ }
84
+
85
+ export interface ToolBodyRenderOptions {
86
+ /**
87
+ * Render the full tool result body with no middle-elision and no character
88
+ * truncation. The live view keeps bodies bounded so a single tool cannot
89
+ * flood the pane; `/export` sets this so the written transcript reproduces
90
+ * the complete tool output the model actually received.
91
+ */
92
+ unbounded?: boolean;
93
+ /** Live rows color mutation diffs; replay and export deliberately use plain text. */
94
+ diffStyle?: "color" | "plain";
95
+ }
96
+
97
+ /** Row cap for a tool body: unbounded lifts both the row and char limits. */
98
+ function resultRowLimit(opts: ToolBodyRenderOptions): number {
99
+ return opts.unbounded === true ? Number.POSITIVE_INFINITY : FULL_RESULT_ROW_LIMIT;
100
+ }
101
+
102
+ function resultCharLimit(opts: ToolBodyRenderOptions): number {
103
+ return opts.unbounded === true ? Number.POSITIVE_INFINITY : FULL_RESULT_PREVIEW_LIMIT;
104
+ }
105
+
106
+ // Counts UTF-16 code units; can split a surrogate pair on non-BMP input. Acceptable for ASCII paths/commands.
107
+ function truncate(value: string, limit: number): string {
108
+ if (value.length <= limit) return value;
109
+ const cut = Math.max(0, limit - 3);
110
+ return `${value.slice(0, cut)}...`;
111
+ }
112
+
113
+ function isPlainObject(value: unknown): value is Record<string, unknown> {
114
+ return value !== null && typeof value === "object" && !Array.isArray(value);
115
+ }
116
+
117
+ const SECRET_KEY_RE =
118
+ /(?:api[-_]?key|access[-_]?key|auth(?:orization)?|credential|password|private[-_]?key|secret|token)/iu;
119
+ const ENV_KEY_RE = /^env(?:ironment)?$/iu;
120
+ const SECRET_STRING_RE = /(https?:\/\/[^\s/@]+:)[^\s/@]+@/giu;
121
+ const SECRET_URL_PARAM_RE =
122
+ /([?&](?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[^=\s]*=)[^&#\s]+/giu;
123
+ const SECRET_ASSIGNMENT_RE =
124
+ /(?<![A-Z0-9_])((?:[A-Z0-9_]*(?:ACCESS|API|AUTH|CREDENTIAL|KEY|PASS(?:WORD)?|PRIVATE|SECRET|TOKEN)[A-Z0-9_]*)=)[^\s;&|]+/giu;
125
+ const SECRET_FLAG_RE =
126
+ /(--?(?:[a-z0-9-]*(?:api[-_]?key|access[-_]?token|auth(?:orization)?|credential|password|secret|token)[a-z0-9-]*))(=|\s+)([^\s;&|]+)/giu;
127
+
128
+ function redactSecretString(value: string): string {
129
+ return value
130
+ .replace(SECRET_STRING_RE, "$1[redacted]@")
131
+ .replace(SECRET_URL_PARAM_RE, "$1[redacted]")
132
+ .replace(SECRET_ASSIGNMENT_RE, "$1[redacted]")
133
+ .replace(SECRET_FLAG_RE, "$1$2[redacted]");
134
+ }
135
+
136
+ function redactEnvironmentValue(value: unknown, depth: number): unknown {
137
+ if (depth > 8) return "[redacted nested values]";
138
+ if (typeof value === "string") return "[redacted]";
139
+ if (Array.isArray(value)) return value.map((item) => redactEnvironmentValue(item, depth + 1));
140
+ if (!isPlainObject(value)) return value;
141
+ const out: Record<string, unknown> = {};
142
+ for (const [childKey, childValue] of Object.entries(value)) {
143
+ out[childKey] = redactEnvironmentValue(childValue, depth + 1);
144
+ }
145
+ return out;
146
+ }
147
+
148
+ /** Project tool arguments for display only; execution and receipts retain the original values. */
149
+ export function redactToolArgs(value: unknown, key = "", depth = 0): unknown {
150
+ if (SECRET_KEY_RE.test(key)) return "[redacted]";
151
+ if (ENV_KEY_RE.test(key)) return redactEnvironmentValue(value, depth);
152
+ if (typeof value === "string") return redactSecretString(value);
153
+ if (depth > 8) return "[redacted nested values]";
154
+ if (Array.isArray(value)) return value.map((item) => redactToolArgs(item, key, depth + 1));
155
+ if (!isPlainObject(value)) return value;
156
+ const out: Record<string, unknown> = {};
157
+ for (const [childKey, childValue] of Object.entries(value)) {
158
+ out[childKey] = redactToolArgs(childValue, childKey, depth + 1);
159
+ }
160
+ return out;
161
+ }
162
+
163
+ function readStringField(args: unknown, key: string): string | null {
164
+ if (!isPlainObject(args)) return null;
165
+ const value = args[key];
166
+ return typeof value === "string" ? redactSecretString(value) : null;
167
+ }
168
+
169
+ function isEmptyArgs(args: unknown): boolean {
170
+ if (args === undefined || args === null) return true;
171
+ if (isPlainObject(args) && Object.keys(args).length === 0) return true;
172
+ return false;
173
+ }
174
+
175
+ function jsonStringifySafe(value: unknown): string {
176
+ try {
177
+ const text = JSON.stringify(value);
178
+ return typeof text === "string" ? text : String(value);
179
+ } catch {
180
+ return String(value);
181
+ }
182
+ }
183
+
184
+ function unquoteShellScript(value: string): string {
185
+ const trimmed = value.trim();
186
+ if (trimmed.length < 2) return trimmed;
187
+ const quote = trimmed.charAt(0);
188
+ if ((quote !== "'" && quote !== '"') || trimmed.charAt(trimmed.length - 1) !== quote) return trimmed;
189
+ const inner = trimmed.slice(1, -1);
190
+ if (quote === "'") return inner.replace(/'\\''/g, "'");
191
+ return inner.replace(/\\"/g, '"').replace(/\\`/g, "`").replace(/\\\$/g, "$").replace(/\\\\/g, "\\");
192
+ }
193
+
194
+ function stripShellWrapperForDisplay(command: string): string {
195
+ const trimmed = command.trim();
196
+ const match = /^(?:(?:\/(?:usr\/)?bin\/)?(?:bash|zsh|sh))\s+-lc\s+([\s\S]+)$/u.exec(trimmed);
197
+ if (!match?.[1]) return command;
198
+ return unquoteShellScript(match[1]);
199
+ }
200
+
201
+ function displayArg(toolName: string, value: string): string {
202
+ return toolName === "bash" ? stripShellWrapperForDisplay(value) : value;
203
+ }
204
+
205
+ /**
206
+ * Optional-duration guard around the single duration formatter. formatCompactMs
207
+ * is the one formatter for elapsed time, but these call sites carry a
208
+ * `number | undefined` that may be missing, non-finite, or negative and must
209
+ * then omit the ` · <dur>` segment entirely. Returns null in those cases and
210
+ * delegates every real value to formatCompactMs, so durations render as
211
+ * `860ms`, `4.2s`, `42s`, and `1m36s` with no zero padding on the seconds.
212
+ */
213
+ function optionalCompactMs(durationMs: number | undefined): string | null {
214
+ if (durationMs === undefined || !Number.isFinite(durationMs) || durationMs < 0) return null;
215
+ return formatCompactMs(durationMs);
216
+ }
217
+
218
+ function bashExitCodeFromResult(result: unknown): string | null {
219
+ const unwrapped = unwrapResultEnvelope(result);
220
+ const text = typeof unwrapped === "string" ? unwrapped : jsonStringifySafe(unwrapped);
221
+ const match =
222
+ /\bcommand failed \(exit (?<paren>[^)]+)\)/iu.exec(text) ??
223
+ /\bcommand exited with code (?<code>[0-9?]+)/iu.exec(text) ??
224
+ /\bexit (?<short>[0-9?]+)\b/iu.exec(text);
225
+ return match?.groups?.paren ?? match?.groups?.code ?? match?.groups?.short ?? null;
226
+ }
227
+
228
+ /**
229
+ * Map of known tools to their canonical "primary" arg field. When the arg is
230
+ * a string the header summarises it directly and the expanded argument list
231
+ * omits only that repeated field. Tools not in this map (or with an unexpected
232
+ * arg shape) fall back to a JSON summary plus their complete redacted fields.
233
+ */
234
+ const PRIMARY_ARG_FIELD: Record<string, string> = {
235
+ read: "path",
236
+ edit: "path",
237
+ write: "path",
238
+ ls: "path",
239
+ bash: "command",
240
+ grep: "pattern",
241
+ find: "pattern",
242
+ web_fetch: "url",
243
+ git: "op",
244
+ verify: "check",
245
+ code_nav: "query",
246
+ context: "scope",
247
+ artifact: "kind",
248
+ monitor: "run_id",
249
+ steer: "run_id",
250
+ tasks: "action",
251
+ };
252
+
253
+ /**
254
+ * Returns the captured primary-arg string when the header successfully used a
255
+ * known tool's canonical arg, otherwise null. The argument renderer uses the
256
+ * same map to omit that one repeated field below `read(README.md)`.
257
+ */
258
+ function capturedPrimaryArg(toolName: string, args: unknown): string | null {
259
+ const field = PRIMARY_ARG_FIELD[toolName];
260
+ if (field === undefined) return null;
261
+ return readStringField(args, field);
262
+ }
263
+
264
+ /**
265
+ * Pick the most informative single-line summary of a tool's arguments for
266
+ * the header line. Known tools have a canonical "primary" arg (path,
267
+ * command, pattern, url); unknown tools or unexpected shapes fall back to a
268
+ * truncated JSON dump. Returns an empty string when args are absent so the
269
+ * header renders as `tool: <name>()`.
270
+ */
271
+ function summarizeWebFetchArgs(args: unknown): string {
272
+ if (!isPlainObject(args)) return summarizeArgs("", args);
273
+ const compact: Record<string, unknown> = {};
274
+ for (const key of ["url", "format", "max_bytes", "timeout_ms", "method"] as const) {
275
+ if (args[key] !== undefined) compact[key] = args[key];
276
+ }
277
+ return truncate(jsonStringifySafe(Object.keys(compact).length > 0 ? compact : args), WEB_FETCH_ARG_PREVIEW_LIMIT);
278
+ }
279
+
280
+ function summarizeArgs(toolName: string, args: unknown): string {
281
+ if (isEmptyArgs(args)) return "";
282
+ const safeArgs = redactToolArgs(args);
283
+ if (toolName === "web_fetch") return summarizeWebFetchArgs(safeArgs);
284
+ const primary = capturedPrimaryArg(toolName, args);
285
+ if (primary !== null) return truncate(displayArg(toolName, primary), ARG_PREVIEW_LIMIT);
286
+ return truncate(jsonStringifySafe(safeArgs), ARG_PREVIEW_LIMIT);
287
+ }
288
+
289
+ /**
290
+ * Compact resource-read classification. Reads of skill/handbook/agent
291
+ * instruction files and docs pages collapse to one labeled line and never
292
+ * auto-expand; their bodies are reference material, not task output.
293
+ */
294
+ export function classifyResourceRead(toolName: string, args: unknown): string | null {
295
+ if (toolName !== "read") return null;
296
+ const path = readStringField(args, "path");
297
+ if (path === null) return null;
298
+ const normalized = path.replace(/\\/g, "/");
299
+ const base = normalized.split("/").pop() ?? "";
300
+ if (base === "SKILL.md") return "skill";
301
+ if (base === "CLIO-CODER.md") return "handbook";
302
+ if (base === "AGENTS.md") return "agents";
303
+ if (/(^|\/)docs\//.test(normalized)) return "docs";
304
+ return null;
305
+ }
306
+
307
+ function detailsOf(result: unknown): Record<string, unknown> | null {
308
+ if (!isPlainObject(result)) return null;
309
+ return isPlainObject(result.details) ? result.details : null;
310
+ }
311
+
312
+ function observationOf(finished: ToolExecutionFinished): Record<string, unknown> | null {
313
+ const fromDetails = detailsOf(finished.result)?.observation;
314
+ if (isPlainObject(fromDetails)) return fromDetails;
315
+ const fromSummary = finished.resultSummary?.observation;
316
+ return isPlainObject(fromSummary) ? fromSummary : null;
317
+ }
318
+
319
+ function numberField(record: Record<string, unknown> | null, key: string): number | null {
320
+ const value = record?.[key];
321
+ return typeof value === "number" && Number.isFinite(value) ? value : null;
322
+ }
323
+
324
+ function stringField(record: Record<string, unknown> | null, key: string): string | null {
325
+ const value = record?.[key];
326
+ return typeof value === "string" && value.length > 0 ? value : null;
327
+ }
328
+
329
+ function countSummary(observation: Record<string, unknown>): string | null {
330
+ const unit = stringField(observation, "unit") ?? "results";
331
+ const shown = numberField(observation, "shownCount");
332
+ if (shown === null) return null;
333
+ const total = numberField(observation, "totalCount");
334
+ if (total === null) return `${shown}+ ${unit}`;
335
+ if (total === shown) return `${shown} ${unit}`;
336
+ return `${shown}/${total} ${unit}`;
337
+ }
338
+
339
+ /**
340
+ * Outcome facts for the collapsed ledger line, derived from the observation
341
+ * envelope (OBSERVE plane), the exec record (git/verify), or the dispatch
342
+ * receipt counts. Returns null when the result carries no recognizable facts.
343
+ */
344
+ function outcomeSummary(finished: ToolExecutionFinished): string | null {
345
+ const observation = observationOf(finished);
346
+ if (observation !== null) {
347
+ if (finished.toolName === "read") {
348
+ const shown = numberField(observation, "shownCount");
349
+ const total = numberField(observation, "totalCount");
350
+ if (shown !== null && total !== null) {
351
+ const offsetRaw = isPlainObject(finished.args) ? finished.args.offset : undefined;
352
+ const start = typeof offsetRaw === "number" && offsetRaw > 0 ? Math.floor(offsetRaw) : 1;
353
+ return shown > 0 ? `lines ${start}-${start + shown - 1} of ${total}` : `0 of ${total} lines`;
354
+ }
355
+ }
356
+ return countSummary(observation);
357
+ }
358
+ const details = detailsOf(finished.result);
359
+ if (finished.toolName === "git" || finished.toolName === "verify") {
360
+ const exitCode = numberField(details, "exitCode");
361
+ if (exitCode !== null) return `exit ${exitCode}`;
362
+ const status = stringField(details, "status");
363
+ if (status !== null) return status;
364
+ return null;
365
+ }
366
+ if (finished.toolName === "dispatch") {
367
+ const receipts = numberField(details, "receiptCount");
368
+ const failed = numberField(details, "failedCount") ?? 0;
369
+ if (receipts !== null) return `${receipts} task${receipts === 1 ? "" : "s"} -> ${receipts - failed} ok`;
370
+ return null;
371
+ }
372
+ if (finished.toolName === "tasks") {
373
+ const rawCounts = details?.counts;
374
+ const counts = isPlainObject(rawCounts) ? rawCounts : null;
375
+ const completed = numberField(counts, "completed");
376
+ const total = numberField(counts, "total");
377
+ if (completed !== null && total !== null) {
378
+ const blocked = numberField(counts, "blocked") ?? 0;
379
+ return `${completed}/${total} done${blocked > 0 ? ` · ${blocked} blocked` : ""}`;
380
+ }
381
+ return null;
382
+ }
383
+ return null;
384
+ }
385
+
386
+ function offloadPathOf(finished: ToolExecutionFinished): string | null {
387
+ const observation = observationOf(finished);
388
+ const fromObservation = stringField(observation, "offloadPath");
389
+ if (fromObservation !== null) return fromObservation;
390
+ const summary = finished.resultSummary ?? null;
391
+ const fromSummary = stringField(summary, "offloadPath");
392
+ if (fromSummary !== null) return fromSummary;
393
+ const resultSize = detailsOf(finished.result)?.resultSize;
394
+ return isPlainObject(resultSize) ? stringField(resultSize, "offloadPath") : null;
395
+ }
396
+
397
+ function shownBytesOf(finished: ToolExecutionFinished): number | null {
398
+ const observation = observationOf(finished);
399
+ const fromObservation = numberField(observation, "shownBytes");
400
+ if (fromObservation !== null) return fromObservation;
401
+ const resultSize = detailsOf(finished.result)?.resultSize;
402
+ const fromResultSize = isPlainObject(resultSize) ? numberField(resultSize, "shownBytes") : null;
403
+ if (fromResultSize !== null) return fromResultSize;
404
+ return numberField(finished.resultSummary ?? null, "bytes");
405
+ }
406
+
407
+ function totalBytesOf(finished: ToolExecutionFinished): number | null {
408
+ const observation = observationOf(finished);
409
+ const fromObservation = numberField(observation, "totalBytes");
410
+ if (fromObservation !== null) return fromObservation;
411
+ const resultSize = detailsOf(finished.result)?.resultSize;
412
+ if (isPlainObject(resultSize)) {
413
+ const total = numberField(resultSize, "bytes");
414
+ if (total !== null) return total;
415
+ }
416
+ return shownBytesOf(finished);
417
+ }
418
+
419
+ function resultSizeOf(finished: ToolExecutionFinished): Record<string, unknown> | null {
420
+ const value = detailsOf(finished.result)?.resultSize;
421
+ return isPlainObject(value) ? value : null;
422
+ }
423
+
424
+ function isTruncatedResult(finished: ToolExecutionFinished): boolean {
425
+ const observation = observationOf(finished);
426
+ if (observation?.truncated === true) return true;
427
+ if (resultSizeOf(finished)?.truncated === true) return true;
428
+ const truncation = detailsOf(finished.result)?.truncation;
429
+ if (isPlainObject(truncation) && truncation.truncated === true) return true;
430
+ return finished.resultSummary?.truncated === true;
431
+ }
432
+
433
+ function structuredExitCode(finished: ToolExecutionFinished): string | null {
434
+ if (isNonExecutedOutcome(finished.outcome)) return null;
435
+ if (finished.exitCode !== undefined && finished.exitCode !== null) return String(finished.exitCode);
436
+ const exitCode = detailsOf(finished.result)?.exitCode;
437
+ if (typeof exitCode === "number" || typeof exitCode === "string") return String(exitCode);
438
+ return finished.toolName === "bash" && finished.isError ? bashExitCodeFromResult(finished.result) : null;
439
+ }
440
+
441
+ /**
442
+ * The dim ledger tail appended to a finished collapsed subline: outcome facts,
443
+ * then byte size (duration rides on the status glyph), then the offload path
444
+ * for truncated calls. One line of plain text carries signature and outcome
445
+ * when copied.
446
+ */
447
+ function ledgerTail(finished: ToolExecutionFinished): { facts: string; offload: string } {
448
+ const parts: string[] = [];
449
+ const outcome = outcomeSummary(finished);
450
+ if (outcome !== null) parts.push(outcome);
451
+ const bytes = isNonExecutedOutcome(finished.outcome) ? null : shownBytesOf(finished);
452
+ if (bytes !== null && bytes > 0) parts.push(formatSize(bytes));
453
+ const offloadPath = offloadPathOf(finished);
454
+ return {
455
+ facts: parts.length > 0 ? dim(` · ${parts.join(" · ")}`) : "",
456
+ offload: offloadPath !== null ? dim(` · full: ${offloadPath}`) : "",
457
+ };
458
+ }
459
+
460
+ /**
461
+ * Marker for a call parked at admission awaiting operator approval. Rendered
462
+ * in place of the elapsed counter so a parked call never reads as executing
463
+ * work; the ⏸ glyph matches the footer's blocked phase.
464
+ */
465
+ const AWAITING_APPROVAL_TAIL = ` ${yellow(GLYPH.phaseBlocked)}${dim(" awaiting approval")}`;
466
+
467
+ /**
468
+ * Subline for an in-flight call whose body is parked at the permission gate.
469
+ * No elapsed counter (nothing is running) and no status glyph (nothing has
470
+ * finished): the awaiting-approval tail is the segment's whole state.
471
+ */
472
+ export function renderToolAwaitingApproval(
473
+ call: ToolExecutionStart,
474
+ width: number,
475
+ view?: ApprovalRequestView,
476
+ ): string[] {
477
+ const parts = sublineParts({ toolCallId: call.toolCallId, toolName: call.toolName, args: call.args }, undefined, {});
478
+ const lines = wrapSublineWithTail(parts.lead, AWAITING_APPROVAL_TAIL, width);
479
+ if (view === undefined) return lines;
480
+ const axis = view.axis.kind === "net" ? `safety-net rail ${view.axis.ruleId}` : `autonomy level ${view.axis.level}`;
481
+ const facts = [
482
+ ["action", view.actionClass],
483
+ ["axis", axis],
484
+ ...(view.target !== undefined && view.target.length > 0 ? [["target", view.target]] : []),
485
+ ] as const;
486
+ for (const [label, value] of facts) {
487
+ lines.push(...indentAndWrap(`${dim(`${label} ·`)} ${value}`, width, false));
488
+ }
489
+ return lines;
490
+ }
491
+
492
+ /**
493
+ * Header status follows Pi's call lifecycle before and during execution, then
494
+ * becomes `"ok"` or `"error"` at settlement. The
495
+ * glyph hangs off the right of the header line so the tool name + args read
496
+ * left-to-right without extra punctuation.
497
+ */
498
+ type HeaderStatus = "forming" | "ready" | "running" | "ok" | "error" | undefined;
499
+
500
+ /** Keeps a refusal reason to one scannable clause on the status tail. */
501
+ const BLOCK_REASON_LIMIT = 72;
502
+
503
+ interface StatusMeta {
504
+ durationMs?: number | undefined;
505
+ elapsedMs?: number | undefined;
506
+ exitCode?: string | null;
507
+ outcome?: ToolExecutionFinished["outcome"];
508
+ /** Refusal reason, rendered only alongside a non-executed outcome. */
509
+ blockReason?: string | undefined;
510
+ }
511
+
512
+ function statusGlyph(status: HeaderStatus, meta: StatusMeta = {}): string {
513
+ if (status === undefined) return "";
514
+ if (status === "forming") return ` ${dim(GLYPH.queued)}${dim(" forming call")}`;
515
+ if (status === "ready") return ` ${dim(GLYPH.queued)}${dim(" ready")}`;
516
+ if (status === "running") {
517
+ const elapsed = optionalCompactMs(meta.elapsedMs);
518
+ return ` ${cyan(GLYPH.running)}${dim(elapsed === null ? " running" : ` running · ${elapsed}`)}`;
519
+ }
520
+ const duration = optionalCompactMs(meta.durationMs);
521
+ const durationSuffix = duration ? dim(` · ${duration}`) : "";
522
+ if (status === "ok") return ` ${green(STATUS_OK_GLYPH)}${durationSuffix}`;
523
+ const exitSuffix = meta.exitCode ? dim(` (exit ${meta.exitCode})`) : "";
524
+ const outcomeSuffix = meta.outcome ? dim(` ${meta.outcome}`) : "";
525
+ // A refusal that names no rule tells the operator only that something was
526
+ // stopped. The reason rides the same tail as the outcome word so the
527
+ // collapsed subline and the expanded header state it identically.
528
+ const reason = meta.outcome !== undefined ? meta.blockReason?.trim() : undefined;
529
+ const reasonSuffix = reason ? dim(` · ${truncate(reason, BLOCK_REASON_LIMIT)}`) : "";
530
+ return ` ${red(STATUS_ERROR_GLYPH)}${outcomeSuffix}${reasonSuffix}${exitSuffix}${durationSuffix}`;
531
+ }
532
+
533
+ function headerLine(toolName: string, args: unknown, status: HeaderStatus, meta: StatusMeta = {}): string {
534
+ const summary = summarizeArgs(toolName, args);
535
+ const head = `${dim(HEADER_PREFIX_PLAIN)}${cyanBold(toolName)}${dim("(")}${cyan(summary)}${dim(")")}`;
536
+ return `${head}${statusGlyph(status, meta)}`;
537
+ }
538
+
539
+ function sublineLead(token: string, rest: string): string {
540
+ return `${cyanBold(token)}${rest}`;
541
+ }
542
+
543
+ function styleSublineBody(body: string): string {
544
+ const match = /^(?<lead>[^ (]+)(?<rest>.*)$/u.exec(body);
545
+ if (match?.groups?.lead === undefined || match.groups.rest === undefined) return body;
546
+ return sublineLead(match.groups.lead, match.groups.rest);
547
+ }
548
+
549
+ function buildUnknownToolBody(toolName: string, args: unknown): string {
550
+ return `${toolName}(${summarizeArgs(toolName, args)})`;
551
+ }
552
+
553
+ function buildFieldSublineBody(
554
+ args: unknown,
555
+ key: string,
556
+ lead: string,
557
+ options: { wrapInBackticks?: boolean } = {},
558
+ ): string | null {
559
+ const value = readStringField(args, key);
560
+ if (value === null) return null;
561
+ const preview = truncate(key === "command" ? stripShellWrapperForDisplay(value) : value, ARG_PREVIEW_LIMIT);
562
+ if (options.wrapInBackticks) return `${lead}\`${preview}\``;
563
+ return `${lead}${preview}`;
564
+ }
565
+
566
+ function dispatchSublineBody(args: unknown): string | null {
567
+ if (!isPlainObject(args)) return null;
568
+ if (args.list === true) return "listing fleet agents";
569
+ const sharedAgent =
570
+ (typeof args.agent === "string" && args.agent.trim()) ||
571
+ (typeof args.agent_id === "string" && args.agent_id.trim()) ||
572
+ "coder";
573
+ let rawTasks: unknown = args.tasks;
574
+ if (typeof rawTasks === "string") {
575
+ const trimmed = rawTasks.trim();
576
+ if (trimmed.startsWith("[") || trimmed.startsWith("{")) {
577
+ try {
578
+ rawTasks = JSON.parse(trimmed) as unknown;
579
+ } catch {
580
+ // Keep the string as one plain task; dispatch itself reports malformed JSON.
581
+ }
582
+ }
583
+ }
584
+ const tasks = Array.isArray(rawTasks) ? rawTasks : rawTasks === undefined ? [] : [rawTasks];
585
+ if (tasks.length === 0) return null;
586
+ const first = tasks[0];
587
+ const record = isPlainObject(first) ? first : null;
588
+ const agent =
589
+ (record && typeof record.agent === "string" && record.agent.trim()) ||
590
+ (record && typeof record.agent_id === "string" && record.agent_id.trim()) ||
591
+ sharedAgent;
592
+ const taskText = typeof first === "string" ? first : record && typeof record.task === "string" ? record.task : "";
593
+ const taskPreview = truncate(sanitizeCallTargetText(taskText), ARG_PREVIEW_LIMIT);
594
+ const more = tasks.length > 1 ? ` +${tasks.length - 1} more` : "";
595
+ if (taskPreview.length === 0) return `dispatching ${tasks.length} task${tasks.length === 1 ? "" : "s"}${more}`;
596
+ return `dispatching ${agent}: ${taskPreview}${more}`;
597
+ }
598
+
599
+ const SUBLINE_BODY_BUILDERS: Readonly<Record<string, (args: unknown) => string | null>> = {
600
+ read: (args) => buildFieldSublineBody(args, "path", "reading "),
601
+ edit: (args) => buildFieldSublineBody(args, "path", "editing "),
602
+ write: (args) => buildFieldSublineBody(args, "path", "writing "),
603
+ ls: (args) => buildFieldSublineBody(args, "path", "listing "),
604
+ bash: (args) => buildFieldSublineBody(args, "command", "running ", { wrapInBackticks: true }),
605
+ grep: (args) => buildFieldSublineBody(args, "pattern", "searching for ", { wrapInBackticks: true }),
606
+ find: (args) => buildFieldSublineBody(args, "pattern", "finding ", { wrapInBackticks: true }),
607
+ git: (args) => buildFieldSublineBody(args, "op", "git "),
608
+ verify: (args) => buildFieldSublineBody(args, "check", "verifying "),
609
+ code_nav: (args) => {
610
+ const mode = readStringField(args, "mode");
611
+ const query = readStringField(args, "query")?.trim() ?? "";
612
+ const queryPart = query.length > 0 ? ` \`${truncate(query, ARG_PREVIEW_LIMIT)}\`` : "";
613
+ if (mode !== null && mode.length > 0) return `navigating ${mode}${queryPart}`;
614
+ return queryPart.length > 0 ? `navigating${queryPart}` : null;
615
+ },
616
+ context: (args) => {
617
+ const scope = readStringField(args, "scope");
618
+ if (scope === null || scope.length === 0) return null;
619
+ const query = readStringField(args, "query")?.trim() ?? "";
620
+ const name = readStringField(args, "name")?.trim() ?? "";
621
+ if (scope === "docs" && query.length > 0) return `context docs \`${truncate(query, ARG_PREVIEW_LIMIT)}\``;
622
+ if (scope === "skills" && name.length > 0) return `context skills ${truncate(name, ARG_PREVIEW_LIMIT)}`;
623
+ return `context ${scope}`;
624
+ },
625
+ artifact: (args) => buildFieldSublineBody(args, "kind", "writing "),
626
+ monitor: (args) => buildFieldSublineBody(args, "run_id", "monitoring "),
627
+ steer: (args) => buildFieldSublineBody(args, "run_id", "steering "),
628
+ tasks: (args) => {
629
+ const action = readStringField(args, "action");
630
+ if (action === null) return null;
631
+ if (action === "plan") {
632
+ const title = readStringField(args, "title");
633
+ return title === null ? "tasks plan" : `tasks plan ${truncate(`"${title}"`, ARG_PREVIEW_LIMIT)}`;
634
+ }
635
+ const id = readStringField(args, "id");
636
+ return id === null ? `tasks ${action}` : `tasks ${action} ${id}`;
637
+ },
638
+ dispatch: dispatchSublineBody,
639
+ };
640
+
641
+ /**
642
+ * Per-tool subline templates. Maps a tool name to a function that builds the
643
+ * verb-led subline body without the leading glyph and without the trailing
644
+ * status glyph. Unknown tools fall back to the existing `<name>(<arg>)` form.
645
+ */
646
+ function webFetchMeta(result: unknown): string | null {
647
+ if (!isPlainObject(result) || !isPlainObject(result.details)) return null;
648
+ const status = typeof result.details.status === "number" ? String(result.details.status) : null;
649
+ const format = typeof result.details.format === "string" ? result.details.format : null;
650
+ const bytesRead = typeof result.details.bytesRead === "number" ? result.details.bytesRead : null;
651
+ const truncated = result.details.truncated === true ? "truncated" : null;
652
+ const bytes = bytesRead === null ? null : bytesRead >= 1024 ? `${(bytesRead / 1024).toFixed(1)}KB` : `${bytesRead}B`;
653
+ const parts = [status, format, bytes, truncated].filter(
654
+ (part): part is string => typeof part === "string" && part.length > 0,
655
+ );
656
+ return parts.length > 0 ? parts.join(" · ") : null;
657
+ }
658
+
659
+ /**
660
+ * A call the permission gate blocked never executed, so the collapsed row must
661
+ * not claim it did. `ran \`id\` · 667B ✗ blocked` read as a command that ran and
662
+ * produced 667 bytes, while the expanded header for the same node correctly said
663
+ * `bash(id) ✗ blocked`. Blocked rows use that same call-signature form, and the
664
+ * ledger byte count is suppressed because those bytes are the denial text, not
665
+ * output.
666
+ */
667
+ function isNonExecutedOutcome(outcome: ToolExecutionFinished["outcome"]): boolean {
668
+ return outcome === "blocked";
669
+ }
670
+
671
+ function buildSublineBody(
672
+ toolName: string,
673
+ args: unknown,
674
+ status: HeaderStatus,
675
+ result?: unknown,
676
+ outcome?: ToolExecutionFinished["outcome"],
677
+ ): string {
678
+ if (isNonExecutedOutcome(outcome)) return buildUnknownToolBody(toolName, args);
679
+ if (status === "forming" || status === "ready") return buildUnknownToolBody(toolName, args);
680
+ if (toolName === "web_fetch") {
681
+ const meta = status === undefined ? null : webFetchMeta(result);
682
+ return `${buildUnknownToolBody(toolName, args)}${meta ? dim(` · ${meta}`) : ""}`;
683
+ }
684
+ if (toolName === "bash") {
685
+ const lead = status === "running" || status === undefined ? "running " : "ran ";
686
+ return (
687
+ buildFieldSublineBody(args, "command", lead, { wrapInBackticks: true }) ?? buildUnknownToolBody(toolName, args)
688
+ );
689
+ }
690
+ const body = SUBLINE_BODY_BUILDERS[toolName]?.(args);
691
+ if (body !== null && body !== undefined) return body;
692
+ return buildUnknownToolBody(toolName, args);
693
+ }
694
+
695
+ interface SublineParts {
696
+ /** Verb, object, and ledger facts. Breakable across wraps. */
697
+ lead: string;
698
+ /**
699
+ * Status glyph, duration, and any offload path, composed as one unit. The
700
+ * caller appends the expand hint here so the whole tail stays atomic: a wrap
701
+ * may fall before the status glyph but never between the glyph, the
702
+ * duration, and the hint. Begins with a joining space so it attaches to the
703
+ * lead's last line when they share a row. Empty for in-flight calls, which
704
+ * carry no status glyph.
705
+ */
706
+ tail: string;
707
+ }
708
+
709
+ function sublineParts(
710
+ call: ToolExecutionStart | ToolExecutionFinished,
711
+ status: HeaderStatus,
712
+ meta: StatusMeta,
713
+ ): SublineParts {
714
+ const finished = "result" in call ? call : null;
715
+ const body = styleSublineBody(buildSublineBody(call.toolName, call.args, status, finished?.result, finished?.outcome));
716
+ const resourceLabel = classifyResourceRead(call.toolName, call.args);
717
+ const resource = resourceLabel !== null ? dim(` · ${resourceLabel}`) : "";
718
+ if (finished !== null) {
719
+ const ledger = ledgerTail(finished);
720
+ return {
721
+ lead: `${dim(HEADER_PREFIX_PLAIN)}${body}${resource}${ledger.facts}`,
722
+ tail: `${statusGlyph(status, meta)}${ledger.offload}`,
723
+ };
724
+ }
725
+ return { lead: `${dim(HEADER_PREFIX_PLAIN)}${body}${resource}`, tail: statusGlyph(status, meta) };
726
+ }
727
+
728
+ /**
729
+ * Wrap a collapsed subline while keeping its status tail atomic. The lead wraps
730
+ * normally; the tail (status glyph, duration, offload, and the optional expand
731
+ * hint) is placed as a single unit. When the whole line fits it renders on one
732
+ * row; otherwise the tail joins the lead's last wrapped line if it fits there,
733
+ * and only falls to its own row when it cannot, so the status glyph and
734
+ * duration are never separated by a wrap.
735
+ */
736
+ function wrapSublineWithTail(lead: string, tail: string, width: number): string[] {
737
+ if (tail.length === 0) return wrap(lead, width);
738
+ if (visibleWidth(`${lead}${tail}`) <= width) return [`${lead}${tail}`];
739
+ const leadLines = wrap(lead, width);
740
+ const last = leadLines[leadLines.length - 1];
741
+ if (last !== undefined && visibleWidth(`${last}${tail}`) <= width) {
742
+ leadLines[leadLines.length - 1] = `${last}${tail}`;
743
+ return leadLines;
744
+ }
745
+ // The tail cannot sit beside the lead: give it its own row, dropping the
746
+ // joining leading space so it starts flush at the left.
747
+ return [...leadLines, ...wrap(tail.replace(/^ +/u, ""), width)];
748
+ }
749
+
750
+ function wrap(line: string, width: number): string[] {
751
+ return wrapTextWithAnsi(line, width);
752
+ }
753
+
754
+ /**
755
+ * Apply the body rail to a line and wrap it. The rail (`│ `) is dim by
756
+ * default and red on error so the tool block reads as a single visual unit
757
+ * even when its result spans many lines. Uses the hoisted `RAIL_DIM` /
758
+ * `RAIL_ERROR` constants so we do not allocate a fresh styled prefix per
759
+ * wrapped line.
760
+ */
761
+ function indentAndWrap(line: string, width: number, isError: boolean): string[] {
762
+ const rail = isError ? RAIL_ERROR : RAIL_DIM;
763
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
764
+ const out: string[] = [];
765
+ for (const wrapped of wrap(line, bodyWidth)) {
766
+ out.push(`${rail}${wrapped}`);
767
+ }
768
+ return out;
769
+ }
770
+
771
+ function scalarArgValue(value: unknown): string | null {
772
+ if (typeof value === "string") {
773
+ const lines = value.split("\n").length;
774
+ const bytes = Buffer.byteLength(value, "utf8");
775
+ if (lines > 1 || value.length > 160) return dim(`<${lines} lines · ${formatSize(bytes)} text>`);
776
+ return green(JSON.stringify(value));
777
+ }
778
+ if (typeof value === "number") return cyan(String(value));
779
+ if (typeof value === "boolean") return yellow(String(value));
780
+ if (value === null) return dim("null");
781
+ return null;
782
+ }
783
+
784
+ /**
785
+ * Render secondary arguments as a compact typed field list. The primary path,
786
+ * command, pattern, or query already lives in the call signature; keeping the
787
+ * rest means `cwd`, timeout, range, glob, and flags no longer disappear merely
788
+ * because one field was important enough for the header. Nested values retain
789
+ * the structured JSON renderer, while large strings become byte/line facts
790
+ * instead of flooding the transcript.
791
+ */
792
+ function renderArgsBody(toolName: string, args: unknown, width: number, isError: boolean): string[] {
793
+ if (isEmptyArgs(args)) return [];
794
+ const safeArgs = redactToolArgs(args);
795
+ if (!isPlainObject(safeArgs)) {
796
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
797
+ const lines = tryRenderJson(safeArgs, bodyWidth, { lineLimit: ARGS_BODY_LINE_LIMIT });
798
+ return lines?.flatMap((line) => indentAndWrap(line, width, isError)) ?? [];
799
+ }
800
+ const primary = PRIMARY_ARG_FIELD[toolName];
801
+ const entries = Object.entries(safeArgs).filter(([key]) => key !== primary);
802
+ if (entries.length === 0) return [];
803
+ const out: string[] = [];
804
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
805
+ out.push(...indentAndWrap(`${cyanBold("args")}${dim(` · ${entries.length}`)}`, width, isError));
806
+ const keyWidth = Math.min(18, Math.max(...entries.map(([key]) => visibleWidth(key))));
807
+ for (const [key, value] of entries) {
808
+ const label = `${cyan(key.padEnd(keyWidth))} `;
809
+ const scalar = scalarArgValue(value);
810
+ if (scalar !== null) {
811
+ out.push(...indentAndWrap(`${label}${scalar}`, width, isError));
812
+ continue;
813
+ }
814
+ out.push(...indentAndWrap(cyan(key), width, isError));
815
+ const lines = tryRenderJson(value, Math.max(1, bodyWidth - 2), { lineLimit: ARGS_BODY_LINE_LIMIT });
816
+ for (const line of lines ?? [jsonStringifySafe(value)]) {
817
+ out.push(...indentAndWrap(` ${line}`, width, isError));
818
+ if (out.length >= ARGS_BODY_LINE_LIMIT) break;
819
+ }
820
+ if (out.length >= ARGS_BODY_LINE_LIMIT) break;
821
+ }
822
+ if (out.length >= ARGS_BODY_LINE_LIMIT) out.push(...indentAndWrap(dim("… more arguments hidden"), width, isError));
823
+ return out;
824
+ }
825
+
826
+ /**
827
+ * pi-agent-core wraps tool results in `{ content: [{ type: "text", text }, ...] }`
828
+ * envelopes. Rendering that JSON verbatim hides the actual output and, for a
829
+ * mixed result, can dump a base64 image into the terminal. Text blocks are
830
+ * joined, image blocks become compact MIME/size placeholders, and unknown
831
+ * content blocks are named without serializing their payload.
832
+ */
833
+ function unwrapResultEnvelope(result: unknown): unknown {
834
+ if (typeof result === "string" || result === null || result === undefined) return result;
835
+ const blocks = Array.isArray(result)
836
+ ? result
837
+ : isPlainObject(result) && Array.isArray(result.content)
838
+ ? result.content
839
+ : null;
840
+ if (blocks === null) return result;
841
+ const parts: string[] = [];
842
+ for (const block of blocks) {
843
+ if (!isPlainObject(block)) return result;
844
+ if (block.type === "text" && typeof block.text === "string") {
845
+ parts.push(block.text);
846
+ continue;
847
+ }
848
+ if (block.type === "image" && typeof block.data === "string") {
849
+ const mimeType = typeof block.mimeType === "string" ? block.mimeType : "image/unknown";
850
+ const padding = block.data.endsWith("==") ? 2 : block.data.endsWith("=") ? 1 : 0;
851
+ const bytes = Math.max(0, Math.floor((block.data.length * 3) / 4) - padding);
852
+ parts.push(`[image ${mimeType} · ${formatSize(bytes)}]`);
853
+ continue;
854
+ }
855
+ if (typeof block.type === "string") {
856
+ parts.push(`[${block.type} content]`);
857
+ continue;
858
+ }
859
+ return result;
860
+ }
861
+ if (parts.length === 0) return result;
862
+ return parts.join("\n");
863
+ }
864
+
865
+ function isEmptyResult(result: unknown): boolean {
866
+ if (result === null || result === undefined) return true;
867
+ if (typeof result === "string" && result.length === 0) return true;
868
+ return false;
869
+ }
870
+
871
+ function resultText(result: unknown, limit = FULL_RESULT_PREVIEW_LIMIT): string {
872
+ if (typeof result === "string") return truncate(result, limit);
873
+ return truncate(jsonStringifySafe(result), limit);
874
+ }
875
+
876
+ function truncateRowsMiddle(rows: ReadonlyArray<string>, rowLimit: number, isError: boolean): string[] {
877
+ if (rows.length <= rowLimit) return [...rows];
878
+ if (rowLimit <= 1) return [`${isError ? RAIL_ERROR : RAIL_DIM}${dim(`... ${rows.length} lines hidden`)}`];
879
+ const available = rowLimit - 1;
880
+ const head = Math.floor(available / 2);
881
+ const tail = available - head;
882
+ const hidden = Math.max(0, rows.length - head - tail);
883
+ return [
884
+ ...rows.slice(0, head),
885
+ `${isError ? RAIL_ERROR : RAIL_DIM}${dim(`... ${hidden} lines hidden`)}`,
886
+ ...rows.slice(-tail),
887
+ ];
888
+ }
889
+
890
+ function renderOutputRows(text: string, width: number, isError: boolean, rowLimit: number): string[] {
891
+ const rows: string[] = [];
892
+ for (const raw of text.split("\n")) {
893
+ rows.push(...indentAndWrap(raw, width, isError));
894
+ }
895
+ return truncateRowsMiddle(rows, rowLimit, isError);
896
+ }
897
+
898
+ function renderStructuredOutputRows(
899
+ value: unknown,
900
+ width: number,
901
+ isError: boolean,
902
+ rowLimit: number,
903
+ ): string[] | null {
904
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
905
+ const unwrapped = unwrapResultEnvelope(value);
906
+ const structured =
907
+ typeof unwrapped === "string"
908
+ ? (tryRenderJson(unwrapped, bodyWidth, { lineLimit: rowLimit }) ??
909
+ tryRenderXml(unwrapped, bodyWidth, { lineLimit: rowLimit }))
910
+ : tryRenderJson(unwrapped, bodyWidth, { lineLimit: rowLimit });
911
+ if (!structured) return null;
912
+ const out: string[] = [];
913
+ for (const row of structured) out.push(...indentAndWrap(row, width, isError));
914
+ return out;
915
+ }
916
+
917
+ function highlightBashCommand(command: string): string {
918
+ const tokens = command.match(/'[^']*'|"[^"]*"|\|\||&&|[|;()<>]|[^\s|;&()<>]+|\s+/gu) ?? [command];
919
+ return tokens
920
+ .map((token) => {
921
+ if (/^\s+$/u.test(token)) return token;
922
+ if (/^'[^']*'$|^"[^"]*"$/u.test(token)) return green(token);
923
+ if (/^(?:\|\||&&|[|;()<>])$/u.test(token)) return dim(token);
924
+ if (/^-{1,2}[\w-]+/u.test(token)) return yellow(token);
925
+ return token;
926
+ })
927
+ .join("");
928
+ }
929
+
930
+ function resultDiff(result: unknown): string | null {
931
+ const value = detailsOf(result)?.diff;
932
+ return typeof value === "string" && value.length > 0 ? value : null;
933
+ }
934
+
935
+ function renderMutationDiffBlock(diff: string, width: number, color: boolean): string[] {
936
+ const bodyWidth = Math.max(1, width - BODY_INDENT_VISIBLE_WIDTH);
937
+ return renderDiffLines(diff, bodyWidth, { color }).map((line) => `${RAIL_DIM}${line}`);
938
+ }
939
+
940
+ interface BashArgs {
941
+ command: string;
942
+ }
943
+
944
+ /**
945
+ * Defensive shape check: bash-tool args must carry a string `command` for the
946
+ * `$ <cmd>` echo line to render. Anything else falls through to the standard
947
+ * result block so the dispatch is opportunistic and never throws.
948
+ */
949
+ function asBashArgs(args: unknown): BashArgs | null {
950
+ if (!isPlainObject(args)) return null;
951
+ const command = args.command;
952
+ if (typeof command !== "string") return null;
953
+ return { command: redactSecretString(command) };
954
+ }
955
+
956
+ function resultLineCount(result: unknown): number {
957
+ const unwrapped = unwrapResultEnvelope(result);
958
+ if (typeof unwrapped !== "string" || unwrapped.length === 0) return 0;
959
+ const normalized = unwrapped.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
960
+ const withoutTerminator = normalized.endsWith("\n") ? normalized.slice(0, -1) : normalized;
961
+ return withoutTerminator.split("\n").length;
962
+ }
963
+
964
+ function toolUsageFact(result: unknown): string | null {
965
+ if (!isPlainObject(result) || !isPlainObject(result.usage)) return null;
966
+ const total = numberField(result.usage, "totalTokens");
967
+ if (total === null || total <= 0) return null;
968
+ return `${total} tool token${total === 1 ? "" : "s"}`;
969
+ }
970
+
971
+ function outputFacts(finished: ToolExecutionFinished): string[] {
972
+ const parts: string[] = [];
973
+ if (isNonExecutedOutcome(finished.outcome)) {
974
+ if (finished.excludeFromContext === true) parts.push("excluded from context");
975
+ return parts;
976
+ }
977
+ const exitCode = structuredExitCode(finished) ?? (finished.toolName === "bash" && !finished.isError ? "0" : null);
978
+ if (exitCode !== null) parts.push(`exit ${exitCode}`);
979
+ const observation = observationOf(finished);
980
+ const count = observation === null ? null : countSummary(observation);
981
+ if (count !== null) parts.push(count);
982
+ const lines = resultLineCount(finished.result);
983
+ if (count === null && lines > 0) parts.push(`${lines} line${lines === 1 ? "" : "s"}`);
984
+ const shownBytes = shownBytesOf(finished);
985
+ const totalBytes = totalBytesOf(finished);
986
+ if (shownBytes !== null && shownBytes > 0) {
987
+ parts.push(
988
+ totalBytes !== null && totalBytes > shownBytes
989
+ ? `${formatSize(shownBytes)} shown / ${formatSize(totalBytes)} total`
990
+ : formatSize(shownBytes),
991
+ );
992
+ }
993
+ if (isTruncatedResult(finished)) parts.push("truncated");
994
+ const details = detailsOf(finished.result);
995
+ if (details?.timedOut === true) parts.push("timed out");
996
+ if (details?.outputCapped === true) parts.push("output capped");
997
+ const usage = toolUsageFact(finished.result);
998
+ if (usage !== null) parts.push(usage);
999
+ if (isPlainObject(finished.result) && Array.isArray(finished.result.addedToolNames)) {
1000
+ const added = finished.result.addedToolNames.filter((name): name is string => typeof name === "string");
1001
+ if (added.length > 0) parts.push(`added ${added.join(", ")}`);
1002
+ }
1003
+ if (isPlainObject(finished.result) && finished.result.terminate === true) parts.push("terminal result");
1004
+ if (finished.excludeFromContext === true) parts.push("excluded from context");
1005
+ return parts;
1006
+ }
1007
+
1008
+ function renderOutputMeta(
1009
+ finished: ToolExecutionFinished,
1010
+ width: number,
1011
+ isError: boolean,
1012
+ label = "output",
1013
+ ): string[] {
1014
+ const facts = outputFacts(finished);
1015
+ const suffix = facts.length > 0 ? dim(` · ${facts.join(" · ")}`) : "";
1016
+ return indentAndWrap(`${cyanBold(label)}${suffix}`, width, isError);
1017
+ }
1018
+
1019
+ function renderOutputFooter(finished: ToolExecutionFinished, width: number, isError: boolean): string[] {
1020
+ const out: string[] = [];
1021
+ const offloadPath = isNonExecutedOutcome(finished.outcome) ? null : offloadPathOf(finished);
1022
+ if (offloadPath !== null) out.push(...indentAndWrap(`${yellow("full output")} ${offloadPath}`, width, isError));
1023
+ const hint =
1024
+ stringField(resultSizeOf(finished), "followUpHint") ?? stringField(finished.resultSummary ?? null, "followUpHint");
1025
+ if (hint !== null) out.push(...indentAndWrap(`${dim("next")} ${hint}`, width, isError));
1026
+ return out;
1027
+ }
1028
+
1029
+ /**
1030
+ * Bash subrenderer: emits `$ <cmd>` (full command) on its own line under the
1031
+ * rail, then the unwrapped output via the same chain as `renderResultBlock`.
1032
+ * Mirrors pi-coding-agent's bash component shape so users see exactly what
1033
+ * was executed before the output. Failures use the same command and output
1034
+ * body while the caller selects the red rail and error status.
1035
+ */
1036
+ function renderBashResultBlock(
1037
+ args: BashArgs,
1038
+ result: unknown,
1039
+ width: number,
1040
+ isError: boolean,
1041
+ opts: ToolBodyRenderOptions = {},
1042
+ ): string[] {
1043
+ const out: string[] = [];
1044
+ const commandLine = `${cyanBold("$")} ${highlightBashCommand(stripShellWrapperForDisplay(args.command))}`;
1045
+ out.push(...indentAndWrap(commandLine, width, isError));
1046
+ const unwrapped = unwrapResultEnvelope(result);
1047
+ if (isEmptyResult(unwrapped)) {
1048
+ out.push(...indentAndWrap(dim("(no output)"), width, isError));
1049
+ return out;
1050
+ }
1051
+ out.push(...renderOutputRows(resultText(unwrapped, resultCharLimit(opts)), width, isError, resultRowLimit(opts)));
1052
+ return out;
1053
+ }
1054
+
1055
+ function renderResultBlock(
1056
+ result: unknown,
1057
+ isError: boolean,
1058
+ width: number,
1059
+ opts: ToolBodyRenderOptions = {},
1060
+ ): string[] {
1061
+ const unwrapped = unwrapResultEnvelope(result);
1062
+ if (isEmptyResult(unwrapped)) {
1063
+ return indentAndWrap(dim("(no output)"), width, isError);
1064
+ }
1065
+ const structured = renderStructuredOutputRows(unwrapped, width, isError, resultRowLimit(opts));
1066
+ if (structured) return structured;
1067
+ return renderOutputRows(resultText(unwrapped, resultCharLimit(opts)), width, isError, resultRowLimit(opts));
1068
+ }
1069
+
1070
+ /**
1071
+ * Header-only render for a tool call that has not yet finished. Used by the
1072
+ * live chat panel from streamed argument formation through execution. The
1073
+ * lifecycle tail distinguishes a forming call, a ready call, and a running
1074
+ * call without inventing execution time before Pi starts the tool.
1075
+ */
1076
+ export function renderToolCallHeader(call: ToolExecutionStart, width: number): string[] {
1077
+ return wrap(
1078
+ headerLine(call.toolName, call.args, call.phase ?? "running", {
1079
+ elapsedMs: call.elapsedMs,
1080
+ }),
1081
+ width,
1082
+ );
1083
+ }
1084
+
1085
+ /** Running-only footer used when an operator pauses live output; execution continues. */
1086
+ export function renderToolRunningStatus(call: ToolExecutionStart, width: number): string[] {
1087
+ const elapsed = optionalCompactMs(call.elapsedMs);
1088
+ return [
1089
+ ...renderToolCallHeader(call, width),
1090
+ ...indentAndWrap(dim(elapsed ? `live output paused · ${elapsed}` : "live output paused"), width, false),
1091
+ ];
1092
+ }
1093
+
1094
+ function sublineStatus(call: ToolExecutionStart | ToolExecutionFinished): HeaderStatus {
1095
+ // Discriminate on `result` rather than `isError`: only `ToolExecutionFinished`
1096
+ // carries a `result` field, so a `ToolExecutionStart` with a stray
1097
+ // `isError: false` (e.g. from a future event-shape change) cannot trip the
1098
+ // finished path. `result` is the type's load-bearing field.
1099
+ if (!("result" in call)) return call.phase ?? "running";
1100
+ return call.isError ? "error" : "ok";
1101
+ }
1102
+
1103
+ /**
1104
+ * One-line subline form of a tool call. Format:
1105
+ * ▸ <body><status>
1106
+ * `status` is "" for in-flight, " ✓" green for success, " ✗" red for error.
1107
+ * Output is width-wrapped via wrapTextWithAnsi.
1108
+ *
1109
+ * When `expandKey` is supplied AND the call has finished, a dim ` (<key>)`
1110
+ * discoverability hint rides at the very end of the atomic status tail so users
1111
+ * see how to expand the collapsed block. Composing the full line (facts, status
1112
+ * glyph, duration, offload, and hint) before wrapping keeps the status glyph
1113
+ * and duration together on one row. The hint is suppressed for in-flight calls
1114
+ * (still running, no useful body to expand yet) and when `expandKey` is
1115
+ * empty/undefined (no key bound, hint would be misleading). The renderer never
1116
+ * imports the keybindings manager directly; the caller resolves the key string
1117
+ * and passes it in to keep this module pure.
1118
+ */
1119
+ export function renderToolSubline(
1120
+ call: ToolExecutionStart | ToolExecutionFinished,
1121
+ width: number,
1122
+ expandKey?: string,
1123
+ ): string[] {
1124
+ const status = sublineStatus(call);
1125
+ const meta: StatusMeta =
1126
+ "result" in call
1127
+ ? {
1128
+ durationMs: call.durationMs,
1129
+ exitCode: structuredExitCode(call),
1130
+ outcome: call.outcome,
1131
+ blockReason: call.blockReason,
1132
+ }
1133
+ : { elapsedMs: call.elapsedMs };
1134
+ const parts = sublineParts(call, status, meta);
1135
+ const showHint = "result" in call && expandKey !== undefined && expandKey.length > 0;
1136
+ const tail = showHint ? `${parts.tail}${dim(` (${expandKey})`)}` : parts.tail;
1137
+ return wrapSublineWithTail(parts.lead, tail, width);
1138
+ }
1139
+
1140
+ /**
1141
+ * Full render: header + args body (if non-empty) + result block. Used by
1142
+ * the live chat panel on `tool_execution_end` and by the replay path when a
1143
+ * tool result can be paired with its prior call's args. Header carries a
1144
+ * green check on success and a red cross on error so the user can scan tool
1145
+ * outcomes without reading the body.
1146
+ */
1147
+ export function renderToolExecution(
1148
+ finished: ToolExecutionFinished,
1149
+ width: number,
1150
+ opts: ToolBodyRenderOptions = {},
1151
+ ): string[] {
1152
+ const status: HeaderStatus = finished.isError ? "error" : "ok";
1153
+ const statusMeta: StatusMeta = {
1154
+ durationMs: finished.durationMs,
1155
+ exitCode: structuredExitCode(finished),
1156
+ outcome: finished.outcome,
1157
+ blockReason: finished.blockReason,
1158
+ };
1159
+ const out: string[] = [];
1160
+ out.push(...wrap(headerLine(finished.toolName, finished.args, status, statusMeta), width));
1161
+
1162
+ // Edit and write tools produce one bounded numbered diff on result.details.
1163
+ // It is the authority because canonical edit args can contain multiple
1164
+ // replacements and fuzzy matching can change the actual base text. Live rows
1165
+ // receive Pi's word-level styling; replay and export request plain rows.
1166
+ if ((finished.toolName === "edit" || finished.toolName === "write") && finished.isError === false) {
1167
+ const diff = resultDiff(finished.result);
1168
+ if (diff !== null) {
1169
+ out.push(...renderOutputMeta(finished, width, false, "change"));
1170
+ out.push(...renderMutationDiffBlock(diff, width, opts.diffStyle !== "plain"));
1171
+ out.push(...renderOutputFooter(finished, width, false));
1172
+ return out;
1173
+ }
1174
+ }
1175
+
1176
+ // Bash-tool dispatch: when `args.command` is a string, prefix the result
1177
+ // body with `$ <cmd>` on its own line so the user sees the display command
1178
+ // above its output. Failures use the red rail and expose the parsed exit
1179
+ // code in the header when the result includes one.
1180
+ if (finished.toolName === "bash") {
1181
+ const bashArgs = asBashArgs(redactToolArgs(finished.args));
1182
+ if (bashArgs !== null) {
1183
+ out.push(...renderArgsBody(finished.toolName, finished.args, width, finished.isError));
1184
+ out.push(
1185
+ ...renderOutputMeta(
1186
+ finished,
1187
+ width,
1188
+ finished.isError,
1189
+ isNonExecutedOutcome(finished.outcome) ? "decision" : "output",
1190
+ ),
1191
+ );
1192
+ out.push(...renderBashResultBlock(bashArgs, finished.result, width, finished.isError, opts));
1193
+ out.push(...renderOutputFooter(finished, width, finished.isError));
1194
+ return out;
1195
+ }
1196
+ }
1197
+
1198
+ // The primary argument already lives in the signature. Keep the secondary
1199
+ // fields below it so flags, ranges, working directories, and timeouts remain
1200
+ // inspectable without repeating the primary value.
1201
+ out.push(...renderArgsBody(finished.toolName, finished.args, width, finished.isError));
1202
+ out.push(
1203
+ ...renderOutputMeta(
1204
+ finished,
1205
+ width,
1206
+ finished.isError,
1207
+ isNonExecutedOutcome(finished.outcome) ? "decision" : "output",
1208
+ ),
1209
+ );
1210
+ out.push(...renderResultBlock(finished.result, finished.isError, width, opts));
1211
+ out.push(...renderOutputFooter(finished, width, finished.isError));
1212
+ return out;
1213
+ }
1214
+
1215
+ /**
1216
+ * Result-only render for replayed tool results that arrived without a
1217
+ * matching prior tool-call entry (orphan results in the session log).
1218
+ * Identical to `renderToolExecution` minus the args body.
1219
+ */
1220
+ export function renderToolResultOnly(
1221
+ finished: Omit<ToolExecutionFinished, "args">,
1222
+ width: number,
1223
+ opts: ToolBodyRenderOptions = {},
1224
+ ): string[] {
1225
+ const status: HeaderStatus = finished.isError ? "error" : "ok";
1226
+ const statusMeta: StatusMeta = {
1227
+ durationMs: finished.durationMs,
1228
+ exitCode: structuredExitCode(finished),
1229
+ outcome: finished.outcome,
1230
+ blockReason: finished.blockReason,
1231
+ };
1232
+ const out: string[] = [];
1233
+ out.push(...wrap(headerLine(finished.toolName, undefined, status, statusMeta), width));
1234
+ out.push(...renderOutputMeta(finished, width, finished.isError));
1235
+ out.push(...renderResultBlock(finished.result, finished.isError, width, opts));
1236
+ out.push(...renderOutputFooter(finished, width, finished.isError));
1237
+ return out;
1238
+ }
1239
+
1240
+ /**
1241
+ * Streaming render for an in-flight tool call whose expanded block should
1242
+ * surface the latest partial output. Used by the chat panel between
1243
+ * `tool_execution_start` and `tool_execution_end` when the user has expanded
1244
+ * the tool segment. The header carries the running lifecycle tail, secondary
1245
+ * arguments remain visible, and the latest cumulative Pi result renders under
1246
+ * a labeled live-output rail capped at the streaming row limit. An empty result renders
1247
+ * `(no output yet)` so the user can distinguish a slow start from a stalled
1248
+ * call.
1249
+ */
1250
+ export function renderToolStreamingExecution(
1251
+ call: ToolExecutionStart,
1252
+ width: number,
1253
+ partialResult: unknown,
1254
+ ): string[] {
1255
+ const out: string[] = [];
1256
+ out.push(...renderToolCallHeader({ ...call, phase: "running" }, width));
1257
+ out.push(...renderArgsBody(call.toolName, call.args, width, false));
1258
+ const partial: ToolExecutionFinished = {
1259
+ toolCallId: call.toolCallId,
1260
+ toolName: call.toolName,
1261
+ args: call.args,
1262
+ result: partialResult,
1263
+ isError: false,
1264
+ };
1265
+ out.push(...renderOutputMeta(partial, width, false, "live output"));
1266
+ const partialOutput = unwrapResultEnvelope(partialResult);
1267
+ if (isEmptyResult(partialOutput)) {
1268
+ out.push(...indentAndWrap(dim("(no output yet)"), width, false));
1269
+ } else {
1270
+ if (call.toolName === "bash") {
1271
+ const bashArgs = asBashArgs(redactToolArgs(call.args));
1272
+ if (bashArgs !== null) {
1273
+ const commandLine = `${cyanBold("$")} ${highlightBashCommand(stripShellWrapperForDisplay(bashArgs.command))}`;
1274
+ out.push(...indentAndWrap(commandLine, width, false));
1275
+ }
1276
+ }
1277
+ out.push(
1278
+ ...renderOutputRows(resultText(partialOutput, FULL_RESULT_PREVIEW_LIMIT), width, false, STREAMING_RESULT_ROW_LIMIT),
1279
+ );
1280
+ }
1281
+ return out;
1282
+ }
1283
+
1284
+ /** Display-only lifecycle for operator-issued `!` and `!!` bash commands. */
1285
+ export interface BashTranscriptExecution {
1286
+ command: string;
1287
+ output: string;
1288
+ running: boolean;
1289
+ elapsedMs?: number | undefined;
1290
+ totalBytes?: number | undefined;
1291
+ exitCode?: number | null | undefined;
1292
+ cancelled?: boolean | undefined;
1293
+ truncated?: boolean | undefined;
1294
+ fullOutputPath?: string | undefined;
1295
+ excludeFromContext?: boolean | undefined;
1296
+ error?: string | undefined;
1297
+ }
1298
+
1299
+ /**
1300
+ * Render local bash with the same call, argument, output, and settlement grammar
1301
+ * as model-initiated bash. This is a view projection only; callers keep Clio's
1302
+ * existing immutable `bashExecution` ledger entry.
1303
+ */
1304
+ export function renderBashTranscriptExecution(execution: BashTranscriptExecution, width: number): string[] {
1305
+ const shownBytes = Buffer.byteLength(execution.output, "utf8");
1306
+ const totalBytes = execution.totalBytes ?? shownBytes;
1307
+ const args: Record<string, unknown> = { command: execution.command };
1308
+ if (execution.excludeFromContext === true) args.context = "excluded from model context";
1309
+ const details = {
1310
+ resultSize: {
1311
+ bytes: totalBytes,
1312
+ shownBytes,
1313
+ truncated: execution.truncated === true,
1314
+ policy: "tail",
1315
+ ...(execution.fullOutputPath !== undefined ? { offloadPath: execution.fullOutputPath } : {}),
1316
+ },
1317
+ };
1318
+ const result = {
1319
+ content: [{ type: "text", text: execution.output }],
1320
+ details,
1321
+ };
1322
+ if (execution.running) {
1323
+ return renderToolStreamingExecution(
1324
+ {
1325
+ toolCallId: "local-bash",
1326
+ toolName: "bash",
1327
+ args,
1328
+ elapsedMs: execution.elapsedMs,
1329
+ phase: "running",
1330
+ },
1331
+ width,
1332
+ result,
1333
+ );
1334
+ }
1335
+ const message = execution.error?.trim();
1336
+ const output = message
1337
+ ? `${execution.output}${execution.output.length > 0 ? "\n\n" : ""}${message}`
1338
+ : execution.output;
1339
+ return renderToolExecution(
1340
+ {
1341
+ toolCallId: "local-bash",
1342
+ toolName: "bash",
1343
+ args,
1344
+ result: { ...result, content: [{ type: "text", text: output }] },
1345
+ isError: execution.cancelled === true || execution.error !== undefined || (execution.exitCode ?? 0) !== 0,
1346
+ exitCode: execution.exitCode,
1347
+ ...(execution.cancelled === true ? { outcome: "aborted" as const } : {}),
1348
+ excludeFromContext: execution.excludeFromContext,
1349
+ resultSummary: {
1350
+ bytes: shownBytes,
1351
+ truncated: execution.truncated === true,
1352
+ ...(execution.fullOutputPath !== undefined ? { offloadPath: execution.fullOutputPath } : {}),
1353
+ },
1354
+ },
1355
+ width,
1356
+ );
1357
+ }