@iowarp/clio-coder 0.3.1 → 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 (595) hide show
  1. package/CHANGELOG.md +90 -2
  2. package/CONTRIBUTING.md +23 -23
  3. package/README.md +284 -613
  4. package/dist/{acp-FPR54DGL.js → acp-BIYHVZIM.js} +43 -53
  5. package/dist/{agents-OGPIHPJH.js → agents-YT6SSRIT.js} +43 -26
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-IC3K6NIZ.js → auth-5TWEIYDN.js} +20 -12
  8. package/dist/{chunk-PV4JUBVJ.js → chunk-2EHAIA3X.js} +40 -21
  9. package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
  10. package/dist/chunk-2SFS6XQE.js +122 -0
  11. package/dist/chunk-2VTFPG5O.js +48 -0
  12. package/dist/{chunk-MAR7Y6HW.js → chunk-3ZXDFGR5.js} +23 -16
  13. package/dist/chunk-4BJ5BYCE.js +61 -0
  14. package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
  15. package/dist/chunk-4KLWL3UC.js +18 -0
  16. package/dist/chunk-4VP4KH3K.js +962 -0
  17. package/dist/chunk-4ZG3XFUR.js +77 -0
  18. package/dist/chunk-5B2AEOW5.js +5407 -0
  19. package/dist/{chunk-K2ITRMHZ.js → chunk-5TSRNF4G.js} +6 -138
  20. package/dist/{chunk-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
  21. package/dist/chunk-65DEGPJ6.js +52 -0
  22. package/dist/chunk-6EJMN2Y3.js +17 -0
  23. package/dist/chunk-6EJV5X2W.js +16405 -0
  24. package/dist/chunk-6N5PTWMY.js +136 -0
  25. package/dist/chunk-6XLNIQDB.js +27 -0
  26. package/dist/{chunk-TEKV33Q5.js → chunk-77VKQEHF.js} +65 -33
  27. package/dist/chunk-7CR24IG7.js +242 -0
  28. package/dist/{chunk-M5T5VO65.js → chunk-7EYHLWU7.js} +837 -635
  29. package/dist/chunk-7MNJORFF.js +22 -0
  30. package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
  31. package/dist/chunk-AGYYIBLL.js +1069 -0
  32. package/dist/chunk-AO4RKG4M.js +277 -0
  33. package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
  34. package/dist/chunk-ARBGF5F7.js +174 -0
  35. package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
  36. package/dist/chunk-CBCAPZAA.js +229 -0
  37. package/dist/chunk-CMZWFGD2.js +352 -0
  38. package/dist/chunk-ECH6PKUQ.js +39 -0
  39. package/dist/chunk-ED4KHGC3.js +143 -0
  40. package/dist/chunk-EKMEHE4H.js +340 -0
  41. package/dist/{chunk-RPTR2H26.js → chunk-EPVUXGXG.js} +21 -15
  42. package/dist/chunk-FCSXB6T2.js +338 -0
  43. package/dist/chunk-FJ3H4MN5.js +48 -0
  44. package/dist/chunk-FQ4SKYE4.js +29 -0
  45. package/dist/chunk-G2DE3C7R.js +644 -0
  46. package/dist/chunk-G4BMMOKF.js +182 -0
  47. package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
  48. package/dist/chunk-HC4CLZ2Y.js +68 -0
  49. package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
  50. package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
  51. package/dist/chunk-I4HZDVNP.js +73 -0
  52. package/dist/{chunk-4QKXUHSR.js → chunk-IGLFWIYI.js} +70 -20
  53. package/dist/chunk-IKCO5N3L.js +162 -0
  54. package/dist/chunk-IR4CFBFN.js +56 -0
  55. package/dist/{chunk-PFEFKVGL.js → chunk-J5HN4RYU.js} +13 -11
  56. package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
  57. package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
  58. package/dist/chunk-KJ5LWLOE.js +1077 -0
  59. package/dist/chunk-LBMZMYH2.js +285 -0
  60. package/dist/{chunk-G34LV2PF.js → chunk-LBNRH5WM.js} +84 -170
  61. package/dist/{chunk-H6F6BYOH.js → chunk-LZSJBIVT.js} +7003 -7434
  62. package/dist/{chunk-HQQID6OA.js → chunk-M6SHUN7Q.js} +5 -5
  63. package/dist/chunk-MAW544W2.js +1882 -0
  64. package/dist/chunk-MBS4V7ZP.js +217 -0
  65. package/dist/{chunk-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
  66. package/dist/chunk-MNA4JGU4.js +255 -0
  67. package/dist/chunk-MQSRRFWA.js +3428 -0
  68. package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
  69. package/dist/chunk-OAO4GE4M.js +619 -0
  70. package/dist/chunk-OHHN2SO4.js +5135 -0
  71. package/dist/chunk-OKGUZO2U.js +34 -0
  72. package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
  73. package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
  74. package/dist/chunk-OQE5J4C6.js +73 -0
  75. package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
  76. package/dist/chunk-POHLU5DW.js +1186 -0
  77. package/dist/chunk-QKMUKYO7.js +4961 -0
  78. package/dist/{chunk-ASND7OZK.js → chunk-QTYWRVRA.js} +13 -13
  79. package/dist/{chunk-EYOKLTMF.js → chunk-SRF2PJNW.js} +17 -3
  80. package/dist/chunk-SST6Z5JA.js +80 -0
  81. package/dist/chunk-STBPMHSX.js +2456 -0
  82. package/dist/chunk-T6YILFSB.js +80 -0
  83. package/dist/chunk-TZTZS7QK.js +227 -0
  84. package/dist/chunk-UOV2BYIW.js +107 -0
  85. package/dist/{chunk-Q3RUPKEJ.js → chunk-V4RXGQ5Q.js} +58 -189
  86. package/dist/chunk-VAKQQHWR.js +434 -0
  87. package/dist/chunk-VG7TBQIY.js +128 -0
  88. package/dist/chunk-VJWL6YS5.js +244 -0
  89. package/dist/chunk-WEH5XRJQ.js +32 -0
  90. package/dist/chunk-WMSVI4G2.js +2095 -0
  91. package/dist/chunk-WVO7V2QY.js +797 -0
  92. package/dist/chunk-X4RCMKVQ.js +641 -0
  93. package/dist/chunk-X75S7HFS.js +374 -0
  94. package/dist/chunk-XN3L4EYL.js +46 -0
  95. package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
  96. package/dist/chunk-YHZX5GEU.js +193 -0
  97. package/dist/chunk-YXLYO42X.js +91 -0
  98. package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
  99. package/dist/chunk-ZI647VB5.js +37 -0
  100. package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
  101. package/dist/cli/index.js +62 -54
  102. package/dist/clio-4LY5K2AC.js +25 -0
  103. package/dist/code-nav-7AX6FYE6.js +600 -0
  104. package/dist/codewiki/build-worker.js +66 -0
  105. package/dist/compile-cache-CVJMMODC.js +18 -0
  106. package/dist/{components-DMAOEKFB.js → components-KELWS457.js} +11 -6
  107. package/dist/{config-IRUQ7SE4.js → config-GTLUW2PR.js} +92 -55
  108. package/dist/configure-R6A64DHX.js +42 -0
  109. package/dist/context-5VKGUVJJ.js +866 -0
  110. package/dist/{context-3KWFLHJG.js → context-JFZEJ7W5.js} +15 -13
  111. package/dist/{context-5RADCKTR.js → context-RW5HC47S.js} +71 -35
  112. package/dist/{context-clear-7TSNPAAI.js → context-clear-6ZHBAZZT.js} +54 -28
  113. package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
  114. package/dist/dispatch-runner-VKBRCWQC.js +1997 -0
  115. package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
  116. package/dist/{doctor-UC5NAJYQ.js → doctor-KI767GSN.js} +27 -17
  117. package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
  118. package/dist/{evidence-YEGUW4L3.js → evidence-UA6AWDQQ.js} +46 -26
  119. package/dist/{evolve-TXARCTPG.js → evolve-QNTFGV6Z.js} +45 -25
  120. package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
  121. package/dist/{fleet-6G3DHNYE.js → fleet-Q7UOMUSG.js} +163 -54
  122. package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
  123. package/dist/{init-KZ5QTF6M.js → init-WBB65ZHQ.js} +69 -32
  124. package/dist/{memory-73ESV5YC.js → memory-MD3O64RI.js} +48 -27
  125. package/dist/{models-A4PVNWJK.js → models-BZU34YWD.js} +39 -25
  126. package/dist/monitor-MEQA5C3I.js +661 -0
  127. package/dist/{chunk-FCIH3BIZ.js → orchestrator-CGFKEP27.js} +11832 -8687
  128. package/dist/{paths-C4H6IV77.js → paths-UXLN5YYZ.js} +10 -5
  129. package/dist/{preload-6WVMHX3A.js → preload-P6DGH2PZ.js} +2 -2
  130. package/dist/{reset-BGW6OGMV.js → reset-L2FQEE3E.js} +16 -10
  131. package/dist/{run-YTPEYQOH.js → run-IV4Q6RLN.js} +101 -61
  132. package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
  133. package/dist/{skills-2V6RA3OQ.js → skills-LQEKRDTN.js} +34 -14
  134. package/dist/{skills-eval-S2TVJO4F.js → skills-eval-3DC4HEWS.js} +70 -34
  135. package/dist/steer-GGWFUJUD.js +77 -0
  136. package/dist/{targets-TYXLPB23.js → targets-C4SSGQOB.js} +43 -27
  137. package/dist/terminal-lease-IT5JW2NR.js +395 -0
  138. package/dist/{trace-GGOJ6Q6Z.js → trace-PNCASAXC.js} +41 -16
  139. package/dist/{chunk-N6F52NLF.js → tree-sitter-HGKH6LG4.js} +28 -2306
  140. package/dist/{uninstall-LLLT4F4W.js → uninstall-FZCQCDKC.js} +10 -5
  141. package/dist/{upgrade-33G2LMM5.js → upgrade-7TT7SQ3G.js} +45 -25
  142. package/dist/{usage-ZAFSXKKG.js → usage-GV4PKT3M.js} +62 -31
  143. package/dist/verify-G6V4D2G7.js +716 -0
  144. package/dist/web-fetch-2YHJ3KTG.js +638 -0
  145. package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-DQF6Z66B.js} +74 -34
  146. package/dist/worker/entry.js +221 -36
  147. package/dist/workspace-G4ZWUIPR.js +22 -0
  148. package/docs/README.md +22 -17
  149. package/docs/acp.md +168 -16
  150. package/docs/alcf-provider.md +1 -1
  151. package/docs/architecture.md +136 -7
  152. package/docs/artifact-versions.md +1 -1
  153. package/docs/built-in-agents.md +1 -1
  154. package/docs/capacity-and-scheduling.md +1 -1
  155. package/docs/commands-and-modes.md +114 -71
  156. package/docs/config-knobs-audit.md +1 -3
  157. package/docs/configuration-and-targets.md +174 -46
  158. package/docs/context-engine.md +29 -6
  159. package/docs/development-pipeline.md +26 -1
  160. package/docs/dispatch-architecture-rationale.md +1 -1
  161. package/docs/documentation-coverage.md +2 -2
  162. package/docs/documentation-guide.md +1 -1
  163. package/docs/environment-variables.md +13 -5
  164. package/docs/eval-runner.md +1 -1
  165. package/docs/evals-internal.md +1 -1
  166. package/docs/evidence-and-memory.md +6 -2
  167. package/docs/evolution.md +2 -2
  168. package/docs/exit-codes-and-output.md +15 -9
  169. package/docs/extensions-and-sharing.md +9 -9
  170. package/docs/fleet-dispatch.md +7 -5
  171. package/docs/git-commit-provenance.md +120 -0
  172. package/docs/glossary.md +1 -1
  173. package/docs/installation-and-lifecycle.md +34 -27
  174. package/docs/middleware-and-components.md +1 -1
  175. package/docs/model-catalog.md +45 -14
  176. package/docs/observability.md +8 -5
  177. package/docs/performance-methodology.md +491 -0
  178. package/docs/pi-boundary.md +72 -0
  179. package/docs/proactive-memory.md +3 -3
  180. package/docs/prompt-envelope-and-tools.md +24 -3
  181. package/docs/provider-adapter-cookbook.md +57 -4
  182. package/docs/release-cut-checklist.md +129 -115
  183. package/docs/safety-model.md +9 -5
  184. package/docs/scientific-validation.md +3 -3
  185. package/docs/session-lifecycle.md +55 -12
  186. package/docs/skills-marketplace.md +12 -8
  187. package/docs/time-conventions.md +1 -1
  188. package/docs/tool-usage.md +3 -3
  189. package/docs/trace-store.md +1 -1
  190. package/docs/troubleshooting.md +10 -7
  191. package/docs/tui-design.md +47 -10
  192. package/docs/worker-dispatch-mechanics.md +1 -1
  193. package/package.json +19 -22
  194. package/skills/coding/ast-grep/SKILL.md +136 -0
  195. package/skills/coding/ast-grep/evals.md +56 -0
  196. package/skills/coding/ast-grep/references/rule_reference.md +297 -0
  197. package/skills/coding/coding-standards/SKILL.md +113 -0
  198. package/skills/coding/coding-standards/evals.md +34 -0
  199. package/skills/coding/prototype/SKILL.md +86 -0
  200. package/skills/coding/prototype/evals.md +42 -0
  201. package/skills/coding/prototype/references/LOGIC.md +67 -0
  202. package/skills/coding/prototype/references/UI.md +112 -0
  203. package/skills/coding/tdd/SKILL.md +101 -0
  204. package/skills/coding/tdd/evals.md +41 -0
  205. package/skills/coding/tdd/references/mocking.md +59 -0
  206. package/skills/coding/tdd/references/tests.md +77 -0
  207. package/skills/context/context-handoff/SKILL.md +126 -0
  208. package/skills/context/context-handoff/evals.md +57 -0
  209. package/skills/context/context-handoff/scripts/new-handoff.sh +26 -0
  210. package/skills/context/context-prime/SKILL.md +95 -0
  211. package/skills/context/context-prime/evals.md +54 -0
  212. package/skills/meta/clio-dev/SKILL.md +91 -0
  213. package/skills/meta/clio-dev/evals.md +45 -0
  214. package/skills/meta/clio-test/SKILL.md +130 -0
  215. package/skills/meta/clio-test/evals.md +43 -0
  216. package/skills/meta/clio-test/references/harness.md +97 -0
  217. package/skills/meta/clio-test/references/test-map.md +59 -0
  218. package/skills/meta/credentials/SKILL.md +125 -0
  219. package/skills/meta/credentials/evals.md +104 -0
  220. package/skills/meta/find-skills/SKILL.md +72 -0
  221. package/skills/meta/find-skills/evals.md +47 -0
  222. package/skills/meta/herdr/SKILL.md +127 -0
  223. package/skills/meta/herdr/evals.md +38 -0
  224. package/skills/meta/skill-craft/SKILL.md +102 -0
  225. package/skills/meta/skill-craft/evals.md +41 -0
  226. package/skills/planning/architecture/SKILL.md +129 -0
  227. package/skills/planning/architecture/evals.md +36 -0
  228. package/skills/planning/backlog/SKILL.md +90 -0
  229. package/skills/planning/backlog/evals.md +43 -0
  230. package/skills/planning/prd/SKILL.md +82 -0
  231. package/skills/planning/prd/evals.md +49 -0
  232. package/skills/planning/product-intent/SKILL.md +112 -0
  233. package/skills/planning/product-intent/evals.md +36 -0
  234. package/skills/planning/tech-spec/SKILL.md +115 -0
  235. package/skills/planning/tech-spec/evals.md +47 -0
  236. package/skills/registry.yaml +136 -0
  237. package/skills/research/arxiv-literature/SKILL.md +104 -0
  238. package/skills/research/arxiv-literature/evals.md +58 -0
  239. package/skills/research/experiment-protocol/SKILL.md +122 -0
  240. package/skills/research/experiment-protocol/evals.md +91 -0
  241. package/skills/research/scientific-debugging/SKILL.md +119 -0
  242. package/skills/research/scientific-debugging/evals.md +138 -0
  243. package/skills/research/scientific-modernization/SKILL.md +138 -0
  244. package/skills/research/scientific-modernization/evals.md +84 -0
  245. package/skills/workflow/design-council/SKILL.md +139 -0
  246. package/skills/workflow/design-council/evals.md +97 -0
  247. package/skills/workflow/grill-me/SKILL.md +186 -0
  248. package/skills/workflow/grill-me/evals.md +78 -0
  249. package/skills/workflow/workflow-distiller/SKILL.md +136 -0
  250. package/skills/workflow/workflow-distiller/evals.md +107 -0
  251. package/src/cli/acp.ts +31 -4
  252. package/src/cli/clio.ts +68 -6
  253. package/src/cli/config-inspect.ts +28 -22
  254. package/src/cli/configure.ts +47 -9
  255. package/src/cli/context-clear.ts +2 -2
  256. package/src/cli/context-index.ts +21 -23
  257. package/src/cli/context.ts +13 -8
  258. package/src/cli/default-target.ts +9 -17
  259. package/src/cli/docs.ts +11 -5
  260. package/src/cli/evidence.ts +4 -1
  261. package/src/cli/extensions.ts +10 -1
  262. package/src/cli/fleet.ts +47 -6
  263. package/src/cli/index.ts +55 -26
  264. package/src/cli/memory.ts +3 -1
  265. package/src/cli/models.ts +1 -1
  266. package/src/cli/modes/json-stream.ts +37 -1
  267. package/src/cli/modes/print.ts +24 -9
  268. package/src/cli/run.ts +2 -2
  269. package/src/cli/skills-eval.ts +23 -8
  270. package/src/cli/skills.ts +19 -4
  271. package/src/cli/targets.ts +4 -0
  272. package/src/cli/text-layout.ts +15 -5
  273. package/src/cli/trace.ts +62 -14
  274. package/src/cli/upgrade.ts +18 -2
  275. package/src/cli/usage.ts +10 -3
  276. package/src/cli/wiki-generate.ts +2 -1
  277. package/src/core/agent-environment.ts +7 -0
  278. package/src/core/bash-exec.ts +72 -1
  279. package/src/core/boot-trace.ts +9 -4
  280. package/src/core/bus-events.ts +20 -4
  281. package/src/core/commit-attribution.ts +157 -0
  282. package/src/core/compile-cache.ts +159 -0
  283. package/src/core/config.ts +131 -2
  284. package/src/core/defaults.ts +39 -5
  285. package/src/core/domain-loader.ts +12 -5
  286. package/src/core/git-commit-attribution.ts +362 -0
  287. package/src/core/incomplete-installation.ts +45 -0
  288. package/src/core/response-schema.ts +1 -1
  289. package/src/core/safe-exec.ts +13 -1
  290. package/src/core/settings-layers.ts +155 -21
  291. package/src/core/skill-activation.ts +1 -1
  292. package/src/core/startup-timer.ts +3 -3
  293. package/src/core/state-file-lock.ts +13 -1
  294. package/src/core/termination.ts +78 -5
  295. package/src/domains/config/classify.ts +15 -3
  296. package/src/domains/config/extension.ts +19 -13
  297. package/src/domains/config/index.ts +10 -0
  298. package/src/domains/config/keybindings.ts +42 -6
  299. package/src/domains/context/bootstrap-prompt.ts +1 -1
  300. package/src/domains/context/bootstrap.ts +111 -18
  301. package/src/domains/context/clear.ts +16 -11
  302. package/src/domains/context/clio-md.ts +111 -9
  303. package/src/domains/context/codewiki/artifact.ts +400 -0
  304. package/src/domains/context/codewiki/build-worker-protocol.ts +24 -0
  305. package/src/domains/context/codewiki/build-worker.ts +54 -0
  306. package/src/domains/context/codewiki/coordinator.ts +182 -0
  307. package/src/domains/context/codewiki/indexer.ts +59 -144
  308. package/src/domains/context/codewiki/paths.ts +67 -0
  309. package/src/domains/context/codewiki/schema.ts +80 -0
  310. package/src/domains/context/codewiki/tree-sitter.ts +1 -1
  311. package/src/domains/context/contract.ts +11 -5
  312. package/src/domains/context/extension.ts +94 -143
  313. package/src/domains/context/fingerprint.ts +3 -1
  314. package/src/domains/context/index.ts +12 -22
  315. package/src/domains/context/project-metadata.ts +19 -0
  316. package/src/domains/context/prompt-context.ts +9 -10
  317. package/src/domains/context/refresh.ts +29 -21
  318. package/src/domains/context/runtime.ts +17 -0
  319. package/src/domains/context/wiki/generate.ts +39 -34
  320. package/src/domains/context/wiki/plan.ts +1 -1
  321. package/src/domains/context/wiki/prompts.ts +21 -8
  322. package/src/domains/dispatch/code-step.ts +20 -1
  323. package/src/domains/dispatch/extension.ts +158 -21
  324. package/src/domains/dispatch/failure-classification.ts +6 -0
  325. package/src/domains/dispatch/fleet-commit-attribution.ts +56 -0
  326. package/src/domains/dispatch/orphan-recovery.ts +50 -8
  327. package/src/domains/dispatch/receipt-integrity.ts +5 -0
  328. package/src/domains/dispatch/state.ts +31 -6
  329. package/src/domains/dispatch/transport.ts +2 -1
  330. package/src/domains/dispatch/types.ts +14 -0
  331. package/src/domains/dispatch/worker-spawn.ts +21 -2
  332. package/src/domains/eval/metrics/context.ts +1 -1
  333. package/src/domains/eval/types.ts +0 -1
  334. package/src/domains/evidence/build.ts +41 -1
  335. package/src/domains/lifecycle/migrations/2026-08-18-lmstudio-runtime-id.ts +52 -0
  336. package/src/domains/lifecycle/migrations/index.ts +24 -4
  337. package/src/domains/middleware/hooks-io.ts +12 -0
  338. package/src/domains/middleware/skills-reminder.ts +30 -15
  339. package/src/domains/prompts/compiler.ts +142 -84
  340. package/src/domains/prompts/contract.ts +18 -2
  341. package/src/domains/prompts/extension.ts +39 -7
  342. package/src/domains/prompts/fragment-loader.ts +0 -1
  343. package/src/domains/prompts/fragments/identity/clio.md +2 -4
  344. package/src/domains/prompts/fragments/identity/docs-routing.md +10 -0
  345. package/src/domains/prompts/fragments/identity/self-awareness.md +1 -45
  346. package/src/domains/prompts/fragments/operating/contract.md +4 -50
  347. package/src/domains/prompts/fragments/operating/delegation.md +42 -0
  348. package/src/domains/prompts/fragments/operating/skills.md +26 -0
  349. package/src/domains/prompts/fragments/operating/worker.md +16 -0
  350. package/src/domains/prompts/fragments/safety/auto-edit.md +5 -5
  351. package/src/domains/prompts/fragments/safety/full-auto.md +3 -3
  352. package/src/domains/prompts/fragments/safety/read-only.md +4 -4
  353. package/src/domains/prompts/fragments/safety/suggest.md +2 -2
  354. package/src/domains/prompts/fragments/wiki/page.md +10 -0
  355. package/src/domains/prompts/fragments/wiki/plan.md +10 -0
  356. package/src/domains/prompts/preload.ts +3 -3
  357. package/src/domains/providers/auth/api-key.ts +1 -1
  358. package/src/domains/providers/auth/backend-file.ts +20 -10
  359. package/src/domains/providers/auth/backend-memory.ts +59 -4
  360. package/src/domains/providers/auth/boot-status.ts +65 -0
  361. package/src/domains/providers/auth/oauth.ts +2 -1
  362. package/src/domains/providers/auth/storage.ts +97 -38
  363. package/src/domains/providers/capabilities.ts +12 -4
  364. package/src/domains/providers/contract.ts +15 -4
  365. package/src/domains/providers/extension.ts +18 -6
  366. package/src/domains/providers/model-runtime-capabilities.ts +15 -4
  367. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +118 -35
  368. package/src/domains/providers/plugins.ts +5 -3
  369. package/src/domains/providers/probe/fingerprint.ts +25 -5
  370. package/src/domains/providers/registry.ts +31 -10
  371. package/src/domains/providers/runtimes/boot-manifest.ts +55 -0
  372. package/src/domains/providers/runtimes/builtins.ts +2 -2
  373. package/src/domains/providers/runtimes/common/lmstudio-http.ts +423 -0
  374. package/src/domains/providers/runtimes/common/local-synth.ts +6 -7
  375. package/src/domains/providers/runtimes/local-native/lmstudio.ts +241 -0
  376. package/src/domains/providers/support.ts +6 -3
  377. package/src/domains/providers/types/local-model-quirks.ts +7 -9
  378. package/src/domains/providers/types/runtime-descriptor.ts +12 -1
  379. package/src/domains/providers/types/target-descriptor.ts +22 -0
  380. package/src/domains/resources/contract.ts +0 -1
  381. package/src/domains/resources/extension.ts +1 -3
  382. package/src/domains/resources/loader.ts +3 -4
  383. package/src/domains/resources/prompts/loader.ts +16 -2
  384. package/src/domains/resources/prompts/substitute.ts +1 -65
  385. package/src/domains/resources/skills/content-hash.ts +2 -0
  386. package/src/domains/resources/skills/install.ts +17 -0
  387. package/src/domains/resources/skills/loader.ts +17 -10
  388. package/src/domains/resources/skills/marketplace.ts +55 -9
  389. package/src/domains/safety/action-classifier.ts +4 -2
  390. package/src/domains/safety/audit.ts +8 -2
  391. package/src/domains/safety/extension.ts +1 -1
  392. package/src/domains/session/compaction/branch-summary.ts +3 -2
  393. package/src/domains/session/compaction/cut-point.ts +2 -1
  394. package/src/domains/session/compaction/tokens.ts +2 -1
  395. package/src/domains/session/context-ledger.ts +14 -0
  396. package/src/domains/session/contract.ts +15 -0
  397. package/src/domains/session/decision-board.ts +190 -0
  398. package/src/domains/session/entries.ts +66 -3
  399. package/src/domains/session/extension.ts +93 -12
  400. package/src/domains/session/retry.ts +10 -18
  401. package/src/domains/session/session-artifacts.ts +107 -0
  402. package/src/domains/session/task-board.ts +207 -13
  403. package/src/domains/session/tree/active-path.ts +44 -5
  404. package/src/domains/session/tree/fork.ts +26 -27
  405. package/src/domains/session/tree/preview.ts +2 -2
  406. package/src/domains/session/workspace/git-probe.ts +17 -11
  407. package/src/domains/user-tasks/store.ts +297 -0
  408. package/src/engine/acp/errors.ts +96 -0
  409. package/src/engine/acp/server.ts +1728 -146
  410. package/src/engine/acp/transport.ts +135 -14
  411. package/src/engine/acp/types.ts +26 -0
  412. package/src/engine/agent.ts +3 -3
  413. package/src/engine/ai.ts +32 -27
  414. package/src/engine/alcf-oauth.ts +26 -19
  415. package/src/engine/api-registry.ts +223 -0
  416. package/src/engine/apis/index.ts +3 -7
  417. package/src/engine/apis/llamacpp-residency.ts +49 -9
  418. package/src/engine/apis/lmstudio-residency.ts +5 -21
  419. package/src/engine/apis/lmstudio.ts +243 -0
  420. package/src/engine/apis/ollama-native.ts +24 -3
  421. package/src/engine/apis/openai-completions.ts +170 -91
  422. package/src/engine/apis/residency.ts +139 -3
  423. package/src/engine/apis/types.ts +16 -0
  424. package/src/engine/env-api-keys.ts +98 -0
  425. package/src/engine/gemma-channel-filter.ts +223 -0
  426. package/src/engine/instrumented-tui.ts +192 -0
  427. package/src/engine/messages.ts +14 -0
  428. package/src/engine/models.ts +42 -0
  429. package/src/engine/oauth.ts +16 -12
  430. package/src/engine/prompt-templates.ts +1 -0
  431. package/src/engine/provider-payload.ts +16 -59
  432. package/src/engine/strip-tokenizer-sentinels.ts +1 -1
  433. package/src/engine/truncate.ts +9 -0
  434. package/src/engine/tui.ts +17 -9
  435. package/src/engine/types.ts +3 -6
  436. package/src/engine/worker-runtime-capabilities.ts +5 -0
  437. package/src/engine/worker-runtime.ts +1 -1
  438. package/src/engine/worker-tools.ts +9 -4
  439. package/src/entry/boot-options.ts +50 -0
  440. package/src/entry/orchestrator.ts +288 -150
  441. package/src/interactive/application-controller.ts +89 -2
  442. package/src/interactive/chat-loop.ts +266 -41
  443. package/src/interactive/chat-panel.ts +173 -47
  444. package/src/interactive/chat-renderer.ts +262 -72
  445. package/src/interactive/clio-editor.ts +3 -8
  446. package/src/interactive/command-fallbacks.ts +2 -2
  447. package/src/interactive/context-overlay.ts +27 -1
  448. package/src/interactive/editor-submit.ts +228 -24
  449. package/src/interactive/export-html/ansi-to-html.ts +161 -0
  450. package/src/interactive/export-html/index.ts +51 -0
  451. package/src/interactive/export-html/template.ts +45 -0
  452. package/src/interactive/export-html/tool-renderer.ts +54 -0
  453. package/src/interactive/footer/dashboard.ts +4 -0
  454. package/src/interactive/footer/notifications.ts +1 -1
  455. package/src/interactive/footer/widgets.ts +20 -2
  456. package/src/interactive/footer-panel.ts +2 -2
  457. package/src/interactive/format-time.ts +14 -2
  458. package/src/interactive/interactive-application.ts +201 -17
  459. package/src/interactive/interactive-event-projection.ts +6 -1
  460. package/src/interactive/interactive-input-runtime.ts +50 -4
  461. package/src/interactive/interactive-presentation.ts +151 -19
  462. package/src/interactive/interactive-shell.ts +268 -14
  463. package/src/interactive/interactive-slash-runtime.ts +176 -114
  464. package/src/interactive/interactive-tickers.ts +38 -7
  465. package/src/interactive/keybinding-manager.ts +1 -1
  466. package/src/interactive/layout.ts +40 -3
  467. package/src/interactive/overlay-frame.ts +1 -1
  468. package/src/interactive/overlay-general-openers.ts +58 -1
  469. package/src/interactive/overlay-key-routing.ts +3 -0
  470. package/src/interactive/overlay-lifecycle.ts +13 -0
  471. package/src/interactive/overlay-permission-lifecycle.ts +2 -1
  472. package/src/interactive/overlay-session-lifecycle.ts +69 -12
  473. package/src/interactive/overlays/decisions.ts +300 -0
  474. package/src/interactive/overlays/help-reference.ts +15 -10
  475. package/src/interactive/overlays/model-selector.ts +34 -16
  476. package/src/interactive/overlays/session-selector.ts +18 -0
  477. package/src/interactive/overlays/settings.ts +105 -17
  478. package/src/interactive/overlays/skills-hub.ts +4 -4
  479. package/src/interactive/overlays/tree-selector.ts +41 -6
  480. package/src/interactive/render-trace.ts +499 -90
  481. package/src/interactive/renderers/compaction-summary.ts +2 -2
  482. package/src/interactive/renderers/diff.ts +115 -104
  483. package/src/interactive/renderers/mermaid.ts +53 -0
  484. package/src/interactive/renderers/tool-execution.ts +386 -133
  485. package/src/interactive/renderers/worker-entry.ts +20 -4
  486. package/src/interactive/session-switch-settlement.ts +10 -0
  487. package/src/interactive/slash-autocomplete.ts +6 -114
  488. package/src/interactive/slash-commands.ts +135 -47
  489. package/src/interactive/slash-spec.ts +9 -38
  490. package/src/interactive/status/controller.ts +5 -1
  491. package/src/interactive/stdout-backpressure.ts +99 -0
  492. package/src/interactive/stream-pacer.ts +530 -0
  493. package/src/interactive/stream-pacing-policy.ts +66 -0
  494. package/src/interactive/tasks-overlay.ts +368 -14
  495. package/src/interactive/terminal-lease.ts +485 -0
  496. package/src/interactive/theme/tokens.ts +1 -1
  497. package/src/interactive/turn-context.ts +4 -3
  498. package/src/interactive/turn-persistence.ts +30 -13
  499. package/src/interactive/turn-queues.ts +12 -0
  500. package/src/interactive/turn-recovery.ts +25 -8
  501. package/src/interactive/turn-runtime.ts +79 -12
  502. package/src/interactive/turn-state.ts +10 -0
  503. package/src/interactive/view/artifacts.ts +114 -4
  504. package/src/interactive/view/view-overlay.ts +3 -0
  505. package/src/interactive/welcome-dashboard.ts +17 -16
  506. package/src/interactive/worker-receipts.ts +52 -3
  507. package/src/interactive/worker-stream.ts +5 -1
  508. package/src/tools/agent-tools.ts +23 -3
  509. package/src/tools/artifact.ts +2 -2
  510. package/src/tools/ask-user.ts +23 -13
  511. package/src/tools/bash.ts +30 -2
  512. package/src/tools/bootstrap.ts +34 -431
  513. package/src/tools/builtin-tool-catalog.ts +265 -0
  514. package/src/tools/codewiki/code-nav-surface.ts +29 -0
  515. package/src/tools/codewiki/code-nav.ts +8 -22
  516. package/src/tools/codewiki/shared.ts +41 -38
  517. package/src/tools/context/docs-engine.ts +14 -3
  518. package/src/tools/context/index.ts +107 -28
  519. package/src/tools/context/surface.ts +19 -0
  520. package/src/tools/core-bootstrap.ts +168 -0
  521. package/src/tools/credential-present.ts +5 -5
  522. package/src/tools/dispatch-admission.ts +533 -0
  523. package/src/tools/dispatch-background.ts +54 -0
  524. package/src/tools/dispatch-event-text.ts +6 -0
  525. package/src/tools/dispatch-plan.ts +9 -4
  526. package/src/tools/dispatch-run-events.ts +238 -0
  527. package/src/tools/dispatch-runner.ts +2370 -0
  528. package/src/tools/dispatch-scout-admission.ts +295 -0
  529. package/src/tools/dispatch-types.ts +77 -0
  530. package/src/tools/dispatch.ts +67 -3161
  531. package/src/tools/find.ts +4 -2
  532. package/src/tools/grep.ts +2 -2
  533. package/src/tools/lazy-tool.ts +60 -0
  534. package/src/tools/ledger.ts +3 -3
  535. package/src/tools/monitor-surface.ts +36 -0
  536. package/src/tools/monitor.ts +2 -32
  537. package/src/tools/observers.ts +2 -2
  538. package/src/tools/registry.ts +39 -27
  539. package/src/tools/safe-exec.ts +2 -2
  540. package/src/tools/steer-surface.ts +17 -0
  541. package/src/tools/steer.ts +2 -13
  542. package/src/tools/tasks.ts +108 -11
  543. package/src/tools/truncate.ts +25 -184
  544. package/src/tools/verify/frontend.ts +3 -1
  545. package/src/tools/verify/index.ts +3 -38
  546. package/src/tools/verify/surface.ts +46 -0
  547. package/src/tools/web-fetch-surface.ts +23 -0
  548. package/src/tools/web-fetch.ts +2 -20
  549. package/src/tools/write.ts +7 -2
  550. package/src/worker/entry.ts +39 -2
  551. package/src/worker/spec-contract.ts +26 -5
  552. package/dist/chunk-7SS2CTV2.js +0 -61361
  553. package/dist/chunk-DKGKUHFA.js +0 -924
  554. package/dist/chunk-GEP36Y4X.js +0 -12796
  555. package/dist/chunk-XYWBQRDM.js +0 -137
  556. package/dist/clio-BZVGEUFJ.js +0 -58
  557. package/dist/configure-S7S6F6CL.js +0 -32
  558. package/docs/html/agents_blueprint.html +0 -936
  559. package/docs/html/alcf_blueprint.html +0 -324
  560. package/docs/html/architecture_blueprint.html +0 -850
  561. package/docs/html/commands_blueprint.html +0 -939
  562. package/docs/html/config_knobs_audit_blueprint.html +0 -178
  563. package/docs/html/configuration_blueprint.html +0 -1080
  564. package/docs/html/context_blueprint.html +0 -603
  565. package/docs/html/documentation_blueprint.html +0 -832
  566. package/docs/html/environment_blueprint.html +0 -404
  567. package/docs/html/eval_blueprint.html +0 -743
  568. package/docs/html/evals_internal_blueprint.html +0 -190
  569. package/docs/html/evolution_blueprint.html +0 -674
  570. package/docs/html/extensions_blueprint.html +0 -2065
  571. package/docs/html/fleet_dispatch_blueprint.html +0 -286
  572. package/docs/html/index.html +0 -919
  573. package/docs/html/lifecycle_blueprint.html +0 -723
  574. package/docs/html/memory_blueprint.html +0 -699
  575. package/docs/html/middleware_blueprint.html +0 -664
  576. package/docs/html/models_blueprint.html +0 -2366
  577. package/docs/html/observability_blueprint.html +0 -683
  578. package/docs/html/provider_adapter_blueprint.html +0 -245
  579. package/docs/html/safety_blueprint.html +0 -1386
  580. package/docs/html/shared.css +0 -571
  581. package/docs/html/shared.js +0 -143
  582. package/docs/html/skills_blueprint.html +0 -671
  583. package/docs/html/soak_blueprint.html +0 -182
  584. package/docs/html/tool_usage_blueprint.html +0 -350
  585. package/docs/html/tools_blueprint.html +0 -2249
  586. package/docs/html/trace_blueprint.html +0 -235
  587. package/docs/html/tui_design_blueprint.html +0 -374
  588. package/docs/html/validation_blueprint.html +0 -961
  589. package/docs/html/worker_dispatch_blueprint.html +0 -231
  590. package/src/core/release.ts +0 -2
  591. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
  592. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
  593. package/src/engine/apis/lmstudio-native.ts +0 -1438
  594. package/src/engine/apis/thinking-replay.ts +0 -11
  595. package/src/tools/string-enum.ts +0 -15
@@ -21,7 +21,16 @@
21
21
  import { existsSync, readFileSync } from "node:fs";
22
22
  import { join } from "node:path";
23
23
  import { parse as parseYaml } from "yaml";
24
- import { type ClioSettings, settingsPath, validateSettings } from "./config.js";
24
+ import {
25
+ applySettingsDelta,
26
+ type ClioSettings,
27
+ type SettingsIssue,
28
+ type SettingsMutator,
29
+ SettingsValidationError,
30
+ settingsPath,
31
+ updateSavedSettingsDocument,
32
+ validateSettings,
33
+ } from "./config.js";
25
34
 
26
35
  export type SettingsOrigin = "built-in" | "user" | "project" | "project.local" | "cli";
27
36
 
@@ -29,6 +38,7 @@ export interface SettingsLayerIssue {
29
38
  origin: SettingsOrigin;
30
39
  path: string;
31
40
  message: string;
41
+ kind?: SettingsIssue["kind"];
32
42
  }
33
43
 
34
44
  export interface SettingsLayerInfo {
@@ -45,6 +55,9 @@ export interface LayeredSettings {
45
55
  layers: SettingsLayerInfo[];
46
56
  }
47
57
 
58
+ const STRICT_USER_ISSUES = Symbol("strict-user-issues");
59
+ type InternalLayeredSettings = LayeredSettings & { [STRICT_USER_ISSUES]: SettingsIssue[] };
60
+
48
61
  // Keys whose presence in a project layer means a credential leaked into a
49
62
  // committed file. `auth` carries target headers and api keys; the rest cover
50
63
  // stray secrets. Stripped from project layers with a diagnostic.
@@ -54,6 +67,18 @@ function isRecord(value: unknown): value is Record<string, unknown> {
54
67
  return value !== null && typeof value === "object" && !Array.isArray(value);
55
68
  }
56
69
 
70
+ function deepEquals(a: unknown, b: unknown): boolean {
71
+ if (a === b) return true;
72
+ if (Array.isArray(a) || Array.isArray(b)) {
73
+ if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;
74
+ return a.every((entry, index) => deepEquals(entry, b[index]));
75
+ }
76
+ if (!isRecord(a) || !isRecord(b)) return false;
77
+ const keys = Object.keys(a);
78
+ if (keys.length !== Object.keys(b).length) return false;
79
+ return keys.every((key) => key in b && deepEquals(a[key], b[key]));
80
+ }
81
+
57
82
  interface RawLayer {
58
83
  origin: SettingsOrigin;
59
84
  path: string;
@@ -62,16 +87,33 @@ interface RawLayer {
62
87
 
63
88
  function readRawLayer(origin: SettingsOrigin, path: string, issues: SettingsLayerIssue[]): RawLayer {
64
89
  if (!existsSync(path)) return { origin, path, blob: undefined };
90
+ let text: string;
91
+ try {
92
+ text = readFileSync(path, "utf8");
93
+ } catch (err) {
94
+ issues.push({
95
+ origin,
96
+ path: "(root)",
97
+ message: `unreadable: ${err instanceof Error ? err.message : String(err)}`,
98
+ kind: "unreadable",
99
+ });
100
+ return { origin, path, blob: undefined };
101
+ }
65
102
  let parsed: unknown;
66
103
  try {
67
- parsed = parseYaml(readFileSync(path, "utf8"));
104
+ parsed = parseYaml(text);
68
105
  } catch (err) {
69
- issues.push({ origin, path, message: `invalid YAML: ${err instanceof Error ? err.message : String(err)}` });
106
+ issues.push({
107
+ origin,
108
+ path: "(root)",
109
+ message: `invalid YAML: ${err instanceof Error ? err.message : String(err)}`,
110
+ kind: "syntax",
111
+ });
70
112
  return { origin, path, blob: undefined };
71
113
  }
72
114
  if (parsed === null || parsed === undefined) return { origin, path, blob: {} };
73
115
  if (!isRecord(parsed)) {
74
- issues.push({ origin, path, message: "settings file must be a mapping at the root" });
116
+ issues.push({ origin, path: "(root)", message: "settings file must be a mapping at the root" });
75
117
  return { origin, path, blob: undefined };
76
118
  }
77
119
  return { origin, path, blob: parsed };
@@ -146,22 +188,20 @@ export interface ReadLayeredSettingsOptions {
146
188
  userPath?: string;
147
189
  }
148
190
 
149
- /**
150
- * Read and layer settings for `cwd`, returning the validated effective settings
151
- * plus per-leaf source attribution. Never throws: validation issues and layer
152
- * problems are returned, and the effective settings always validate (invalid
153
- * merges fall back to the schema defaults for the offending keys).
154
- */
155
- export function readLayeredSettings(cwd: string, options: ReadLayeredSettingsOptions = {}): LayeredSettings {
156
- const issues: SettingsLayerIssue[] = [];
157
- const userFile = options.userPath ?? settingsPath();
191
+ interface PreparedLayers {
192
+ projectFile: string;
193
+ localFile: string;
194
+ projectRaw: RawLayer;
195
+ localRaw: RawLayer;
196
+ project: RawLayer;
197
+ local: RawLayer;
198
+ }
199
+
200
+ function prepareProjectLayers(cwd: string, issues: SettingsLayerIssue[]): PreparedLayers {
158
201
  const projectFile = join(cwd, ".clio-coder", "settings.yaml");
159
202
  const localFile = join(cwd, ".clio-coder", "settings.local.yaml");
160
-
161
- const user = readRawLayer("user", userFile, issues);
162
203
  const projectRaw = readRawLayer("project", projectFile, issues);
163
204
  const localRaw = readRawLayer("project.local", localFile, issues);
164
-
165
205
  const project: RawLayer = {
166
206
  ...projectRaw,
167
207
  blob:
@@ -176,24 +216,118 @@ export function readLayeredSettings(cwd: string, options: ReadLayeredSettingsOpt
176
216
  ? undefined
177
217
  : (stripCredentials(localRaw.blob, "project.local", "", issues) as Record<string, unknown>),
178
218
  };
219
+ return { projectFile, localFile, projectRaw, localRaw, project, local };
220
+ }
179
221
 
180
- const { merged, sources } = mergeLayersWithSources([user, project, local]);
222
+ function validateLayerStack(
223
+ user: RawLayer,
224
+ prepared: PreparedLayers,
225
+ issues: SettingsLayerIssue[],
226
+ ): { settings: ClioSettings; sources: Record<string, SettingsOrigin> } {
227
+ const { merged, sources } = mergeLayersWithSources([user, prepared.project, prepared.local]);
181
228
  const validation = validateSettings(merged);
182
229
  for (const issue of validation.issues) {
183
230
  issues.push({ origin: settingsSourceFor(sources, issue.path), path: issue.path, message: issue.message });
184
231
  }
232
+ return { settings: validation.settings, sources };
233
+ }
234
+
235
+ /**
236
+ * Read and layer settings for `cwd`, returning the validated effective settings
237
+ * plus per-leaf source attribution. Never throws: validation issues and layer
238
+ * problems are returned, and the effective settings always validate (invalid
239
+ * merges fall back to the schema defaults for the offending keys).
240
+ */
241
+ export function readLayeredSettings(cwd: string, options: ReadLayeredSettingsOptions = {}): LayeredSettings {
242
+ const issues: SettingsLayerIssue[] = [];
243
+ const userFile = options.userPath ?? settingsPath();
244
+ const user = readRawLayer("user", userFile, issues);
245
+ const prepared = prepareProjectLayers(cwd, issues);
246
+ const { settings, sources } = validateLayerStack(user, prepared, issues);
185
247
 
248
+ const strictUserIssues =
249
+ user.blob === undefined
250
+ ? []
251
+ : validateSettings(user.blob).issues.map((issue) => ({
252
+ path: issue.path,
253
+ message: issue.message,
254
+ ...(issue.kind ? { kind: issue.kind } : {}),
255
+ }));
186
256
  return {
187
- settings: validation.settings,
257
+ settings,
188
258
  sources,
189
259
  issues,
190
260
  layers: [
191
261
  { origin: "built-in", path: "(defaults)", present: true },
192
262
  { origin: "user", path: userFile, present: user.blob !== undefined },
193
- { origin: "project", path: projectFile, present: projectRaw.blob !== undefined },
194
- { origin: "project.local", path: localFile, present: localRaw.blob !== undefined },
263
+ { origin: "project", path: prepared.projectFile, present: prepared.projectRaw.blob !== undefined },
264
+ { origin: "project.local", path: prepared.localFile, present: prepared.localRaw.blob !== undefined },
195
265
  ],
196
- };
266
+ [STRICT_USER_ISSUES]: strictUserIssues,
267
+ } as InternalLayeredSettings;
268
+ }
269
+
270
+ /**
271
+ * Read the complete effective stack once while retaining settings.yaml's
272
+ * strict launch gate. Project-layer issues remain diagnostics, matching the
273
+ * established best-effort workspace overlay contract.
274
+ */
275
+ export function readStrictLayeredSettings(cwd: string, options: ReadLayeredSettingsOptions = {}): LayeredSettings {
276
+ const layered = readLayeredSettings(cwd, options) as InternalLayeredSettings;
277
+ const reportedUserIssues = layered.issues
278
+ .filter((issue) => issue.origin === "user")
279
+ .map(({ path, message, kind }): SettingsIssue => ({ path, message, ...(kind ? { kind } : {}) }));
280
+ const userIssues = [...reportedUserIssues, ...layered[STRICT_USER_ISSUES]].filter(
281
+ (issue, index, all) =>
282
+ all.findIndex(
283
+ (candidate) =>
284
+ candidate.path === issue.path && candidate.message === issue.message && candidate.kind === issue.kind,
285
+ ) === index,
286
+ );
287
+ if (userIssues.length > 0) throw new SettingsValidationError(userIssues);
288
+ return layered;
289
+ }
290
+
291
+ /**
292
+ * Atomically persist a mutation of the effective workspace settings into the
293
+ * user layer. The candidate user document is re-layered with the same project
294
+ * files before it is written. This preserves references to project-only
295
+ * targets while refusing a mutation that a higher-precedence project leaf
296
+ * would silently override.
297
+ */
298
+ export function updateLayeredSettings(cwd: string, mutate: SettingsMutator): ClioSettings {
299
+ let committed: ClioSettings | null = null;
300
+ updateSavedSettingsDocument((saved) => {
301
+ const userValidation = validateSettings(saved);
302
+ if (userValidation.issues.length > 0) throw new SettingsValidationError(userValidation.issues);
303
+ const issues: SettingsLayerIssue[] = [];
304
+ const prepared = prepareProjectLayers(cwd, issues);
305
+ const user: RawLayer = {
306
+ origin: "user",
307
+ path: settingsPath(),
308
+ blob: isRecord(saved) ? saved : {},
309
+ };
310
+ const before = validateLayerStack(user, prepared, issues).settings;
311
+ const candidate = structuredClone(before);
312
+ const next = mutate(candidate) ?? candidate;
313
+ const candidateValidation = validateSettings(JSON.parse(JSON.stringify(next)));
314
+ if (candidateValidation.issues.length > 0) throw new SettingsValidationError(candidateValidation.issues);
315
+
316
+ const nextSaved = applySettingsDelta(saved, before, candidateValidation.settings);
317
+ const finalIssues: SettingsLayerIssue[] = [];
318
+ const final = validateLayerStack(
319
+ { origin: "user", path: settingsPath(), blob: isRecord(nextSaved) ? nextSaved : {} },
320
+ prepared,
321
+ finalIssues,
322
+ ).settings;
323
+ if (!deepEquals(final, candidateValidation.settings)) {
324
+ throw new Error("a higher-precedence project setting prevents this settings update");
325
+ }
326
+ committed = final;
327
+ return nextSaved;
328
+ });
329
+ if (committed === null) throw new Error("layered settings update did not commit");
330
+ return committed;
197
331
  }
198
332
 
199
333
  /**
@@ -7,7 +7,7 @@ export type PendingSkillRequestSource = "slash-command" | "selector" | "marketpl
7
7
  * reminder, and the operator-gate denial all cite this exact line so the
8
8
  * model learns a single protocol.
9
9
  */
10
- export const SKILL_SUGGESTION_ANCHOR = "Suggested skill: /skill:<name>";
10
+ export const SKILL_SUGGESTION_ANCHOR = "Suggested skill: /skill <name>";
11
11
 
12
12
  /**
13
13
  * The part of the anchor a real reply keeps once `<name>` is substituted.
@@ -15,13 +15,13 @@ export class StartupTimer {
15
15
  private readonly start = performance.now();
16
16
  private readonly marks: Mark[] = [];
17
17
 
18
- constructor() {
19
- traceBoot("boot start");
18
+ constructor(private readonly trace: (phase: string) => void = traceBoot) {
19
+ this.trace("boot start");
20
20
  }
21
21
 
22
22
  mark(name: string): void {
23
23
  this.marks.push({ name, at: performance.now() - this.start });
24
- traceBoot(name);
24
+ this.trace(name);
25
25
  }
26
26
 
27
27
  snapshot(): { totalMs: number; marks: ReadonlyArray<Mark> } {
@@ -1,6 +1,7 @@
1
1
  import { closeSync, mkdirSync, openSync, readFileSync, statSync, unlinkSync, utimesSync, writeSync } from "node:fs";
2
2
  import { hostname } from "node:os";
3
3
  import { dirname } from "node:path";
4
+ import { setTimeout as sleep } from "node:timers/promises";
4
5
  import { processAlive, processBirthToken } from "./process-identity.js";
5
6
 
6
7
  /**
@@ -36,6 +37,8 @@ export const FILE_LOCK_ACQUIRE_TIMEOUT_MS = 20_000;
36
37
  export interface StateFileLockOptions {
37
38
  /** Acquisition budget. Default `FILE_LOCK_ACQUIRE_TIMEOUT_MS`. */
38
39
  timeoutMs?: number;
40
+ /** Cancel an asynchronous lock wait and never enter or commit its critical section. */
41
+ signal?: AbortSignal;
39
42
  /**
40
43
  * `run-unlocked` runs `fn` anyway when the lock cannot be taken. Residency
41
44
  * mutations need it: serializing them is an optimization and must never fail
@@ -158,9 +161,11 @@ export function withStateFileLockSync<T>(targetPath: string, fn: () => T, option
158
161
  const timeoutMs = options.timeoutMs ?? FILE_LOCK_ACQUIRE_TIMEOUT_MS;
159
162
  let held = false;
160
163
  try {
164
+ options.signal?.throwIfAborted();
161
165
  mkdirSync(dirname(lockPath), { recursive: true });
162
166
  const deadlineMs = Date.now() + timeoutMs;
163
167
  for (let attempt = 1; !tryAcquire(lockPath); attempt += 1) {
168
+ options.signal?.throwIfAborted();
164
169
  if (Date.now() > deadlineMs) throw timeoutError(lockPath, timeoutMs);
165
170
  // Atomics.wait rather than a timer: the callers of this variant are
166
171
  // inside host APIs that cannot yield.
@@ -168,6 +173,7 @@ export function withStateFileLockSync<T>(targetPath: string, fn: () => T, option
168
173
  }
169
174
  held = true;
170
175
  } catch (err) {
176
+ options.signal?.throwIfAborted();
171
177
  if (options.onAcquireFailure !== "run-unlocked") throw err;
172
178
  }
173
179
  try {
@@ -186,15 +192,21 @@ export async function withStateFileLock<T>(
186
192
  const timeoutMs = options.timeoutMs ?? FILE_LOCK_ACQUIRE_TIMEOUT_MS;
187
193
  let held = false;
188
194
  try {
195
+ options.signal?.throwIfAborted();
189
196
  mkdirSync(dirname(lockPath), { recursive: true });
190
197
  const deadlineMs = Date.now() + timeoutMs;
191
198
  for (let attempt = 1; !tryAcquire(lockPath); attempt += 1) {
199
+ options.signal?.throwIfAborted();
192
200
  if (Date.now() > deadlineMs) throw timeoutError(lockPath, timeoutMs);
193
201
  const base = backoffMs(attempt);
194
- await new Promise((resolve) => setTimeout(resolve, base + Math.floor(Math.random() * base)));
202
+ const delayMs = base + Math.floor(Math.random() * base);
203
+ if (options.signal) await sleep(delayMs, undefined, { signal: options.signal });
204
+ else await sleep(delayMs);
195
205
  }
196
206
  held = true;
207
+ options.signal?.throwIfAborted();
197
208
  } catch (err) {
209
+ options.signal?.throwIfAborted();
198
210
  if (options.onAcquireFailure !== "run-unlocked") throw err;
199
211
  }
200
212
  const stopRefresh = held ? startRefresh(lockPath) : null;
@@ -9,6 +9,12 @@
9
9
  * hanging hook cannot block the TUI from exiting. The cap is 500ms by
10
10
  * default and can be overridden via CLIO_CODER_SHUTDOWN_HOOK_MS for tests.
11
11
  * Timed-out hooks are logged and shutdown continues to the next hook.
12
+ *
13
+ * Every diagnostic here is written after the TUI has stopped: the interactive
14
+ * controller stops the terminal before it calls shutdown(), and the signal path
15
+ * stops it from a drain hook, which precedes persist. The renderer is gone, so
16
+ * a diagnostic goes to stderr and is wrapped to the terminal width so it does
17
+ * not overrun the frame the TUI just handed back.
12
18
  */
13
19
 
14
20
  import { BusChannels } from "./bus-events.js";
@@ -27,6 +33,46 @@ const SIGNAL_EXIT_CODES: Partial<Record<NodeJS.Signals, number>> = {
27
33
  SIGTERM: 143,
28
34
  };
29
35
 
36
+ /**
37
+ * Break `text` into lines no wider than `width` columns, at spaces where
38
+ * possible and mid-word when a single token is wider than the terminal.
39
+ */
40
+ export function wrapToWidth(text: string, width: number): string[] {
41
+ if (!Number.isFinite(width) || width < 1) return [text];
42
+ const lines: string[] = [];
43
+ let current = "";
44
+ for (const word of text.split(/\s+/).filter((w) => w.length > 0)) {
45
+ let token = word;
46
+ while (token.length > width) {
47
+ if (current) {
48
+ lines.push(current);
49
+ current = "";
50
+ }
51
+ lines.push(token.slice(0, width));
52
+ token = token.slice(width);
53
+ }
54
+ if (!current) current = token;
55
+ else if (current.length + 1 + token.length <= width) current = `${current} ${token}`;
56
+ else {
57
+ lines.push(current);
58
+ current = token;
59
+ }
60
+ }
61
+ if (current) lines.push(current);
62
+ return lines.length > 0 ? lines : [""];
63
+ }
64
+
65
+ /**
66
+ * Emit a shutdown notice on stderr, wrapped to the terminal width when stderr
67
+ * or stdout is a TTY. Off a TTY the text goes out unwrapped, since a log
68
+ * consumer wants one record per line.
69
+ */
70
+ export function writeShutdownNotice(text: string): void {
71
+ const width = process.stderr.columns ?? process.stdout.columns;
72
+ const lines = width === undefined ? [text] : wrapToWidth(text, width);
73
+ process.stderr.write(`${lines.join("\n")}\n`);
74
+ }
75
+
30
76
  export function resolveShutdownHookBudgetMs(): number {
31
77
  const raw = process.env.CLIO_CODER_SHUTDOWN_HOOK_MS;
32
78
  if (raw === undefined) return DEFAULT_SHUTDOWN_HOOK_MS;
@@ -72,6 +118,8 @@ class TerminationCoordinator {
72
118
  private readonly persistHooks: Hook[] = [];
73
119
  private exitCode = 0;
74
120
  private started = false;
121
+ private drained = false;
122
+ private readonly pendingNotices: string[] = [];
75
123
  private signalHandler: ((signal: NodeJS.Signals) => void) | null = null;
76
124
 
77
125
  getPhase(): TerminationPhase {
@@ -116,6 +164,8 @@ class TerminationCoordinator {
116
164
  log("drain:start");
117
165
  await this.runHooks(this.drainHooks, "drain", budgetMs, log);
118
166
  log("drain:end");
167
+ this.drained = true;
168
+ this.flushNotices();
119
169
  bus.emit(BusChannels.ShutdownDrained, {});
120
170
 
121
171
  this.phase = "terminating";
@@ -142,13 +192,13 @@ class TerminationCoordinator {
142
192
  if (!hook) continue;
143
193
  const t0 = process.hrtime.bigint();
144
194
  const completed = await runWithBudget(hook, budgetMs, (err) => {
145
- console.error("[clio:termination] hook failed:", err);
195
+ const message = err instanceof Error ? err.message : String(err);
196
+ writeShutdownNotice(`[clio:termination] ${phase}[${i}] failed: ${message}`);
197
+ if (err instanceof Error && err.stack) log(err.stack);
146
198
  });
147
199
  const dt = Number(process.hrtime.bigint() - t0) / 1e6;
148
200
  if (!completed) {
149
- process.stderr.write(
150
- `[clio:termination] ${phase}[${i}] exceeded ${budgetMs}ms budget; abandoning and continuing shutdown\n`,
151
- );
201
+ writeShutdownNotice(`[clio:termination] ${phase}[${i}] exceeded ${budgetMs}ms budget; shutdown continues`);
152
202
  }
153
203
  log(` ${phase}[${i}] ${dt.toFixed(1)}ms${completed ? "" : " (timed out)"}`);
154
204
  }
@@ -163,7 +213,7 @@ class TerminationCoordinator {
163
213
  installSignalHandlers(): void {
164
214
  if (this.signalHandler) return;
165
215
  const handler = (signal: NodeJS.Signals): void => {
166
- process.stderr.write(`\nClio Coder: received ${signal}, shutting down...\n`);
216
+ this.notice(`Clio Coder: received ${signal}, shutting down...`);
167
217
  void this.shutdown(SIGNAL_EXIT_CODES[signal] ?? 143);
168
218
  };
169
219
  this.signalHandler = handler;
@@ -172,6 +222,29 @@ class TerminationCoordinator {
172
222
  process.once("SIGHUP", handler);
173
223
  }
174
224
 
225
+ /**
226
+ * Report something the operator should read after the process is gone,
227
+ * such as which signal ended it. Nothing here knows whether a TUI is on
228
+ * screen, but it does know that the terminal teardown is a drain hook: so
229
+ * until drain has finished the notice is held, and the moment it has, the
230
+ * notice goes to the terminal the TUI just handed back. Written straight
231
+ * away once drain is over, which is the case for a re-armed SIGINT arriving
232
+ * mid-shutdown. A second SIGTERM or SIGHUP inside the drain window takes
233
+ * Node's default action and the held notice dies with the process; that
234
+ * window is bounded by the per-hook budget and the shell reports the kill.
235
+ */
236
+ notice(text: string): void {
237
+ if (this.drained) {
238
+ writeShutdownNotice(text);
239
+ return;
240
+ }
241
+ this.pendingNotices.push(text);
242
+ }
243
+
244
+ private flushNotices(): void {
245
+ for (const text of this.pendingNotices.splice(0)) writeShutdownNotice(text);
246
+ }
247
+
175
248
  /**
176
249
  * Hand SIGINT to a foreground owner and return the call that takes it back.
177
250
  *
@@ -21,7 +21,14 @@ export interface ConfigDiff {
21
21
  restartRequired: string[];
22
22
  }
23
23
 
24
- const HOT_RELOAD_FIELDS = new Set<string>(["theme", "keybindings", "autonomy", "modelSelector"]);
24
+ const HOT_RELOAD_FIELDS = new Set<string>([
25
+ "theme",
26
+ "keybindings",
27
+ "autonomy",
28
+ "modelSelector",
29
+ "terminal.smoothStreaming",
30
+ "attribution.gitCommits",
31
+ ]);
25
32
 
26
33
  const NEXT_TURN_FIELDS = new Set<string>([
27
34
  "identity",
@@ -52,7 +59,12 @@ const NEXT_TURN_FIELDS = new Set<string>([
52
59
  "retry",
53
60
  ]);
54
61
 
55
- const RESTART_REQUIRED_FIELDS = new Set<string>(["budget.concurrency", "runtimePlugins"]);
62
+ const RESTART_REQUIRED_FIELDS = new Set<string>([
63
+ "budget.concurrency",
64
+ "runtimePlugins",
65
+ "terminal.tuiMode",
66
+ "terminal.fullscreenScrollbar",
67
+ ]);
56
68
 
57
69
  function matchesPrefix(path: string, fields: Set<string>): boolean {
58
70
  if (fields.has(path)) return true;
@@ -67,8 +79,8 @@ export function diffSettings(prev: ClioSettings, next: ClioSettings): ConfigDiff
67
79
  const diff: ConfigDiff = { hotReload: [], nextTurn: [], restartRequired: [] };
68
80
  for (const p of changed) {
69
81
  if (matchesPrefix(p, HOT_RELOAD_FIELDS)) diff.hotReload.push(p);
70
- else if (matchesPrefix(p, NEXT_TURN_FIELDS)) diff.nextTurn.push(p);
71
82
  else if (matchesPrefix(p, RESTART_REQUIRED_FIELDS)) diff.restartRequired.push(p);
83
+ else if (matchesPrefix(p, NEXT_TURN_FIELDS)) diff.nextTurn.push(p);
72
84
  else {
73
85
  // Unknown field falls back to restartRequired to fail closed.
74
86
  diff.restartRequired.push(p);
@@ -1,7 +1,8 @@
1
1
  import { BusChannels, type ConfigChangePayload } from "../../core/bus-events.js";
2
- import { type ClioSettings, formatSettingsFailure, readSettings, updateSettings } from "../../core/config.js";
2
+ import { type ClioSettings, formatSettingsFailure } from "../../core/config.js";
3
3
  import type { DomainBundle, DomainContext, DomainExtension } from "../../core/domain-loader.js";
4
- import { readLayeredSettings } from "../../core/settings-layers.js";
4
+ import { setGitCommitAttributionEnabled } from "../../core/git-commit-attribution.js";
5
+ import { readStrictLayeredSettings, updateLayeredSettings } from "../../core/settings-layers.js";
5
6
  import { assertAgentIdNamespace } from "./agent-namespace.js";
6
7
  import { type ChangeKind, diffSettings } from "./classify.js";
7
8
  import type { ConfigContract } from "./contract.js";
@@ -13,7 +14,10 @@ interface NativeAgentNamespace {
13
14
  list(): ReadonlyArray<{ id: string }>;
14
15
  }
15
16
 
16
- export function createConfigBundle(context: DomainContext): DomainBundle<ConfigContract> {
17
+ export function createConfigBundle(
18
+ context: DomainContext,
19
+ initialSettings?: Readonly<ClioSettings>,
20
+ ): DomainBundle<ConfigContract> {
17
21
  let watcher: ConfigWatcher | null = null;
18
22
  let snapshot: ClioSettings | null = null;
19
23
  let reloadFailure: string | null = null;
@@ -62,10 +66,9 @@ export function createConfigBundle(context: DomainContext): DomainBundle<ConfigC
62
66
  function onWatcherFire(): void {
63
67
  let next: ClioSettings;
64
68
  try {
65
- // readSettings keeps the strict throw-on-invalid-user-settings gate; the
66
- // layered read then overlays project .clio-coder/settings(.local).yaml.
67
- readSettings();
68
- next = readLayeredSettings(process.cwd()).settings;
69
+ // One file read keeps the strict user-settings gate while workspace
70
+ // overlays retain their established best-effort diagnostics.
71
+ next = readStrictLayeredSettings(process.cwd()).settings;
69
72
  } catch (err) {
70
73
  // The rejection is the whole effect: `snapshot` is untouched, so the
71
74
  // session keeps running on the last good settings.
@@ -81,6 +84,7 @@ export function createConfigBundle(context: DomainContext): DomainBundle<ConfigC
81
84
  }
82
85
  publishReloadFailure(null);
83
86
  snapshot = next;
87
+ setGitCommitAttributionEnabled(next.attribution.gitCommits);
84
88
  if (!prev) return;
85
89
  const diff = diffSettings(prev, next);
86
90
  if (diff.hotReload.length > 0) dispatch("hotReload", { diff, settings: next });
@@ -90,8 +94,9 @@ export function createConfigBundle(context: DomainContext): DomainBundle<ConfigC
90
94
 
91
95
  const extension: DomainExtension = {
92
96
  async start() {
93
- readSettings();
94
- snapshot = readLayeredSettings(process.cwd()).settings;
97
+ if (initialSettings) snapshot = structuredClone(initialSettings);
98
+ else snapshot = readStrictLayeredSettings(process.cwd()).settings;
99
+ setGitCommitAttributionEnabled(snapshot.attribution.gitCommits);
95
100
  watcher = startConfigWatcher(() => onWatcherFire());
96
101
  },
97
102
  async stop() {
@@ -114,11 +119,12 @@ export function createConfigBundle(context: DomainContext): DomainBundle<ConfigC
114
119
  const candidate = structuredClone(previous);
115
120
  mutate(candidate);
116
121
  assertAgentNamespace(candidate);
117
- // updateSettings writes the user layer; re-layer so project overlays
118
- // stay applied in the refreshed snapshot.
119
- updateSettings(mutate);
120
- const normalized = readLayeredSettings(process.cwd()).settings;
122
+ // Apply the effective-view delta to the user document under one lock,
123
+ // then validate it with the project layers before writing. In particular,
124
+ // a route may name a target supplied only by this workspace.
125
+ const normalized = updateLayeredSettings(process.cwd(), mutate);
121
126
  snapshot = normalized;
127
+ setGitCommitAttributionEnabled(normalized.attribution.gitCommits);
122
128
  const diff = diffSettings(previous, normalized);
123
129
  if (diff.hotReload.length > 0) dispatch("hotReload", { diff, settings: normalized });
124
130
  if (diff.nextTurn.length > 0) dispatch("nextTurn", { diff, settings: normalized });
@@ -7,6 +7,16 @@ export const ConfigDomainModule: DomainModule = {
7
7
  createExtension: createConfigBundle,
8
8
  };
9
9
 
10
+ /** Bind the one strict startup snapshot without changing other command paths. */
11
+ export function createConfigDomainModule(
12
+ initialSettings: Readonly<import("../../core/config.js").ClioSettings>,
13
+ ): DomainModule {
14
+ return {
15
+ manifest: ConfigManifest,
16
+ createExtension: (context) => createConfigBundle(context, initialSettings),
17
+ };
18
+ }
19
+
10
20
  export { assertAgentIdNamespace } from "./agent-namespace.js";
11
21
  export { type ChangeKind, type ConfigDiff, diffSettings } from "./classify.js";
12
22
  export type { ConfigContract } from "./contract.js";