@iowarp/clio-coder 0.3.7 → 0.3.9

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 (400) hide show
  1. package/CHANGELOG.md +80 -0
  2. package/README.md +13 -4
  3. package/dist/{acp-SK4MD6MM.js → acp-7LOELQFP.js} +13 -13
  4. package/dist/{agents-2FN2K6ME.js → agents-FIBG2SHA.js} +41 -37
  5. package/dist/assets/codewiki.json +1 -1
  6. package/dist/{auth-QIYZWM5I.js → auth-OI4LIH2I.js} +31 -24
  7. package/dist/builtins-AD25UL3C.js +17 -0
  8. package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
  9. package/dist/chunk-3DPEIQKN.js +113 -0
  10. package/dist/{chunk-EOOQZZDE.js → chunk-3DUR4WUA.js} +19 -19
  11. package/dist/{chunk-WHJYKASB.js → chunk-3MRC2YSQ.js} +2 -2
  12. package/dist/{chunk-EBEFWSGL.js → chunk-3UUY7R3Z.js} +14 -10
  13. package/dist/{chunk-LADCF22A.js → chunk-3V5AYSEQ.js} +113 -54
  14. package/dist/{chunk-BMWK7ZIZ.js → chunk-465CC7FK.js} +16 -13
  15. package/dist/{chunk-5WIGXA4T.js → chunk-47CMYGET.js} +111 -4
  16. package/dist/{chunk-CEYBNUGC.js → chunk-4H6ULJ3H.js} +378 -36
  17. package/dist/{chunk-YTYFXUI3.js → chunk-4LJX2PUC.js} +9 -9
  18. package/dist/{chunk-DOOEX22V.js → chunk-56KB5IJP.js} +5 -5
  19. package/dist/{chunk-SPULKLCF.js → chunk-5DQRIYDZ.js} +2 -2
  20. package/dist/{chunk-TSHXZTOQ.js → chunk-5HFBWUMU.js} +23 -11
  21. package/dist/{chunk-5UJ6ECTS.js → chunk-5PVQ4SRS.js} +80 -8
  22. package/dist/{chunk-ZWLZP4ZT.js → chunk-5QKCQQ3E.js} +359 -17
  23. package/dist/{chunk-6M7VS3J3.js → chunk-5T7RBWN2.js} +111 -5
  24. package/dist/chunk-774ILSRL.js +172 -0
  25. package/dist/chunk-7C6RYZGQ.js +391 -0
  26. package/dist/{chunk-GH5622CP.js → chunk-A2NJGIB3.js} +2 -2
  27. package/dist/{chunk-C4JBQ5SR.js → chunk-AD7Y7STJ.js} +6 -6
  28. package/dist/{chunk-GEYXPTRF.js → chunk-AEYBF3TB.js} +33 -12
  29. package/dist/{chunk-2SFS6XQE.js → chunk-AMKHQW3C.js} +3 -2
  30. package/dist/{chunk-D4MDIG46.js → chunk-B5CSFE7B.js} +7 -7
  31. package/dist/{chunk-MXI6J5JF.js → chunk-B5XRQOLB.js} +10 -10
  32. package/dist/{chunk-X2KV5FXT.js → chunk-BVDVID7E.js} +2 -2
  33. package/dist/{chunk-JNXPYBB4.js → chunk-CA42X6KT.js} +3 -3
  34. package/dist/{chunk-VREKEFLL.js → chunk-D73KXYPF.js} +3 -3
  35. package/dist/{chunk-JTSEDYVQ.js → chunk-DG4M6ZUE.js} +7 -7
  36. package/dist/{chunk-DQA7QLMD.js → chunk-EBOC7MT3.js} +10 -25
  37. package/dist/{chunk-KZ2H5X4G.js → chunk-ECUO3KDP.js} +129 -14
  38. package/dist/{chunk-JRIO5UD2.js → chunk-EQ63NRB7.js} +5 -5
  39. package/dist/{chunk-YD734TPH.js → chunk-FALJGAWU.js} +2 -2
  40. package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
  41. package/dist/{chunk-XEGB6BCN.js → chunk-GAYUJ7LE.js} +68 -14
  42. package/dist/{chunk-UND3GU2L.js → chunk-H7IXIC72.js} +2 -2
  43. package/dist/{chunk-IR4CFBFN.js → chunk-HAY4ZE2P.js} +12 -12
  44. package/dist/{chunk-UVDSQ6LW.js → chunk-HCBCAYZU.js} +74 -147
  45. package/dist/{chunk-4DWFMQDR.js → chunk-HJB5IUKP.js} +89 -145
  46. package/dist/{chunk-M4AKACEO.js → chunk-HKO36JWF.js} +33 -5
  47. package/dist/{chunk-KCMKRQX4.js → chunk-HPCTNZM2.js} +45 -82
  48. package/dist/{chunk-465YSENW.js → chunk-IFBNV6H6.js} +3 -3
  49. package/dist/{chunk-FJ3H4MN5.js → chunk-IHKBWSXF.js} +2 -2
  50. package/dist/chunk-JEQQR47K.js +3025 -0
  51. package/dist/{chunk-FO5ZOVUY.js → chunk-KV2AOLDF.js} +27 -7
  52. package/dist/chunk-LU7P4LHA.js +33 -0
  53. package/dist/{chunk-6TUKSZVF.js → chunk-LXPJXFM5.js} +11 -11
  54. package/dist/{chunk-VQNODYQ4.js → chunk-MIX5N5AC.js} +488 -3668
  55. package/dist/chunk-MLOK6ZOS.js +2888 -0
  56. package/dist/{chunk-ZZMN5OM4.js → chunk-MV2VUEJC.js} +2 -2
  57. package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
  58. package/dist/{chunk-OBMAI2DP.js → chunk-N3PBVRTZ.js} +12 -388
  59. package/dist/{chunk-WJHBC77E.js → chunk-N5XKWMDW.js} +17 -7
  60. package/dist/{chunk-5C3AQNDW.js → chunk-NNNWO6F2.js} +124 -36
  61. package/dist/{chunk-UFQ3F4FW.js → chunk-NQ6UCCOD.js} +4 -4
  62. package/dist/chunk-NUGM5KR6.js +165 -0
  63. package/dist/{chunk-DMD2AGVS.js → chunk-NZU6YDNV.js} +20 -18
  64. package/dist/{chunk-WHGPSPT5.js → chunk-O6I4CIEU.js} +151 -13
  65. package/dist/{chunk-XN3L4EYL.js → chunk-OEDBCISO.js} +2 -2
  66. package/dist/{chunk-PD3MESLB.js → chunk-P3JGPQFL.js} +4 -4
  67. package/dist/{chunk-UHXRNZ2J.js → chunk-PNY46YEY.js} +23 -6
  68. package/dist/{chunk-THKY7CD7.js → chunk-PZ4I4JE2.js} +134 -29
  69. package/dist/{chunk-SROCI7ZU.js → chunk-QQ7EKM72.js} +5 -5
  70. package/dist/{chunk-QCTRSGHQ.js → chunk-R7LNVMCS.js} +91 -53
  71. package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
  72. package/dist/chunk-RKKLTLYB.js +45 -0
  73. package/dist/{chunk-OB5HIGJY.js → chunk-RKRLDWD3.js} +4 -1
  74. package/dist/{chunk-DJNLUABN.js → chunk-S4COXYBG.js} +588 -32
  75. package/dist/{chunk-3HAPLH5M.js → chunk-T3Z6VAAF.js} +172 -11
  76. package/dist/{chunk-FOT2FX5J.js → chunk-TD7UE2L5.js} +12 -10
  77. package/dist/{chunk-UUANF5CR.js → chunk-TEO2TLVN.js} +856 -967
  78. package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
  79. package/dist/{chunk-EELBMBT6.js → chunk-VKBMFOYV.js} +74 -15
  80. package/dist/chunk-VO2LKSTM.js +165 -0
  81. package/dist/{chunk-5C77SEEY.js → chunk-VPTUJU4P.js} +3 -3
  82. package/dist/{chunk-WEH5XRJQ.js → chunk-WIE7ZOSW.js} +2 -2
  83. package/dist/{chunk-J7PIKKWC.js → chunk-WXCJ7VME.js} +8 -8
  84. package/dist/{chunk-4DGYLA73.js → chunk-XDOQXGFO.js} +22 -7
  85. package/dist/{chunk-PPAMZ32Z.js → chunk-XK56QHLX.js} +6 -1
  86. package/dist/{chunk-AB4XIIVB.js → chunk-YKOFT37S.js} +6 -6
  87. package/dist/chunk-YSEHGPCT.js +127 -0
  88. package/dist/{chunk-HFSBBKSQ.js → chunk-YW7UVM5V.js} +138 -3
  89. package/dist/cli/index.js +32 -32
  90. package/dist/{clio-WBVQEBKO.js → clio-LT5V7SSZ.js} +9 -9
  91. package/dist/{code-nav-FGGFIE7L.js → code-nav-LMW275PA.js} +5 -5
  92. package/dist/codewiki/build-worker.js +4 -4
  93. package/dist/{components-F7OEATSO.js → components-ZFA3SAER.js} +8 -8
  94. package/dist/{config-TRBL3RCF.js → config-RXS5T3JT.js} +98 -65
  95. package/dist/{configure-OLCVPHNM.js → configure-2WYWSCSD.js} +26 -22
  96. package/dist/{context-MJIJ6GOX.js → context-I3BTOTCS.js} +12 -12
  97. package/dist/{context-XEWE3MOJ.js → context-MVOORGMF.js} +54 -47
  98. package/dist/{context-WFPKQSM6.js → context-PALKKQYL.js} +28 -28
  99. package/dist/{context-clear-KNOS2JPB.js → context-clear-N2WOYZ2K.js} +53 -46
  100. package/dist/{context-index-SSR5ECNE.js → context-index-HNG3MOME.js} +6 -6
  101. package/dist/{context-working-set-EUXAZI6N.js → context-working-set-MIEVECVZ.js} +17 -18
  102. package/dist/{dispatch-runner-B7MTOVKL.js → dispatch-runner-VVA4SRRH.js} +90 -61
  103. package/dist/{docs-FLJTIDSE.js → docs-7LQ23DLM.js} +8 -8
  104. package/dist/doctor-TWBWFK5V.js +165 -0
  105. package/dist/eval-IJ5VEZDJ.js +4483 -0
  106. package/dist/{evidence-JZNBUOQZ.js → evidence-L5APPXNV.js} +68 -61
  107. package/dist/{evolve-FJVC4KKI.js → evolve-RGNKFJ52.js} +47 -40
  108. package/dist/{extensions-IQL36S7K.js → extensions-7WYWUX5A.js} +13 -7
  109. package/dist/{fleet-BDKYJFCP.js → fleet-6CNVBZZP.js} +113 -76
  110. package/dist/{fleet-commands-ZFIWZSB3.js → fleet-commands-L2SXSYEI.js} +10 -10
  111. package/dist/{fleet-graph-Y6HPXIVF.js → fleet-graph-2J3OOIPO.js} +17 -15
  112. package/dist/{fleet-preflight-BHSNPBMH.js → fleet-preflight-CZRJ4JP5.js} +5 -6
  113. package/dist/{fleet-validate-BIYREGIK.js → fleet-validate-C5RI6DP7.js} +20 -19
  114. package/dist/{init-LQUB5COQ.js → init-VBN2ACVA.js} +70 -63
  115. package/dist/{library-NJAHIGG4.js → library-JHGUMLY2.js} +22 -20
  116. package/dist/{memory-OG6HOYKM.js → memory-K4OQIYWG.js} +49 -42
  117. package/dist/{models-5ZG5XY7J.js → models-2NCZUWDD.js} +35 -29
  118. package/dist/{monitor-TJ7AMTGB.js → monitor-MMVTJABD.js} +64 -45
  119. package/dist/{orchestrator-WZYB54DM.js → orchestrator-ZKBPCHW6.js} +1971 -520
  120. package/dist/{paths-XUC7GS6E.js → paths-DBXMZMDU.js} +5 -5
  121. package/dist/registry-LG64LTF4.js +11 -0
  122. package/dist/{reset-PXQT45IY.js → reset-DD5JGOY3.js} +11 -11
  123. package/dist/{run-FQ74YF62.js → run-QEGNX7FL.js} +89 -83
  124. package/dist/{share-FW7SVCL3.js → share-JKD3BQMW.js} +20 -18
  125. package/dist/{skills-7E7IRB3R.js → skills-LMQIKDOZ.js} +23 -21
  126. package/dist/{skills-eval-LI75W6OK.js → skills-eval-I7X2774U.js} +59 -52
  127. package/dist/{steer-GGWFUJUD.js → steer-CF5TDANS.js} +3 -3
  128. package/dist/support-I7LOJLIF.js +38 -0
  129. package/dist/{targets-4CIFKCTW.js → targets-RUSR6B5Z.js} +77 -42
  130. package/dist/{terminal-lease-WUZY7ZV5.js → terminal-lease-QYVORFR4.js} +6 -4
  131. package/dist/{trace-PNCASAXC.js → trace-ODOQIVIW.js} +61 -6
  132. package/dist/{uninstall-7FV7IP4E.js → uninstall-ZJF5H5ZN.js} +8 -8
  133. package/dist/{upgrade-K2HVIVMQ.js → upgrade-XANW3FXB.js} +29 -26
  134. package/dist/{usage-GTZELZQX.js → usage-4H7ZRXQT.js} +110 -61
  135. package/dist/{verifiers-RLAHT27O.js → verifiers-UZXNBZEB.js} +13 -13
  136. package/dist/{verify-BX3BRKH5.js → verify-BVKWTNDL.js} +9 -9
  137. package/dist/{wiki-generate-ASIFASCN.js → wiki-generate-MY7WV2QI.js} +76 -69
  138. package/dist/worker/entry.js +69 -66
  139. package/docs/alcf-provider.md +1 -1
  140. package/docs/architecture.md +1 -1
  141. package/docs/artifact-versions.md +11 -5
  142. package/docs/built-in-agents.md +1 -1
  143. package/docs/capacity-and-scheduling.md +23 -2
  144. package/docs/commands-and-modes.md +2 -2
  145. package/docs/configuration-and-targets.md +37 -5
  146. package/docs/context-engine.md +63 -4
  147. package/docs/documentation-coverage.md +3 -3
  148. package/docs/documentation-guide.md +1 -1
  149. package/docs/environment-variables.md +2 -0
  150. package/docs/eval-runner.md +262 -11
  151. package/docs/evals-internal.md +72 -2
  152. package/docs/evidence-and-memory.md +77 -12
  153. package/docs/evolution.md +1 -1
  154. package/docs/extensions-and-sharing.md +3 -1
  155. package/docs/fleet-dispatch.md +34 -9
  156. package/docs/glossary.md +21 -1
  157. package/docs/installation-and-lifecycle.md +1 -1
  158. package/docs/middleware-and-components.md +1 -1
  159. package/docs/model-catalog.md +1 -1
  160. package/docs/observability.md +54 -3
  161. package/docs/proactive-memory.md +127 -14
  162. package/docs/prompt-envelope-and-tools.md +22 -2
  163. package/docs/provider-adapter-cookbook.md +1 -1
  164. package/docs/release-cut-checklist.md +60 -41
  165. package/docs/safety-model.md +1 -1
  166. package/docs/scientific-validation.md +1 -1
  167. package/docs/skills-marketplace.md +1 -1
  168. package/docs/tool-usage.md +1 -1
  169. package/docs/trace-store.md +1 -1
  170. package/docs/troubleshooting.md +87 -0
  171. package/docs/tui-design.md +1 -1
  172. package/docs/worker-dispatch-mechanics.md +1 -1
  173. package/package.json +2 -2
  174. package/src/cli/agents.ts +1 -1
  175. package/src/cli/argv.ts +5 -0
  176. package/src/cli/config-inspect.ts +33 -6
  177. package/src/cli/config.ts +1 -1
  178. package/src/cli/configure.ts +107 -23
  179. package/src/cli/doctor-state-size.ts +82 -0
  180. package/src/cli/doctor.ts +7 -1
  181. package/src/cli/eval.ts +80 -16
  182. package/src/cli/evidence.ts +30 -25
  183. package/src/cli/extensions.ts +5 -1
  184. package/src/cli/fleet-preflight.ts +2 -12
  185. package/src/cli/fleet.ts +32 -3
  186. package/src/cli/shared.ts +1 -0
  187. package/src/cli/targets.ts +45 -11
  188. package/src/cli/trace.ts +63 -4
  189. package/src/cli/usage.ts +63 -14
  190. package/src/cli/validate-model.ts +60 -5
  191. package/src/core/bus-events.ts +54 -1
  192. package/src/core/cache-telemetry.ts +42 -0
  193. package/src/core/commit-attribution.ts +4 -4
  194. package/src/core/config.ts +18 -0
  195. package/src/core/defaults.ts +36 -6
  196. package/src/core/endpoint-key.ts +27 -0
  197. package/src/core/path-boundary.ts +100 -0
  198. package/src/core/residency-target-key.ts +25 -0
  199. package/src/core/response-schema.ts +36 -2
  200. package/src/domains/agents/extension.ts +2 -11
  201. package/src/domains/agents/fleet-contract.ts +30 -12
  202. package/src/domains/agents/recipe.ts +7 -1
  203. package/src/domains/agents/registry.ts +73 -5
  204. package/src/domains/agents/result-contract.ts +128 -17
  205. package/src/domains/agents/write-boundary.ts +15 -50
  206. package/src/domains/config/classify.ts +3 -0
  207. package/src/domains/context/codewiki/coordinator.ts +12 -4
  208. package/src/domains/context/project-rules.ts +51 -1
  209. package/src/domains/dispatch/admission.ts +40 -3
  210. package/src/domains/dispatch/assignment-reconcile.ts +22 -5
  211. package/src/domains/dispatch/assignment-store.ts +151 -14
  212. package/src/domains/dispatch/capacity-lease.ts +98 -9
  213. package/src/domains/dispatch/contract.ts +26 -1
  214. package/src/domains/dispatch/delegation-plan.ts +2 -5
  215. package/src/domains/dispatch/execution-plan.ts +44 -4
  216. package/src/domains/dispatch/execution-role.ts +9 -1
  217. package/src/domains/dispatch/extension.ts +309 -96
  218. package/src/domains/dispatch/fleet-run.ts +78 -4
  219. package/src/domains/dispatch/gate-role-prompts.ts +38 -0
  220. package/src/domains/dispatch/heartbeat.ts +32 -8
  221. package/src/domains/dispatch/index.ts +6 -1
  222. package/src/domains/dispatch/intent-requirements.ts +40 -0
  223. package/src/domains/dispatch/intent.ts +84 -8
  224. package/src/domains/dispatch/orphan-recovery.ts +5 -0
  225. package/src/domains/dispatch/path-scope.ts +370 -0
  226. package/src/domains/dispatch/receipt-integrity.ts +2 -1
  227. package/src/domains/dispatch/reservation-store.ts +116 -8
  228. package/src/domains/dispatch/state.ts +4 -0
  229. package/src/domains/dispatch/types.ts +14 -7
  230. package/src/domains/dispatch/validation.ts +6 -3
  231. package/src/domains/dispatch/worker-spawn.ts +25 -11
  232. package/src/domains/dispatch/write-boundary-enforcer.ts +62 -0
  233. package/src/domains/dispatch/write-boundary.ts +262 -22
  234. package/src/domains/eval/artifacts/store.ts +62 -0
  235. package/src/domains/eval/compare/behavioral.ts +224 -0
  236. package/src/domains/eval/compare/compare.ts +355 -2
  237. package/src/domains/eval/compare/envelope.ts +128 -0
  238. package/src/domains/eval/compare/gates.ts +24 -6
  239. package/src/domains/eval/compare/thresholds.ts +30 -3
  240. package/src/domains/eval/execution-provenance.ts +240 -0
  241. package/src/domains/eval/metrics/aggregate.ts +136 -0
  242. package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
  243. package/src/domains/eval/metrics/evidence.ts +79 -2
  244. package/src/domains/eval/metrics/tracked.ts +413 -0
  245. package/src/domains/eval/provenance.ts +117 -0
  246. package/src/domains/eval/reports/comparison.ts +128 -0
  247. package/src/domains/eval/reports/junit.ts +17 -3
  248. package/src/domains/eval/reports/markdown.ts +3 -3
  249. package/src/domains/eval/reports/text.ts +14 -0
  250. package/src/domains/eval/run-compare.ts +20 -0
  251. package/src/domains/eval/runners/clio-run.ts +139 -2
  252. package/src/domains/eval/runners/external-command.ts +28 -3
  253. package/src/domains/eval/schema/adapter.ts +111 -0
  254. package/src/domains/eval/schema/artifact.ts +20 -0
  255. package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
  256. package/src/domains/eval/schema/behavioral.ts +520 -0
  257. package/src/domains/eval/schema/execution-envelope.ts +194 -0
  258. package/src/domains/eval/schema/serving.ts +74 -0
  259. package/src/domains/eval/schema/suite.ts +38 -8
  260. package/src/domains/eval/schema/validate.ts +58 -3
  261. package/src/domains/eval/schema/verdict.ts +237 -0
  262. package/src/domains/eval/suites/resolve.ts +2 -0
  263. package/src/domains/eval/suites/run.ts +264 -33
  264. package/src/domains/eval/verifiers/command.ts +2 -1
  265. package/src/domains/eval/workspaces/temp-copy.ts +145 -13
  266. package/src/domains/evidence/build.ts +68 -21
  267. package/src/domains/evidence/eval.ts +2 -12
  268. package/src/domains/evidence/findings-markdown.ts +33 -0
  269. package/src/domains/evidence/index.ts +21 -0
  270. package/src/domains/evidence/provenance.ts +46 -11
  271. package/src/domains/evidence/run-trust.ts +7 -113
  272. package/src/domains/evidence/trust-projection.ts +274 -0
  273. package/src/domains/evidence/trust-status.ts +145 -17
  274. package/src/domains/evidence/types.ts +4 -0
  275. package/src/domains/extensions/compatibility.ts +285 -0
  276. package/src/domains/extensions/discovery.ts +126 -4
  277. package/src/domains/extensions/resources.ts +21 -9
  278. package/src/domains/extensions/state.ts +18 -5
  279. package/src/domains/extensions/types.ts +6 -1
  280. package/src/domains/lifecycle/doctor.ts +209 -2
  281. package/src/domains/memory/index.ts +14 -0
  282. package/src/domains/memory/task-bank-promotion.ts +64 -0
  283. package/src/domains/memory/task-memory-policy.ts +77 -8
  284. package/src/domains/memory/task-memory-spend.ts +131 -0
  285. package/src/domains/memory/task-memory-status.ts +7 -0
  286. package/src/domains/memory/task-memory-telemetry.ts +2 -0
  287. package/src/domains/middleware/index.ts +1 -0
  288. package/src/domains/middleware/memory-intervention.ts +69 -5
  289. package/src/domains/middleware/memory-step-endpoint.ts +71 -0
  290. package/src/domains/observability/background-memory-usage.ts +140 -0
  291. package/src/domains/observability/cost.ts +1 -1
  292. package/src/domains/observability/index.ts +7 -0
  293. package/src/domains/observability/out-of-turn-usage.ts +51 -2
  294. package/src/domains/observability/trace-store.ts +192 -2
  295. package/src/domains/prompts/compiler.ts +100 -13
  296. package/src/domains/prompts/contract.ts +3 -5
  297. package/src/domains/providers/endpoint-capacity.ts +96 -0
  298. package/src/domains/providers/extension.ts +30 -2
  299. package/src/domains/providers/index.ts +10 -0
  300. package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
  301. package/src/domains/providers/runtime-resolution.ts +8 -1
  302. package/src/domains/providers/runtimes/common/probe-helpers.ts +31 -9
  303. package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
  304. package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
  305. package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
  306. package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
  307. package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
  308. package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
  309. package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
  310. package/src/domains/providers/types/capability-flags.ts +2 -0
  311. package/src/domains/providers/types/target-descriptor.ts +2 -0
  312. package/src/domains/resources/common-loader.ts +3 -0
  313. package/src/domains/resources/prompts/loader.ts +184 -17
  314. package/src/domains/safety/call-target.ts +52 -0
  315. package/src/domains/safety/policy-engine.ts +5 -5
  316. package/src/domains/safety/run-effects.ts +96 -2
  317. package/src/domains/safety/scope.ts +7 -12
  318. package/src/domains/session/context-accounting.ts +52 -1
  319. package/src/domains/session/context-ledger.ts +37 -13
  320. package/src/domains/session/index.ts +6 -0
  321. package/src/domains/session/prompt-cache.ts +140 -0
  322. package/src/domains/session/prompt-manifest.ts +42 -0
  323. package/src/engine/acp/adapter.ts +18 -3
  324. package/src/engine/acp/server.ts +4 -1
  325. package/src/engine/ai.ts +35 -0
  326. package/src/engine/apis/llamacpp-residency.ts +55 -3
  327. package/src/engine/apis/lmstudio.ts +25 -5
  328. package/src/engine/apis/ollama-native.ts +2 -1
  329. package/src/engine/apis/openai-completions.ts +80 -17
  330. package/src/engine/apis/residency-lock.ts +3 -1
  331. package/src/engine/apis/residency.ts +34 -1
  332. package/src/engine/prompt-templates.ts +18 -1
  333. package/src/engine/provider-payload.ts +29 -1
  334. package/src/engine/worker-runtime.ts +6 -3
  335. package/src/entry/orchestrator.ts +176 -30
  336. package/src/interactive/chat-loop-messages.ts +26 -7
  337. package/src/interactive/chat-loop.ts +318 -41
  338. package/src/interactive/chat-panel.ts +62 -8
  339. package/src/interactive/clio-editor.ts +45 -8
  340. package/src/interactive/context-activity.ts +5 -1
  341. package/src/interactive/context-meter.ts +1 -1
  342. package/src/interactive/context-overlay.ts +40 -10
  343. package/src/interactive/cost-overlay.ts +64 -6
  344. package/src/interactive/dispatch-board.ts +127 -5
  345. package/src/interactive/fleet-run-preview.ts +41 -15
  346. package/src/interactive/handoff-round.ts +41 -2
  347. package/src/interactive/interactive-application.ts +24 -1
  348. package/src/interactive/interactive-event-projection.ts +14 -0
  349. package/src/interactive/interactive-input-runtime.ts +8 -0
  350. package/src/interactive/interactive-presentation.ts +4 -0
  351. package/src/interactive/interactive-shell.ts +20 -17
  352. package/src/interactive/interactive-slash-runtime.ts +27 -4
  353. package/src/interactive/memory-overlay.ts +8 -0
  354. package/src/interactive/mutation-preview.ts +295 -0
  355. package/src/interactive/overlay-general-openers.ts +16 -0
  356. package/src/interactive/overlay-key-routing.ts +38 -0
  357. package/src/interactive/overlay-lifecycle.ts +38 -5
  358. package/src/interactive/overlay-permission-lifecycle.ts +22 -2
  359. package/src/interactive/overlay-session-lifecycle.ts +73 -9
  360. package/src/interactive/overlays/ask-user.ts +91 -19
  361. package/src/interactive/overlays/help-reference.ts +4 -0
  362. package/src/interactive/overlays/prompts.ts +11 -1
  363. package/src/interactive/overlays/settings.ts +176 -48
  364. package/src/interactive/permission-hint.ts +34 -2
  365. package/src/interactive/permission-overlay.ts +159 -9
  366. package/src/interactive/prewarm.ts +197 -0
  367. package/src/interactive/render-trace.ts +162 -15
  368. package/src/interactive/renderers/tool-execution.ts +4 -0
  369. package/src/interactive/side-question.ts +58 -1
  370. package/src/interactive/slash-commands.ts +7 -2
  371. package/src/interactive/status/controller.ts +11 -0
  372. package/src/interactive/status/state-machine.ts +54 -2
  373. package/src/interactive/status/types.ts +7 -0
  374. package/src/interactive/terminal-lease.ts +2 -0
  375. package/src/interactive/turn-context.ts +299 -31
  376. package/src/interactive/turn-persistence.ts +14 -4
  377. package/src/interactive/turn-prewarm.ts +364 -0
  378. package/src/interactive/turn-queues.ts +7 -4
  379. package/src/interactive/turn-runtime.ts +8 -1
  380. package/src/interactive/turn-state.ts +23 -0
  381. package/src/interactive/view/artifacts.ts +42 -9
  382. package/src/interactive/view/view-overlay.ts +43 -6
  383. package/src/interactive/worker-receipts.ts +14 -2
  384. package/src/interactive/worker-stream.ts +8 -0
  385. package/src/tools/ask-user.ts +43 -2
  386. package/src/tools/dispatch-admission.ts +12 -13
  387. package/src/tools/dispatch-arguments.ts +27 -0
  388. package/src/tools/dispatch-plan.ts +46 -9
  389. package/src/tools/dispatch-runner.ts +48 -13
  390. package/src/tools/dispatch-scout.ts +1 -1
  391. package/src/tools/monitor.ts +13 -0
  392. package/src/tools/registry.ts +16 -0
  393. package/src/tools/worker-evidence.ts +19 -13
  394. package/src/worker/spec-contract.ts +2 -1
  395. package/dist/chunk-AOCYTWAV.js +0 -449
  396. package/dist/chunk-HWUFFB6L.js +0 -83
  397. package/dist/chunk-R346GLFC.js +0 -31
  398. package/dist/chunk-ZGH7FGS5.js +0 -1079
  399. package/dist/doctor-RN4YKO2X.js +0 -87
  400. package/dist/eval-RUBJVSNQ.js +0 -2557
@@ -1,7 +1,25 @@
1
+ /**
2
+ * What a target advertised when it was asked, for runtimes with no static
3
+ * catalog. `models` is the id list the probe returned and `resident` the
4
+ * subset the server reports as loaded, when it reports load state at all.
5
+ */
6
+ export interface LiveModelInventory {
7
+ targetId: string;
8
+ url?: string | undefined;
9
+ models: ReadonlyArray<string>;
10
+ resident: ReadonlyArray<string>;
11
+ }
12
+
1
13
  export interface ValidateModelInput {
2
14
  runtimeId: string;
3
15
  modelId: string;
4
16
  knownModels: ReadonlyArray<string>;
17
+ /**
18
+ * The live list, when one was fetched. It is consulted only when the static
19
+ * catalog is empty, so the catalog stays the authority for cloud runtimes
20
+ * and the probe becomes the authority where there is nothing else.
21
+ */
22
+ live?: LiveModelInventory | undefined;
5
23
  force: boolean;
6
24
  }
7
25
 
@@ -9,9 +27,30 @@ export type ValidateModelResult =
9
27
  | { ok: true; warning?: string }
10
28
  | { ok: false; reason: string; knownModels: ReadonlyArray<string> };
11
29
 
30
+ const SAMPLE_SIZE = 10;
31
+
32
+ function sample(models: ReadonlyArray<string>): string {
33
+ const shown = models.slice(0, SAMPLE_SIZE).join(", ");
34
+ return models.length > SAMPLE_SIZE ? `${shown}, …` : shown;
35
+ }
36
+
37
+ function describeLiveTarget(live: LiveModelInventory): string {
38
+ return live.url ? `target '${live.targetId}' at ${live.url}` : `target '${live.targetId}'`;
39
+ }
40
+
41
+ /** The refusal `configure` prints for a model the live target does not advertise. */
42
+ export function formatUnadvertisedModelReason(modelId: string, live: LiveModelInventory): string {
43
+ const resident = live.resident.length > 0 ? live.resident.join(", ") : "none";
44
+ return (
45
+ `${describeLiveTarget(live)} does not advertise model '${modelId}'. ` +
46
+ `Advertised (${live.models.length}): ${sample(live.models)}. Resident instances: ${resident}. ` +
47
+ "Pass one of the advertised ids with --model, or --force to save a model the target cannot serve."
48
+ );
49
+ }
50
+
12
51
  export function validateModelChoice(input: ValidateModelInput): ValidateModelResult {
13
- const { runtimeId, modelId, knownModels, force } = input;
14
- if (knownModels.length === 0) return { ok: true };
52
+ const { runtimeId, modelId, knownModels, live, force } = input;
53
+ if (knownModels.length === 0) return validateAgainstLive(modelId, live, force);
15
54
  if (knownModels.includes(modelId)) return { ok: true };
16
55
  if (force) {
17
56
  return {
@@ -19,10 +58,26 @@ export function validateModelChoice(input: ValidateModelInput): ValidateModelRes
19
58
  warning: `model '${modelId}' not in ${runtimeId} catalog (use without --force to reject)`,
20
59
  };
21
60
  }
22
- const sample = knownModels.slice(0, 10).join(", ");
23
61
  return {
24
62
  ok: false,
25
- reason: `model '${modelId}' not in ${runtimeId} catalog. Known: ${sample}. Use --force to skip validation.`,
26
- knownModels: knownModels.slice(0, 10),
63
+ reason: `model '${modelId}' not in ${runtimeId} catalog. Known: ${sample(knownModels)}. Use --force to skip validation.`,
64
+ knownModels: knownModels.slice(0, SAMPLE_SIZE),
27
65
  };
28
66
  }
67
+
68
+ /**
69
+ * With no catalog, the live list is the only evidence there is. An empty
70
+ * catalog used to be an early `ok` on its own, which is how a placeholder id
71
+ * was written next to the very list that ruled it out.
72
+ */
73
+ function validateAgainstLive(
74
+ modelId: string,
75
+ live: LiveModelInventory | undefined,
76
+ force: boolean,
77
+ ): ValidateModelResult {
78
+ if (!live || live.models.length === 0) return { ok: true };
79
+ if (live.models.includes(modelId)) return { ok: true };
80
+ const reason = formatUnadvertisedModelReason(modelId, live);
81
+ if (force) return { ok: true, warning: `${reason.replace(/ Pass one of.*$/u, "")} Saved anyway because of --force.` };
82
+ return { ok: false, reason, knownModels: live.models.slice(0, SAMPLE_SIZE) };
83
+ }
@@ -51,6 +51,8 @@ export const BusChannels = {
51
51
  ToolBudgetExceeded: "safety.toolBudgetExceeded",
52
52
  ProviderHealth: "provider.health",
53
53
  RuntimeNotice: "runtime.notice",
54
+ ResidencyMutation: "residency.mutation",
55
+ DispatchScopeNotice: "dispatch.scopeNotice",
54
56
  DispatchEnqueued: "dispatch.enqueued",
55
57
  DispatchStarted: "dispatch.started",
56
58
  DispatchProgress: "dispatch.progress",
@@ -63,6 +65,7 @@ export const BusChannels = {
63
65
  ContextWarning: "context.warning",
64
66
  ContextPruned: "context.pruned",
65
67
  ContextRecalled: "context.recalled",
68
+ MemoryStepCompleted: "memory.stepCompleted",
66
69
  AgentStatusChanged: "agent.status.changed",
67
70
  RunAborted: "run.aborted",
68
71
  BudgetAlert: "budget.alert",
@@ -99,6 +102,28 @@ export interface RuntimeNoticePayload {
99
102
  detail?: Record<string, number | string | boolean>;
100
103
  }
101
104
 
105
+ /**
106
+ * One completed proactive-memory model step, published on
107
+ * {@link BusChannels.MemoryStepCompleted}. It carries the endpoint the step
108
+ * called and nothing about what the step decided: the only consumer is the
109
+ * turn context, which stamps an expected-cold reason when a step ran between
110
+ * turns on the endpoint the chat target streams against.
111
+ */
112
+ export interface MemoryStepCompletedPayload {
113
+ endpointKey: string;
114
+ targetId: string;
115
+ }
116
+
117
+ /** A successful model load or eviction on one residency-managed endpoint. */
118
+ export interface ResidencyMutationPayload {
119
+ targetKey: string;
120
+ targetId: string;
121
+ runtimeId: string;
122
+ model: string;
123
+ operation: "load" | "evict";
124
+ at: number;
125
+ }
126
+
102
127
  /**
103
128
  * Window-resolution warning published on {@link BusChannels.ContextWarning}.
104
129
  * Emitted on transitions only: `warning` carries the text when a warning
@@ -108,8 +133,31 @@ export interface ContextWarningPayload {
108
133
  warning: string | null;
109
134
  }
110
135
 
136
+ /** A dispatch path-scope decision that must remain visible in the operator transcript. */
137
+ export type DispatchScopeNoticePayload =
138
+ | {
139
+ code: "typed_scope_replaced_inferred_paths";
140
+ level: "warning";
141
+ agentId: string;
142
+ omittedPaths: ReadonlyArray<string>;
143
+ message: string;
144
+ }
145
+ | {
146
+ code: "legacy_scope_inferred" | "legacy_scope_empty";
147
+ level: "warning";
148
+ agentId: string;
149
+ paths: ReadonlyArray<{
150
+ path: string;
151
+ policy: "working-context" | "write-boundary";
152
+ provenance: "declared" | "derived" | "inferred";
153
+ source: "intent.read_roots" | "intent.write_roots" | "intent.relevant_paths" | "writeRoots" | "task" | "briefing";
154
+ confidence: "certain" | "high" | "medium" | "low";
155
+ }>;
156
+ message: string;
157
+ };
158
+
111
159
  export type ContextActivityKind = "context-init" | "context-clear" | "context-refresh" | "context-wiki" | "compaction";
112
- export type ContextActivityPhase = "scan" | "codewiki" | "generate" | "clio-md" | "state" | "done";
160
+ export type ContextActivityPhase = "scan" | "codewiki" | "generate" | "clio-md" | "state" | "compact" | "done";
113
161
  export type ContextActivityStatus = "started" | "running" | "completed" | "failed";
114
162
 
115
163
  /** Structured progress for context operations. Interactive renders this as a live context island. */
@@ -481,6 +529,8 @@ export interface DispatchRunIdentity {
481
529
  wireModelId: string;
482
530
  runtimeId: string;
483
531
  runtimeKind: RunKind;
532
+ /** Canonical inference scheduler and its resolved request-slot bound. */
533
+ endpoint?: { key: string; label: string; limit: number } | undefined;
484
534
  /** Admitted invocation budget provenance for native workers. */
485
535
  budget?: RunToolBudgetEnvelope | undefined;
486
536
  /** Fleet node id the run was placed on; absent renders as the local node. */
@@ -737,6 +787,8 @@ export type BusPayloadMap = {
737
787
  [BusChannels.ToolBudgetExceeded]: ToolBudgetExceededPayload;
738
788
  [BusChannels.ProviderHealth]: ProviderHealthPayload;
739
789
  [BusChannels.RuntimeNotice]: RuntimeNoticePayload;
790
+ [BusChannels.ResidencyMutation]: ResidencyMutationPayload;
791
+ [BusChannels.DispatchScopeNotice]: DispatchScopeNoticePayload;
740
792
  [BusChannels.DispatchEnqueued]: DispatchEnqueuedPayload;
741
793
  [BusChannels.DispatchStarted]: DispatchStartedPayload;
742
794
  [BusChannels.DispatchProgress]: DispatchProgressPayload;
@@ -749,6 +801,7 @@ export type BusPayloadMap = {
749
801
  [BusChannels.ContextWarning]: ContextWarningPayload;
750
802
  [BusChannels.ContextPruned]: ContextPrunedPayload;
751
803
  [BusChannels.ContextRecalled]: ContextRecalledPayload;
804
+ [BusChannels.MemoryStepCompleted]: MemoryStepCompletedPayload;
752
805
  [BusChannels.AgentStatusChanged]: AgentStatusChangedPayload;
753
806
  [BusChannels.RunAborted]: RunAbortedPayload;
754
807
  [BusChannels.BudgetAlert]: BudgetAlertPayload;
@@ -0,0 +1,42 @@
1
+ /** Cache classification for one backend completion call. */
2
+ export type BackendCacheVerdict = "hot" | "partial" | "cold" | "small";
3
+
4
+ /** Backend timing source that directly reports local prefill work. */
5
+ export type BackendTimingsSource = "llamacpp-timings" | "lmstudio-timings";
6
+
7
+ /** Normalized prefill and prediction timings reported by the serving backend. */
8
+ export interface BackendCompletionTimings {
9
+ promptTokens: number;
10
+ cachedTokens: number | null;
11
+ predictedTokens: number;
12
+ promptMs: number;
13
+ predictedMs: number;
14
+ source: BackendTimingsSource;
15
+ }
16
+
17
+ /** Per-session call counts grouped by backend cache verdict. */
18
+ export interface CacheVerdictCounts {
19
+ hot: number;
20
+ partial: number;
21
+ cold: number;
22
+ small: number;
23
+ }
24
+
25
+ export function emptyCacheVerdictCounts(): CacheVerdictCounts {
26
+ return { hot: 0, partial: 0, cold: 0, small: 0 };
27
+ }
28
+
29
+ /** Return newly evaluated prefill tokens when the backend reports cache reads. */
30
+ export function uncachedPrefillTokens(backend: BackendCompletionTimings | null | undefined): number | null {
31
+ if (backend === null || backend === undefined || backend.cachedTokens === null) return null;
32
+ if (
33
+ !Number.isFinite(backend.promptTokens) ||
34
+ backend.promptTokens < 0 ||
35
+ !Number.isFinite(backend.cachedTokens) ||
36
+ backend.cachedTokens < 0 ||
37
+ backend.cachedTokens > backend.promptTokens
38
+ ) {
39
+ return null;
40
+ }
41
+ return backend.promptTokens - backend.cachedTokens;
42
+ }
@@ -16,7 +16,7 @@ export const CLIO_COMMIT_TRAILERS = {
16
16
  } as const;
17
17
 
18
18
  export interface CommitReceiptEvidence {
19
- version: 19;
19
+ version: 20;
20
20
  algorithm: "sha256";
21
21
  digest: string;
22
22
  /** The receipt was checked against its run-ledger envelope. */
@@ -58,7 +58,7 @@ const KNOWN_CLIO_TRAILERS = new Set(
58
58
  );
59
59
 
60
60
  function isClioTrailer(key: string): boolean {
61
- return KNOWN_CLIO_TRAILERS.has(key) || key.startsWith("clio-evidence:receipt-v19/sha256:");
61
+ return KNOWN_CLIO_TRAILERS.has(key) || key.startsWith("clio-evidence:receipt-v20/sha256:");
62
62
  }
63
63
 
64
64
  /**
@@ -87,7 +87,7 @@ function trailerBlockStart(lines: ReadonlyArray<string>): number | null {
87
87
 
88
88
  function receiptTrailer(receipt: CommitReceiptEvidence | undefined): string | null {
89
89
  if (
90
- receipt?.version !== 19 ||
90
+ receipt?.version !== 20 ||
91
91
  receipt.algorithm !== "sha256" ||
92
92
  receipt.integrityValid !== true ||
93
93
  receipt.directlyRelevant !== true ||
@@ -95,7 +95,7 @@ function receiptTrailer(receipt: CommitReceiptEvidence | undefined): string | nu
95
95
  ) {
96
96
  return null;
97
97
  }
98
- return `Clio-Evidence: receipt-v19/sha256:${receipt.digest}`;
98
+ return `Clio-Evidence: receipt-v20/sha256:${receipt.digest}`;
99
99
  }
100
100
 
101
101
  /**
@@ -521,6 +521,7 @@ function validateTarget(issues: Issues, path: string, value: unknown): ClioSetti
521
521
  "gateway",
522
522
  "pricing",
523
523
  "lmstudio",
524
+ "maxConcurrentRequests",
524
525
  ]);
525
526
  const id = "id" in value ? expectString(issues, `${path}.id`, value.id) : undefined;
526
527
  const runtime = "runtime" in value ? expectString(issues, `${path}.runtime`, value.runtime) : undefined;
@@ -566,6 +567,10 @@ function validateTarget(issues: Issues, path: string, value: unknown): ClioSetti
566
567
  const v = validateLmStudioSettings(issues, `${path}.lmstudio`, value.lmstudio);
567
568
  if (v !== undefined) target.lmstudio = v;
568
569
  }
570
+ if ("maxConcurrentRequests" in value) {
571
+ const v = expectInteger(issues, `${path}.maxConcurrentRequests`, value.maxConcurrentRequests, { min: 1 });
572
+ if (v !== undefined) target.maxConcurrentRequests = v;
573
+ }
569
574
  return target;
570
575
  }
571
576
 
@@ -1004,6 +1009,7 @@ const TOP_LEVEL_KEYS = [
1004
1009
  "keybindings",
1005
1010
  "compaction",
1006
1011
  "context",
1012
+ "prewarm",
1007
1013
  "retry",
1008
1014
  "guardrails",
1009
1015
  ] as const;
@@ -1589,6 +1595,18 @@ export function validateSettings(raw: unknown): SettingsValidationResult {
1589
1595
  }
1590
1596
  }
1591
1597
 
1598
+ if ("prewarm" in raw) {
1599
+ if (!isPlainObject(raw.prewarm)) {
1600
+ issues.add("prewarm", `expected a map, got ${describe(raw.prewarm)}`);
1601
+ } else {
1602
+ issues.unknownKeys("prewarm", raw.prewarm, ["enabled"]);
1603
+ if ("enabled" in raw.prewarm) {
1604
+ const v = expectBoolean(issues, "prewarm.enabled", raw.prewarm.enabled);
1605
+ if (v !== undefined) settings.prewarm.enabled = v;
1606
+ }
1607
+ }
1608
+ }
1609
+
1592
1610
  if ("retry" in raw) {
1593
1611
  if (!isPlainObject(raw.retry)) {
1594
1612
  issues.add("retry", `expected a map, got ${describe(raw.retry)}`);
@@ -151,6 +151,21 @@ export interface WorkingSetSettings {
151
151
  minEvictableTokens: number;
152
152
  }
153
153
 
154
+ /**
155
+ * Prompt pre-warm settings (`prewarm`). On a local server prefill is the cost,
156
+ * and the prefix the next turn will send is fully known before the operator
157
+ * types anything: at session start, after a resume rebuilds the message array,
158
+ * and after a compaction settles. Clio sends that prefix to the backend right
159
+ * then so the slot's prefix cache already holds it when the real turn arrives.
160
+ *
161
+ * - enabled: master switch. The feature is off on every tier but
162
+ * `local-native` whatever this says, and off for workers and headless runs,
163
+ * because it buys latency for an operator watching a local server.
164
+ */
165
+ export interface PrewarmSettings {
166
+ enabled: boolean;
167
+ }
168
+
154
169
  /**
155
170
  * Transient provider retry controls for the interactive chat loop. These are
156
171
  * intentionally small and mirror the session retry helper defaults. Dispatched
@@ -354,11 +369,15 @@ export const DEFAULT_SETTINGS = {
354
369
  everyNTools: 10,
355
370
  windowSteps: 8,
356
371
  maxTokens: 400,
357
- // A memory step runs detached from the turn that triggered it, so a
358
- // generous deadline costs no interactive latency. Measured steps on a
359
- // small local route ranged past two minutes, and a deadline shorter than
360
- // the model discards finished work as a timeout.
361
- timeoutMs: 180_000,
372
+ // A memory step runs detached from the turn that triggered it, but it
373
+ // runs on a real inference endpoint that the operator's own turns and
374
+ // dispatched workers also queue against. The operator's ledger over 14
375
+ // days recorded 60 llm-tier steps spending 1,666 seconds of model time
376
+ // for 6 injections, with one step holding a local server for 102.5
377
+ // seconds to answer nothing. The deadline is what a turn boundary can
378
+ // actually wait for; a step that runs past it is recorded as timed out
379
+ // rather than spending the remaining minutes unobserved.
380
+ timeoutMs: 30_000,
362
381
  },
363
382
  },
364
383
  watchdog: { enabled: false } as WatchdogSettings,
@@ -444,6 +463,9 @@ export const DEFAULT_SETTINGS = {
444
463
  context: {
445
464
  workingSet: DEFAULT_WORKING_SET_SETTINGS,
446
465
  },
466
+ prewarm: {
467
+ enabled: true,
468
+ } as PrewarmSettings,
447
469
  retry: {
448
470
  enabled: true,
449
471
  maxRetries: 3,
@@ -539,7 +561,7 @@ memory:
539
561
  everyNTools: 10
540
562
  windowSteps: 8
541
563
  maxTokens: 400
542
- timeoutMs: 180000
564
+ timeoutMs: 30000
543
565
 
544
566
  # Opt-in turn-end watchdog. When enabled, a turn that changed the tree is
545
567
  # reviewed by one read-only verifier run briefed with the turn's coalesced diff
@@ -751,6 +773,14 @@ context:
751
773
  protectLastTurns: 6
752
774
  minEvictableTokens: 200
753
775
 
776
+ # Prompt pre-warm. At session start, after a resume rebuilds the message array,
777
+ # and after a compaction settles, Clio sends the prefix the next turn would send
778
+ # (minus your text) so a local server has already prefilled it when you press
779
+ # Enter. Local-native targets only, interactive sessions only, and never while a
780
+ # turn or a dispatch is running.
781
+ prewarm:
782
+ enabled: true
783
+
754
784
  # Transient provider/stream retry controls for interactive chat.
755
785
  # Retryable errors include overloads, rate limits, 5xx responses, network
756
786
  # resets, and timeouts. Context overflow uses compaction recovery instead.
@@ -0,0 +1,27 @@
1
+ /**
2
+ * Canonical identity of an OpenAI-compatible inference endpoint: normalized
3
+ * HTTP scheme, lower-cased host, normalized port, and normalized base path with
4
+ * a conventional terminal `/v1` mount stripped. Credentials, query, and
5
+ * fragment do not participate. Host aliases are not resolved, so
6
+ * `localhost` and `127.0.0.1` stay distinct. Shared by dispatch capacity and
7
+ * residency locking so both speak the same key for one server.
8
+ */
9
+ export function canonicalEndpointUrl(raw: string | null | undefined): string | null {
10
+ if (!raw?.trim()) return null;
11
+ try {
12
+ const url = new URL(raw.trim().replace(/^ws:/u, "http:").replace(/^wss:/u, "https:"));
13
+ url.protocol = url.protocol.toLowerCase();
14
+ if (url.protocol !== "http:" && url.protocol !== "https:") return null;
15
+ url.hostname = url.hostname.toLowerCase();
16
+ url.username = "";
17
+ url.password = "";
18
+ url.hash = "";
19
+ url.search = "";
20
+ let path = url.pathname.replace(/\/{2,}/gu, "/").replace(/\/$/u, "");
21
+ if (path.endsWith("/v1")) path = path.slice(0, -3);
22
+ url.pathname = path || "/";
23
+ return url.toString().replace(/\/$/u, "");
24
+ } catch {
25
+ return null;
26
+ }
27
+ }
@@ -0,0 +1,100 @@
1
+ import path from "node:path";
2
+
3
+ export const PATH_BOUNDARY_MAX_ENTRIES = 32;
4
+
5
+ export type PathBoundary = ReadonlyArray<string>;
6
+
7
+ type PathBoundaryErrorCode = "empty" | "separator" | "glob" | "absolute" | "parent" | "dot";
8
+
9
+ export class PathBoundaryError extends Error {
10
+ readonly code: PathBoundaryErrorCode;
11
+
12
+ constructor(code: PathBoundaryErrorCode, message: string) {
13
+ super(message);
14
+ this.name = "PathBoundaryError";
15
+ this.code = code;
16
+ }
17
+ }
18
+
19
+ const GLOB_CHARACTERS = /[*?[\]{}]/u;
20
+
21
+ /** Normalize one repository-relative boundary entry. */
22
+ export function normalizePathBoundaryEntry(entry: string): string {
23
+ const raw = entry.trim();
24
+ if (raw.length === 0) throw new PathBoundaryError("empty", "write boundary: entry must be a non-empty path");
25
+ if (raw.includes("\\")) {
26
+ throw new PathBoundaryError("separator", `write boundary: entry '${entry}' must use '/' separators`);
27
+ }
28
+ if (GLOB_CHARACTERS.test(raw)) {
29
+ throw new PathBoundaryError("glob", `write boundary: entry '${entry}' looks like a glob, which v1 does not support`);
30
+ }
31
+ if (raw.startsWith("/") || /^[A-Za-z]:/u.test(raw)) {
32
+ throw new PathBoundaryError("absolute", `write boundary: entry '${entry}' must be repository-relative, not absolute`);
33
+ }
34
+ const subtree = raw.endsWith("/");
35
+ const segments = raw.split("/").filter((segment) => segment.length > 0);
36
+ if (segments.length === 0) {
37
+ throw new PathBoundaryError("empty", `write boundary: entry '${entry}' must name a path inside the repository`);
38
+ }
39
+ for (const segment of segments) {
40
+ if (segment === "..") {
41
+ throw new PathBoundaryError("parent", `write boundary: entry '${entry}' must not contain '..'`);
42
+ }
43
+ if (segment === ".") {
44
+ throw new PathBoundaryError("dot", `write boundary: entry '${entry}' must not contain '.' segments`);
45
+ }
46
+ }
47
+ const joined = segments.join("/");
48
+ return subtree ? `${joined}/` : joined;
49
+ }
50
+
51
+ /** Normalize, deduplicate, and sort a boundary declaration. */
52
+ export function normalizePathBoundary(entries: ReadonlyArray<string>): string[] {
53
+ if (entries.length > PATH_BOUNDARY_MAX_ENTRIES) {
54
+ throw new Error(`write boundary: at most ${PATH_BOUNDARY_MAX_ENTRIES} entries may be declared`);
55
+ }
56
+ return [...new Set(entries.map(normalizePathBoundaryEntry))].sort();
57
+ }
58
+
59
+ function toPosixBoundaryPath(value: string): string {
60
+ return value.split("\\").join("/");
61
+ }
62
+
63
+ function isDirectoryPathBoundary(entry: string): boolean {
64
+ return toPosixBoundaryPath(entry).endsWith("/");
65
+ }
66
+
67
+ /** Convert a path to the subtree form spoken by the boundary grammar. */
68
+ export function asDirectoryPathBoundary(entry: string): string {
69
+ const normalized = toPosixBoundaryPath(entry);
70
+ return normalized.endsWith("/") ? normalized : `${normalized}/`;
71
+ }
72
+
73
+ /** Resolve a repository-relative boundary while retaining exact or subtree meaning. */
74
+ export function resolvePathBoundary(cwd: string, entry: string): string {
75
+ const directory = isDirectoryPathBoundary(entry);
76
+ const withoutMarker = directory ? entry.slice(0, -1) : entry;
77
+ const resolved = toPosixBoundaryPath(path.resolve(cwd, withoutMarker));
78
+ return directory ? asDirectoryPathBoundary(resolved) : resolved;
79
+ }
80
+
81
+ /** Whether one boundary entry contains another exact path or subtree. */
82
+ export function pathBoundaryEntryCovers(outer: string, inner: string): boolean {
83
+ const normalizedOuter = toPosixBoundaryPath(outer);
84
+ const normalizedInner = toPosixBoundaryPath(inner);
85
+ return normalizedOuter.endsWith("/")
86
+ ? normalizedInner.startsWith(normalizedOuter)
87
+ : !normalizedInner.endsWith("/") && normalizedInner === normalizedOuter;
88
+ }
89
+
90
+ /** Whether any entry in a boundary contains the candidate. */
91
+ export function pathBoundaryCovers(boundary: PathBoundary, candidate: string): boolean {
92
+ return boundary.some((entry) => pathBoundaryEntryCovers(entry, candidate));
93
+ }
94
+
95
+ /** Whether two boundary declarations share any possible path. */
96
+ export function pathBoundariesOverlap(left: PathBoundary, right: PathBoundary): boolean {
97
+ return left.some((entry) =>
98
+ right.some((other) => pathBoundaryEntryCovers(entry, other) || pathBoundaryEntryCovers(other, entry)),
99
+ );
100
+ }
@@ -0,0 +1,25 @@
1
+ import { canonicalEndpointUrl } from "./endpoint-key.js";
2
+
3
+ /** Runtime families whose model residency Clio can actively mutate. */
4
+ export type ResidencyRuntimeId = "llamacpp" | "lmstudio" | "ollama-native";
5
+
6
+ const RESIDENCY_RUNTIME_IDS: ReadonlySet<string> = new Set<ResidencyRuntimeId>([
7
+ "llamacpp",
8
+ "lmstudio",
9
+ "ollama-native",
10
+ ]);
11
+
12
+ export function residencyTargetKey(runtimeId: ResidencyRuntimeId, baseUrl: string): string;
13
+ export function residencyTargetKey(runtimeId: string, baseUrl: string | null | undefined): string | null;
14
+ /** Stable key for one residency-managed server endpoint: its canonical URL. */
15
+ export function residencyTargetKey(runtimeId: string, baseUrl: string | null | undefined): string | null {
16
+ if (!RESIDENCY_RUNTIME_IDS.has(runtimeId) || typeof baseUrl !== "string") return null;
17
+ // The key is the canonical endpoint itself, without a runtime prefix, so the
18
+ // residency lock and dispatch capacity name one server the same way (#250).
19
+ // A base url the canonical form refuses, such as one written without a
20
+ // scheme, still gets a key: callers store this in `ResidencyAdapter.targetKey`,
21
+ // which is a `string`, and dispatch capacity has no key for that target
22
+ // either, so there is nothing to agree with and nothing to gain by dropping
23
+ // the lock the reconciler serializes on.
24
+ return canonicalEndpointUrl(baseUrl) ?? baseUrl;
25
+ }
@@ -11,11 +11,45 @@ export const RESPONSE_SCHEMA_MAX_SERIALIZED_BYTES = 64 * 1024;
11
11
  * `schema` key, and returns HTTP 200 with unconstrained JSON, so widening this
12
12
  * to the api family would convert a clean refusal into a silent
13
13
  * non-enforcement. lmstudio declares `structuredOutputs: "json-schema"`
14
- * truthfully and is still excluded here, because Clio has no dialect for its
15
- * transport. Widen this only together with a dialect for the runtime added.
14
+ * truthfully and is still excluded here, because the worker seam has no
15
+ * dialect for its transport. Widen this only together with a dialect for the
16
+ * runtime added; {@link responseSchemaDialectFor} is where the out-of-turn
17
+ * seam did exactly that (issue #223).
16
18
  */
17
19
  export const RESPONSE_SCHEMA_RUNTIME_ID = "llamacpp";
18
20
 
21
+ /** The runtime that takes the standard OpenAI `json_schema` response format. */
22
+ export const OPENAI_SCHEMA_RUNTIME_ID = "lmstudio";
23
+
24
+ /**
25
+ * How a runtime spells a JSON-schema response constraint on the wire.
26
+ *
27
+ * `llamacpp-json-object` is llama-server's own `response_format: { type:
28
+ * "json_object", schema }`, which it compiles into a sampler grammar.
29
+ * `openai-json-schema` is the standard `response_format: { type:
30
+ * "json_schema", json_schema: { name, strict, schema } }` that LM Studio
31
+ * implements.
32
+ */
33
+ export type ResponseSchemaDialect = "llamacpp-json-object" | "openai-json-schema";
34
+
35
+ /**
36
+ * The dialect this runtime takes, or null when Clio has none for it and the
37
+ * request has to go unconstrained.
38
+ *
39
+ * Deliberately a name check, for the reason {@link RESPONSE_SCHEMA_RUNTIME_ID}
40
+ * gives: a generic OpenAI-compatible gateway answers HTTP 200 to a spelling it
41
+ * does not implement and returns unconstrained JSON, so a capability flag would
42
+ * turn a known non-enforcement into a silent one. This is the out-of-turn
43
+ * seam's table; the worker seam keeps the narrower
44
+ * {@link runtimeSpeaksResponseSchemaDialect} check, because a worker that
45
+ * cannot enforce a contract must refuse admission rather than degrade.
46
+ */
47
+ export function responseSchemaDialectFor(runtimeId: string): ResponseSchemaDialect | null {
48
+ if (runtimeId === RESPONSE_SCHEMA_RUNTIME_ID) return "llamacpp-json-object";
49
+ if (runtimeId === OPENAI_SCHEMA_RUNTIME_ID) return "openai-json-schema";
50
+ return null;
51
+ }
52
+
19
53
  /** Whether this runtime speaks the dialect above. Transport shape, not capability. */
20
54
  export function runtimeSpeaksResponseSchemaDialect(runtime: { id: string; kind: string; apiFamily: string }): boolean {
21
55
  return (
@@ -1,12 +1,9 @@
1
- import path from "node:path";
2
1
  import type { DomainBundle, DomainContext, DomainExtension } from "../../core/domain-loader.js";
3
- import { resolvePackageRoot } from "../../core/package-root.js";
4
- import { clioConfigDir } from "../../core/xdg.js";
5
2
  import { assertAgentIdNamespace } from "../config/agent-namespace.js";
6
3
  import type { ConfigContract } from "../config/contract.js";
7
4
  import type { AgentsContract } from "./contract.js";
8
5
  import type { AgentRecipe } from "./recipe.js";
9
- import { type AgentRecipeDiagnostic, loadRecipesFromDir, mergeRecipes } from "./registry.js";
6
+ import { type AgentRecipeDiagnostic, discoverAgentRecipes } from "./registry.js";
10
7
  import { type AgentSpec, normalizeAgentSpec } from "./spec.js";
11
8
 
12
9
  export function createAgentsBundle(_context: DomainContext): DomainBundle<AgentsContract> {
@@ -15,14 +12,8 @@ export function createAgentsBundle(_context: DomainContext): DomainBundle<Agents
15
12
  let diagnostics: ReadonlyArray<AgentRecipeDiagnostic> = [];
16
13
 
17
14
  function discover(): void {
18
- const builtinDir = path.join(resolvePackageRoot(), "src", "domains", "agents", "builtins");
19
- const userDir = path.join(clioConfigDir(), "agents");
20
- const projectDir = path.join(process.cwd(), ".clio-coder", "agents");
21
15
  const nextDiagnostics: AgentRecipeDiagnostic[] = [];
22
- const builtin = loadRecipesFromDir({ dir: builtinDir, source: "builtin" }, nextDiagnostics);
23
- const user = loadRecipesFromDir({ dir: userDir, source: "user" }, nextDiagnostics);
24
- const project = loadRecipesFromDir({ dir: projectDir, source: "project" }, nextDiagnostics);
25
- const merged = mergeRecipes(builtin, user, project);
16
+ const merged = discoverAgentRecipes(process.cwd(), nextDiagnostics);
26
17
  const config = _context.getContract<ConfigContract>("config");
27
18
  assertAgentIdNamespace(merged, config?.get()?.delegation?.agents ?? []);
28
19
  recipes = merged;