@iowarp/clio-coder 0.3.1 → 0.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (601) hide show
  1. package/CHANGELOG.md +233 -373
  2. package/CONTRIBUTING.md +23 -23
  3. package/README.md +284 -613
  4. package/dist/{acp-FPR54DGL.js → acp-P2AQILE2.js} +43 -53
  5. package/dist/{agents-OGPIHPJH.js → agents-72W3BI7I.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-2DJ2KNFG.js +2095 -0
  9. package/dist/{chunk-IS3ONKU3.js → chunk-2IR2NMPA.js} +6 -4
  10. package/dist/chunk-2SFS6XQE.js +122 -0
  11. package/dist/{chunk-PV4JUBVJ.js → chunk-2TLUCQVG.js} +40 -21
  12. package/dist/chunk-2VTFPG5O.js +48 -0
  13. package/dist/chunk-4BJ5BYCE.js +61 -0
  14. package/dist/{chunk-474KN5II.js → chunk-4BPJXDWC.js} +111 -181
  15. package/dist/chunk-4VP4KH3K.js +962 -0
  16. package/dist/chunk-4XUGQOHA.js +797 -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-4QKXUHSR.js → chunk-5UFT4SUX.js} +70 -20
  21. package/dist/{chunk-OLBBMFRD.js → chunk-5UUP6MWO.js} +24 -62
  22. package/dist/chunk-65DEGPJ6.js +52 -0
  23. package/dist/chunk-6EJMN2Y3.js +17 -0
  24. package/dist/chunk-6N5PTWMY.js +136 -0
  25. package/dist/chunk-6SGHMWE3.js +277 -0
  26. package/dist/chunk-6XLNIQDB.js +27 -0
  27. package/dist/chunk-7CR24IG7.js +242 -0
  28. package/dist/chunk-7MNJORFF.js +22 -0
  29. package/dist/{chunk-KY56HMHH.js → chunk-A3CYT5EX.js} +125 -31
  30. package/dist/chunk-AGYYIBLL.js +1069 -0
  31. package/dist/{chunk-GB6QRBXN.js → chunk-APJ265NV.js} +54 -1187
  32. package/dist/{chunk-673JJUWJ.js → chunk-BMEMKKIT.js} +2 -2
  33. package/dist/chunk-CBCAPZAA.js +229 -0
  34. package/dist/chunk-CMZWFGD2.js +352 -0
  35. package/dist/chunk-COU2UHX6.js +400 -0
  36. package/dist/chunk-DSELYM6W.js +1077 -0
  37. package/dist/chunk-DUYJ5IO6.js +644 -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-FCSXB6T2.js +338 -0
  42. package/dist/chunk-FJ3H4MN5.js +48 -0
  43. package/dist/{chunk-RPTR2H26.js → chunk-FNTMWMX5.js} +21 -15
  44. package/dist/chunk-FQ4SKYE4.js +29 -0
  45. package/dist/chunk-G4BMMOKF.js +182 -0
  46. package/dist/{chunk-ZPY3JZ5E.js → chunk-GGXXDWE4.js} +183 -1233
  47. package/dist/chunk-HC4CLZ2Y.js +68 -0
  48. package/dist/{chunk-LU4TK2PR.js → chunk-HFSBBKSQ.js} +5 -56
  49. package/dist/{chunk-PIUMUEMV.js → chunk-HKIYEGME.js} +10 -6
  50. package/dist/chunk-I4HZDVNP.js +73 -0
  51. package/dist/chunk-IKCO5N3L.js +162 -0
  52. package/dist/chunk-IR4CFBFN.js +56 -0
  53. package/dist/{chunk-R5KLMSBV.js → chunk-J5Q24KAG.js} +2 -2
  54. package/dist/chunk-J7CWMCQD.js +255 -0
  55. package/dist/{chunk-K5XEMXTI.js → chunk-JVCV3ICN.js} +1 -1
  56. package/dist/chunk-KZWTDYJF.js +217 -0
  57. package/dist/chunk-LBMZMYH2.js +285 -0
  58. package/dist/{chunk-G34LV2PF.js → chunk-LM5TQCJZ.js} +84 -170
  59. package/dist/chunk-LW6DSM3M.js +5135 -0
  60. package/dist/chunk-LWLEKMDQ.js +3482 -0
  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-FST4FYJB.js → chunk-MFFY33HR.js} +99 -140
  64. package/dist/{chunk-BSU2YIWB.js → chunk-MVVUPGPW.js} +131 -136
  65. package/dist/chunk-OAO4GE4M.js +619 -0
  66. package/dist/{chunk-Q3RUPKEJ.js → chunk-OC7FIQPC.js} +58 -189
  67. package/dist/chunk-OKGUZO2U.js +34 -0
  68. package/dist/{chunk-GAEBEQVI.js → chunk-OOJYHWRB.js} +32 -346
  69. package/dist/{chunk-Q5WJOSJ7.js → chunk-OQ33BKR3.js} +2 -1
  70. package/dist/chunk-OQE5J4C6.js +73 -0
  71. package/dist/{chunk-KKNLWXI6.js → chunk-ORBHGJC5.js} +8 -8
  72. package/dist/{chunk-MAR7Y6HW.js → chunk-PAJK6MAQ.js} +23 -16
  73. package/dist/{chunk-M5T5VO65.js → chunk-PIWWS5BL.js} +837 -635
  74. package/dist/chunk-POHLU5DW.js +1186 -0
  75. package/dist/chunk-QKMUKYO7.js +4961 -0
  76. package/dist/chunk-SRDMMSEP.js +16405 -0
  77. package/dist/chunk-SST6Z5JA.js +80 -0
  78. package/dist/chunk-STBPMHSX.js +2456 -0
  79. package/dist/chunk-T6YILFSB.js +80 -0
  80. package/dist/chunk-TZK7PACC.js +174 -0
  81. package/dist/chunk-TZTZS7QK.js +227 -0
  82. package/dist/{chunk-ASND7OZK.js → chunk-UFIIWP2H.js} +13 -13
  83. package/dist/chunk-UOV2BYIW.js +107 -0
  84. package/dist/{chunk-PFEFKVGL.js → chunk-V6RTAOC2.js} +13 -11
  85. package/dist/chunk-VAKQQHWR.js +434 -0
  86. package/dist/chunk-VG7TBQIY.js +128 -0
  87. package/dist/chunk-VJWL6YS5.js +244 -0
  88. package/dist/{chunk-EYOKLTMF.js → chunk-VPAYEGVX.js} +17 -3
  89. package/dist/chunk-WEH5XRJQ.js +32 -0
  90. package/dist/chunk-X4RCMKVQ.js +641 -0
  91. package/dist/{chunk-TEKV33Q5.js → chunk-X6IAEBZR.js} +65 -33
  92. package/dist/chunk-XBXAASKX.js +18 -0
  93. package/dist/chunk-XN3L4EYL.js +46 -0
  94. package/dist/{chunk-RDLVBZEO.js → chunk-YCWGATWI.js} +6 -4
  95. package/dist/chunk-YHZX5GEU.js +193 -0
  96. package/dist/chunk-YXLYO42X.js +91 -0
  97. package/dist/{chunk-NMOX6HFD.js → chunk-ZDOOVTXZ.js} +29 -77
  98. package/dist/chunk-ZI647VB5.js +37 -0
  99. package/dist/{chunk-C4PTHK7P.js → chunk-ZWLZP4ZT.js} +5 -5
  100. package/dist/chunk-ZWMF7253.js +1882 -0
  101. package/dist/cli/index.js +62 -54
  102. package/dist/clio-JOU4FXVA.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-XCDVKR23.js} +92 -55
  108. package/dist/configure-4GAP54ZW.js +42 -0
  109. package/dist/{context-5RADCKTR.js → context-4UOGGLQ5.js} +71 -35
  110. package/dist/context-5VKGUVJJ.js +866 -0
  111. package/dist/{context-3KWFLHJG.js → context-77FM5DV5.js} +15 -13
  112. package/dist/{context-clear-7TSNPAAI.js → context-clear-XXJRLCJJ.js} +54 -28
  113. package/dist/{context-index-W4RLWOQH.js → context-index-BZ4UYMTC.js} +30 -24
  114. package/dist/dispatch-runner-QPRDDBDX.js +1997 -0
  115. package/dist/{docs-5AWSPS37.js → docs-2C2LTVT2.js} +23 -10
  116. package/dist/{doctor-UC5NAJYQ.js → doctor-HR46URBJ.js} +27 -17
  117. package/dist/{eval-U6TJHRLX.js → eval-XSSNATB4.js} +29 -16
  118. package/dist/{evidence-YEGUW4L3.js → evidence-6HG2PY2B.js} +46 -26
  119. package/dist/{evolve-TXARCTPG.js → evolve-K7YU3NCY.js} +45 -25
  120. package/dist/{extensions-OZFJ3A3G.js → extensions-QVDOHDGJ.js} +16 -7
  121. package/dist/{fleet-6G3DHNYE.js → fleet-VY3HHKN6.js} +163 -54
  122. package/dist/{fleet-preflight-DSNT37JK.js → fleet-preflight-DDN536IT.js} +7 -4
  123. package/dist/{init-KZ5QTF6M.js → init-JYGXI3FK.js} +69 -32
  124. package/dist/{memory-73ESV5YC.js → memory-WFZMGYHX.js} +48 -27
  125. package/dist/{models-A4PVNWJK.js → models-I5QWSEOM.js} +39 -25
  126. package/dist/monitor-GE4ID3IA.js +661 -0
  127. package/dist/{chunk-FCIH3BIZ.js → orchestrator-EM5MC3HM.js} +15979 -12407
  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-ZU3QMZPZ.js} +101 -61
  132. package/dist/{share-YIFFV4NQ.js → share-S5BZQC5I.js} +15 -8
  133. package/dist/{skills-2V6RA3OQ.js → skills-X5VXCRNQ.js} +34 -14
  134. package/dist/{skills-eval-S2TVJO4F.js → skills-eval-WKIHWTHR.js} +70 -34
  135. package/dist/steer-GGWFUJUD.js +77 -0
  136. package/dist/{targets-TYXLPB23.js → targets-SNCPI2NR.js} +43 -27
  137. package/dist/terminal-lease-BNAHVHBS.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-JQHHPQ4K.js} +45 -25
  142. package/dist/{usage-ZAFSXKKG.js → usage-OR4O5SMZ.js} +62 -31
  143. package/dist/verify-375KUB3Y.js +716 -0
  144. package/dist/web-fetch-2YHJ3KTG.js +638 -0
  145. package/dist/{wiki-generate-NUQCVOQ3.js → wiki-generate-UEXP2ARI.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 +387 -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 +45 -9
  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 +715 -278
  444. package/src/interactive/chat-renderer.ts +306 -85
  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 +253 -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 +42 -22
  456. package/src/interactive/footer-panel.ts +8 -3
  457. package/src/interactive/format-time.ts +14 -2
  458. package/src/interactive/interactive-application.ts +203 -17
  459. package/src/interactive/interactive-event-projection.ts +18 -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 +184 -117
  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/ask-user.ts +146 -24
  474. package/src/interactive/overlays/decisions.ts +300 -0
  475. package/src/interactive/overlays/help-reference.ts +15 -10
  476. package/src/interactive/overlays/model-selector.ts +34 -16
  477. package/src/interactive/overlays/session-selector.ts +18 -0
  478. package/src/interactive/overlays/settings.ts +105 -17
  479. package/src/interactive/overlays/skills-hub.ts +4 -4
  480. package/src/interactive/overlays/tree-selector.ts +41 -6
  481. package/src/interactive/render-trace.ts +499 -90
  482. package/src/interactive/renderers/compaction-summary.ts +2 -2
  483. package/src/interactive/renderers/diff.ts +115 -104
  484. package/src/interactive/renderers/mermaid.ts +53 -0
  485. package/src/interactive/renderers/tool-execution.ts +516 -168
  486. package/src/interactive/renderers/worker-entry.ts +20 -4
  487. package/src/interactive/session-switch-settlement.ts +10 -0
  488. package/src/interactive/slash-autocomplete.ts +6 -114
  489. package/src/interactive/slash-commands.ts +135 -47
  490. package/src/interactive/slash-spec.ts +9 -38
  491. package/src/interactive/status/controller.ts +5 -1
  492. package/src/interactive/status/index.ts +12 -1
  493. package/src/interactive/status/reasoning.ts +87 -0
  494. package/src/interactive/status/summary.ts +13 -2
  495. package/src/interactive/stdout-backpressure.ts +99 -0
  496. package/src/interactive/stream-pacer.ts +530 -0
  497. package/src/interactive/stream-pacing-policy.ts +66 -0
  498. package/src/interactive/tasks-overlay.ts +368 -14
  499. package/src/interactive/terminal-lease.ts +485 -0
  500. package/src/interactive/theme/tokens.ts +1 -1
  501. package/src/interactive/transcript-detail.ts +120 -0
  502. package/src/interactive/turn-context.ts +4 -3
  503. package/src/interactive/turn-persistence.ts +30 -13
  504. package/src/interactive/turn-queues.ts +12 -0
  505. package/src/interactive/turn-recovery.ts +25 -8
  506. package/src/interactive/turn-runtime.ts +79 -12
  507. package/src/interactive/turn-state.ts +10 -0
  508. package/src/interactive/view/artifacts.ts +114 -4
  509. package/src/interactive/view/view-overlay.ts +3 -0
  510. package/src/interactive/welcome-dashboard.ts +17 -16
  511. package/src/interactive/worker-receipts.ts +52 -3
  512. package/src/interactive/worker-stream.ts +5 -1
  513. package/src/tools/agent-tools.ts +23 -3
  514. package/src/tools/artifact.ts +2 -2
  515. package/src/tools/ask-user.ts +23 -13
  516. package/src/tools/bash.ts +30 -2
  517. package/src/tools/bootstrap.ts +34 -431
  518. package/src/tools/builtin-tool-catalog.ts +271 -0
  519. package/src/tools/codewiki/code-nav-surface.ts +29 -0
  520. package/src/tools/codewiki/code-nav.ts +8 -22
  521. package/src/tools/codewiki/shared.ts +41 -38
  522. package/src/tools/context/docs-engine.ts +14 -3
  523. package/src/tools/context/index.ts +107 -28
  524. package/src/tools/context/surface.ts +19 -0
  525. package/src/tools/core-bootstrap.ts +168 -0
  526. package/src/tools/credential-present.ts +5 -5
  527. package/src/tools/dispatch-admission.ts +533 -0
  528. package/src/tools/dispatch-background.ts +54 -0
  529. package/src/tools/dispatch-event-text.ts +6 -0
  530. package/src/tools/dispatch-plan.ts +9 -4
  531. package/src/tools/dispatch-run-events.ts +238 -0
  532. package/src/tools/dispatch-runner.ts +2370 -0
  533. package/src/tools/dispatch-scout-admission.ts +295 -0
  534. package/src/tools/dispatch-types.ts +77 -0
  535. package/src/tools/dispatch.ts +67 -3161
  536. package/src/tools/find.ts +4 -2
  537. package/src/tools/grep.ts +2 -2
  538. package/src/tools/lazy-tool.ts +60 -0
  539. package/src/tools/ledger.ts +3 -3
  540. package/src/tools/monitor-surface.ts +36 -0
  541. package/src/tools/monitor.ts +2 -32
  542. package/src/tools/observers.ts +2 -2
  543. package/src/tools/presentation.ts +107 -0
  544. package/src/tools/registry.ts +45 -27
  545. package/src/tools/safe-exec.ts +2 -2
  546. package/src/tools/steer-surface.ts +17 -0
  547. package/src/tools/steer.ts +2 -13
  548. package/src/tools/tasks.ts +108 -11
  549. package/src/tools/truncate.ts +25 -184
  550. package/src/tools/verify/frontend.ts +3 -1
  551. package/src/tools/verify/index.ts +3 -38
  552. package/src/tools/verify/surface.ts +46 -0
  553. package/src/tools/web-fetch-surface.ts +23 -0
  554. package/src/tools/web-fetch.ts +2 -20
  555. package/src/tools/write.ts +7 -2
  556. package/src/worker/entry.ts +39 -2
  557. package/src/worker/spec-contract.ts +26 -5
  558. package/dist/chunk-7SS2CTV2.js +0 -61361
  559. package/dist/chunk-DKGKUHFA.js +0 -924
  560. package/dist/chunk-GEP36Y4X.js +0 -12796
  561. package/dist/chunk-XYWBQRDM.js +0 -137
  562. package/dist/clio-BZVGEUFJ.js +0 -58
  563. package/dist/configure-S7S6F6CL.js +0 -32
  564. package/docs/html/agents_blueprint.html +0 -936
  565. package/docs/html/alcf_blueprint.html +0 -324
  566. package/docs/html/architecture_blueprint.html +0 -850
  567. package/docs/html/commands_blueprint.html +0 -939
  568. package/docs/html/config_knobs_audit_blueprint.html +0 -178
  569. package/docs/html/configuration_blueprint.html +0 -1080
  570. package/docs/html/context_blueprint.html +0 -603
  571. package/docs/html/documentation_blueprint.html +0 -832
  572. package/docs/html/environment_blueprint.html +0 -404
  573. package/docs/html/eval_blueprint.html +0 -743
  574. package/docs/html/evals_internal_blueprint.html +0 -190
  575. package/docs/html/evolution_blueprint.html +0 -674
  576. package/docs/html/extensions_blueprint.html +0 -2065
  577. package/docs/html/fleet_dispatch_blueprint.html +0 -286
  578. package/docs/html/index.html +0 -919
  579. package/docs/html/lifecycle_blueprint.html +0 -723
  580. package/docs/html/memory_blueprint.html +0 -699
  581. package/docs/html/middleware_blueprint.html +0 -664
  582. package/docs/html/models_blueprint.html +0 -2366
  583. package/docs/html/observability_blueprint.html +0 -683
  584. package/docs/html/provider_adapter_blueprint.html +0 -245
  585. package/docs/html/safety_blueprint.html +0 -1386
  586. package/docs/html/shared.css +0 -571
  587. package/docs/html/shared.js +0 -143
  588. package/docs/html/skills_blueprint.html +0 -671
  589. package/docs/html/soak_blueprint.html +0 -182
  590. package/docs/html/tool_usage_blueprint.html +0 -350
  591. package/docs/html/tools_blueprint.html +0 -2249
  592. package/docs/html/trace_blueprint.html +0 -235
  593. package/docs/html/tui_design_blueprint.html +0 -374
  594. package/docs/html/validation_blueprint.html +0 -961
  595. package/docs/html/worker_dispatch_blueprint.html +0 -231
  596. package/src/core/release.ts +0 -2
  597. package/src/domains/providers/runtimes/common/lmstudio-logger.ts +0 -32
  598. package/src/domains/providers/runtimes/local-native/lmstudio-native.ts +0 -491
  599. package/src/engine/apis/lmstudio-native.ts +0 -1438
  600. package/src/engine/apis/thinking-replay.ts +0 -11
  601. 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";