@iowarp/clio-coder 0.3.9 → 0.4.1
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.
- package/CHANGELOG.md +92 -0
- package/NOTICE +33 -0
- package/README.md +121 -16
- package/dist/{acp-7LOELQFP.js → acp-ZILU3AUO.js} +19 -18
- package/dist/{agents-FIBG2SHA.js → agents-HYWGBGQR.js} +53 -39
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-OI4LIH2I.js → auth-N3QT7CBO.js} +24 -21
- package/dist/{builtins-AD25UL3C.js → builtins-UJLMOVOV.js} +6 -6
- package/dist/{chunk-I4HZDVNP.js → chunk-2LEAKD4C.js} +2 -3
- package/dist/{chunk-465CC7FK.js → chunk-2NM363SV.js} +60 -64
- package/dist/{chunk-4H6ULJ3H.js → chunk-2VG7KLYV.js} +1046 -1370
- package/dist/{chunk-SST6Z5JA.js → chunk-336NSSKI.js} +1 -1
- package/dist/{chunk-NZU6YDNV.js → chunk-3I5NY75V.js} +5 -5
- package/dist/{chunk-47CMYGET.js → chunk-3QSOM6PA.js} +2 -2
- package/dist/chunk-42FMPA75.js +101 -0
- package/dist/{chunk-HAY4ZE2P.js → chunk-5PSMVOLM.js} +2 -2
- package/dist/{chunk-IHKBWSXF.js → chunk-5QIAJV2D.js} +3 -3
- package/dist/chunk-5YHDIDBP.js +97 -0
- package/dist/chunk-6CCS4G3W.js +1529 -0
- package/dist/{chunk-2JDWVJND.js → chunk-6DWBAZ5U.js} +2 -2
- package/dist/{chunk-BVDVID7E.js → chunk-6FN3E6KX.js} +6 -6
- package/dist/{chunk-DG4M6ZUE.js → chunk-6HMJX2VU.js} +59 -59
- package/dist/{chunk-3MRC2YSQ.js → chunk-6I5ILFOF.js} +3 -2
- package/dist/chunk-6NJQITNH.js +1412 -0
- package/dist/chunk-6VC4OV3Z.js +365 -0
- package/dist/{chunk-LU7P4LHA.js → chunk-72GZI5EV.js} +2 -2
- package/dist/{chunk-5T7RBWN2.js → chunk-74YWRRU5.js} +9 -8
- package/dist/{chunk-VPTUJU4P.js → chunk-7EPLI7VL.js} +2 -2
- package/dist/{chunk-CA42X6KT.js → chunk-7OBGU7UB.js} +7 -7
- package/dist/{chunk-56KB5IJP.js → chunk-7PWAODYW.js} +3 -3
- package/dist/chunk-7RY5VZPH.js +573 -0
- package/dist/{chunk-OEDBCISO.js → chunk-ABLSQ6JX.js} +3 -3
- package/dist/{chunk-5HFBWUMU.js → chunk-AFKWHWXF.js} +13 -23
- package/dist/{chunk-FWDFM5ZU.js → chunk-AK5XEFVZ.js} +3 -3
- package/dist/{chunk-WXCJ7VME.js → chunk-AKB4GYDL.js} +7 -7
- package/dist/chunk-AP73CFDC.js +308 -0
- package/dist/{chunk-4LJX2PUC.js → chunk-BBTJOK6Y.js} +5 -5
- package/dist/{chunk-QQ7EKM72.js → chunk-BDPT6GTK.js} +13 -61
- package/dist/chunk-BJGUKIG4.js +302 -0
- package/dist/chunk-BMS5RKQY.js +27 -0
- package/dist/{chunk-TD7UE2L5.js → chunk-BTGG6BG2.js} +81 -40
- package/dist/chunk-BTK3SSSK.js +67 -0
- package/dist/{chunk-M6L6IDJG.js → chunk-BWH6N36D.js} +1 -1
- package/dist/chunk-BWW4HLO4.js +301 -0
- package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
- package/dist/{chunk-HJB5IUKP.js → chunk-C537JADH.js} +18 -18
- package/dist/{chunk-774ILSRL.js → chunk-CDNVLKUX.js} +5 -4
- package/dist/{chunk-HPCTNZM2.js → chunk-CTJ4RNAA.js} +4 -4
- package/dist/{chunk-AEYBF3TB.js → chunk-CWVRRIEI.js} +2 -2
- package/dist/chunk-D4CJV46V.js +462 -0
- package/dist/chunk-D7E7WCDF.js +27 -0
- package/dist/{chunk-5PVQ4SRS.js → chunk-E67WX76H.js} +10 -126
- package/dist/{chunk-FQ4SKYE4.js → chunk-EBY63B7G.js} +2 -5
- package/dist/chunk-EIMVLWB3.js +1842 -0
- package/dist/{chunk-AMKHQW3C.js → chunk-FEFIFZTL.js} +3 -3
- package/dist/{chunk-RAPCMZL4.js → chunk-FSP7CMNU.js} +9 -1
- package/dist/{chunk-3DUR4WUA.js → chunk-FYUN5KZ3.js} +25 -25
- package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
- package/dist/chunk-GIZNH63R.js +40 -0
- package/dist/chunk-GPPB3JBE.js +688 -0
- package/dist/{chunk-B5XRQOLB.js → chunk-GVQJ5CCZ.js} +17 -11
- package/dist/chunk-HHV2GANA.js +88 -0
- package/dist/chunk-HJWWJ6IL.js +184 -0
- package/dist/{chunk-RKRLDWD3.js → chunk-HLW2MRKE.js} +1 -1
- package/dist/chunk-HRQMFLJP.js +75 -0
- package/dist/{chunk-AD7Y7STJ.js → chunk-HUAS7ITX.js} +107 -97
- package/dist/{chunk-O6I4CIEU.js → chunk-I66EAJFY.js} +6 -6
- package/dist/{chunk-S4COXYBG.js → chunk-IG7BCQBA.js} +129 -106
- package/dist/{chunk-N3PBVRTZ.js → chunk-IXJT6DCX.js} +9 -7
- package/dist/chunk-J4HBWF6Y.js +2635 -0
- package/dist/chunk-J5LZHVIT.js +284 -0
- package/dist/{chunk-GAYUJ7LE.js → chunk-JA5QWE4Z.js} +544 -227
- package/dist/{chunk-B5CSFE7B.js → chunk-JIEGK6UF.js} +6 -174
- package/dist/{chunk-VKBMFOYV.js → chunk-JZWT5J3Y.js} +23 -27
- package/dist/chunk-K6BF4U2H.js +1785 -0
- package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
- package/dist/{chunk-YSEHGPCT.js → chunk-MA3H6DM5.js} +6 -6
- package/dist/{chunk-EBOC7MT3.js → chunk-MOPSG2X7.js} +9 -9
- package/dist/{chunk-KV2AOLDF.js → chunk-MQXIVJ35.js} +18 -29
- package/dist/{chunk-P3JGPQFL.js → chunk-N5UK64DP.js} +4 -4
- package/dist/chunk-NDDGJUXD.js +81 -0
- package/dist/chunk-NEKRRTYW.js +56 -0
- package/dist/{chunk-4ZG3XFUR.js → chunk-NLFAQR7Z.js} +12 -1
- package/dist/{chunk-VO2LKSTM.js → chunk-O42A54GG.js} +2 -2
- package/dist/{chunk-T3Z6VAAF.js → chunk-OJTRZGR3.js} +53 -92
- package/dist/{chunk-5DQRIYDZ.js → chunk-PBP4B7XR.js} +3 -3
- package/dist/{chunk-NQ6UCCOD.js → chunk-PJJ6MY27.js} +8 -8
- package/dist/chunk-PMZCIOCJ.js +25 -0
- package/dist/{chunk-ZGVHUX3M.js → chunk-PMZVFWSR.js} +2 -2
- package/dist/{chunk-7C6RYZGQ.js → chunk-PVAMAVBB.js} +5 -4
- package/dist/chunk-QDC3K2U3.js +262 -0
- package/dist/{chunk-JEQQR47K.js → chunk-QKIFBZKT.js} +173 -14
- package/dist/{chunk-R7LNVMCS.js → chunk-QMXC4JB7.js} +70 -78
- package/dist/chunk-QSNYB6ZV.js +195 -0
- package/dist/chunk-QTFGO774.js +644 -0
- package/dist/{chunk-ODFEOB4F.js → chunk-R23Z6K6I.js} +27 -9
- package/dist/{chunk-3UUY7R3Z.js → chunk-R32CLGZ6.js} +14 -14
- package/dist/chunk-R346GLFC.js +31 -0
- package/dist/chunk-RKSR6VSF.js +132 -0
- package/dist/{chunk-N5XKWMDW.js → chunk-SCYB3HA4.js} +73 -27
- package/dist/{chunk-PZ4I4JE2.js → chunk-SINK3QR6.js} +135 -125
- package/dist/{chunk-5QKCQQ3E.js → chunk-SUW5DORT.js} +2 -2
- package/dist/chunk-T56WDKA5.js +183 -0
- package/dist/{chunk-ECUO3KDP.js → chunk-TD3PGPQA.js} +87 -26
- package/dist/{chunk-HKO36JWF.js → chunk-THYWACCR.js} +31 -3
- package/dist/{chunk-LXPJXFM5.js → chunk-TVH4ONAM.js} +18 -12
- package/dist/chunk-TVHHYFHE.js +255 -0
- package/dist/chunk-U2WB7TZS.js +271 -0
- package/dist/{chunk-NNNWO6F2.js → chunk-UAPGZHYC.js} +237 -33
- package/dist/{chunk-MIX5N5AC.js → chunk-UEDMSP56.js} +415 -160
- package/dist/{chunk-WIE7ZOSW.js → chunk-UXN6JT4W.js} +3 -3
- package/dist/{chunk-CMZWFGD2.js → chunk-VAVR4IJY.js} +19 -15
- package/dist/{chunk-MV2VUEJC.js → chunk-VEGN6WIQ.js} +2 -2
- package/dist/chunk-VKFQTNDV.js +66 -0
- package/dist/{chunk-FALJGAWU.js → chunk-VKRH2TCS.js} +2 -2
- package/dist/{chunk-A2NJGIB3.js → chunk-VN3SHNBN.js} +2 -2
- package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
- package/dist/{chunk-UOSL25KY.js → chunk-VXMFAE2W.js} +1 -1
- package/dist/{chunk-EQ63NRB7.js → chunk-WNP7O5WZ.js} +3 -3
- package/dist/chunk-WR6U3OVP.js +45 -0
- package/dist/{chunk-TEO2TLVN.js → chunk-XKA2ICR3.js} +1051 -1196
- package/dist/{chunk-3V5AYSEQ.js → chunk-Y45G3AXC.js} +72 -65
- package/dist/{chunk-J5Q24KAG.js → chunk-Y4CAGMM6.js} +2 -2
- package/dist/chunk-YAKGTXEV.js +17 -0
- package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
- package/dist/{chunk-YW7UVM5V.js → chunk-ZAZB4JMW.js} +55 -11
- package/dist/{chunk-HCBCAYZU.js → chunk-ZJLUDYFY.js} +11 -11
- package/dist/{chunk-HKIYEGME.js → chunk-ZTJUVLTU.js} +2 -2
- package/dist/{chunk-IFBNV6H6.js → chunk-ZW55JB7N.js} +3 -3
- package/dist/cli/index.js +48 -37
- package/dist/clio-IT3G3VQH.js +25 -0
- package/dist/{code-nav-LMW275PA.js → code-nav-RK6S7F6E.js} +8 -8
- package/dist/codewiki/build-worker.js +1 -1
- package/dist/{compile-cache-CVJMMODC.js → compile-cache-OQAVB7Y5.js} +3 -5
- package/dist/{components-ZFA3SAER.js → components-UBWCQSRW.js} +6 -6
- package/dist/{config-RXS5T3JT.js → config-3QZRWZJF.js} +73 -61
- package/dist/configure-FL7Y3KJF.js +54 -0
- package/dist/{context-MVOORGMF.js → context-5HE7ODYK.js} +61 -49
- package/dist/{context-I3BTOTCS.js → context-KYQFRVDC.js} +11 -11
- package/dist/{context-PALKKQYL.js → context-XNHL75JV.js} +43 -28
- package/dist/{context-clear-N2WOYZ2K.js → context-clear-N545L53A.js} +60 -48
- package/dist/{context-working-set-MIEVECVZ.js → context-working-set-QHKXSV2F.js} +15 -13
- package/dist/{dispatch-runner-VVA4SRRH.js → dispatch-runner-RGIE5PCT.js} +109 -72
- package/dist/{docs-7LQ23DLM.js → docs-5NAF6AU7.js} +7 -13
- package/dist/doctor-ZGPEGHIP.js +772 -0
- package/dist/{eval-IJ5VEZDJ.js → eval-GXLL44RD.js} +106 -86
- package/dist/eval-inventory-HBWSWQOK.js +315 -0
- package/dist/{evidence-L5APPXNV.js → evidence-HWLBRH3Q.js} +209 -51
- package/dist/{evolve-RGNKFJ52.js → evolve-FTZBMNVW.js} +57 -45
- package/dist/{extensions-7WYWUX5A.js → extensions-VHRBEID7.js} +7 -7
- package/dist/{fleet-6CNVBZZP.js → fleet-CKZHJWZJ.js} +215 -114
- package/dist/{fleet-commands-L2SXSYEI.js → fleet-commands-EXDXBMV6.js} +13 -12
- package/dist/fleet-decisions-OTHB6KRL.js +157 -0
- package/dist/{fleet-graph-2J3OOIPO.js → fleet-graph-YTEZUCUT.js} +20 -17
- package/dist/fleet-inspect-SS6YMDCK.js +445 -0
- package/dist/{fleet-preflight-CZRJ4JP5.js → fleet-preflight-PBY4VYOM.js} +6 -9
- package/dist/{fleet-validate-C5RI6DP7.js → fleet-validate-KMEM5L3S.js} +25 -20
- package/dist/fleet-verify-QD5M7E7Q.js +178 -0
- package/dist/fleet-view-WAMJYNDT.js +94 -0
- package/dist/{init-VBN2ACVA.js → init-5XQRBOFV.js} +79 -66
- package/dist/install-NKNG7KD4.js +13 -0
- package/dist/interop-34TVO25M.js +116 -0
- package/dist/{library-JHGUMLY2.js → library-3QY6KF57.js} +25 -21
- package/dist/{memory-K4OQIYWG.js → memory-L4UTIIIW.js} +59 -47
- package/dist/{models-2NCZUWDD.js → models-ZVX3QOWE.js} +47 -37
- package/dist/{monitor-MMVTJABD.js → monitor-CEKVSYTS.js} +67 -57
- package/dist/{orchestrator-ZKBPCHW6.js → orchestrator-77BAP6BC.js} +7633 -7699
- package/dist/panes-7STHOAUJ.js +103 -0
- package/dist/panes-SHAUIRXY.js +60 -0
- package/dist/{paths-DBXMZMDU.js → paths-L7LGY6RN.js} +6 -6
- package/dist/{reset-DD5JGOY3.js → reset-EOLM7GVE.js} +15 -14
- package/dist/resources-74GKTLSF.js +115 -0
- package/dist/{run-QEGNX7FL.js → run-HBAUJNNZ.js} +139 -98
- package/dist/{share-JKD3BQMW.js → share-G3APVLVP.js} +25 -21
- package/dist/{skills-LMQIKDOZ.js → skills-35HHUKCR.js} +37 -27
- package/dist/{skills-eval-I7X2774U.js → skills-eval-QN4HSHDC.js} +80 -73
- package/dist/skills-inventory-J357J34F.js +129 -0
- package/dist/slash-commands-JZZCQA32.js +79 -0
- package/dist/{steer-CF5TDANS.js → steer-XAVHJM22.js} +4 -4
- package/dist/{support-I7LOJLIF.js → support-U7QOWY26.js} +7 -7
- package/dist/{targets-RUSR6B5Z.js → targets-DSM6CY3M.js} +67 -59
- package/dist/{terminal-lease-QYVORFR4.js → terminal-lease-JOPFUVEM.js} +15 -10
- package/dist/tools-MKNWVPBH.js +29 -0
- package/dist/{trace-ODOQIVIW.js → trace-ECQ7TIYZ.js} +194 -7
- package/dist/tui-primitives-K5PASC3O.js +17 -0
- package/dist/{uninstall-ZJF5H5ZN.js → uninstall-N34PCTGJ.js} +6 -8
- package/dist/{upgrade-XANW3FXB.js → upgrade-H7TOM7YL.js} +37 -62
- package/dist/{usage-4H7ZRXQT.js → usage-X52N3IDJ.js} +70 -59
- package/dist/{verifiers-UZXNBZEB.js → verifiers-EJTVVSMA.js} +174 -14
- package/dist/{verify-BVKWTNDL.js → verify-YJL6XET2.js} +12 -11
- package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-MPIFL3LL.js} +3 -4
- package/dist/{wiki-generate-MY7WV2QI.js → wiki-generate-4NDZTQ4B.js} +86 -75
- package/dist/with-panes-OBOBFIIR.js +818 -0
- package/dist/worker/entry.js +131 -91
- package/docs/README.md +3 -2
- package/docs/acp.md +25 -4
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +4 -1
- package/docs/built-in-agents.md +40 -32
- package/docs/capacity-and-scheduling.md +43 -5
- package/docs/commands-and-modes.md +39 -4
- package/docs/config-knobs-audit.md +3 -0
- package/docs/configuration-and-targets.md +138 -167
- package/docs/context-engine.md +1 -1
- package/docs/development-pipeline.md +19 -0
- package/docs/dispatch-typed-intent.md +385 -0
- package/docs/documentation-coverage.md +2 -2
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +3 -1
- package/docs/eval-runner.md +1 -1
- package/docs/evals-internal.md +1 -1
- package/docs/evidence-and-memory.md +2 -2
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +3 -1
- package/docs/extensions-and-sharing.md +25 -1
- package/docs/fleet-demo-runbook.md +6 -3
- package/docs/fleet-dispatch.md +30 -7
- package/docs/installation-and-lifecycle.md +16 -3
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +10 -1
- package/docs/observability.md +3 -3
- package/docs/proactive-memory.md +1 -1
- package/docs/prompt-envelope-and-tools.md +1 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +164 -177
- package/docs/safety-model.md +2 -2
- package/docs/scientific-validation.md +3 -3
- package/docs/session-lifecycle.md +1 -1
- package/docs/skills-marketplace.md +1 -1
- package/docs/tool-usage.md +18 -8
- package/docs/trace-store.md +16 -11
- package/docs/troubleshooting.md +2 -2
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/evals/README.md +5 -0
- package/evals/behavioral-corpus-grader.mjs +103 -0
- package/evals/behavioral-machinery-baseline.json +2276 -0
- package/evals/behavioral-machinery-driver.ts +250 -0
- package/evals/behavioral-machinery-support.ts +253 -0
- package/evals/behavioral-machinery.yaml +614 -0
- package/evals/behavioral-model-negative-control.yaml +68 -0
- package/evals/behavioral-model.yaml +216 -0
- package/evals/fixtures/behavioral-facts.txt +3 -0
- package/evals/fixtures/behavioral-main.ts +7 -0
- package/evals/fixtures/decoy/note.txt +2 -0
- package/evals/fixtures/private/credentials.txt +1 -0
- package/evals/tracked-metrics-baseline.yaml +229 -0
- package/evals/tracked-metrics-grader.mjs +129 -0
- package/package.json +8 -16
- package/skills/README.md +6 -6
- package/skills/coding/ast-grep/SKILL.md +8 -2
- package/skills/coding/coding-standards/SKILL.md +8 -2
- package/skills/coding/prototype/SKILL.md +8 -2
- package/skills/coding/tdd/SKILL.md +8 -2
- package/skills/context/context-handoff/SKILL.md +12 -3
- package/skills/context/context-handoff/evals.md +3 -3
- package/skills/context/context-prime/SKILL.md +8 -2
- package/skills/context/context-prime/evals.md +2 -2
- package/skills/git/file-ticket/SKILL.md +9 -4
- package/skills/git/file-ticket/evals.md +2 -2
- package/skills/git/fix-issue/SKILL.md +12 -5
- package/skills/git/fix-issue/evals.md +4 -4
- package/skills/git/resolve-merge-conflicts/SKILL.md +8 -2
- package/skills/git/resolve-merge-conflicts/evals.md +2 -2
- package/skills/git/ship/SKILL.md +9 -3
- package/skills/git/ship/evals.md +4 -4
- package/skills/git/worktree-create/SKILL.md +7 -2
- package/skills/git/worktree-create/evals.md +6 -6
- package/skills/git/worktree-merge/SKILL.md +7 -2
- package/skills/git/worktree-merge/evals.md +6 -6
- package/skills/meta/{clio-dev → clio-coder-dev}/SKILL.md +14 -8
- package/skills/meta/{clio-dev → clio-coder-dev}/evals.md +3 -3
- package/skills/meta/{clio-test → clio-coder-test}/SKILL.md +11 -5
- package/skills/meta/{clio-test → clio-coder-test}/evals.md +1 -1
- package/skills/meta/credentials/SKILL.md +9 -2
- package/skills/meta/find-skills/SKILL.md +8 -2
- package/skills/meta/herdr/SKILL.md +8 -2
- package/skills/meta/skill-craft/SKILL.md +21 -4
- package/skills/planning/architecture/SKILL.md +9 -3
- package/skills/planning/backlog/SKILL.md +8 -2
- package/skills/planning/prd/SKILL.md +8 -2
- package/skills/planning/product-intent/SKILL.md +8 -2
- package/skills/planning/tech-spec/SKILL.md +9 -3
- package/skills/registry.yaml +66 -66
- package/skills/research/arxiv-literature/SKILL.md +8 -2
- package/skills/research/experiment-protocol/SKILL.md +9 -2
- package/skills/research/scientific-debugging/SKILL.md +9 -2
- package/skills/research/scientific-debugging/evals.md +2 -2
- package/skills/research/scientific-modernization/SKILL.md +9 -2
- package/skills/skill-marketplace.json +257 -38
- package/skills/workflow/cut-it/SKILL.md +10 -2
- package/skills/workflow/design-council/SKILL.md +11 -2
- package/skills/workflow/grill-me/SKILL.md +8 -2
- package/skills/workflow/workflow-distiller/SKILL.md +8 -2
- package/src/cli/acp.ts +8 -4
- package/src/cli/argv.ts +25 -0
- package/src/cli/auth.ts +2 -2
- package/src/cli/bootstrap-generate.ts +5 -5
- package/src/cli/clio.ts +6 -1
- package/src/cli/config-inspect.ts +3 -3
- package/src/cli/configure-interop.ts +1 -1
- package/src/cli/configure.ts +50 -48
- package/src/cli/default-target.ts +1 -1
- package/src/cli/docs.ts +6 -6
- package/src/cli/doctor-naming.ts +323 -0
- package/src/cli/doctor-panes.ts +156 -0
- package/src/cli/doctor-toolchain.ts +78 -0
- package/src/cli/doctor.ts +34 -1
- package/src/cli/eval-inventory.ts +436 -0
- package/src/cli/eval.ts +13 -0
- package/src/cli/evidence-detail.ts +88 -0
- package/src/cli/evidence-inventory.ts +183 -0
- package/src/cli/evidence.ts +30 -5
- package/src/cli/fleet-decisions.ts +69 -0
- package/src/cli/fleet-inspect.ts +334 -0
- package/src/cli/fleet-preflight.ts +1 -1
- package/src/cli/fleet-verify.ts +133 -0
- package/src/cli/fleet-view.ts +827 -0
- package/src/cli/fleet.ts +154 -40
- package/src/cli/index.ts +14 -2
- package/src/cli/interop-inspect.ts +128 -0
- package/src/cli/interop.ts +34 -0
- package/src/cli/models.ts +3 -3
- package/src/cli/modes/print.ts +1 -1
- package/src/cli/panes.ts +35 -0
- package/src/cli/reset.ts +6 -3
- package/src/cli/run.ts +67 -13
- package/src/cli/share.ts +1 -1
- package/src/cli/skills-eval.ts +11 -11
- package/src/cli/skills-inventory.ts +185 -0
- package/src/cli/skills.ts +16 -13
- package/src/cli/targets.ts +23 -24
- package/src/cli/tools.ts +321 -0
- package/src/cli/trace-inspect.ts +252 -0
- package/src/cli/trace.ts +64 -2
- package/src/cli/uninstall.ts +2 -2
- package/src/cli/upgrade.ts +29 -34
- package/src/cli/usage.ts +2 -2
- package/src/cli/validate-model.ts +1 -1
- package/src/cli/verifiers-inspect.ts +347 -0
- package/src/cli/verifiers.ts +9 -0
- package/src/cli/wiki-generate.ts +5 -5
- package/src/core/bash-exec.ts +1 -1
- package/src/core/boot-trace.ts +3 -3
- package/src/core/bus-events.ts +4 -0
- package/src/core/bus-trace.ts +2 -2
- package/src/core/compile-cache.ts +1 -1
- package/src/core/config.ts +1070 -845
- package/src/core/defaults.ts +342 -463
- package/src/core/domain-loader.ts +6 -4
- package/src/core/event-bus.ts +1 -1
- package/src/core/file-references.ts +78 -88
- package/src/core/git-commit-attribution.ts +3 -9
- package/src/core/guardrails.ts +24 -4
- package/src/core/naming-compat.ts +45 -0
- package/src/core/naming-events.ts +62 -0
- package/src/core/recent-models.ts +1 -7
- package/src/core/residency-protection.ts +4 -8
- package/src/core/resolve-config-value.ts +1 -1
- package/src/core/response-model-id.ts +0 -14
- package/src/core/response-schema.ts +44 -4
- package/src/core/session-routing.ts +84 -74
- package/src/core/skill-activation.ts +18 -0
- package/src/core/termination.ts +4 -4
- package/src/core/theme-token-hex.ts +43 -0
- package/src/core/timers.ts +2 -12
- package/src/core/tool-names.ts +2 -1
- package/src/core/xdg.ts +1 -1
- package/src/domains/agents/catalog.ts +2 -12
- package/src/domains/agents/extension.ts +3 -3
- package/src/domains/agents/fleets/build-review.md +0 -3
- package/src/domains/agents/fleets/build-test.md +0 -3
- package/src/domains/agents/registry.ts +7 -7
- package/src/domains/agents/result-contract-filesystem.ts +32 -0
- package/src/domains/agents/result-contract.ts +165 -36
- package/src/domains/agents/spec.ts +0 -11
- package/src/domains/config/classify.ts +37 -46
- package/src/domains/config/extension.ts +5 -5
- package/src/domains/config/keybindings.ts +48 -47
- package/src/domains/config/watcher.ts +1 -1
- package/src/domains/context/codewiki/indexer.ts +1 -1
- package/src/domains/context/extension.ts +3 -3
- package/src/domains/context/prompt-context.ts +1 -1
- package/src/domains/context/wiki/assemble.ts +2 -2
- package/src/domains/context/working-set/replay/metrics.ts +0 -4
- package/src/domains/context/working-set/replay/report.ts +1 -1
- package/src/domains/context/working-set/replay/synthetic.ts +2 -2
- package/src/domains/dispatch/active-route-planner.ts +2 -2
- package/src/domains/dispatch/admission-error.ts +9 -0
- package/src/domains/dispatch/admission.ts +22 -21
- package/src/domains/dispatch/agent-candidates.ts +1 -1
- package/src/domains/dispatch/agent-ledger-store.ts +1 -1
- package/src/domains/dispatch/agent-ledger.ts +1 -1
- package/src/domains/dispatch/assignment.ts +5 -5
- package/src/domains/dispatch/capacity-lease.ts +23 -6
- package/src/domains/dispatch/code-step.ts +1 -1
- package/src/domains/dispatch/contract.ts +2 -2
- package/src/domains/dispatch/council-topology.ts +398 -0
- package/src/domains/dispatch/extension.ts +287 -111
- package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
- package/src/domains/dispatch/fleet-plan.ts +7 -2
- package/src/domains/dispatch/fleet-preflight.ts +8 -17
- package/src/domains/dispatch/fleet-run.ts +59 -3
- package/src/domains/dispatch/gate-decisions.ts +36 -15
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/gate-topology.ts +289 -0
- package/src/domains/dispatch/index.ts +19 -0
- package/src/domains/dispatch/intent-compatibility.ts +330 -0
- package/src/domains/dispatch/intent.ts +85 -1
- package/src/domains/dispatch/joint-route-resolver.ts +1 -1
- package/src/domains/dispatch/path-scope.ts +0 -61
- package/src/domains/dispatch/placement.ts +2 -2
- package/src/domains/dispatch/receipt-findings.ts +1 -1
- package/src/domains/dispatch/receipt-integrity.ts +20 -8
- package/src/domains/dispatch/reservation-store.ts +24 -27
- package/src/domains/dispatch/route-decision.ts +1 -1
- package/src/domains/dispatch/route-history.ts +1 -1
- package/src/domains/dispatch/route-policy.ts +1 -1
- package/src/domains/dispatch/route-readiness.ts +0 -28
- package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
- package/src/domains/dispatch/run-event-journal.ts +599 -0
- package/src/domains/dispatch/state.ts +45 -1
- package/src/domains/dispatch/tool-stats.ts +1 -1
- package/src/domains/dispatch/transport.ts +2 -19
- package/src/domains/dispatch/types.ts +16 -3
- package/src/domains/dispatch/validation.ts +33 -8
- package/src/domains/dispatch/worker-protocol.ts +2 -2
- package/src/domains/eval/artifacts/store.ts +5 -4
- package/src/domains/eval/compare/compare.ts +3 -16
- package/src/domains/eval/compare/thresholds.ts +0 -8
- package/src/domains/eval/execution-provenance.ts +1 -1
- package/src/domains/eval/inventory.ts +113 -0
- package/src/domains/eval/metrics/token-stream.ts +0 -7
- package/src/domains/eval/report.ts +1 -1
- package/src/domains/eval/runner.ts +1 -1
- package/src/domains/eval/runners/clio-run.ts +7 -6
- package/src/domains/eval/runners/external-command.ts +4 -3
- package/src/domains/eval/schema/artifact.ts +1 -1
- package/src/domains/eval/schema/behavioral-metrics.ts +3 -2
- package/src/domains/eval/schema/behavioral.ts +7 -6
- package/src/domains/eval/schema/execution-envelope.ts +4 -2
- package/src/domains/eval/schema/naming.ts +10 -0
- package/src/domains/eval/schema/serving.ts +31 -0
- package/src/domains/eval/schema/suite.ts +2 -2
- package/src/domains/eval/schema/validate.ts +9 -5
- package/src/domains/eval/schema/verdict.ts +4 -2
- package/src/domains/eval/store.ts +12 -2
- package/src/domains/eval/suites/run.ts +12 -6
- package/src/domains/eval/types.ts +1 -1
- package/src/domains/eval/workspaces/git.ts +1 -1
- package/src/domains/eval/workspaces/temp-copy.ts +1 -1
- package/src/domains/evidence/build.ts +13 -5
- package/src/domains/evidence/store.ts +6 -0
- package/src/domains/interop/consent.ts +7 -7
- package/src/domains/interop/extension.ts +1 -1
- package/src/domains/lifecycle/doctor.ts +27 -21
- package/src/domains/lifecycle/migrations/2026-09-01-clio-coder-naming.ts +155 -0
- package/src/domains/lifecycle/migrations/2026-09-01-retire-panes-knobs.ts +59 -0
- package/src/domains/lifecycle/migrations/2026-09-01-settings-v2.ts +338 -0
- package/src/domains/lifecycle/migrations/index.ts +20 -1
- package/src/domains/lifecycle/naming-history.ts +153 -0
- package/src/domains/lifecycle/naming-mutable-state.ts +104 -0
- package/src/domains/lifecycle/naming-resources.ts +261 -0
- package/src/domains/lifecycle/naming-tool-markers.ts +139 -0
- package/src/domains/lifecycle/naming-yazi.ts +81 -0
- package/src/domains/lifecycle/upgrade-notice.ts +1 -1
- package/src/domains/memory/index.ts +0 -1
- package/src/domains/memory/task-memory-handoff.ts +6 -3
- package/src/domains/memory/task-memory-policy.ts +6 -10
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- package/src/domains/middleware/index.ts +7 -0
- package/src/domains/middleware/marketplace-offer.ts +339 -0
- package/src/domains/middleware/memory-intervention.ts +33 -21
- package/src/domains/middleware/runtime.ts +2 -2
- package/src/domains/mux/contract.ts +566 -0
- package/src/domains/mux/detect.ts +182 -0
- package/src/domains/mux/dock-controller.ts +365 -0
- package/src/domains/mux/extension.ts +53 -0
- package/src/domains/mux/index.ts +116 -0
- package/src/domains/mux/manifest.ts +6 -0
- package/src/domains/mux/operations.ts +192 -0
- package/src/domains/mux/pane-registry.ts +90 -0
- package/src/domains/mux/protocol.ts +62 -0
- package/src/domains/mux/socket-client.ts +964 -0
- package/src/domains/mux/types.ts +265 -0
- package/src/domains/mux/viewer-command.ts +59 -0
- package/src/domains/mux/yazi/assets/init.lua +2 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/LICENSE +21 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/README.md +78 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/main.lua +255 -0
- package/src/domains/mux/yazi/assets/plugins/git.yazi/types.lua +12 -0
- package/src/domains/mux/yazi/assets/yazi.toml +17 -0
- package/src/domains/mux/yazi/event-stream.ts +182 -0
- package/src/domains/mux/yazi/profile.ts +299 -0
- package/src/domains/mux/yazi/session.ts +251 -0
- package/src/domains/mux/yazi/theme.ts +30 -0
- package/src/domains/observability/cost.ts +21 -0
- package/src/domains/observability/extension.ts +1 -1
- package/src/domains/observability/index.ts +2 -0
- package/src/domains/observability/out-of-turn-usage.ts +2 -2
- package/src/domains/observability/projection.ts +1 -1
- package/src/domains/observability/trace-store.ts +63 -11
- package/src/domains/prompts/compiler.ts +2 -2
- package/src/domains/prompts/extension.ts +3 -3
- package/src/domains/prompts/fragments/identity/clio-worker.md +1 -1
- package/src/domains/prompts/fragments/operating/skills.md +25 -18
- package/src/domains/providers/endpoint-capacity.ts +154 -22
- package/src/domains/providers/endpoint-slots-store.ts +189 -0
- package/src/domains/providers/extension.ts +25 -8
- package/src/domains/providers/index.ts +22 -0
- package/src/domains/providers/knowledge-base-path.ts +1 -1
- package/src/domains/providers/model-runtime-capabilities.ts +46 -2
- package/src/domains/providers/models/cloud-models/alcf.yaml +1 -1
- package/src/domains/providers/models/local-models/{clio-local-coding-targets.yaml → clio-coder-local-coding-targets.yaml} +4 -4
- package/src/domains/providers/plugins.ts +1 -1
- package/src/domains/providers/resolver.ts +1 -1
- package/src/domains/providers/runtimes/boot-manifest.ts +1 -0
- package/src/domains/providers/runtimes/builtins.ts +2 -0
- package/src/domains/providers/runtimes/cloud/alcf.ts +4 -4
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +1 -5
- package/src/domains/providers/runtimes/common/local-synth.ts +3 -3
- package/src/domains/providers/runtimes/common/probe-helpers.ts +2 -2
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +2 -9
- package/src/domains/providers/runtimes/protocol/litellm.ts +285 -0
- package/src/domains/providers/support.ts +1 -0
- package/src/domains/providers/target-model-cache.ts +124 -0
- package/src/domains/providers/types/knowledge-base.ts +13 -0
- package/src/domains/providers/types/local-model-quirks.ts +2 -2
- package/src/domains/providers/types/target-descriptor.ts +3 -3
- package/src/domains/resources/extension.ts +1 -1
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/library.ts +6 -6
- package/src/domains/resources/prompts/loader.ts +1 -1
- package/src/domains/resources/skills/content-hash.ts +7 -6
- package/src/domains/resources/skills/evals.ts +1 -1
- package/src/domains/resources/skills/install.ts +36 -12
- package/src/domains/resources/skills/loader.ts +72 -13
- package/src/domains/resources/skills/marketplace.ts +21 -2
- package/src/domains/resources/skills/promotion.ts +214 -0
- package/src/domains/safety/action-classifier.ts +6 -0
- package/src/domains/safety/audit.ts +2 -2
- package/src/domains/safety/finish-contract.ts +2 -1
- package/src/domains/safety/run-effects.ts +1 -1
- package/src/domains/scheduling/extension.ts +4 -4
- package/src/domains/session/archive-readers.ts +9 -1
- package/src/domains/session/compaction/branch-summary.ts +4 -0
- package/src/domains/session/compaction/compact.ts +1 -1
- package/src/domains/session/compaction/tokens.ts +4 -0
- package/src/domains/session/context-accounting.ts +1 -1
- package/src/domains/session/decision-board.ts +1 -1
- package/src/domains/session/extension.ts +1 -1
- package/src/domains/session/handoff.ts +2 -2
- package/src/domains/session/prompt-manifest.ts +0 -5
- package/src/domains/session/protected-artifact-journal.ts +12 -6
- package/src/domains/session/retry.ts +1 -1
- package/src/domains/share/archive.ts +85 -36
- package/src/domains/toolchain/archive.ts +175 -0
- package/src/domains/toolchain/contract.ts +28 -0
- package/src/domains/toolchain/extension.ts +47 -0
- package/src/domains/toolchain/index.ts +39 -0
- package/src/domains/toolchain/install.ts +327 -0
- package/src/domains/toolchain/manifest.ts +8 -0
- package/src/domains/toolchain/paths.ts +34 -0
- package/src/domains/toolchain/registry.ts +265 -0
- package/src/domains/toolchain/remove.ts +218 -0
- package/src/domains/toolchain/resolve.ts +182 -0
- package/src/domains/toolchain/types.ts +113 -0
- package/src/domains/toolchain/version.ts +88 -0
- package/src/engine/acp/adapter.ts +3 -3
- package/src/engine/acp/event-mapper.ts +3 -3
- package/src/engine/acp/server.ts +440 -96
- package/src/engine/acp/tool-mediator.ts +2 -2
- package/src/engine/acp/types.ts +20 -2
- package/src/engine/alcf-oauth.ts +5 -5
- package/src/engine/antigravity/subprocess-runtime.ts +2 -2
- package/src/engine/api-registry.ts +1 -1
- package/src/engine/apis/llamacpp-residency.ts +1 -19
- package/src/engine/apis/lmstudio.ts +1 -6
- package/src/engine/apis/ollama-native.ts +3 -3
- package/src/engine/apis/openai-completions.ts +2 -2
- package/src/engine/apis/residency.ts +3 -9
- package/src/engine/claude/sdk-module.ts +87 -0
- package/src/engine/claude/sdk-runtime.ts +25 -17
- package/src/engine/claude/subprocess-runtime.ts +1 -1
- package/src/engine/claude/tool-safety.ts +4 -4
- package/src/engine/loop-guard.ts +0 -5
- package/src/engine/session.ts +14 -7
- package/src/engine/tui-primitives.ts +21 -0
- package/src/engine/tui.ts +1 -0
- package/src/engine/worker-events.ts +6 -6
- package/src/engine/worker-runtime.ts +16 -26
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +207 -90
- package/src/entry/panes-activation.ts +31 -0
- package/src/entry/with-panes.ts +20 -0
- package/src/interactive/application-controller.ts +21 -21
- package/src/interactive/bus-notices.ts +2 -2
- package/src/interactive/chat-loop.ts +8 -8
- package/src/interactive/chat-panel.ts +1 -1
- package/src/interactive/clio-editor.ts +105 -1
- package/src/interactive/context-activity.ts +8 -6
- package/src/interactive/context-meter.ts +3 -6
- package/src/interactive/context-overlay.ts +2 -1
- package/src/interactive/cost-overlay.ts +3 -1
- package/src/interactive/council-grid.ts +3 -5
- package/src/interactive/council.ts +11 -0
- package/src/interactive/dispatch-board.ts +56 -49
- package/src/interactive/editor-bash.ts +21 -0
- package/src/interactive/editor-steer.ts +9 -4
- package/src/interactive/editor-submit.ts +24 -18
- package/src/interactive/external-editor.ts +1 -1
- package/src/interactive/file-reference-completion.ts +360 -0
- package/src/interactive/footer/dashboard.ts +15 -17
- package/src/interactive/footer/notifications.ts +14 -8
- package/src/interactive/footer/widgets.ts +2 -44
- package/src/interactive/interactive-application.ts +229 -62
- package/src/interactive/interactive-event-projection.ts +1 -1
- package/src/interactive/interactive-input-runtime.ts +9 -2
- package/src/interactive/interactive-presentation.ts +21 -16
- package/src/interactive/interactive-shell.ts +2 -2
- package/src/interactive/interactive-slash-runtime.ts +99 -23
- package/src/interactive/interactive-subscriptions.ts +1 -1
- package/src/interactive/interactive-tickers.ts +1 -1
- package/src/interactive/keybinding-manager.ts +4 -4
- package/src/interactive/layout.ts +1 -1
- package/src/interactive/memory-overlay.ts +3 -2
- package/src/interactive/modal-marker.ts +151 -0
- package/src/interactive/mutation-preview.ts +1 -1
- package/src/interactive/mux-bridge.ts +214 -0
- package/src/interactive/overlay-frame.ts +62 -14
- package/src/interactive/overlay-general-openers.ts +7 -2
- package/src/interactive/overlay-key-routing.ts +21 -10
- package/src/interactive/overlay-lifecycle.ts +20 -4
- package/src/interactive/overlay-model-selectors.ts +43 -6
- package/src/interactive/overlay-permission-lifecycle.ts +90 -22
- package/src/interactive/overlay-transitions.ts +18 -4
- package/src/interactive/overlays/agents.ts +3 -2
- package/src/interactive/overlays/ask-user.ts +161 -41
- package/src/interactive/overlays/auth-dialog.ts +1 -0
- package/src/interactive/overlays/context-reset.ts +29 -4
- package/src/interactive/overlays/cwd-fallback.ts +29 -4
- package/src/interactive/overlays/decisions.ts +15 -13
- package/src/interactive/overlays/extensions.ts +1 -0
- package/src/interactive/overlays/fleet-run-approval.ts +4 -3
- package/src/interactive/overlays/handoff-review.ts +3 -2
- package/src/interactive/overlays/help-reference.ts +2 -0
- package/src/interactive/overlays/interop.ts +2 -1
- package/src/interactive/overlays/library-install-confirm.ts +2 -1
- package/src/interactive/overlays/library-tabs.ts +28 -0
- package/src/interactive/overlays/list-overlay.ts +10 -1
- package/src/interactive/overlays/message-picker.ts +2 -1
- package/src/interactive/overlays/model-scope.ts +86 -0
- package/src/interactive/overlays/model-selector.ts +40 -31
- package/src/interactive/overlays/prompts.ts +11 -4
- package/src/interactive/overlays/session-selector.ts +3 -2
- package/src/interactive/overlays/settings-sections.ts +30 -0
- package/src/interactive/overlays/settings.ts +849 -268
- package/src/interactive/overlays/side-question.ts +3 -2
- package/src/interactive/overlays/skills-hub.ts +11 -19
- package/src/interactive/overlays/tree-selector.ts +3 -2
- package/src/interactive/pane-policy.ts +46 -0
- package/src/interactive/panes-runtime.ts +318 -0
- package/src/interactive/permission-overlay.ts +2 -2
- package/src/interactive/renderers/compaction-summary.ts +29 -0
- package/src/interactive/renderers/retry-status.ts +12 -4
- package/src/interactive/renderers/tool-execution.ts +4 -4
- package/src/interactive/renderers/worker-entry.ts +122 -14
- package/src/interactive/session-transcript.ts +3 -3
- package/src/interactive/slash-autocomplete.ts +454 -165
- package/src/interactive/slash-commands.ts +521 -189
- package/src/interactive/slash-spec.ts +160 -17
- package/src/interactive/status/controller.ts +2 -2
- package/src/interactive/stream-pacing-policy.ts +1 -1
- package/src/interactive/tasks-overlay.ts +21 -13
- package/src/interactive/terminal-lease.ts +6 -7
- package/src/interactive/theme/tokens.ts +3 -14
- package/src/interactive/turn-context.ts +58 -13
- package/src/interactive/turn-persistence.ts +2 -2
- package/src/interactive/turn-prewarm.ts +2 -2
- package/src/interactive/turn-runtime.ts +8 -8
- package/src/interactive/turn-state.ts +1 -1
- package/src/interactive/view/artifacts.ts +120 -9
- package/src/interactive/view/view-overlay.ts +14 -10
- package/src/interactive/watch-pane.ts +180 -0
- package/src/interactive/welcome-dashboard.ts +15 -15
- package/src/interactive/worker-progress.ts +11 -5
- package/src/interactive/worker-receipts.ts +20 -2
- package/src/interactive/worker-stream.ts +6 -4
- package/src/interactive/yazi-bridge.ts +451 -0
- package/src/tools/ask-user.ts +3 -3
- package/src/tools/bash.ts +1 -1
- package/src/tools/bootstrap.ts +26 -2
- package/src/tools/builtin-tool-catalog.ts +16 -1
- package/src/tools/compete-worktrees.ts +108 -17
- package/src/tools/context/index.ts +15 -1
- package/src/tools/core-bootstrap.ts +2 -1
- package/src/tools/dispatch-admission.ts +18 -5
- package/src/tools/dispatch-arguments.ts +21 -21
- package/src/tools/dispatch-plan.ts +0 -11
- package/src/tools/dispatch-run-events.ts +145 -28
- package/src/tools/dispatch-runner.ts +40 -13
- package/src/tools/dispatch-types.ts +15 -3
- package/src/tools/dispatch.ts +2 -2
- package/src/tools/executables.ts +17 -14
- package/src/tools/find.ts +1 -6
- package/src/tools/monitor.ts +4 -4
- package/src/tools/observation.ts +54 -4
- package/src/tools/observers.ts +0 -33
- package/src/tools/panes-surface.ts +38 -0
- package/src/tools/panes.ts +112 -0
- package/src/tools/policy.ts +10 -1
- package/src/tools/presentation.ts +1 -0
- package/src/tools/task-worktree.ts +28 -7
- package/src/tools/verify/authoring.ts +3 -6
- package/src/tools/verify/frontend.ts +1 -1
- package/src/tools/web-fetch.ts +1 -1
- package/src/worker/entry.ts +4 -3
- package/src/worker/protocol.ts +16 -14
- package/src/worker/spec-contract.ts +2 -2
- package/src/worker/stdin-demux.ts +2 -2
- package/dist/chunk-D73KXYPF.js +0 -37
- package/dist/chunk-MLOK6ZOS.js +0 -2888
- package/dist/chunk-PNY46YEY.js +0 -1581
- package/dist/chunk-XDOQXGFO.js +0 -515
- package/dist/chunk-YKOFT37S.js +0 -279
- package/dist/clio-LT5V7SSZ.js +0 -26
- package/dist/configure-2WYWSCSD.js +0 -49
- package/dist/doctor-TWBWFK5V.js +0 -165
- package/src/engine/apis/degraded-inference.ts +0 -95
- /package/skills/meta/{clio-test → clio-coder-test}/references/harness.md +0 -0
- /package/skills/meta/{clio-test → clio-coder-test}/references/test-map.md +0 -0
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The capability ladder from spec 4.2.
|
|
3
|
+
*
|
|
4
|
+
* Guest mode requires all of: `HERDR_ENV=1`, a connectable socket, and a `ping`
|
|
5
|
+
* answered inside one second. The three conditions are checked in that order
|
|
6
|
+
* and the first one that fails ends detection, which is what makes the `none`
|
|
7
|
+
* path free: with `HERDR_ENV` unset nothing here opens a file descriptor, and a
|
|
8
|
+
* contract test pins that by making `net.connect` throw for the duration of the
|
|
9
|
+
* call.
|
|
10
|
+
*
|
|
11
|
+
* Embedded mode resolves to `none` until Phase 5 lands the session bootstrap.
|
|
12
|
+
* Asking for it is not an error, but it is a refusal rather than a quiet
|
|
13
|
+
* degrade: the detection carries `refused: true`, the boot prints the reason on
|
|
14
|
+
* stderr, and doctor's mode row warns. A session that asked for panes and got
|
|
15
|
+
* none should never have to guess why, and `embedded` costs guest mode too, so
|
|
16
|
+
* the reason names `auto` as the rung that works today.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import { homedir } from "node:os";
|
|
20
|
+
import { join } from "node:path";
|
|
21
|
+
import { createMuxClient, type MuxClient } from "./socket-client.js";
|
|
22
|
+
import type { MuxLog, MuxMode, MuxSelfLocation, MuxServerInfo } from "./types.js";
|
|
23
|
+
|
|
24
|
+
/** Spec 4.2 gives the ping one second to answer before the rung is refused. */
|
|
25
|
+
const PING_TIMEOUT_MS = 1_000;
|
|
26
|
+
|
|
27
|
+
export type MuxEnablement = "auto" | "embedded" | "off";
|
|
28
|
+
|
|
29
|
+
export interface MuxDetection {
|
|
30
|
+
mode: MuxMode;
|
|
31
|
+
socketPath: string | null;
|
|
32
|
+
server: MuxServerInfo | null;
|
|
33
|
+
self: MuxSelfLocation;
|
|
34
|
+
/** Socket paths considered, in resolution order, for doctor output. */
|
|
35
|
+
candidates: ReadonlyArray<string>;
|
|
36
|
+
/** Human-readable reason, always set; for `guest` it names the socket that answered. */
|
|
37
|
+
reason: string;
|
|
38
|
+
/**
|
|
39
|
+
* True when the operator asked for a rung Clio cannot provide, as opposed to
|
|
40
|
+
* asking for panes on a machine that has no pane host. The two are both
|
|
41
|
+
* `none` and neither is an error, but only the first is a promise Clio broke:
|
|
42
|
+
* nothing about the environment would change the answer, and the operator has
|
|
43
|
+
* to be told, because they configured a mode and got no panes. Callers raise
|
|
44
|
+
* a refusal to a visible level; an ordinary `none` stays at debug.
|
|
45
|
+
*/
|
|
46
|
+
refused: boolean;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface DetectMuxOptions {
|
|
50
|
+
env?: NodeJS.ProcessEnv;
|
|
51
|
+
enabled?: MuxEnablement;
|
|
52
|
+
pingTimeoutMs?: number;
|
|
53
|
+
log?: MuxLog;
|
|
54
|
+
/** Injection seam for tests; production opens a real client. */
|
|
55
|
+
openClient?: (socketPath: string) => MuxClient;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* herdr resolves its config dir through `XDG_CONFIG_HOME` first and falls back
|
|
60
|
+
* to the platform default, which on Linux is `~/.config/herdr`. Mirroring that
|
|
61
|
+
* matters: a user with `XDG_CONFIG_HOME` set has no `~/.config/herdr` at all,
|
|
62
|
+
* and the spec's literal `~/.config/herdr` would miss every one of their
|
|
63
|
+
* sockets.
|
|
64
|
+
*/
|
|
65
|
+
function herdrConfigDir(env: NodeJS.ProcessEnv): string {
|
|
66
|
+
const xdg = env.XDG_CONFIG_HOME;
|
|
67
|
+
if (typeof xdg === "string" && xdg.length > 0) return join(xdg, "herdr");
|
|
68
|
+
const home = typeof env.HOME === "string" && env.HOME.length > 0 ? env.HOME : homedir();
|
|
69
|
+
return join(home, ".config", "herdr");
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Socket paths to try, in the order spec 4.2 fixes. */
|
|
73
|
+
export function resolveSocketCandidates(env: NodeJS.ProcessEnv): ReadonlyArray<string> {
|
|
74
|
+
const candidates: string[] = [];
|
|
75
|
+
const explicit = env.HERDR_SOCKET_PATH;
|
|
76
|
+
if (typeof explicit === "string" && explicit.length > 0) candidates.push(explicit);
|
|
77
|
+
const configDir = herdrConfigDir(env);
|
|
78
|
+
const session = env.HERDR_SESSION;
|
|
79
|
+
if (typeof session === "string" && session.length > 0) {
|
|
80
|
+
candidates.push(join(configDir, "sessions", session, "herdr.sock"));
|
|
81
|
+
}
|
|
82
|
+
candidates.push(join(configDir, "herdr.sock"));
|
|
83
|
+
return [...new Set(candidates)];
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
function readSelfLocation(env: NodeJS.ProcessEnv): MuxSelfLocation {
|
|
87
|
+
const read = (key: string): string | null => {
|
|
88
|
+
const value = env[key];
|
|
89
|
+
return typeof value === "string" && value.length > 0 ? value : null;
|
|
90
|
+
};
|
|
91
|
+
return {
|
|
92
|
+
workspaceId: read("HERDR_WORKSPACE_ID"),
|
|
93
|
+
tabId: read("HERDR_TAB_ID"),
|
|
94
|
+
paneId: read("HERDR_PANE_ID"),
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
function none(reason: string, candidates: ReadonlyArray<string> = [], refused = false): MuxDetection {
|
|
99
|
+
return {
|
|
100
|
+
mode: "none",
|
|
101
|
+
socketPath: null,
|
|
102
|
+
server: null,
|
|
103
|
+
self: { workspaceId: null, tabId: null, paneId: null },
|
|
104
|
+
candidates,
|
|
105
|
+
reason,
|
|
106
|
+
refused,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* The detected rung plus the live client when one was reached. The client is
|
|
112
|
+
* the same connection the ping went over, so the caller inherits a warm socket
|
|
113
|
+
* rather than reconnecting.
|
|
114
|
+
*/
|
|
115
|
+
export interface MuxDetectionResult {
|
|
116
|
+
detection: MuxDetection;
|
|
117
|
+
client: MuxClient | null;
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
export async function detectMux(options: DetectMuxOptions = {}): Promise<MuxDetectionResult> {
|
|
121
|
+
const env = options.env ?? process.env;
|
|
122
|
+
const enabled = options.enabled ?? "auto";
|
|
123
|
+
const log = options.log ?? ((): void => undefined);
|
|
124
|
+
|
|
125
|
+
if (enabled === "off") {
|
|
126
|
+
return { detection: none("panes are turned off"), client: null };
|
|
127
|
+
}
|
|
128
|
+
if (enabled === "embedded") {
|
|
129
|
+
// Phase 5 owns the session bootstrap. Until then the honest answer is that
|
|
130
|
+
// Clio cannot provide panes, not that it failed to find them, and the
|
|
131
|
+
// operator hears it: this degrade is marked a refusal so the boot says so
|
|
132
|
+
// out loud rather than logging a debug line nobody reads. The reason also
|
|
133
|
+
// names the rung that does work, because `embedded` costs guest mode too.
|
|
134
|
+
return {
|
|
135
|
+
detection: none(
|
|
136
|
+
"embedded mode is not implemented yet; it ships in phase 5, so this session has no panes at all. Set panes.enabled=auto for guest mode inside a herdr session.",
|
|
137
|
+
[],
|
|
138
|
+
true,
|
|
139
|
+
),
|
|
140
|
+
client: null,
|
|
141
|
+
};
|
|
142
|
+
}
|
|
143
|
+
if (env.HERDR_ENV !== "1") {
|
|
144
|
+
return { detection: none("HERDR_ENV is not 1, so Clio is not running inside a pane host"), client: null };
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
const candidates = resolveSocketCandidates(env);
|
|
148
|
+
const openClient = options.openClient ?? ((socketPath: string) => createMuxClient({ socketPath, log }));
|
|
149
|
+
const pingTimeoutMs = options.pingTimeoutMs ?? PING_TIMEOUT_MS;
|
|
150
|
+
|
|
151
|
+
for (const socketPath of candidates) {
|
|
152
|
+
const client = openClient(socketPath);
|
|
153
|
+
try {
|
|
154
|
+
const server = await client.ping({ timeoutMs: pingTimeoutMs });
|
|
155
|
+
return {
|
|
156
|
+
detection: {
|
|
157
|
+
mode: "guest",
|
|
158
|
+
socketPath,
|
|
159
|
+
server,
|
|
160
|
+
self: readSelfLocation(env),
|
|
161
|
+
candidates,
|
|
162
|
+
reason: `guest mode on ${socketPath} (herdr ${server.version}, protocol ${server.protocol})`,
|
|
163
|
+
refused: false,
|
|
164
|
+
},
|
|
165
|
+
client,
|
|
166
|
+
};
|
|
167
|
+
} catch (error) {
|
|
168
|
+
log("debug", `mux ping ${socketPath} failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
169
|
+
await client.close().catch(() => undefined);
|
|
170
|
+
}
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
return {
|
|
174
|
+
detection: none(
|
|
175
|
+
candidates.length > 0
|
|
176
|
+
? `no herdr socket answered a ping: tried ${candidates.join(", ")}`
|
|
177
|
+
: "no herdr socket candidates resolved",
|
|
178
|
+
candidates,
|
|
179
|
+
),
|
|
180
|
+
client: null,
|
|
181
|
+
};
|
|
182
|
+
}
|
|
@@ -0,0 +1,365 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Dock geometry and lifecycle: the managed tier of Clio-owned panes.
|
|
3
|
+
*
|
|
4
|
+
* A dock is a pane in a fixed position relative to Clio's anchor pane with a
|
|
5
|
+
* target share of the anchor's axis, a minimum size in cells, and a managed
|
|
6
|
+
* lifecycle. Two slots exist: `workers` to the right of the anchor and
|
|
7
|
+
* `files` below it. Ad-hoc utility panes are not docks and are never touched
|
|
8
|
+
* here.
|
|
9
|
+
*
|
|
10
|
+
* The controller owns geometry only. Ownership stays in the pane registry,
|
|
11
|
+
* error swallowing stays in the contract's `attempt` wrapper: every method
|
|
12
|
+
* here that talks to the socket may throw a `MuxError`, and the contract is
|
|
13
|
+
* the layer that turns that into a null/false answer.
|
|
14
|
+
*
|
|
15
|
+
* Three rules run through the reconciliation logic:
|
|
16
|
+
*
|
|
17
|
+
* 1. A user action is a decision. A resize observed via `layout.updated`
|
|
18
|
+
* that does not match what Clio last applied becomes the new target; a
|
|
19
|
+
* closed dock stays closed; a moved dock is followed to its new id.
|
|
20
|
+
* 2. Clio's own corrections must not read as user actions. Every applied
|
|
21
|
+
* share is remembered and an observation matching it (or the target)
|
|
22
|
+
* within {@link SHARE_EPSILON} is a no-op.
|
|
23
|
+
* 3. Opening never steals focus. Focus and zoom live on the contract and
|
|
24
|
+
* only ever run on explicit request.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import type { MuxClient } from "./socket-client.js";
|
|
28
|
+
import type { MuxLayoutNode, MuxLog, MuxPaneRef, MuxRect, MuxTabGeometry } from "./types.js";
|
|
29
|
+
|
|
30
|
+
/** The two managed dock positions. */
|
|
31
|
+
export type DockSlot = "workers" | "files";
|
|
32
|
+
|
|
33
|
+
export interface DockSpec {
|
|
34
|
+
slot: DockSlot;
|
|
35
|
+
direction: "right" | "down";
|
|
36
|
+
/** Default share of the anchor's axis the dock takes when none is configured. */
|
|
37
|
+
defaultShare: number;
|
|
38
|
+
/** Floor in cells (columns for `right`, rows for `down`) below which a dock is useless. */
|
|
39
|
+
minCells: number;
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/**
|
|
43
|
+
* Fixed per slot rather than heuristic: the workers viewer wants columns, the
|
|
44
|
+
* file pane wants rows, and a dock that wanders per terminal width would make
|
|
45
|
+
* the layout feel like weather.
|
|
46
|
+
*/
|
|
47
|
+
export const DOCK_SPECS: Readonly<Record<DockSlot, DockSpec>> = {
|
|
48
|
+
workers: { slot: "workers", direction: "right", defaultShare: 0.34, minCells: 48 },
|
|
49
|
+
files: { slot: "files", direction: "down", defaultShare: 0.3, minCells: 12 },
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
/** A dock may never take more than half the axis, whatever the share asks. */
|
|
53
|
+
export const DOCK_MAX_SHARE = 0.5;
|
|
54
|
+
/** Observed-vs-applied share differences below this are rounding, not a user drag. */
|
|
55
|
+
export const SHARE_EPSILON = 0.02;
|
|
56
|
+
|
|
57
|
+
export interface DockState {
|
|
58
|
+
slot: DockSlot;
|
|
59
|
+
paneId: string;
|
|
60
|
+
tabId: string;
|
|
61
|
+
/** Share of the axis the dock should hold; user resizes overwrite it. */
|
|
62
|
+
targetShare: number;
|
|
63
|
+
/** What Clio last set, so its own correction is not adopted as a user drag. */
|
|
64
|
+
lastAppliedShare: number;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Wire ratio for a split where the dock is the `second` child: the anchor keeps the rest. */
|
|
68
|
+
export function ratioForDockShare(share: number): number {
|
|
69
|
+
return 1 - share;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** Clamps a requested share into (0, DOCK_MAX_SHARE]. */
|
|
73
|
+
export function clampDockShare(share: number): number {
|
|
74
|
+
if (!Number.isFinite(share) || share <= 0) return DOCK_SPECS.workers.defaultShare;
|
|
75
|
+
return Math.min(DOCK_MAX_SHARE, share);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
/** The axis length in cells a spec's direction measures on a rect. */
|
|
79
|
+
function axisCells(rect: { width: number; height: number }, spec: DockSpec): number {
|
|
80
|
+
return spec.direction === "right" ? rect.width : rect.height;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
/**
|
|
84
|
+
* Boolean path from the root to the split separating `anchorPaneId` from
|
|
85
|
+
* `dockPaneId`, plus which side the dock sits on. Null when the tree does not
|
|
86
|
+
* hold such a split, which is how a stale path is detected after user moves.
|
|
87
|
+
*/
|
|
88
|
+
export function deriveSplitPath(
|
|
89
|
+
root: MuxLayoutNode,
|
|
90
|
+
anchorPaneId: string,
|
|
91
|
+
dockPaneId: string,
|
|
92
|
+
): { path: ReadonlyArray<boolean>; dockIsSecond: boolean; direction: "right" | "down" } | null {
|
|
93
|
+
const contains = (node: MuxLayoutNode, paneId: string): boolean => {
|
|
94
|
+
if (node.type === "pane") return node.paneId === paneId;
|
|
95
|
+
return contains(node.first, paneId) || contains(node.second, paneId);
|
|
96
|
+
};
|
|
97
|
+
const walk = (
|
|
98
|
+
node: MuxLayoutNode,
|
|
99
|
+
path: boolean[],
|
|
100
|
+
): { path: boolean[]; dockIsSecond: boolean; direction: "right" | "down" } | null => {
|
|
101
|
+
if (node.type !== "split") return null;
|
|
102
|
+
const dockFirst = contains(node.first, dockPaneId);
|
|
103
|
+
const dockSecond = contains(node.second, dockPaneId);
|
|
104
|
+
const anchorFirst = contains(node.first, anchorPaneId);
|
|
105
|
+
const anchorSecond = contains(node.second, anchorPaneId);
|
|
106
|
+
if (dockFirst && anchorSecond) return { path, dockIsSecond: false, direction: node.direction };
|
|
107
|
+
if (dockSecond && anchorFirst) return { path, dockIsSecond: true, direction: node.direction };
|
|
108
|
+
if (dockFirst && anchorFirst) return walk(node.first, [...path, false]);
|
|
109
|
+
if (dockSecond && anchorSecond) return walk(node.second, [...path, true]);
|
|
110
|
+
return null;
|
|
111
|
+
};
|
|
112
|
+
return walk(root, []);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/** Whether `outer` contains `inner`, cell-inclusive. */
|
|
116
|
+
function containsRect(outer: MuxRect, inner: MuxRect): boolean {
|
|
117
|
+
return (
|
|
118
|
+
outer.x <= inner.x &&
|
|
119
|
+
outer.y <= inner.y &&
|
|
120
|
+
outer.x + outer.width >= inner.x + inner.width &&
|
|
121
|
+
outer.y + outer.height >= inner.y + inner.height
|
|
122
|
+
);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* The dock side's observed share at the split separating it from the anchor,
|
|
127
|
+
* from live geometry. The separating split is the smallest split rect holding
|
|
128
|
+
* both panes: split rects nest, so that is their lowest common ancestor. Its
|
|
129
|
+
* live ratio is read directly rather than summing pane cells, because the
|
|
130
|
+
* anchor's rect stops standing for its whole side the moment the user splits
|
|
131
|
+
* it for something else, and a cell sum then misreads an untouched dock as a
|
|
132
|
+
* resize. A separating split on the wrong axis measures nothing.
|
|
133
|
+
*/
|
|
134
|
+
export function observedDockShare(
|
|
135
|
+
geometry: MuxTabGeometry,
|
|
136
|
+
spec: DockSpec,
|
|
137
|
+
anchorPaneId: string,
|
|
138
|
+
dockPaneId: string,
|
|
139
|
+
): number | null {
|
|
140
|
+
const anchor = geometry.panes.find((pane) => pane.paneId === anchorPaneId);
|
|
141
|
+
const dock = geometry.panes.find((pane) => pane.paneId === dockPaneId);
|
|
142
|
+
if (!anchor || !dock) return null;
|
|
143
|
+
let separating: MuxTabGeometry["splits"][number] | null = null;
|
|
144
|
+
for (const split of geometry.splits) {
|
|
145
|
+
if (!containsRect(split.rect, anchor.rect) || !containsRect(split.rect, dock.rect)) continue;
|
|
146
|
+
if (!separating || split.rect.width * split.rect.height < separating.rect.width * separating.rect.height) {
|
|
147
|
+
separating = split;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
if (!separating || separating.direction !== spec.direction) return null;
|
|
151
|
+
// On opposite sides of the divider, the second child always starts past the
|
|
152
|
+
// first, so a coordinate compare says which side the dock holds.
|
|
153
|
+
const dockIsSecond = spec.direction === "right" ? dock.rect.x > anchor.rect.x : dock.rect.y > anchor.rect.y;
|
|
154
|
+
return dockIsSecond ? 1 - separating.ratio : separating.ratio;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
export interface DockOpenPlan {
|
|
158
|
+
direction: "right" | "down";
|
|
159
|
+
/** Wire ratio for `pane.split`: the share the anchor keeps. */
|
|
160
|
+
ratio: number;
|
|
161
|
+
share: number;
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Decides whether a dock fits beside the anchor and with what split ratio,
|
|
166
|
+
* from the anchor's current rect. Refusal happens here, before any split
|
|
167
|
+
* reaches the wire, so a too-small terminal never flashes a sliver pane.
|
|
168
|
+
*/
|
|
169
|
+
export function planDockOpen(
|
|
170
|
+
anchorRect: { width: number; height: number },
|
|
171
|
+
spec: DockSpec,
|
|
172
|
+
requestedShare?: number,
|
|
173
|
+
): DockOpenPlan | { refused: string } {
|
|
174
|
+
const axis = axisCells(anchorRect, spec);
|
|
175
|
+
if (axis * DOCK_MAX_SHARE < spec.minCells) {
|
|
176
|
+
return {
|
|
177
|
+
refused: `the ${spec.slot} dock needs ${spec.minCells} cells and at most half of ${axis} is available`,
|
|
178
|
+
};
|
|
179
|
+
}
|
|
180
|
+
const share = Math.max(clampDockShare(requestedShare ?? spec.defaultShare), spec.minCells / axis);
|
|
181
|
+
return { direction: spec.direction, ratio: ratioForDockShare(share), share };
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
export interface DockControllerOptions {
|
|
185
|
+
client: MuxClient;
|
|
186
|
+
anchorPaneId: string;
|
|
187
|
+
log?: MuxLog;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
export interface DockController {
|
|
191
|
+
/** Live dock states, for status output. */
|
|
192
|
+
states(): ReadonlyArray<DockState>;
|
|
193
|
+
stateFor(slot: DockSlot): DockState | null;
|
|
194
|
+
/**
|
|
195
|
+
* Splits the anchor for a dock and converges it to its cell floor. Returns
|
|
196
|
+
* the new pane, or null when the anchor is too small. Throws MuxError on
|
|
197
|
+
* wire failure; the contract's attempt wrapper owns that.
|
|
198
|
+
*/
|
|
199
|
+
open(
|
|
200
|
+
slot: DockSlot,
|
|
201
|
+
options?: { share?: number; cwd?: string; env?: Readonly<Record<string, string>> },
|
|
202
|
+
): Promise<MuxPaneRef | null>;
|
|
203
|
+
/** Record an adopted pane (crash recovery) as this slot's dock. */
|
|
204
|
+
adopt(slot: DockSlot, ref: MuxPaneRef): void;
|
|
205
|
+
/** Set a dock's share explicitly, as `/panes` resize does. */
|
|
206
|
+
resize(slot: DockSlot, share: number): Promise<boolean>;
|
|
207
|
+
/** Feed a `layout.updated` push; user resizes become the new target. */
|
|
208
|
+
noteLayoutUpdated(geometry: MuxTabGeometry): void;
|
|
209
|
+
/** Feed a pane departure; a closed dock is a decision, not a fault. */
|
|
210
|
+
notePaneGone(paneId: string): void;
|
|
211
|
+
/** Feed a `pane.moved` id rewrite; the dock is followed to its new id. */
|
|
212
|
+
notePaneMoved(previousPaneId: string, paneId: string, tabId: string): void;
|
|
213
|
+
/** Pane ids of every live dock, for the contract's clean-exit sweep. */
|
|
214
|
+
paneIds(): ReadonlyArray<string>;
|
|
215
|
+
clear(): void;
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
export function createDockController(options: DockControllerOptions): DockController {
|
|
219
|
+
const { client, anchorPaneId } = options;
|
|
220
|
+
const log = options.log ?? ((): void => undefined);
|
|
221
|
+
const bySlot = new Map<DockSlot, DockState>();
|
|
222
|
+
|
|
223
|
+
/**
|
|
224
|
+
* Re-derives the split path from a fresh export and applies a ratio for the
|
|
225
|
+
* dock's share. The path is never cached: user splits and moves invalidate
|
|
226
|
+
* it silently, and one export per resize is cheap.
|
|
227
|
+
*/
|
|
228
|
+
const applyShare = async (state: DockState, share: number): Promise<boolean> => {
|
|
229
|
+
const tree = await client.layoutExport({ tabId: state.tabId });
|
|
230
|
+
const derived = deriveSplitPath(tree.root, anchorPaneId, state.paneId);
|
|
231
|
+
if (!derived) {
|
|
232
|
+
log("debug", `mux ${state.slot} dock split path is gone from ${state.tabId}; leaving layout alone`);
|
|
233
|
+
return false;
|
|
234
|
+
}
|
|
235
|
+
// After a user move the separating split can run the other axis, and the
|
|
236
|
+
// share would then set a height where minCells measures columns. Wrong-axis
|
|
237
|
+
// geometry is declined, not silently applied.
|
|
238
|
+
if (derived.direction !== DOCK_SPECS[state.slot].direction) {
|
|
239
|
+
log("debug", `mux ${state.slot} dock split runs ${derived.direction}; declining the wrong-axis resize`);
|
|
240
|
+
return false;
|
|
241
|
+
}
|
|
242
|
+
const ratio = derived.dockIsSecond ? ratioForDockShare(share) : share;
|
|
243
|
+
await client.layoutSetSplitRatio({ tabId: state.tabId, path: derived.path, ratio });
|
|
244
|
+
state.targetShare = share;
|
|
245
|
+
state.lastAppliedShare = share;
|
|
246
|
+
return true;
|
|
247
|
+
};
|
|
248
|
+
|
|
249
|
+
return {
|
|
250
|
+
states(): ReadonlyArray<DockState> {
|
|
251
|
+
return [...bySlot.values()].map((state) => ({ ...state }));
|
|
252
|
+
},
|
|
253
|
+
|
|
254
|
+
stateFor(slot: DockSlot): DockState | null {
|
|
255
|
+
const state = bySlot.get(slot);
|
|
256
|
+
return state ? { ...state } : null;
|
|
257
|
+
},
|
|
258
|
+
|
|
259
|
+
async open(slot, openOptions = {}): Promise<MuxPaneRef | null> {
|
|
260
|
+
const existing = bySlot.get(slot);
|
|
261
|
+
if (existing) {
|
|
262
|
+
return { paneId: existing.paneId, tabId: existing.tabId, workspaceId: "" };
|
|
263
|
+
}
|
|
264
|
+
const spec = DOCK_SPECS[slot];
|
|
265
|
+
const geometry = await client.paneLayout(anchorPaneId);
|
|
266
|
+
const anchorRect = geometry.panes.find((pane) => pane.paneId === anchorPaneId)?.rect;
|
|
267
|
+
if (!anchorRect) {
|
|
268
|
+
log("debug", `mux ${slot} dock open found no anchor rect for ${anchorPaneId}`);
|
|
269
|
+
return null;
|
|
270
|
+
}
|
|
271
|
+
const plan = planDockOpen(anchorRect, spec, openOptions.share);
|
|
272
|
+
if ("refused" in plan) {
|
|
273
|
+
log("info", `mux ${slot} dock refused: ${plan.refused}`);
|
|
274
|
+
return null;
|
|
275
|
+
}
|
|
276
|
+
const pane = await client.paneSplit({
|
|
277
|
+
direction: plan.direction,
|
|
278
|
+
targetPaneId: anchorPaneId,
|
|
279
|
+
ratio: plan.ratio,
|
|
280
|
+
focus: false,
|
|
281
|
+
...(openOptions.cwd !== undefined ? { cwd: openOptions.cwd } : {}),
|
|
282
|
+
...(openOptions.env ? { env: openOptions.env } : {}),
|
|
283
|
+
});
|
|
284
|
+
const state: DockState = {
|
|
285
|
+
slot,
|
|
286
|
+
paneId: pane.paneId,
|
|
287
|
+
tabId: pane.tabId,
|
|
288
|
+
targetShare: plan.share,
|
|
289
|
+
lastAppliedShare: plan.share,
|
|
290
|
+
};
|
|
291
|
+
bySlot.set(slot, state);
|
|
292
|
+
// Ratio-at-split lands on the anchor's old rect; prior splits or a
|
|
293
|
+
// resize since the read can leave the dock under its floor. One
|
|
294
|
+
// converge pass fixes it; failure to converge is not failure to open.
|
|
295
|
+
try {
|
|
296
|
+
const after = await client.paneLayout(anchorPaneId);
|
|
297
|
+
const dockRect = after.panes.find((entry) => entry.paneId === pane.paneId)?.rect;
|
|
298
|
+
if (dockRect && axisCells(dockRect, spec) < spec.minCells) {
|
|
299
|
+
const anchorAfter = after.panes.find((entry) => entry.paneId === anchorPaneId)?.rect;
|
|
300
|
+
const total = anchorAfter ? axisCells(anchorAfter, spec) + axisCells(dockRect, spec) : 0;
|
|
301
|
+
if (total > 0) await applyShare(state, Math.min(DOCK_MAX_SHARE, spec.minCells / total));
|
|
302
|
+
}
|
|
303
|
+
} catch (error) {
|
|
304
|
+
log("debug", `mux ${slot} dock converge skipped: ${error instanceof Error ? error.message : String(error)}`);
|
|
305
|
+
}
|
|
306
|
+
return { paneId: pane.paneId, tabId: pane.tabId, workspaceId: pane.workspaceId };
|
|
307
|
+
},
|
|
308
|
+
|
|
309
|
+
adopt(slot: DockSlot, ref: MuxPaneRef): void {
|
|
310
|
+
const spec = DOCK_SPECS[slot];
|
|
311
|
+
bySlot.set(slot, {
|
|
312
|
+
slot,
|
|
313
|
+
paneId: ref.paneId,
|
|
314
|
+
tabId: ref.tabId,
|
|
315
|
+
// The surviving pane's actual share is adopted lazily by the next
|
|
316
|
+
// layout observation; until then the default is the best guess.
|
|
317
|
+
targetShare: spec.defaultShare,
|
|
318
|
+
lastAppliedShare: spec.defaultShare,
|
|
319
|
+
});
|
|
320
|
+
},
|
|
321
|
+
|
|
322
|
+
async resize(slot: DockSlot, share: number): Promise<boolean> {
|
|
323
|
+
const state = bySlot.get(slot);
|
|
324
|
+
if (!state) return false;
|
|
325
|
+
return await applyShare(state, Math.max(clampDockShare(share), 0.01));
|
|
326
|
+
},
|
|
327
|
+
|
|
328
|
+
noteLayoutUpdated(geometry: MuxTabGeometry): void {
|
|
329
|
+
for (const state of bySlot.values()) {
|
|
330
|
+
if (state.tabId !== geometry.tabId) continue;
|
|
331
|
+
const observed = observedDockShare(geometry, DOCK_SPECS[state.slot], anchorPaneId, state.paneId);
|
|
332
|
+
if (observed === null) continue;
|
|
333
|
+
if (Math.abs(observed - state.targetShare) <= SHARE_EPSILON) continue;
|
|
334
|
+
if (Math.abs(observed - state.lastAppliedShare) <= SHARE_EPSILON) continue;
|
|
335
|
+
// The user dragged the divider. Their ratio is the target now, and a
|
|
336
|
+
// later terminal resize must not fight them back to the old one.
|
|
337
|
+
log("debug", `mux ${state.slot} dock resized by the user to ${(observed * 100).toFixed(0)}%`);
|
|
338
|
+
state.targetShare = observed;
|
|
339
|
+
state.lastAppliedShare = observed;
|
|
340
|
+
}
|
|
341
|
+
},
|
|
342
|
+
|
|
343
|
+
notePaneGone(paneId: string): void {
|
|
344
|
+
for (const [slot, state] of bySlot) {
|
|
345
|
+
if (state.paneId === paneId) bySlot.delete(slot);
|
|
346
|
+
}
|
|
347
|
+
},
|
|
348
|
+
|
|
349
|
+
notePaneMoved(previousPaneId: string, paneId: string, tabId: string): void {
|
|
350
|
+
for (const state of bySlot.values()) {
|
|
351
|
+
if (state.paneId !== previousPaneId) continue;
|
|
352
|
+
state.paneId = paneId;
|
|
353
|
+
state.tabId = tabId;
|
|
354
|
+
}
|
|
355
|
+
},
|
|
356
|
+
|
|
357
|
+
paneIds(): ReadonlyArray<string> {
|
|
358
|
+
return [...bySlot.values()].map((state) => state.paneId);
|
|
359
|
+
},
|
|
360
|
+
|
|
361
|
+
clear(): void {
|
|
362
|
+
bySlot.clear();
|
|
363
|
+
},
|
|
364
|
+
};
|
|
365
|
+
}
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Domain wiring for the pane layer.
|
|
3
|
+
*
|
|
4
|
+
* `createExtension` runs the detection ladder once at boot. This module only
|
|
5
|
+
* loads on a `--with-panes` boot (src/entry/with-panes.ts), so a plain session
|
|
6
|
+
* never reaches this code at all; within an active session, detection failures
|
|
7
|
+
* are never fatal, and a wedged herdr server delays boot by at most the
|
|
8
|
+
* one-second ping budget per socket candidate.
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import type { DomainBundle, DomainContext, DomainExtension } from "../../core/domain-loader.js";
|
|
12
|
+
import { createMuxRuntime, type MuxContract } from "./contract.js";
|
|
13
|
+
import { detectMux, type MuxEnablement } from "./detect.js";
|
|
14
|
+
import type { MuxLog } from "./types.js";
|
|
15
|
+
|
|
16
|
+
export interface MuxDomainOptions {
|
|
17
|
+
/** `off` skips detection entirely; `embedded` degrades to `none` until phase 5. */
|
|
18
|
+
enabled?: MuxEnablement;
|
|
19
|
+
env?: NodeJS.ProcessEnv;
|
|
20
|
+
log?: MuxLog;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export async function createMuxBundle(
|
|
24
|
+
_context: DomainContext,
|
|
25
|
+
options: MuxDomainOptions = {},
|
|
26
|
+
): Promise<DomainBundle<MuxContract>> {
|
|
27
|
+
const log = options.log ?? ((): void => undefined);
|
|
28
|
+
const { detection, client } = await detectMux({
|
|
29
|
+
...(options.enabled ? { enabled: options.enabled } : {}),
|
|
30
|
+
...(options.env ? { env: options.env } : {}),
|
|
31
|
+
log,
|
|
32
|
+
});
|
|
33
|
+
// A `none` that nobody asked for is background noise and stays at debug. A
|
|
34
|
+
// refusal is the operator's own setting being turned down, so it goes to
|
|
35
|
+
// `warning`, which the orchestrator routes to boot stderr.
|
|
36
|
+
log(
|
|
37
|
+
detection.refused ? "warning" : detection.mode === "none" ? "debug" : "info",
|
|
38
|
+
detection.refused ? `panes refused: ${detection.reason}` : `mux mode ${detection.mode}: ${detection.reason}`,
|
|
39
|
+
);
|
|
40
|
+
|
|
41
|
+
const runtime = createMuxRuntime({ detection, client, log });
|
|
42
|
+
|
|
43
|
+
const extension: DomainExtension = {
|
|
44
|
+
async start(): Promise<void> {
|
|
45
|
+
await runtime.start();
|
|
46
|
+
},
|
|
47
|
+
async stop(): Promise<void> {
|
|
48
|
+
await runtime.stop();
|
|
49
|
+
},
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
return { extension, contract: runtime.contract };
|
|
53
|
+
}
|