@iowarp/clio-coder 0.3.9 → 0.4.0

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 (416) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/NOTICE +33 -0
  3. package/README.md +7 -2
  4. package/dist/{acp-7LOELQFP.js → acp-G5WJBNCT.js} +13 -12
  5. package/dist/{agents-FIBG2SHA.js → agents-FMV2Q5G4.js} +39 -36
  6. package/dist/assets/codewiki.json +1 -1
  7. package/dist/{auth-OI4LIH2I.js → auth-3IDSJEIK.js} +16 -15
  8. package/dist/{builtins-AD25UL3C.js → builtins-XCZWXSC7.js} +3 -3
  9. package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
  10. package/dist/{chunk-56KB5IJP.js → chunk-2OQE55CK.js} +3 -3
  11. package/dist/{chunk-N3PBVRTZ.js → chunk-32KWKNSF.js} +9 -7
  12. package/dist/{chunk-VKBMFOYV.js → chunk-36EJLSQQ.js} +23 -27
  13. package/dist/{chunk-465CC7FK.js → chunk-3BT2XMV4.js} +16 -13
  14. package/dist/{chunk-NQ6UCCOD.js → chunk-3URVFKWK.js} +7 -7
  15. package/dist/{chunk-WIE7ZOSW.js → chunk-3XML7CDN.js} +2 -2
  16. package/dist/chunk-42FMPA75.js +101 -0
  17. package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
  18. package/dist/{chunk-HAY4ZE2P.js → chunk-5PSMVOLM.js} +2 -2
  19. package/dist/{chunk-JEQQR47K.js → chunk-6DB53AJS.js} +168 -9
  20. package/dist/{chunk-KV2AOLDF.js → chunk-76ONBSIA.js} +5 -25
  21. package/dist/{chunk-FALJGAWU.js → chunk-7MCTRUCE.js} +2 -2
  22. package/dist/{chunk-5T7RBWN2.js → chunk-AB44T6BB.js} +5 -5
  23. package/dist/chunk-B7OBL7PK.js +1405 -0
  24. package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
  25. package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
  26. package/dist/{chunk-O6I4CIEU.js → chunk-BKFJHQCA.js} +6 -6
  27. package/dist/chunk-BKFM6EJV.js +462 -0
  28. package/dist/chunk-BMS5RKQY.js +27 -0
  29. package/dist/{chunk-MV2VUEJC.js → chunk-BPKCPIL7.js} +2 -2
  30. package/dist/{chunk-TEO2TLVN.js → chunk-BUMFYQFY.js} +964 -1120
  31. package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
  32. package/dist/chunk-C2LTL2W6.js +2447 -0
  33. package/dist/{chunk-EBOC7MT3.js → chunk-CODPRO7Q.js} +8 -8
  34. package/dist/{chunk-HPCTNZM2.js → chunk-CTJ4RNAA.js} +4 -4
  35. package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
  36. package/dist/{chunk-MIX5N5AC.js → chunk-DQITNCXG.js} +394 -154
  37. package/dist/{chunk-S4COXYBG.js → chunk-DYJP44XW.js} +129 -106
  38. package/dist/{chunk-N5XKWMDW.js → chunk-F4CKPOEQ.js} +6 -6
  39. package/dist/{chunk-AMKHQW3C.js → chunk-FEFIFZTL.js} +3 -3
  40. package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
  41. package/dist/{chunk-7C6RYZGQ.js → chunk-GKF55TAZ.js} +3 -3
  42. package/dist/{chunk-B5XRQOLB.js → chunk-GR5G2PVF.js} +9 -8
  43. package/dist/{chunk-XDOQXGFO.js → chunk-GXNLGKAB.js} +64 -8
  44. package/dist/chunk-HHV2GANA.js +88 -0
  45. package/dist/{chunk-774ILSRL.js → chunk-HI63TFOG.js} +4 -3
  46. package/dist/{chunk-R7LNVMCS.js → chunk-HJJTYUHX.js} +64 -72
  47. package/dist/{chunk-RKRLDWD3.js → chunk-HLW2MRKE.js} +1 -1
  48. package/dist/{chunk-CA42X6KT.js → chunk-HWHKMHUA.js} +6 -6
  49. package/dist/chunk-HZHHCK24.js +1631 -0
  50. package/dist/{chunk-HJB5IUKP.js → chunk-I5VEOC6I.js} +12 -12
  51. package/dist/chunk-IBEBSCYA.js +564 -0
  52. package/dist/chunk-IQ7KR472.js +362 -0
  53. package/dist/{chunk-4H6ULJ3H.js → chunk-J4W7KFM7.js} +921 -990
  54. package/dist/{chunk-4LJX2PUC.js → chunk-JDG2WCRO.js} +5 -5
  55. package/dist/{chunk-NZU6YDNV.js → chunk-K5C3NCBD.js} +4 -4
  56. package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
  57. package/dist/{chunk-NNNWO6F2.js → chunk-KFZI4NIL.js} +93 -3
  58. package/dist/chunk-KMVISBZR.js +132 -0
  59. package/dist/{chunk-BVDVID7E.js → chunk-LDQ2ZF2M.js} +2 -2
  60. package/dist/{chunk-OEDBCISO.js → chunk-LQ3DZAMX.js} +2 -2
  61. package/dist/{chunk-PZ4I4JE2.js → chunk-LY4S7GJC.js} +124 -116
  62. package/dist/{chunk-3DUR4WUA.js → chunk-MLKNTWH2.js} +19 -19
  63. package/dist/chunk-NEKRRTYW.js +56 -0
  64. package/dist/{chunk-5DQRIYDZ.js → chunk-NHCZP4K7.js} +2 -2
  65. package/dist/chunk-NHLBIGRH.js +1506 -0
  66. package/dist/chunk-NQQH3YT7.js +302 -0
  67. package/dist/chunk-NYS75XW5.js +15 -0
  68. package/dist/{chunk-TD7UE2L5.js → chunk-O4XIVISU.js} +7 -7
  69. package/dist/{chunk-WXCJ7VME.js → chunk-O6TL7WWY.js} +6 -6
  70. package/dist/chunk-OQBA45DZ.js +97 -0
  71. package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
  72. package/dist/chunk-PMZCIOCJ.js +25 -0
  73. package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
  74. package/dist/{chunk-HKO36JWF.js → chunk-QBJA7R7N.js} +31 -3
  75. package/dist/chunk-QDC3K2U3.js +262 -0
  76. package/dist/{chunk-5HFBWUMU.js → chunk-QLFS5GO2.js} +4 -4
  77. package/dist/{chunk-GAYUJ7LE.js → chunk-QLL7ILRG.js} +41 -32
  78. package/dist/{chunk-LXPJXFM5.js → chunk-QREDIESB.js} +7 -7
  79. package/dist/chunk-QSNYB6ZV.js +195 -0
  80. package/dist/chunk-R346GLFC.js +31 -0
  81. package/dist/{chunk-VPTUJU4P.js → chunk-SJ5ZKQ4S.js} +2 -2
  82. package/dist/{chunk-QQ7EKM72.js → chunk-SP2RXXYO.js} +6 -54
  83. package/dist/chunk-SUCTJL45.js +45 -0
  84. package/dist/{chunk-5QKCQQ3E.js → chunk-SUW5DORT.js} +2 -2
  85. package/dist/chunk-T56WDKA5.js +183 -0
  86. package/dist/chunk-TVHHYFHE.js +255 -0
  87. package/dist/{chunk-IHKBWSXF.js → chunk-TZ3SGWZZ.js} +2 -2
  88. package/dist/{chunk-ECUO3KDP.js → chunk-U77AMWDL.js} +47 -7
  89. package/dist/{chunk-3UUY7R3Z.js → chunk-ULC6OTWO.js} +7 -7
  90. package/dist/{chunk-AEYBF3TB.js → chunk-UM7N4G5A.js} +2 -2
  91. package/dist/{chunk-3V5AYSEQ.js → chunk-UXMFQ54G.js} +43 -36
  92. package/dist/{chunk-YW7UVM5V.js → chunk-V5DHCITQ.js} +34 -1
  93. package/dist/{chunk-47CMYGET.js → chunk-VAZSBTKF.js} +2 -2
  94. package/dist/{chunk-3MRC2YSQ.js → chunk-VEO4AP2K.js} +2 -2
  95. package/dist/{chunk-PNY46YEY.js → chunk-VFA6GDY5.js} +47 -3
  96. package/dist/chunk-VO67MWHC.js +75 -0
  97. package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
  98. package/dist/{chunk-AD7Y7STJ.js → chunk-VYMXRQI6.js} +36 -22
  99. package/dist/{chunk-T3Z6VAAF.js → chunk-W5VSYASO.js} +19 -17
  100. package/dist/{chunk-5PVQ4SRS.js → chunk-WZR7K7ZX.js} +7 -123
  101. package/dist/{chunk-DG4M6ZUE.js → chunk-X3YGUTOB.js} +4 -4
  102. package/dist/chunk-X75E3D2N.js +686 -0
  103. package/dist/{chunk-P3JGPQFL.js → chunk-YDFRH54B.js} +4 -4
  104. package/dist/chunk-YJX4SHTD.js +40 -0
  105. package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
  106. package/dist/{chunk-YSEHGPCT.js → chunk-Z2RR6MAK.js} +3 -3
  107. package/dist/{chunk-HCBCAYZU.js → chunk-Z4TXYIEG.js} +5 -5
  108. package/dist/cli/index.js +47 -36
  109. package/dist/{clio-LT5V7SSZ.js → clio-2JXHBBY5.js} +7 -7
  110. package/dist/{code-nav-LMW275PA.js → code-nav-3YYRMYNF.js} +6 -6
  111. package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
  112. package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
  113. package/dist/{config-RXS5T3JT.js → config-QZPCMYSO.js} +58 -50
  114. package/dist/{configure-2WYWSCSD.js → configure-TEGEBYCA.js} +21 -19
  115. package/dist/{context-I3BTOTCS.js → context-AV7OEZ4D.js} +11 -11
  116. package/dist/{context-MVOORGMF.js → context-E6H5RNMC.js} +49 -41
  117. package/dist/{context-PALKKQYL.js → context-GSXUE4CT.js} +25 -23
  118. package/dist/{context-clear-N2WOYZ2K.js → context-clear-SHIBYK6T.js} +48 -40
  119. package/dist/{context-working-set-MIEVECVZ.js → context-working-set-5ZGKPGZQ.js} +11 -10
  120. package/dist/{dispatch-runner-VVA4SRRH.js → dispatch-runner-EFMJT4LD.js} +88 -60
  121. package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
  122. package/dist/doctor-QOA5FNY5.js +313 -0
  123. package/dist/{eval-IJ5VEZDJ.js → eval-TFBYQH4H.js} +66 -64
  124. package/dist/eval-inventory-SXH7PDKX.js +316 -0
  125. package/dist/{evidence-L5APPXNV.js → evidence-ERGESKGN.js} +198 -44
  126. package/dist/{evolve-RGNKFJ52.js → evolve-VDXTSYCJ.js} +46 -38
  127. package/dist/{extensions-7WYWUX5A.js → extensions-7BGBHN57.js} +6 -6
  128. package/dist/{fleet-6CNVBZZP.js → fleet-2RRVDF2V.js} +189 -101
  129. package/dist/{fleet-commands-L2SXSYEI.js → fleet-commands-VJ726XIA.js} +10 -10
  130. package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
  131. package/dist/{fleet-graph-2J3OOIPO.js → fleet-graph-JF5QOATM.js} +16 -15
  132. package/dist/fleet-inspect-VLY4S7QM.js +442 -0
  133. package/dist/{fleet-preflight-CZRJ4JP5.js → fleet-preflight-AIZUEJOY.js} +6 -5
  134. package/dist/{fleet-validate-C5RI6DP7.js → fleet-validate-AJRPDMDV.js} +20 -18
  135. package/dist/fleet-verify-JFEL2L3H.js +175 -0
  136. package/dist/fleet-view-ZCON35AG.js +102 -0
  137. package/dist/{init-VBN2ACVA.js → init-DN2WWLFE.js} +64 -56
  138. package/dist/install-XGLBQY5E.js +13 -0
  139. package/dist/interop-OZBKXAYL.js +114 -0
  140. package/dist/{library-JHGUMLY2.js → library-YWZG7IMW.js} +19 -18
  141. package/dist/{memory-K4OQIYWG.js → memory-I4C4HMLW.js} +48 -40
  142. package/dist/{models-2NCZUWDD.js → models-CEYXJBO6.js} +30 -28
  143. package/dist/{monitor-MMVTJABD.js → monitor-NZ6GCI3P.js} +53 -47
  144. package/dist/{orchestrator-ZKBPCHW6.js → orchestrator-GCGQ4N5I.js} +6311 -7145
  145. package/dist/panes-HMABYVO4.js +58 -0
  146. package/dist/panes-KY6W3V2E.js +103 -0
  147. package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
  148. package/dist/{reset-DD5JGOY3.js → reset-DQ6FGCSH.js} +13 -11
  149. package/dist/resources-BB3MVJMD.js +111 -0
  150. package/dist/{run-QEGNX7FL.js → run-H2GQDUER.js} +113 -82
  151. package/dist/{share-JKD3BQMW.js → share-GTJN6A5O.js} +18 -17
  152. package/dist/{skills-LMQIKDOZ.js → skills-L55TEW6R.js} +31 -24
  153. package/dist/{skills-eval-I7X2774U.js → skills-eval-XVXPH2JI.js} +61 -52
  154. package/dist/skills-inventory-S4MXPJFV.js +126 -0
  155. package/dist/slash-commands-ZSGASKJC.js +77 -0
  156. package/dist/{steer-CF5TDANS.js → steer-RZGSCY4R.js} +3 -3
  157. package/dist/{support-I7LOJLIF.js → support-PKEUNNQL.js} +4 -4
  158. package/dist/{targets-RUSR6B5Z.js → targets-NCPZ644J.js} +31 -29
  159. package/dist/{terminal-lease-QYVORFR4.js → terminal-lease-44SV3YCN.js} +4 -4
  160. package/dist/tools-DAF3DI3C.js +27 -0
  161. package/dist/{trace-ODOQIVIW.js → trace-FYVW2MQA.js} +149 -7
  162. package/dist/tui-primitives-2AKXQNZK.js +13 -0
  163. package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
  164. package/dist/{upgrade-XANW3FXB.js → upgrade-3XPP6OQL.js} +26 -24
  165. package/dist/{usage-4H7ZRXQT.js → usage-3NLHGTU2.js} +57 -49
  166. package/dist/{verifiers-UZXNBZEB.js → verifiers-SSQONKRT.js} +171 -12
  167. package/dist/{verify-BVKWTNDL.js → verify-3U6J7FZI.js} +9 -9
  168. package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
  169. package/dist/{wiki-generate-MY7WV2QI.js → wiki-generate-CEHYGPGQ.js} +67 -59
  170. package/dist/with-panes-MKB46MPQ.js +782 -0
  171. package/dist/worker/entry.js +101 -66
  172. package/docs/README.md +3 -2
  173. package/docs/acp.md +24 -3
  174. package/docs/alcf-provider.md +1 -1
  175. package/docs/architecture.md +2 -2
  176. package/docs/artifact-versions.md +4 -1
  177. package/docs/built-in-agents.md +1 -1
  178. package/docs/capacity-and-scheduling.md +43 -5
  179. package/docs/commands-and-modes.md +31 -2
  180. package/docs/configuration-and-targets.md +40 -10
  181. package/docs/context-engine.md +1 -1
  182. package/docs/development-pipeline.md +19 -0
  183. package/docs/dispatch-typed-intent.md +385 -0
  184. package/docs/documentation-coverage.md +2 -2
  185. package/docs/documentation-guide.md +1 -1
  186. package/docs/environment-variables.md +1 -0
  187. package/docs/eval-runner.md +1 -1
  188. package/docs/evals-internal.md +1 -1
  189. package/docs/evidence-and-memory.md +2 -2
  190. package/docs/evolution.md +1 -1
  191. package/docs/exit-codes-and-output.md +1 -1
  192. package/docs/extensions-and-sharing.md +25 -1
  193. package/docs/fleet-dispatch.md +22 -1
  194. package/docs/installation-and-lifecycle.md +15 -2
  195. package/docs/middleware-and-components.md +1 -1
  196. package/docs/model-catalog.md +10 -1
  197. package/docs/observability.md +3 -3
  198. package/docs/proactive-memory.md +1 -1
  199. package/docs/prompt-envelope-and-tools.md +1 -1
  200. package/docs/provider-adapter-cookbook.md +1 -1
  201. package/docs/safety-model.md +2 -2
  202. package/docs/scientific-validation.md +3 -3
  203. package/docs/session-lifecycle.md +1 -1
  204. package/docs/skills-marketplace.md +1 -1
  205. package/docs/tool-usage.md +18 -8
  206. package/docs/trace-store.md +1 -1
  207. package/docs/troubleshooting.md +1 -1
  208. package/docs/tui-design.md +1 -1
  209. package/docs/worker-dispatch-mechanics.md +1 -1
  210. package/package.json +4 -2
  211. package/src/cli/acp.ts +6 -2
  212. package/src/cli/argv.ts +25 -0
  213. package/src/cli/configure.ts +23 -21
  214. package/src/cli/doctor-panes.ts +124 -0
  215. package/src/cli/doctor-toolchain.ts +57 -0
  216. package/src/cli/doctor.ts +20 -1
  217. package/src/cli/eval-inventory.ts +436 -0
  218. package/src/cli/eval.ts +13 -0
  219. package/src/cli/evidence-detail.ts +88 -0
  220. package/src/cli/evidence-inventory.ts +183 -0
  221. package/src/cli/evidence.ts +30 -5
  222. package/src/cli/fleet-decisions.ts +69 -0
  223. package/src/cli/fleet-inspect.ts +334 -0
  224. package/src/cli/fleet-verify.ts +133 -0
  225. package/src/cli/fleet-view.ts +810 -0
  226. package/src/cli/fleet.ts +148 -37
  227. package/src/cli/index.ts +14 -2
  228. package/src/cli/interop-inspect.ts +128 -0
  229. package/src/cli/interop.ts +34 -0
  230. package/src/cli/panes.ts +35 -0
  231. package/src/cli/reset.ts +5 -2
  232. package/src/cli/run.ts +58 -0
  233. package/src/cli/skills-inventory.ts +185 -0
  234. package/src/cli/skills.ts +16 -13
  235. package/src/cli/tools.ts +321 -0
  236. package/src/cli/trace-inspect.ts +252 -0
  237. package/src/cli/trace.ts +23 -2
  238. package/src/cli/verifiers-inspect.ts +347 -0
  239. package/src/cli/verifiers.ts +9 -0
  240. package/src/core/bus-events.ts +4 -0
  241. package/src/core/config.ts +49 -0
  242. package/src/core/defaults.ts +93 -7
  243. package/src/core/response-schema.ts +44 -4
  244. package/src/core/theme-token-hex.ts +43 -0
  245. package/src/core/tool-names.ts +2 -1
  246. package/src/core/xdg.ts +1 -1
  247. package/src/domains/agents/fleets/build-review.md +0 -3
  248. package/src/domains/agents/fleets/build-test.md +0 -3
  249. package/src/domains/agents/result-contract-filesystem.ts +32 -0
  250. package/src/domains/agents/result-contract.ts +164 -35
  251. package/src/domains/config/classify.ts +3 -0
  252. package/src/domains/dispatch/admission-error.ts +9 -0
  253. package/src/domains/dispatch/admission.ts +22 -21
  254. package/src/domains/dispatch/capacity-lease.ts +21 -1
  255. package/src/domains/dispatch/council-topology.ts +398 -0
  256. package/src/domains/dispatch/extension.ts +222 -50
  257. package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
  258. package/src/domains/dispatch/fleet-plan.ts +7 -2
  259. package/src/domains/dispatch/fleet-run.ts +64 -1
  260. package/src/domains/dispatch/gate-decisions.ts +11 -1
  261. package/src/domains/dispatch/gate-role-prompts.ts +9 -0
  262. package/src/domains/dispatch/gate-topology.ts +289 -0
  263. package/src/domains/dispatch/index.ts +19 -0
  264. package/src/domains/dispatch/intent-compatibility.ts +330 -0
  265. package/src/domains/dispatch/intent.ts +85 -1
  266. package/src/domains/dispatch/reservation-store.ts +24 -4
  267. package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
  268. package/src/domains/dispatch/run-event-journal.ts +598 -0
  269. package/src/domains/dispatch/state.ts +45 -1
  270. package/src/domains/dispatch/types.ts +13 -0
  271. package/src/domains/dispatch/validation.ts +33 -8
  272. package/src/domains/eval/compare/compare.ts +3 -16
  273. package/src/domains/eval/inventory.ts +113 -0
  274. package/src/domains/eval/schema/serving.ts +31 -0
  275. package/src/domains/evidence/store.ts +6 -0
  276. package/src/domains/memory/index.ts +0 -1
  277. package/src/domains/memory/task-memory-policy.ts +6 -10
  278. package/src/domains/memory/task-memory-telemetry.ts +1 -0
  279. package/src/domains/middleware/memory-intervention.ts +33 -21
  280. package/src/domains/mux/contract.ts +434 -0
  281. package/src/domains/mux/detect.ts +158 -0
  282. package/src/domains/mux/extension.ts +47 -0
  283. package/src/domains/mux/index.ts +96 -0
  284. package/src/domains/mux/manifest.ts +6 -0
  285. package/src/domains/mux/operations.ts +164 -0
  286. package/src/domains/mux/pane-registry.ts +90 -0
  287. package/src/domains/mux/protocol.ts +49 -0
  288. package/src/domains/mux/socket-client.ts +816 -0
  289. package/src/domains/mux/types.ts +222 -0
  290. package/src/domains/mux/viewer-command.ts +59 -0
  291. package/src/domains/mux/yazi/assets/init.lua +2 -0
  292. package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
  293. package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
  294. package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
  295. package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
  296. package/src/domains/mux/yazi/assets/yazi.toml +17 -0
  297. package/src/domains/mux/yazi/event-stream.ts +180 -0
  298. package/src/domains/mux/yazi/profile.ts +299 -0
  299. package/src/domains/mux/yazi/session.ts +228 -0
  300. package/src/domains/mux/yazi/theme.ts +30 -0
  301. package/src/domains/observability/cost.ts +21 -0
  302. package/src/domains/observability/index.ts +2 -0
  303. package/src/domains/observability/trace-store.ts +42 -0
  304. package/src/domains/providers/endpoint-capacity.ts +154 -22
  305. package/src/domains/providers/endpoint-slots-store.ts +189 -0
  306. package/src/domains/providers/extension.ts +20 -3
  307. package/src/domains/providers/index.ts +22 -0
  308. package/src/domains/providers/model-runtime-capabilities.ts +32 -0
  309. package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
  310. package/src/domains/providers/runtimes/builtins.ts +2 -0
  311. package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
  312. package/src/domains/providers/support.ts +1 -0
  313. package/src/domains/providers/target-model-cache.ts +124 -0
  314. package/src/domains/resources/index.ts +3 -0
  315. package/src/domains/resources/skills/loader.ts +33 -0
  316. package/src/domains/safety/action-classifier.ts +6 -0
  317. package/src/domains/toolchain/archive.ts +175 -0
  318. package/src/domains/toolchain/contract.ts +28 -0
  319. package/src/domains/toolchain/extension.ts +47 -0
  320. package/src/domains/toolchain/index.ts +39 -0
  321. package/src/domains/toolchain/install.ts +327 -0
  322. package/src/domains/toolchain/manifest.ts +8 -0
  323. package/src/domains/toolchain/paths.ts +34 -0
  324. package/src/domains/toolchain/registry.ts +265 -0
  325. package/src/domains/toolchain/remove.ts +218 -0
  326. package/src/domains/toolchain/resolve.ts +182 -0
  327. package/src/domains/toolchain/types.ts +113 -0
  328. package/src/domains/toolchain/version.ts +88 -0
  329. package/src/engine/acp/server.ts +413 -70
  330. package/src/engine/acp/types.ts +19 -1
  331. package/src/engine/claude/sdk-module.ts +98 -0
  332. package/src/engine/claude/sdk-runtime.ts +19 -11
  333. package/src/engine/tui-primitives.ts +21 -0
  334. package/src/engine/tui.ts +1 -0
  335. package/src/engine/worker-runtime.ts +2 -13
  336. package/src/entry/boot-options.ts +2 -0
  337. package/src/entry/orchestrator.ts +103 -5
  338. package/src/entry/panes-activation.ts +31 -0
  339. package/src/entry/with-panes.ts +20 -0
  340. package/src/interactive/context-overlay.ts +1 -0
  341. package/src/interactive/cost-overlay.ts +2 -0
  342. package/src/interactive/council-grid.ts +1 -3
  343. package/src/interactive/council.ts +11 -0
  344. package/src/interactive/dispatch-board.ts +26 -16
  345. package/src/interactive/interactive-application.ts +153 -6
  346. package/src/interactive/interactive-input-runtime.ts +7 -0
  347. package/src/interactive/interactive-slash-runtime.ts +36 -6
  348. package/src/interactive/memory-overlay.ts +1 -0
  349. package/src/interactive/modal-marker.ts +170 -0
  350. package/src/interactive/mux-bridge.ts +214 -0
  351. package/src/interactive/overlay-frame.ts +58 -2
  352. package/src/interactive/overlay-general-openers.ts +1 -0
  353. package/src/interactive/overlay-key-routing.ts +14 -3
  354. package/src/interactive/overlay-lifecycle.ts +19 -3
  355. package/src/interactive/overlay-model-selectors.ts +40 -3
  356. package/src/interactive/overlay-permission-lifecycle.ts +90 -22
  357. package/src/interactive/overlay-transitions.ts +18 -4
  358. package/src/interactive/overlays/agents.ts +1 -0
  359. package/src/interactive/overlays/ask-user.ts +136 -30
  360. package/src/interactive/overlays/auth-dialog.ts +1 -0
  361. package/src/interactive/overlays/context-reset.ts +1 -0
  362. package/src/interactive/overlays/cwd-fallback.ts +1 -0
  363. package/src/interactive/overlays/decisions.ts +11 -11
  364. package/src/interactive/overlays/extensions.ts +1 -0
  365. package/src/interactive/overlays/fleet-run-approval.ts +1 -0
  366. package/src/interactive/overlays/handoff-review.ts +1 -0
  367. package/src/interactive/overlays/help-reference.ts +2 -0
  368. package/src/interactive/overlays/interop.ts +1 -0
  369. package/src/interactive/overlays/library-install-confirm.ts +1 -0
  370. package/src/interactive/overlays/library-tabs.ts +28 -0
  371. package/src/interactive/overlays/list-overlay.ts +10 -1
  372. package/src/interactive/overlays/message-picker.ts +1 -0
  373. package/src/interactive/overlays/model-scope.ts +86 -0
  374. package/src/interactive/overlays/model-selector.ts +1 -0
  375. package/src/interactive/overlays/prompts.ts +1 -0
  376. package/src/interactive/overlays/session-selector.ts +1 -0
  377. package/src/interactive/overlays/settings-sections.ts +30 -0
  378. package/src/interactive/overlays/settings.ts +579 -44
  379. package/src/interactive/overlays/side-question.ts +1 -0
  380. package/src/interactive/overlays/skills-hub.ts +3 -11
  381. package/src/interactive/overlays/tree-selector.ts +1 -0
  382. package/src/interactive/pane-policy.ts +46 -0
  383. package/src/interactive/panes-runtime.ts +292 -0
  384. package/src/interactive/renderers/compaction-summary.ts +29 -0
  385. package/src/interactive/renderers/worker-entry.ts +122 -14
  386. package/src/interactive/slash-commands.ts +251 -15
  387. package/src/interactive/tasks-overlay.ts +1 -0
  388. package/src/interactive/theme/tokens.ts +3 -14
  389. package/src/interactive/turn-context.ts +47 -2
  390. package/src/interactive/view/artifacts.ts +109 -1
  391. package/src/interactive/view/view-overlay.ts +1 -0
  392. package/src/interactive/watch-pane.ts +152 -0
  393. package/src/interactive/worker-progress.ts +7 -1
  394. package/src/interactive/worker-receipts.ts +19 -1
  395. package/src/interactive/worker-stream.ts +5 -0
  396. package/src/interactive/yazi-bridge.ts +444 -0
  397. package/src/tools/bootstrap.ts +26 -2
  398. package/src/tools/builtin-tool-catalog.ts +15 -0
  399. package/src/tools/compete-worktrees.ts +83 -2
  400. package/src/tools/core-bootstrap.ts +2 -1
  401. package/src/tools/dispatch-admission.ts +14 -3
  402. package/src/tools/dispatch-arguments.ts +20 -20
  403. package/src/tools/dispatch-run-events.ts +134 -19
  404. package/src/tools/dispatch-runner.ts +29 -7
  405. package/src/tools/dispatch-types.ts +15 -3
  406. package/src/tools/dispatch.ts +1 -1
  407. package/src/tools/executables.ts +17 -14
  408. package/src/tools/observation.ts +54 -4
  409. package/src/tools/panes-surface.ts +38 -0
  410. package/src/tools/panes.ts +112 -0
  411. package/src/tools/policy.ts +10 -1
  412. package/src/tools/presentation.ts +1 -0
  413. package/dist/chunk-D73KXYPF.js +0 -37
  414. package/dist/chunk-MLOK6ZOS.js +0 -2888
  415. package/dist/chunk-YKOFT37S.js +0 -279
  416. package/dist/doctor-TWBWFK5V.js +0 -165
@@ -0,0 +1,180 @@
1
+ import { closeSync, openSync, readSync, statSync } from "node:fs";
2
+ import { StringDecoder } from "node:string_decoder";
3
+
4
+ export const YAZI_STREAM_POLL_MS = 250;
5
+ export const YAZI_STREAM_MAX_BYTES = 1024 * 1024;
6
+
7
+ export interface YaziCdEvent {
8
+ kind: "cd";
9
+ receiver: string;
10
+ sender: string;
11
+ tab: string;
12
+ cwd: string;
13
+ }
14
+
15
+ export interface YaziPickEvent {
16
+ kind: "clio-pick";
17
+ receiver: string;
18
+ sender: string;
19
+ values: ReadonlyArray<string>;
20
+ }
21
+
22
+ export type YaziEvent = YaziCdEvent | YaziPickEvent;
23
+ export type YaziEventStreamStopReason = "stopped" | "pane-gone" | "file-missing" | "size-cap";
24
+
25
+ export interface YaziEventStreamStats {
26
+ bytesRead: number;
27
+ linesRead: number;
28
+ malformedLines: number;
29
+ lastLineAt: number | null;
30
+ stopReason: YaziEventStreamStopReason | null;
31
+ }
32
+
33
+ export type YaziStreamLog = (level: "debug" | "warning", message: string) => void;
34
+
35
+ export interface YaziEventStreamOptions {
36
+ path: string;
37
+ onEvent: (event: YaziEvent) => void;
38
+ isAlive: () => boolean | Promise<boolean>;
39
+ log?: YaziStreamLog;
40
+ now?: () => number;
41
+ pollMs?: number;
42
+ maxBytes?: number;
43
+ autoStart?: boolean;
44
+ }
45
+
46
+ export interface YaziEventStream {
47
+ poll(): Promise<void>;
48
+ stop(reason?: YaziEventStreamStopReason): void;
49
+ stats(): Readonly<YaziEventStreamStats>;
50
+ done: Promise<YaziEventStreamStopReason>;
51
+ }
52
+
53
+ function record(value: unknown): value is Record<string, unknown> {
54
+ return typeof value === "object" && value !== null && !Array.isArray(value);
55
+ }
56
+
57
+ /** Parse the four DDS fields with the same three-comma split Yazi uses. */
58
+ export function parseYaziEventLine(line: string): YaziEvent | null {
59
+ const first = line.indexOf(",");
60
+ const second = first < 0 ? -1 : line.indexOf(",", first + 1);
61
+ const third = second < 0 ? -1 : line.indexOf(",", second + 1);
62
+ if (first <= 0 || second <= first + 1 || third <= second + 1) return null;
63
+ const kind = line.slice(0, first);
64
+ if (kind !== "cd" && kind !== "clio-pick") return null;
65
+ const receiver = line.slice(first + 1, second);
66
+ const sender = line.slice(second + 1, third);
67
+ try {
68
+ const body: unknown = JSON.parse(line.slice(third + 1));
69
+ if (kind === "cd") {
70
+ if (!record(body) || typeof body.url !== "string") return null;
71
+ const tab = body.tab;
72
+ if (typeof tab !== "number" && typeof tab !== "string") return null;
73
+ return { kind, receiver, sender, tab: String(tab), cwd: body.url };
74
+ }
75
+ if (!Array.isArray(body) || !body.every((value) => typeof value === "string")) return null;
76
+ return { kind, receiver, sender, values: body };
77
+ } catch {
78
+ return null;
79
+ }
80
+ }
81
+
82
+ /** Poll-tail one bounded DDS stdout file without knowing anything about panes or composers. */
83
+ export function createYaziEventStream(options: YaziEventStreamOptions): YaziEventStream {
84
+ const log = options.log ?? ((): void => undefined);
85
+ const now = options.now ?? Date.now;
86
+ const maxBytes = options.maxBytes ?? YAZI_STREAM_MAX_BYTES;
87
+ let offset = 0;
88
+ let carry = "";
89
+ let decoder = new StringDecoder("utf8");
90
+ let stopped = false;
91
+ let polling = false;
92
+ let interval: NodeJS.Timeout | null = null;
93
+ let settleDone: (reason: YaziEventStreamStopReason) => void = () => {};
94
+ const done = new Promise<YaziEventStreamStopReason>((resolve) => {
95
+ settleDone = resolve;
96
+ });
97
+ const state: YaziEventStreamStats = {
98
+ bytesRead: 0,
99
+ linesRead: 0,
100
+ malformedLines: 0,
101
+ lastLineAt: null,
102
+ stopReason: null,
103
+ };
104
+
105
+ const stop = (reason: YaziEventStreamStopReason = "stopped"): void => {
106
+ if (stopped) return;
107
+ stopped = true;
108
+ state.stopReason = reason;
109
+ if (interval) clearInterval(interval);
110
+ interval = null;
111
+ log(reason === "size-cap" ? "warning" : "debug", `yazi event stream stopped (${reason}): ${options.path}`);
112
+ settleDone(reason);
113
+ };
114
+
115
+ const poll = async (): Promise<void> => {
116
+ if (stopped || polling) return;
117
+ polling = true;
118
+ try {
119
+ if (!(await options.isAlive())) {
120
+ stop("pane-gone");
121
+ return;
122
+ }
123
+ const stat = statSync(options.path, { throwIfNoEntry: false });
124
+ if (!stat?.isFile()) {
125
+ stop("file-missing");
126
+ return;
127
+ }
128
+ if (stat.size > maxBytes) {
129
+ stop("size-cap");
130
+ return;
131
+ }
132
+ if (stat.size < offset) {
133
+ offset = 0;
134
+ carry = "";
135
+ decoder = new StringDecoder("utf8");
136
+ }
137
+ const remaining = stat.size - offset;
138
+ if (remaining <= 0) return;
139
+ const bytes = Buffer.allocUnsafe(remaining);
140
+ const fd = openSync(options.path, "r");
141
+ let read = 0;
142
+ try {
143
+ read = readSync(fd, bytes, 0, remaining, offset);
144
+ } finally {
145
+ closeSync(fd);
146
+ }
147
+ offset += read;
148
+ state.bytesRead += read;
149
+ const complete = `${carry}${decoder.write(bytes.subarray(0, read))}`.split("\n");
150
+ carry = complete.pop() ?? "";
151
+ for (const raw of complete) {
152
+ const line = raw.endsWith("\r") ? raw.slice(0, -1) : raw;
153
+ if (line.length === 0) continue;
154
+ const kind = line.slice(0, line.indexOf(","));
155
+ if (kind !== "cd" && kind !== "clio-pick") continue;
156
+ const event = parseYaziEventLine(line);
157
+ if (!event) {
158
+ state.malformedLines += 1;
159
+ continue;
160
+ }
161
+ state.linesRead += 1;
162
+ state.lastLineAt = now();
163
+ try {
164
+ options.onEvent(event);
165
+ } catch (error) {
166
+ log("warning", `yazi event consumer failed: ${error instanceof Error ? error.message : String(error)}`);
167
+ }
168
+ }
169
+ } finally {
170
+ polling = false;
171
+ }
172
+ };
173
+
174
+ if (options.autoStart !== false) {
175
+ interval = setInterval(() => void poll(), options.pollMs ?? YAZI_STREAM_POLL_MS);
176
+ interval.unref();
177
+ void poll();
178
+ }
179
+ return { poll, stop, stats: () => ({ ...state }), done };
180
+ }
@@ -0,0 +1,299 @@
1
+ import { spawnSync } from "node:child_process";
2
+ import { createHash } from "node:crypto";
3
+ import {
4
+ cpSync,
5
+ mkdirSync,
6
+ mkdtempSync,
7
+ readdirSync,
8
+ readFileSync,
9
+ renameSync,
10
+ rmSync,
11
+ statSync,
12
+ writeFileSync,
13
+ } from "node:fs";
14
+ import { homedir } from "node:os";
15
+ import { dirname, isAbsolute, join, relative } from "node:path";
16
+ import { readClioVersion, resolvePackageRoot } from "../../../core/package-root.js";
17
+ import { parseTomlDocument } from "../../../core/toml.js";
18
+ import { clioCacheDir, resolveClioDirs } from "../../../core/xdg.js";
19
+ import { findPinnedTool } from "../../toolchain/registry.js";
20
+ import { resolveToolBinary } from "../../toolchain/resolve.js";
21
+ import { renderYaziTheme } from "./theme.js";
22
+
23
+ const PROFILE_FILES = ["yazi.toml", "keymap.toml", "theme.toml", "init.lua"] as const;
24
+ const PROFILE_PLUGIN_FILES = ["main.lua", "types.lua", "LICENSE", "README.md"] as const;
25
+ const STAMP_FILE = "stamp.json";
26
+
27
+ export interface YaziProfileStamp {
28
+ yaziVersion: string;
29
+ clioVersion: string;
30
+ yaPath: string;
31
+ assetSha256: string;
32
+ themeSha256: string;
33
+ }
34
+
35
+ export interface YaziProfile {
36
+ dir: string;
37
+ stamp: Readonly<YaziProfileStamp>;
38
+ }
39
+
40
+ export type YaziProfileState = "current" | "stale" | "missing";
41
+
42
+ export interface YaziProfileInspection {
43
+ dir: string;
44
+ userConfigDir: string;
45
+ state: YaziProfileState;
46
+ stamp: Readonly<YaziProfileStamp>;
47
+ }
48
+
49
+ export interface YaziProfileOptions {
50
+ yaPath: string;
51
+ profileDir?: string;
52
+ assetDir?: string;
53
+ yaziVersion?: string;
54
+ clioVersion?: string;
55
+ themeToml?: string;
56
+ yaziToml?: string;
57
+ keymapToml?: string;
58
+ }
59
+
60
+ export interface EnsureYaziProfileOptions extends YaziProfileOptions {
61
+ yaziPath: string;
62
+ }
63
+
64
+ /** The managed profile location without creating the cache root. */
65
+ export function yaziProfileDir(cacheDir: string = resolveClioDirs().cache): string {
66
+ return join(cacheDir, "yazi", "profile");
67
+ }
68
+
69
+ /** The config path Yazi itself would use when Clio does not set its override. */
70
+ export function userYaziConfigDir(env: NodeJS.ProcessEnv = process.env, home: string = homedir()): string {
71
+ const xdg = env.XDG_CONFIG_HOME;
72
+ return xdg && isAbsolute(xdg) ? join(xdg, "yazi") : join(home, ".config", "yazi");
73
+ }
74
+
75
+ /** Remove only Clio's reproducible profile. The user's Yazi config is never addressed. */
76
+ export function resetYaziProfile(profileDir: string = yaziProfileDir()): void {
77
+ rmSync(profileDir, { recursive: true, force: true });
78
+ }
79
+
80
+ function defaultAssetDir(): string {
81
+ return join(resolvePackageRoot(), "src", "domains", "mux", "yazi", "assets");
82
+ }
83
+
84
+ function yaziPin(): string {
85
+ return findPinnedTool("yazi")?.version ?? "unknown";
86
+ }
87
+
88
+ function sha256(input: string | Buffer): string {
89
+ return createHash("sha256").update(input).digest("hex");
90
+ }
91
+
92
+ function filesBelow(root: string, current: string = root): string[] {
93
+ const files: string[] = [];
94
+ for (const entry of readdirSync(current, { withFileTypes: true }).sort((left, right) =>
95
+ left.name.localeCompare(right.name),
96
+ )) {
97
+ const path = join(current, entry.name);
98
+ if (entry.isDirectory()) files.push(...filesBelow(root, path));
99
+ else if (entry.isFile()) files.push(relative(root, path).replaceAll("\\", "/"));
100
+ }
101
+ return files;
102
+ }
103
+
104
+ /** Hash file names and bytes in a stable order, so any vendored-asset change invalidates the profile. */
105
+ export function hashYaziAssetTree(assetDir: string): string {
106
+ const hash = createHash("sha256");
107
+ for (const file of filesBelow(assetDir)) {
108
+ hash.update(file);
109
+ hash.update("\0");
110
+ hash.update(readFileSync(join(assetDir, file)));
111
+ hash.update("\0");
112
+ }
113
+ return hash.digest("hex");
114
+ }
115
+
116
+ function shellQuote(value: string): string {
117
+ return `'${value.replaceAll("'", `'\\''`)}'`;
118
+ }
119
+
120
+ /** Render the one Clio key chord, with an absolute `ya` path for vendored installs. */
121
+ export function renderYaziKeymap(yaPath: string): string {
122
+ const command = `shell -- ${shellQuote(yaPath)} pub-to "$YAZI_ID" clio-pick --list "$CLIO_YAZI_PICK_TOKEN" %s`;
123
+ return `# Generated by Clio Coder. Changes are replaced when the managed profile regenerates.
124
+
125
+ [[mgr.prepend_keymap]]
126
+ on = "<C-y>"
127
+ run = ${JSON.stringify(command)}
128
+ desc = "Send the selection to Clio"
129
+ `;
130
+ }
131
+
132
+ function expected(options: YaziProfileOptions): {
133
+ dir: string;
134
+ assetDir: string;
135
+ yaziToml: string;
136
+ keymapToml: string;
137
+ themeToml: string;
138
+ stamp: YaziProfileStamp;
139
+ } {
140
+ const assetDir = options.assetDir ?? defaultAssetDir();
141
+ const themeToml = options.themeToml ?? renderYaziTheme();
142
+ const yaziToml = options.yaziToml ?? readFileSync(join(assetDir, "yazi.toml"), "utf8");
143
+ const keymapToml = options.keymapToml ?? renderYaziKeymap(options.yaPath);
144
+ return {
145
+ dir: options.profileDir ?? yaziProfileDir(),
146
+ assetDir,
147
+ yaziToml,
148
+ keymapToml,
149
+ themeToml,
150
+ stamp: {
151
+ yaziVersion: options.yaziVersion ?? yaziPin(),
152
+ clioVersion: options.clioVersion ?? readClioVersion(),
153
+ yaPath: options.yaPath,
154
+ assetSha256: hashYaziAssetTree(assetDir),
155
+ themeSha256: sha256(themeToml),
156
+ },
157
+ };
158
+ }
159
+
160
+ function readStamp(dir: string): YaziProfileStamp | null {
161
+ try {
162
+ const value = JSON.parse(readFileSync(join(dir, STAMP_FILE), "utf8")) as Partial<YaziProfileStamp>;
163
+ if (
164
+ typeof value.yaziVersion !== "string" ||
165
+ typeof value.clioVersion !== "string" ||
166
+ typeof value.yaPath !== "string" ||
167
+ typeof value.assetSha256 !== "string" ||
168
+ typeof value.themeSha256 !== "string"
169
+ ) {
170
+ return null;
171
+ }
172
+ return value as YaziProfileStamp;
173
+ } catch {
174
+ return null;
175
+ }
176
+ }
177
+
178
+ function sameStamp(left: Readonly<YaziProfileStamp> | null, right: Readonly<YaziProfileStamp>): boolean {
179
+ return (
180
+ left !== null &&
181
+ left.yaziVersion === right.yaziVersion &&
182
+ left.clioVersion === right.clioVersion &&
183
+ left.yaPath === right.yaPath &&
184
+ left.assetSha256 === right.assetSha256 &&
185
+ left.themeSha256 === right.themeSha256
186
+ );
187
+ }
188
+
189
+ function profileFilesExist(dir: string): boolean {
190
+ return (
191
+ PROFILE_FILES.every((file) => statSync(join(dir, file), { throwIfNoEntry: false })?.isFile()) &&
192
+ PROFILE_PLUGIN_FILES.every(
193
+ (file) => statSync(join(dir, "plugins", "git.yazi", file), { throwIfNoEntry: false })?.isFile() === true,
194
+ )
195
+ );
196
+ }
197
+
198
+ /** Read whether the cached profile matches current inputs without creating or rewriting it. */
199
+ export function inspectYaziProfile(options: YaziProfileOptions): YaziProfileInspection {
200
+ const inputs = expected(options);
201
+ const present = statSync(inputs.dir, { throwIfNoEntry: false })?.isDirectory() === true;
202
+ const current = present && profileFilesExist(inputs.dir) && sameStamp(readStamp(inputs.dir), inputs.stamp);
203
+ return {
204
+ dir: inputs.dir,
205
+ userConfigDir: userYaziConfigDir(),
206
+ state: current ? "current" : present ? "stale" : "missing",
207
+ stamp: inputs.stamp,
208
+ };
209
+ }
210
+
211
+ /** Inspect the profile against the `ya` path the shared resolution ladder currently chooses. */
212
+ export function inspectCurrentYaziProfile(): YaziProfileInspection {
213
+ return inspectYaziProfile({ yaPath: resolveToolBinary("ya").binaryPath ?? "(unresolved)" });
214
+ }
215
+
216
+ /** One shared sentence for `tools status yazi` and the doctor profile row. */
217
+ export function describeYaziProfile(inspection: Readonly<YaziProfileInspection>): string {
218
+ return `${inspection.dir} (${inspection.state}); user config ${inspection.userConfigDir} is separate and untouched`;
219
+ }
220
+
221
+ function parseGenerated(dir: string): boolean {
222
+ return ["yazi.toml", "keymap.toml", "theme.toml"].every((file) => {
223
+ try {
224
+ return parseTomlDocument(readFileSync(join(dir, file), "utf8")) !== null;
225
+ } catch {
226
+ return false;
227
+ }
228
+ });
229
+ }
230
+
231
+ const YAZI_CONFIG_ERROR_MARKERS = ["Failed to parse config", "Press <Enter> to continue with preset settings"];
232
+
233
+ /** Ask the resolved Yazi binary to load the staged profile before it can become current. */
234
+ function validatesWithYazi(dir: string, yaziPath: string): boolean {
235
+ const scratchHome = mkdtempSync(join(dirname(dir), ".yazi-validation-"));
236
+ try {
237
+ const result = spawnSync(yaziPath, ["--debug"], {
238
+ cwd: scratchHome,
239
+ env: {
240
+ ...process.env,
241
+ HOME: scratchHome,
242
+ XDG_CACHE_HOME: join(scratchHome, "cache"),
243
+ XDG_CONFIG_HOME: join(scratchHome, "config"),
244
+ YAZI_CONFIG_HOME: dir,
245
+ },
246
+ encoding: "utf8",
247
+ timeout: 5_000,
248
+ });
249
+ const output = `${result.stdout ?? ""}\n${result.stderr ?? ""}`;
250
+ return (
251
+ result.error === undefined &&
252
+ result.status === 0 &&
253
+ YAZI_CONFIG_ERROR_MARKERS.every((marker) => !output.includes(marker))
254
+ );
255
+ } catch {
256
+ return false;
257
+ } finally {
258
+ rmSync(scratchHome, { recursive: true, force: true });
259
+ }
260
+ }
261
+
262
+ /**
263
+ * Materialize Clio's deterministic Yazi profile, replacing it only when its
264
+ * recorded inputs differ. No path outside `<cache>/yazi/` is read or written.
265
+ */
266
+ export function ensureYaziProfile(options: EnsureYaziProfileOptions): YaziProfile | null {
267
+ let inputs: ReturnType<typeof expected>;
268
+ try {
269
+ inputs = expected({ ...options, profileDir: options.profileDir ?? yaziProfileDir(clioCacheDir()) });
270
+ } catch {
271
+ return null;
272
+ }
273
+ if (profileFilesExist(inputs.dir) && sameStamp(readStamp(inputs.dir), inputs.stamp)) {
274
+ return { dir: inputs.dir, stamp: inputs.stamp };
275
+ }
276
+
277
+ mkdirSync(dirname(inputs.dir), { recursive: true });
278
+ const staging = mkdtempSync(join(dirname(inputs.dir), ".profile-"));
279
+ try {
280
+ cpSync(join(inputs.assetDir, "init.lua"), join(staging, "init.lua"));
281
+ cpSync(join(inputs.assetDir, "plugins"), join(staging, "plugins"), { recursive: true });
282
+ writeFileSync(join(staging, "yazi.toml"), inputs.yaziToml);
283
+ writeFileSync(join(staging, "keymap.toml"), inputs.keymapToml);
284
+ writeFileSync(join(staging, "theme.toml"), inputs.themeToml);
285
+ writeFileSync(join(staging, STAMP_FILE), `${JSON.stringify(inputs.stamp, null, 2)}\n`);
286
+ if (!parseGenerated(staging) || !validatesWithYazi(staging, options.yaziPath)) {
287
+ rmSync(inputs.dir, { recursive: true, force: true });
288
+ return null;
289
+ }
290
+ rmSync(inputs.dir, { recursive: true, force: true });
291
+ renameSync(staging, inputs.dir);
292
+ return { dir: inputs.dir, stamp: inputs.stamp };
293
+ } catch {
294
+ rmSync(inputs.dir, { recursive: true, force: true });
295
+ return null;
296
+ } finally {
297
+ rmSync(staging, { recursive: true, force: true });
298
+ }
299
+ }
@@ -0,0 +1,228 @@
1
+ import { spawn } from "node:child_process";
2
+ import { randomUUID } from "node:crypto";
3
+ import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
4
+ import { join } from "node:path";
5
+ import { clioCacheDir } from "../../../core/xdg.js";
6
+ import { findPinnedTool } from "../../toolchain/registry.js";
7
+ import { describeResolution, resolveToolBinary, toolStatus } from "../../toolchain/resolve.js";
8
+ import type { MuxContract } from "../contract.js";
9
+ import type { MuxPaneRef } from "../types.js";
10
+ import { createYaziEventStream, YAZI_STREAM_POLL_MS, type YaziEvent, type YaziEventStream } from "./event-stream.js";
11
+ import { ensureYaziProfile, type YaziProfile, yaziProfileDir } from "./profile.js";
12
+
13
+ export type YaziSessionMode = "companion" | "chooser";
14
+ export type YaziProfileMode = "managed" | "user";
15
+
16
+ export interface YaziResolvedBinaries {
17
+ yaziPath: string | null;
18
+ yaPath: string | null;
19
+ missingYaziDetail: string;
20
+ }
21
+
22
+ export interface YaziChooserResult {
23
+ paths: ReadonlyArray<string>;
24
+ cwd: string;
25
+ }
26
+
27
+ export interface YaziSessionSnapshot {
28
+ mode: YaziSessionMode;
29
+ paneId: string;
30
+ paneCwd: string;
31
+ instanceId: string | null;
32
+ lastLineAt: number | null;
33
+ streamPath: string | null;
34
+ chooserPath: string | null;
35
+ }
36
+
37
+ export interface YaziSession {
38
+ readonly mode: YaziSessionMode;
39
+ readonly pane: Readonly<MuxPaneRef>;
40
+ readonly token: string | null;
41
+ readonly profile: Readonly<YaziProfile> | null;
42
+ snapshot(): Readonly<YaziSessionSnapshot>;
43
+ pushCwd(cwd: string): Promise<boolean>;
44
+ close(): Promise<void>;
45
+ }
46
+
47
+ export type YaziSessionOpenResult =
48
+ | { status: "opened"; session: YaziSession }
49
+ | { status: "missing-binary"; binary: "yazi" | "ya"; detail: string }
50
+ | { status: "profile-error"; reason: string }
51
+ | { status: "unavailable"; reason: string };
52
+
53
+ export interface YaziSessionOptions {
54
+ mux: MuxContract;
55
+ mode: YaziSessionMode;
56
+ profileMode: YaziProfileMode;
57
+ cwd: string;
58
+ onEvent: (event: YaziEvent) => void;
59
+ onChooser: (result: YaziChooserResult) => void;
60
+ onStopped?: (reason: string) => void;
61
+ log?: (level: "debug" | "warning", message: string) => void;
62
+ cacheDir?: string;
63
+ sessionId?: string;
64
+ pickToken?: string;
65
+ pollMs?: number;
66
+ resolveBinaries?: () => YaziResolvedBinaries;
67
+ ensureProfile?: typeof ensureYaziProfile;
68
+ runYa?: (file: string, args: ReadonlyArray<string>, env: Readonly<NodeJS.ProcessEnv>) => Promise<boolean>;
69
+ }
70
+
71
+ export function resolveYaziBinaries(): YaziResolvedBinaries {
72
+ const entry = findPinnedTool("yazi");
73
+ const status = entry ? toolStatus(entry) : null;
74
+ return {
75
+ yaziPath: status?.resolution.binaryPath ?? null,
76
+ yaPath: resolveToolBinary("ya").binaryPath,
77
+ missingYaziDetail: status ? describeResolution(status) : "yazi is not in the pinned tool registry",
78
+ };
79
+ }
80
+
81
+ function runYa(file: string, args: ReadonlyArray<string>, env: Readonly<NodeJS.ProcessEnv>): Promise<boolean> {
82
+ return new Promise((resolve) => {
83
+ const child = spawn(file, args, { env: { ...env }, stdio: "ignore" });
84
+ child.once("error", () => resolve(false));
85
+ child.once("exit", (code) => resolve(code === 0));
86
+ });
87
+ }
88
+
89
+ function readOptional(path: string): string {
90
+ try {
91
+ return readFileSync(path, "utf8");
92
+ } catch {
93
+ return "";
94
+ }
95
+ }
96
+
97
+ /** Open one mux-hosted Yazi process and own its DDS or chooser-file transport. */
98
+ export async function createYaziSession(options: YaziSessionOptions): Promise<YaziSessionOpenResult> {
99
+ const binaries = (options.resolveBinaries ?? resolveYaziBinaries)();
100
+ if (!binaries.yaziPath) {
101
+ return { status: "missing-binary", binary: "yazi", detail: binaries.missingYaziDetail };
102
+ }
103
+ if (options.profileMode === "managed" && !binaries.yaPath) {
104
+ return {
105
+ status: "missing-binary",
106
+ binary: "ya",
107
+ detail: "the Yazi helper `ya` is not available; install the complete pinned Yazi tool",
108
+ };
109
+ }
110
+
111
+ const cacheDir = options.cacheDir ?? clioCacheDir();
112
+ const sessionId = options.sessionId ?? randomUUID();
113
+ const sessionsDir = join(cacheDir, "yazi", "sessions");
114
+ mkdirSync(sessionsDir, { recursive: true });
115
+ const managedProfile =
116
+ options.profileMode === "managed"
117
+ ? (options.ensureProfile ?? ensureYaziProfile)({
118
+ yaPath: binaries.yaPath as string,
119
+ yaziPath: binaries.yaziPath,
120
+ profileDir: yaziProfileDir(cacheDir),
121
+ })
122
+ : null;
123
+ if (options.profileMode === "managed" && !managedProfile) {
124
+ return { status: "profile-error", reason: "Clio could not generate a valid managed Yazi profile" };
125
+ }
126
+
127
+ const streamPath = join(sessionsDir, `${sessionId}.stream`);
128
+ const chooserPath = join(sessionsDir, `${sessionId}.chooser`);
129
+ const cwdPath = join(sessionsDir, `${sessionId}.cwd`);
130
+ const token = options.mode === "companion" ? (options.pickToken ?? randomUUID()) : null;
131
+ const env: Record<string, string> = {
132
+ ...(managedProfile ? { YAZI_CONFIG_HOME: managedProfile.dir } : {}),
133
+ ...(token ? { CLIO_YAZI_PICK_TOKEN: token } : {}),
134
+ };
135
+ let argv: ReadonlyArray<string>;
136
+ let stdoutPath: string | undefined;
137
+ if (options.mode === "companion") {
138
+ writeFileSync(streamPath, "");
139
+ argv = [binaries.yaziPath, "--local-events", "cd,clio-pick", "--remote-events", "clio-pick"];
140
+ stdoutPath = streamPath;
141
+ } else {
142
+ writeFileSync(chooserPath, "");
143
+ writeFileSync(cwdPath, "");
144
+ argv = [binaries.yaziPath, options.cwd, "--chooser-file", chooserPath, "--cwd-file", cwdPath];
145
+ }
146
+
147
+ const pane = await options.mux.openUtilityPane({
148
+ argv,
149
+ cwd: options.cwd,
150
+ label: "yazi",
151
+ ...(Object.keys(env).length > 0 ? { env } : {}),
152
+ ...(stdoutPath ? { stdoutPath } : {}),
153
+ });
154
+ if (!pane) return { status: "unavailable", reason: "pane host refused to open yazi" };
155
+
156
+ let paneCwd = options.cwd;
157
+ let instanceId: string | null = null;
158
+ let stream: YaziEventStream | null = null;
159
+ let chooserTimer: NodeJS.Timeout | null = null;
160
+ let stopped = false;
161
+ const alive = (): boolean => options.mux.list().some((record) => record.ref.paneId === pane.paneId);
162
+ const stop = (reason: string): void => {
163
+ if (stopped) return;
164
+ stopped = true;
165
+ if (chooserTimer) clearInterval(chooserTimer);
166
+ chooserTimer = null;
167
+ options.onStopped?.(reason);
168
+ };
169
+
170
+ if (options.mode === "companion") {
171
+ stream = createYaziEventStream({
172
+ path: streamPath,
173
+ isAlive: alive,
174
+ ...(options.pollMs !== undefined ? { pollMs: options.pollMs } : {}),
175
+ ...(options.log ? { log: options.log } : {}),
176
+ onEvent: (event) => {
177
+ if (event.kind === "cd") {
178
+ paneCwd = event.cwd;
179
+ instanceId = event.sender;
180
+ }
181
+ options.onEvent(event);
182
+ },
183
+ });
184
+ void stream.done.then((reason) => stop(reason));
185
+ } else {
186
+ const pollChooser = (): void => {
187
+ if (stopped || alive()) return;
188
+ const raw = readOptional(chooserPath);
189
+ const cwd = readOptional(cwdPath).trim() || paneCwd;
190
+ paneCwd = cwd;
191
+ const paths = raw.length === 0 ? [] : raw.split("\n").filter((path) => path.length > 0);
192
+ options.onChooser({ paths, cwd });
193
+ stop("pane-gone");
194
+ };
195
+ chooserTimer = setInterval(pollChooser, options.pollMs ?? YAZI_STREAM_POLL_MS);
196
+ chooserTimer.unref();
197
+ }
198
+
199
+ const session: YaziSession = {
200
+ mode: options.mode,
201
+ pane,
202
+ token,
203
+ profile: managedProfile,
204
+ snapshot: () => ({
205
+ mode: options.mode,
206
+ paneId: pane.paneId,
207
+ paneCwd,
208
+ instanceId,
209
+ lastLineAt: stream?.stats().lastLineAt ?? null,
210
+ streamPath: options.mode === "companion" ? streamPath : null,
211
+ chooserPath: options.mode === "chooser" ? chooserPath : null,
212
+ }),
213
+ async pushCwd(cwd: string): Promise<boolean> {
214
+ if (!instanceId || !binaries.yaPath) return false;
215
+ const pushed = await (options.runYa ?? runYa)(binaries.yaPath, ["emit-to", instanceId, "cd", cwd], {
216
+ ...process.env,
217
+ ...(managedProfile ? { YAZI_CONFIG_HOME: managedProfile.dir } : {}),
218
+ });
219
+ return pushed;
220
+ },
221
+ async close(): Promise<void> {
222
+ stream?.stop();
223
+ stop("stopped");
224
+ await options.mux.closePane(pane.paneId);
225
+ },
226
+ };
227
+ return { status: "opened", session };
228
+ }