@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,964 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Newline-delimited JSON client for a herdr server's Unix domain socket.
|
|
3
|
+
*
|
|
4
|
+
* Two connection kinds, because the server treats them differently:
|
|
5
|
+
*
|
|
6
|
+
* 1. One connection per request. herdr's `handle_connection` reads exactly one
|
|
7
|
+
* request line, writes the response, and closes
|
|
8
|
+
* (`src/api/server.rs:172`, verified against herdr 0.7.5 / protocol 17), so
|
|
9
|
+
* a second request written to the same socket dies with EPIPE. Spec 4.3
|
|
10
|
+
* describes a persistent request/response connection with a pending map;
|
|
11
|
+
* that is not what the pinned binary does. Each call still gets a monotonic
|
|
12
|
+
* id and still checks the echoed id, which catches a server answering
|
|
13
|
+
* something other than what was asked. A call with no response inside its
|
|
14
|
+
* budget rejects with {@link MuxRequestTimeout}.
|
|
15
|
+
* 2. One dedicated connection per `events.subscribe` stream. This is one of
|
|
16
|
+
* the two methods that keep a connection open (the other is
|
|
17
|
+
* `pane.graphics.stream`): herdr acknowledges once and then pushes event
|
|
18
|
+
* lines forever.
|
|
19
|
+
*
|
|
20
|
+
* Connect failures back off with a capped exponential delay, so a dead socket
|
|
21
|
+
* is not hammered once per call. After a subscription reconnect the client
|
|
22
|
+
* refetches `session.snapshot` and hands it to the resync handler: herdr's
|
|
23
|
+
* documented pattern is snapshot once and then trust events, and events missed
|
|
24
|
+
* while the socket was down are simply gone.
|
|
25
|
+
*
|
|
26
|
+
* The interactive app never shells out to the `herdr` CLI. CLI wrappers exist
|
|
27
|
+
* for humans, doctor, and scripts.
|
|
28
|
+
*
|
|
29
|
+
* This is the only module in the tree that reads herdr wire shapes. Every
|
|
30
|
+
* public method returns the Clio types from `types.ts`, and unknown fields on a
|
|
31
|
+
* response are ignored, which is herdr's stated forward-compatibility rule.
|
|
32
|
+
*/
|
|
33
|
+
|
|
34
|
+
import * as net from "node:net";
|
|
35
|
+
import {
|
|
36
|
+
MuxError,
|
|
37
|
+
type MuxEvent,
|
|
38
|
+
type MuxEventKind,
|
|
39
|
+
type MuxLayoutNode,
|
|
40
|
+
type MuxLayoutTree,
|
|
41
|
+
type MuxLog,
|
|
42
|
+
type MuxNotificationSound,
|
|
43
|
+
type MuxPane,
|
|
44
|
+
type MuxRect,
|
|
45
|
+
type MuxReportableAgentState,
|
|
46
|
+
MuxRequestTimeout,
|
|
47
|
+
type MuxServerInfo,
|
|
48
|
+
type MuxSnapshot,
|
|
49
|
+
type MuxTab,
|
|
50
|
+
type MuxTabGeometry,
|
|
51
|
+
type MuxWorktree,
|
|
52
|
+
type MuxWorktreeSource,
|
|
53
|
+
muxErrorKind,
|
|
54
|
+
} from "./types.js";
|
|
55
|
+
|
|
56
|
+
/** Default per-request budget from spec 4.3. */
|
|
57
|
+
const DEFAULT_REQUEST_TIMEOUT_MS = 5_000;
|
|
58
|
+
/** Connect budget. Detection uses a tighter one; see `detect.ts`. */
|
|
59
|
+
const DEFAULT_CONNECT_TIMEOUT_MS = 2_000;
|
|
60
|
+
const DEFAULT_BACKOFF = { initialDelayMs: 250, maxDelayMs: 5_000, factor: 2 } as const;
|
|
61
|
+
/**
|
|
62
|
+
* A single response line larger than this means the peer is not a herdr server
|
|
63
|
+
* (or is wedged), so the connection is dropped rather than buffered forever.
|
|
64
|
+
*/
|
|
65
|
+
const MAX_LINE_BYTES = 8 * 1024 * 1024;
|
|
66
|
+
|
|
67
|
+
export interface MuxBackoffOptions {
|
|
68
|
+
initialDelayMs: number;
|
|
69
|
+
maxDelayMs: number;
|
|
70
|
+
factor: number;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
export interface MuxClientOptions {
|
|
74
|
+
socketPath: string;
|
|
75
|
+
requestTimeoutMs?: number;
|
|
76
|
+
connectTimeoutMs?: number;
|
|
77
|
+
backoff?: MuxBackoffOptions;
|
|
78
|
+
log?: MuxLog;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
export interface MuxSubscription {
|
|
82
|
+
close(): void;
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
export interface MuxSplitRequest {
|
|
86
|
+
direction: "right" | "down";
|
|
87
|
+
targetPaneId?: string;
|
|
88
|
+
workspaceId?: string;
|
|
89
|
+
cwd?: string;
|
|
90
|
+
env?: Readonly<Record<string, string>>;
|
|
91
|
+
focus?: boolean;
|
|
92
|
+
ratio?: number;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface MuxReportAgentRequest {
|
|
96
|
+
paneId: string;
|
|
97
|
+
source: string;
|
|
98
|
+
agent: string;
|
|
99
|
+
state: MuxReportableAgentState;
|
|
100
|
+
message?: string;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export interface MuxReportMetadataRequest {
|
|
104
|
+
paneId: string;
|
|
105
|
+
source: string;
|
|
106
|
+
agent?: string;
|
|
107
|
+
title?: string;
|
|
108
|
+
displayAgent?: string;
|
|
109
|
+
tokens?: Readonly<Record<string, string | null>>;
|
|
110
|
+
stateLabels?: Readonly<Record<string, string>>;
|
|
111
|
+
ttlMs?: number;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export interface MuxSubscribeOptions {
|
|
115
|
+
/** Called after a dropped stream reconnects, with a freshly taken snapshot. */
|
|
116
|
+
onResync?: (snapshot: MuxSnapshot) => void;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export interface MuxNotificationRequest {
|
|
120
|
+
title: string;
|
|
121
|
+
body?: string;
|
|
122
|
+
sound?: MuxNotificationSound;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* What the server did with a toast. `shown: false` is a normal answer: the
|
|
127
|
+
* operator's own herdr config can disable toasts, rate-limit them, or have no
|
|
128
|
+
* foreground client to paint one, and none of those is a Clio failure.
|
|
129
|
+
*/
|
|
130
|
+
export interface MuxNotificationResult {
|
|
131
|
+
shown: boolean;
|
|
132
|
+
reason: string;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
export interface MuxWorktreeListRequest {
|
|
136
|
+
workspaceId?: string;
|
|
137
|
+
cwd?: string;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
export interface MuxWorktreeCreateRequest extends MuxWorktreeListRequest {
|
|
141
|
+
branch?: string;
|
|
142
|
+
base?: string;
|
|
143
|
+
path?: string;
|
|
144
|
+
label?: string;
|
|
145
|
+
focus?: boolean;
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export interface MuxWorktreeOpenRequest extends MuxWorktreeListRequest {
|
|
149
|
+
branch?: string;
|
|
150
|
+
path?: string;
|
|
151
|
+
label?: string;
|
|
152
|
+
focus?: boolean;
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
export interface MuxWorktreeListResult {
|
|
156
|
+
source: MuxWorktreeSource;
|
|
157
|
+
worktrees: ReadonlyArray<MuxWorktree>;
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
export interface MuxWorktreeCreatedResult {
|
|
161
|
+
workspaceId: string;
|
|
162
|
+
tab: MuxTab;
|
|
163
|
+
rootPane: MuxPane;
|
|
164
|
+
worktree: MuxWorktree;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
export interface MuxWorktreeOpenedResult extends MuxWorktreeCreatedResult {
|
|
168
|
+
alreadyOpen: boolean;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
export interface MuxWorktreeRemovedResult {
|
|
172
|
+
workspaceId: string;
|
|
173
|
+
path: string;
|
|
174
|
+
forced: boolean;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* The domain-facing surface. Phase 1 covers exactly the wire methods spec 4.3
|
|
179
|
+
* lists for this phase, plus `pane.send_text`, `pane.report_agent`,
|
|
180
|
+
* `pane.report_metadata` (see the notes on those methods below).
|
|
181
|
+
*/
|
|
182
|
+
export interface MuxClient {
|
|
183
|
+
readonly socketPath: string;
|
|
184
|
+
/** Whether the most recent request reached the server. Requests are one per connection. */
|
|
185
|
+
connected(): boolean;
|
|
186
|
+
/** Protocol/version recorded from the most recent successful ping or snapshot. */
|
|
187
|
+
server(): MuxServerInfo | null;
|
|
188
|
+
/** Most recent `session.snapshot`, including the post-reconnect refetch. */
|
|
189
|
+
cachedSnapshot(): MuxSnapshot | null;
|
|
190
|
+
|
|
191
|
+
ping(options?: { timeoutMs?: number }): Promise<MuxServerInfo>;
|
|
192
|
+
snapshot(): Promise<MuxSnapshot>;
|
|
193
|
+
paneCurrent(callerPaneId?: string): Promise<MuxPane>;
|
|
194
|
+
paneList(workspaceId?: string): Promise<ReadonlyArray<MuxPane>>;
|
|
195
|
+
paneSplit(request: MuxSplitRequest): Promise<MuxPane>;
|
|
196
|
+
/** Set the pane's operator-facing label. Available on herdr protocol 17. */
|
|
197
|
+
paneRename(paneId: string, label: string): Promise<void>;
|
|
198
|
+
paneClose(paneId: string): Promise<void>;
|
|
199
|
+
/**
|
|
200
|
+
* Cell-precise geometry of the tab holding `paneId` (the server's focused
|
|
201
|
+
* pane when omitted): outer area, pane rects, and live split ratios.
|
|
202
|
+
*/
|
|
203
|
+
paneLayout(paneId?: string): Promise<MuxTabGeometry>;
|
|
204
|
+
/**
|
|
205
|
+
* Focus a pane. This switches the focused tab as well as the pane (verified
|
|
206
|
+
* on 0.8.2), so it is only ever driven by an explicit "show me" request,
|
|
207
|
+
* never by background bookkeeping.
|
|
208
|
+
*/
|
|
209
|
+
paneFocus(paneId: string): Promise<void>;
|
|
210
|
+
/** Zoom a pane. Zooming an unfocused pane steals focus; same rule as paneFocus. */
|
|
211
|
+
paneZoom(paneId: string, mode: "on" | "off" | "toggle"): Promise<{ changed: boolean; focusChanged: boolean }>;
|
|
212
|
+
/** Portable layout tree for a tab, or the tab holding `paneId`. */
|
|
213
|
+
layoutExport(request?: { tabId?: string; paneId?: string }): Promise<MuxLayoutTree>;
|
|
214
|
+
/**
|
|
215
|
+
* Set one split's ratio, addressed by a boolean path from the root split
|
|
216
|
+
* (`false` descends first, `true` second; `[]` is the root). Returns the
|
|
217
|
+
* updated tree.
|
|
218
|
+
*/
|
|
219
|
+
layoutSetSplitRatio(request: {
|
|
220
|
+
tabId?: string;
|
|
221
|
+
paneId?: string;
|
|
222
|
+
path: ReadonlyArray<boolean>;
|
|
223
|
+
ratio: number;
|
|
224
|
+
}): Promise<MuxLayoutTree>;
|
|
225
|
+
worktreeList(request?: MuxWorktreeListRequest): Promise<MuxWorktreeListResult>;
|
|
226
|
+
worktreeCreate(request: MuxWorktreeCreateRequest): Promise<MuxWorktreeCreatedResult>;
|
|
227
|
+
worktreeOpen(request: MuxWorktreeOpenRequest): Promise<MuxWorktreeOpenedResult>;
|
|
228
|
+
worktreeRemove(workspaceId: string, options?: { force?: boolean }): Promise<MuxWorktreeRemovedResult>;
|
|
229
|
+
/**
|
|
230
|
+
* Deliver a command line into a pane's shell. herdr has no argv parameter on
|
|
231
|
+
* `pane.split`, so this is the only way an argv utility pane can run what it
|
|
232
|
+
* was asked to run.
|
|
233
|
+
*/
|
|
234
|
+
paneSendText(paneId: string, text: string): Promise<void>;
|
|
235
|
+
/** Takes agent authority over a pane. Only ever called on Clio-owned panes and Clio's own pane. */
|
|
236
|
+
paneReportAgent(request: MuxReportAgentRequest): Promise<void>;
|
|
237
|
+
paneReportMetadata(request: MuxReportMetadataRequest): Promise<void>;
|
|
238
|
+
/**
|
|
239
|
+
* Ask the foreground client to paint a toast. Protocol-gated; see
|
|
240
|
+
* `protocol.ts`. The server answers whether it painted one and why not.
|
|
241
|
+
*/
|
|
242
|
+
notificationShow(request: MuxNotificationRequest): Promise<MuxNotificationResult>;
|
|
243
|
+
subscribe(
|
|
244
|
+
kinds: ReadonlyArray<MuxEventKind>,
|
|
245
|
+
handler: (event: MuxEvent) => void,
|
|
246
|
+
options?: MuxSubscribeOptions,
|
|
247
|
+
): Promise<MuxSubscription>;
|
|
248
|
+
|
|
249
|
+
close(): Promise<void>;
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
/** Opens one socket, or rejects with a typed transport error. */
|
|
253
|
+
function connectSocket(socketPath: string, timeoutMs: number): Promise<net.Socket> {
|
|
254
|
+
return new Promise((resolve, reject) => {
|
|
255
|
+
const socket = net.connect({ path: socketPath });
|
|
256
|
+
socket.setNoDelay(true);
|
|
257
|
+
const timer = setTimeout(() => {
|
|
258
|
+
socket.destroy();
|
|
259
|
+
reject(new MuxError("transport", `mux socket connect to ${socketPath} timed out after ${timeoutMs}ms`));
|
|
260
|
+
}, timeoutMs);
|
|
261
|
+
timer.unref?.();
|
|
262
|
+
const settle = (error: Error | null): void => {
|
|
263
|
+
clearTimeout(timer);
|
|
264
|
+
socket.removeListener("connect", onConnect);
|
|
265
|
+
socket.removeListener("error", onError);
|
|
266
|
+
if (error) {
|
|
267
|
+
socket.destroy();
|
|
268
|
+
reject(new MuxError("transport", `mux socket connect to ${socketPath} failed: ${error.message}`));
|
|
269
|
+
return;
|
|
270
|
+
}
|
|
271
|
+
resolve(socket);
|
|
272
|
+
};
|
|
273
|
+
const onConnect = (): void => settle(null);
|
|
274
|
+
const onError = (error: Error): void => settle(error);
|
|
275
|
+
socket.once("connect", onConnect);
|
|
276
|
+
socket.once("error", onError);
|
|
277
|
+
});
|
|
278
|
+
}
|
|
279
|
+
|
|
280
|
+
/**
|
|
281
|
+
* Splits an incoming byte stream into JSON lines.
|
|
282
|
+
*
|
|
283
|
+
* `onOverflow` fires when one line exceeds the sanity cap, which the caller
|
|
284
|
+
* treats as a dead connection rather than growing the buffer without bound.
|
|
285
|
+
*/
|
|
286
|
+
function readJsonLines(
|
|
287
|
+
socket: net.Socket,
|
|
288
|
+
onValue: (value: Record<string, unknown>) => void,
|
|
289
|
+
onOverflow: () => void,
|
|
290
|
+
): void {
|
|
291
|
+
let buffer = "";
|
|
292
|
+
socket.setEncoding("utf8");
|
|
293
|
+
socket.on("data", (chunk: string) => {
|
|
294
|
+
buffer += chunk;
|
|
295
|
+
if (buffer.length > MAX_LINE_BYTES) {
|
|
296
|
+
buffer = "";
|
|
297
|
+
onOverflow();
|
|
298
|
+
return;
|
|
299
|
+
}
|
|
300
|
+
let newline = buffer.indexOf("\n");
|
|
301
|
+
while (newline >= 0) {
|
|
302
|
+
const line = buffer.slice(0, newline).trim();
|
|
303
|
+
buffer = buffer.slice(newline + 1);
|
|
304
|
+
if (line.length > 0) {
|
|
305
|
+
let parsed: unknown;
|
|
306
|
+
try {
|
|
307
|
+
parsed = JSON.parse(line);
|
|
308
|
+
} catch {
|
|
309
|
+
parsed = null;
|
|
310
|
+
}
|
|
311
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) {
|
|
312
|
+
onValue(parsed as Record<string, unknown>);
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
newline = buffer.indexOf("\n");
|
|
316
|
+
}
|
|
317
|
+
});
|
|
318
|
+
}
|
|
319
|
+
|
|
320
|
+
function asRecord(value: unknown): Record<string, unknown> | null {
|
|
321
|
+
return value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : null;
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
function requireString(source: Record<string, unknown>, key: string, context: string): string {
|
|
325
|
+
const value = source[key];
|
|
326
|
+
if (typeof value !== "string") {
|
|
327
|
+
throw new MuxError("protocol", `mux ${context} response is missing string field ${key}`);
|
|
328
|
+
}
|
|
329
|
+
return value;
|
|
330
|
+
}
|
|
331
|
+
|
|
332
|
+
function optionalString(source: Record<string, unknown>, key: string): string | null {
|
|
333
|
+
const value = source[key];
|
|
334
|
+
return typeof value === "string" ? value : null;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function stringMap(value: unknown): Record<string, string> {
|
|
338
|
+
const source = asRecord(value);
|
|
339
|
+
if (!source) return {};
|
|
340
|
+
const out: Record<string, string> = {};
|
|
341
|
+
for (const [key, entry] of Object.entries(source)) {
|
|
342
|
+
if (typeof entry === "string") out[key] = entry;
|
|
343
|
+
}
|
|
344
|
+
return out;
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
const AGENT_STATES = new Set(["idle", "working", "blocked", "done", "unknown"]);
|
|
348
|
+
|
|
349
|
+
function readAgentState(value: unknown): MuxPane["agentState"] {
|
|
350
|
+
return typeof value === "string" && AGENT_STATES.has(value) ? (value as MuxPane["agentState"]) : "unknown";
|
|
351
|
+
}
|
|
352
|
+
|
|
353
|
+
function readPane(value: unknown): MuxPane {
|
|
354
|
+
const source = asRecord(value);
|
|
355
|
+
if (!source) throw new MuxError("protocol", "mux pane response is not an object");
|
|
356
|
+
const revision = source.revision;
|
|
357
|
+
return {
|
|
358
|
+
paneId: requireString(source, "pane_id", "pane"),
|
|
359
|
+
tabId: requireString(source, "tab_id", "pane"),
|
|
360
|
+
workspaceId: requireString(source, "workspace_id", "pane"),
|
|
361
|
+
focused: source.focused === true,
|
|
362
|
+
agentState: readAgentState(source.agent_status),
|
|
363
|
+
revision: typeof revision === "number" ? revision : 0,
|
|
364
|
+
label: optionalString(source, "label"),
|
|
365
|
+
title: optionalString(source, "title"),
|
|
366
|
+
cwd: optionalString(source, "cwd"),
|
|
367
|
+
agent: optionalString(source, "agent"),
|
|
368
|
+
tokens: stringMap(source.tokens),
|
|
369
|
+
};
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
function readTab(value: unknown): MuxTab {
|
|
373
|
+
const source = asRecord(value);
|
|
374
|
+
if (!source) throw new MuxError("protocol", "mux tab response is not an object");
|
|
375
|
+
const number = source.number;
|
|
376
|
+
const paneCount = source.pane_count;
|
|
377
|
+
return {
|
|
378
|
+
tabId: requireString(source, "tab_id", "tab"),
|
|
379
|
+
workspaceId: requireString(source, "workspace_id", "tab"),
|
|
380
|
+
number: typeof number === "number" ? number : 0,
|
|
381
|
+
label: optionalString(source, "label") ?? "",
|
|
382
|
+
focused: source.focused === true,
|
|
383
|
+
paneCount: typeof paneCount === "number" ? paneCount : 0,
|
|
384
|
+
agentState: readAgentState(source.agent_status),
|
|
385
|
+
};
|
|
386
|
+
}
|
|
387
|
+
|
|
388
|
+
function readWorktree(value: unknown): MuxWorktree {
|
|
389
|
+
const source = asRecord(value);
|
|
390
|
+
if (!source) throw new MuxError("protocol", "mux worktree response is not an object");
|
|
391
|
+
return {
|
|
392
|
+
path: requireString(source, "path", "worktree"),
|
|
393
|
+
branch: optionalString(source, "branch"),
|
|
394
|
+
isBare: source.is_bare === true,
|
|
395
|
+
isDetached: source.is_detached === true,
|
|
396
|
+
isPrunable: source.is_prunable === true,
|
|
397
|
+
isLinkedWorktree: source.is_linked_worktree === true,
|
|
398
|
+
openWorkspaceId: optionalString(source, "open_workspace_id"),
|
|
399
|
+
label: optionalString(source, "label") ?? "",
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
|
|
403
|
+
function readWorktreeSource(value: unknown): MuxWorktreeSource {
|
|
404
|
+
const source = asRecord(value);
|
|
405
|
+
if (!source) throw new MuxError("protocol", "mux worktree source response is not an object");
|
|
406
|
+
return {
|
|
407
|
+
repoKey: requireString(source, "repo_key", "worktree source"),
|
|
408
|
+
repoName: requireString(source, "repo_name", "worktree source"),
|
|
409
|
+
repoRoot: requireString(source, "repo_root", "worktree source"),
|
|
410
|
+
sourceCheckoutPath: requireString(source, "source_checkout_path", "worktree source"),
|
|
411
|
+
sourceWorkspaceId: optionalString(source, "source_workspace_id"),
|
|
412
|
+
};
|
|
413
|
+
}
|
|
414
|
+
|
|
415
|
+
function readArray(source: Record<string, unknown>, key: string): unknown[] {
|
|
416
|
+
const value = source[key];
|
|
417
|
+
return Array.isArray(value) ? value : [];
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
function readServerInfo(source: Record<string, unknown>): MuxServerInfo {
|
|
421
|
+
const protocol = source.protocol;
|
|
422
|
+
return {
|
|
423
|
+
version: optionalString(source, "version") ?? "",
|
|
424
|
+
protocol: typeof protocol === "number" ? protocol : 0,
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
function readSnapshot(value: unknown): MuxSnapshot {
|
|
429
|
+
const source = asRecord(value);
|
|
430
|
+
if (!source) throw new MuxError("protocol", "mux snapshot response is not an object");
|
|
431
|
+
return {
|
|
432
|
+
server: readServerInfo(source),
|
|
433
|
+
focusedPaneId: optionalString(source, "focused_pane_id"),
|
|
434
|
+
focusedTabId: optionalString(source, "focused_tab_id"),
|
|
435
|
+
focusedWorkspaceId: optionalString(source, "focused_workspace_id"),
|
|
436
|
+
panes: readArray(source, "panes").map(readPane),
|
|
437
|
+
tabs: readArray(source, "tabs").map(readTab),
|
|
438
|
+
};
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
function requireNumber(source: Record<string, unknown>, key: string, context: string): number {
|
|
442
|
+
const value = source[key];
|
|
443
|
+
if (typeof value !== "number") {
|
|
444
|
+
throw new MuxError("protocol", `mux ${context} response is missing number field ${key}`);
|
|
445
|
+
}
|
|
446
|
+
return value;
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
function readRect(value: unknown, context: string): MuxRect {
|
|
450
|
+
const source = asRecord(value);
|
|
451
|
+
if (!source) throw new MuxError("protocol", `mux ${context} rect is not an object`);
|
|
452
|
+
return {
|
|
453
|
+
x: requireNumber(source, "x", context),
|
|
454
|
+
y: requireNumber(source, "y", context),
|
|
455
|
+
width: requireNumber(source, "width", context),
|
|
456
|
+
height: requireNumber(source, "height", context),
|
|
457
|
+
};
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
function readSplitDirection(value: unknown, context: string): "right" | "down" {
|
|
461
|
+
if (value === "right" || value === "down") return value;
|
|
462
|
+
throw new MuxError("protocol", `mux ${context} split direction is not right/down`);
|
|
463
|
+
}
|
|
464
|
+
|
|
465
|
+
/** Parses a `PaneLayoutSnapshot`: the shape `pane.layout` and `layout_updated` both carry. */
|
|
466
|
+
function readTabGeometry(value: unknown): MuxTabGeometry {
|
|
467
|
+
const source = asRecord(value);
|
|
468
|
+
if (!source) throw new MuxError("protocol", "mux layout snapshot is not an object");
|
|
469
|
+
return {
|
|
470
|
+
workspaceId: requireString(source, "workspace_id", "layout"),
|
|
471
|
+
tabId: requireString(source, "tab_id", "layout"),
|
|
472
|
+
zoomed: source.zoomed === true,
|
|
473
|
+
area: readRect(source.area, "layout"),
|
|
474
|
+
focusedPaneId: optionalString(source, "focused_pane_id"),
|
|
475
|
+
panes: readArray(source, "panes").map((entry) => {
|
|
476
|
+
const pane = asRecord(entry);
|
|
477
|
+
if (!pane) throw new MuxError("protocol", "mux layout pane entry is not an object");
|
|
478
|
+
return {
|
|
479
|
+
paneId: requireString(pane, "pane_id", "layout pane"),
|
|
480
|
+
focused: pane.focused === true,
|
|
481
|
+
rect: readRect(pane.rect, "layout pane"),
|
|
482
|
+
};
|
|
483
|
+
}),
|
|
484
|
+
splits: readArray(source, "splits").map((entry) => {
|
|
485
|
+
const split = asRecord(entry);
|
|
486
|
+
if (!split) throw new MuxError("protocol", "mux layout split entry is not an object");
|
|
487
|
+
return {
|
|
488
|
+
direction: readSplitDirection(split.direction, "layout"),
|
|
489
|
+
ratio: requireNumber(split, "ratio", "layout split"),
|
|
490
|
+
rect: readRect(split.rect, "layout split"),
|
|
491
|
+
};
|
|
492
|
+
}),
|
|
493
|
+
};
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
function readLayoutNode(value: unknown): MuxLayoutNode {
|
|
497
|
+
const source = asRecord(value);
|
|
498
|
+
if (!source) throw new MuxError("protocol", "mux layout node is not an object");
|
|
499
|
+
if (source.type === "pane") {
|
|
500
|
+
return { type: "pane", paneId: optionalString(source, "pane_id"), label: optionalString(source, "label") };
|
|
501
|
+
}
|
|
502
|
+
if (source.type === "split") {
|
|
503
|
+
return {
|
|
504
|
+
type: "split",
|
|
505
|
+
direction: readSplitDirection(source.direction, "layout tree"),
|
|
506
|
+
ratio: requireNumber(source, "ratio", "layout tree split"),
|
|
507
|
+
first: readLayoutNode(source.first),
|
|
508
|
+
second: readLayoutNode(source.second),
|
|
509
|
+
};
|
|
510
|
+
}
|
|
511
|
+
throw new MuxError("protocol", "mux layout node has an unknown type");
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
function readLayoutTree(value: unknown): MuxLayoutTree {
|
|
515
|
+
const source = asRecord(value);
|
|
516
|
+
if (!source) throw new MuxError("protocol", "mux layout tree is not an object");
|
|
517
|
+
return {
|
|
518
|
+
workspaceId: requireString(source, "workspace_id", "layout tree"),
|
|
519
|
+
tabId: requireString(source, "tab_id", "layout tree"),
|
|
520
|
+
zoomed: source.zoomed === true,
|
|
521
|
+
focusedPaneId: optionalString(source, "focused_pane_id"),
|
|
522
|
+
root: readLayoutNode(source.root),
|
|
523
|
+
};
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/** herdr names lifecycle event kinds with underscores on the wire and dots in subscriptions. */
|
|
527
|
+
const PANE_LEAVE_KIND_BY_WIRE: Readonly<Record<string, "pane.closed" | "pane.exited">> = {
|
|
528
|
+
pane_closed: "pane.closed",
|
|
529
|
+
pane_exited: "pane.exited",
|
|
530
|
+
};
|
|
531
|
+
|
|
532
|
+
function readEvent(line: Record<string, unknown>): MuxEvent | null {
|
|
533
|
+
const wireKind = line.event;
|
|
534
|
+
if (typeof wireKind !== "string") return null;
|
|
535
|
+
const data = asRecord(line.data);
|
|
536
|
+
if (!data) return null;
|
|
537
|
+
const leaveKind = PANE_LEAVE_KIND_BY_WIRE[wireKind];
|
|
538
|
+
if (leaveKind) {
|
|
539
|
+
const paneId = data.pane_id;
|
|
540
|
+
const workspaceId = data.workspace_id;
|
|
541
|
+
if (typeof paneId !== "string" || typeof workspaceId !== "string") return null;
|
|
542
|
+
return { kind: leaveKind, paneId, workspaceId };
|
|
543
|
+
}
|
|
544
|
+
if (wireKind === "pane_moved") {
|
|
545
|
+
// The move rewrites the pane id; the payload carries the new pane record
|
|
546
|
+
// plus the id it replaced, and consumers continue from the new one.
|
|
547
|
+
const pane = asRecord(data.pane);
|
|
548
|
+
const previousPaneId = data.previous_pane_id;
|
|
549
|
+
if (!pane || typeof previousPaneId !== "string") return null;
|
|
550
|
+
const paneId = pane.pane_id;
|
|
551
|
+
const tabId = pane.tab_id;
|
|
552
|
+
const workspaceId = pane.workspace_id;
|
|
553
|
+
if (typeof paneId !== "string" || typeof tabId !== "string" || typeof workspaceId !== "string") return null;
|
|
554
|
+
return { kind: "pane.moved", paneId, previousPaneId, tabId, workspaceId };
|
|
555
|
+
}
|
|
556
|
+
if (wireKind === "layout_updated") {
|
|
557
|
+
// The push already carries the full tab geometry, so a consumer never
|
|
558
|
+
// has to answer a layout event with a layout request.
|
|
559
|
+
try {
|
|
560
|
+
return { kind: "layout.updated", geometry: readTabGeometry(data.layout) };
|
|
561
|
+
} catch {
|
|
562
|
+
return null;
|
|
563
|
+
}
|
|
564
|
+
}
|
|
565
|
+
return null;
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
/** Drops undefined entries so an optional field is absent rather than `null` on the wire. */
|
|
569
|
+
function params(entries: Record<string, unknown>): Record<string, unknown> {
|
|
570
|
+
const out: Record<string, unknown> = {};
|
|
571
|
+
for (const [key, value] of Object.entries(entries)) {
|
|
572
|
+
if (value !== undefined) out[key] = value;
|
|
573
|
+
}
|
|
574
|
+
return out;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
export function createMuxClient(options: MuxClientOptions): MuxClient {
|
|
578
|
+
const socketPath = options.socketPath;
|
|
579
|
+
const requestTimeoutMs = options.requestTimeoutMs ?? DEFAULT_REQUEST_TIMEOUT_MS;
|
|
580
|
+
const connectTimeoutMs = options.connectTimeoutMs ?? DEFAULT_CONNECT_TIMEOUT_MS;
|
|
581
|
+
const backoff = options.backoff ?? DEFAULT_BACKOFF;
|
|
582
|
+
const log = options.log ?? ((): void => undefined);
|
|
583
|
+
|
|
584
|
+
let disposed = false;
|
|
585
|
+
let nextId = 0;
|
|
586
|
+
let reachable = false;
|
|
587
|
+
let serverInfo: MuxServerInfo | null = null;
|
|
588
|
+
let snapshotCache: MuxSnapshot | null = null;
|
|
589
|
+
|
|
590
|
+
/** Consecutive failed connect attempts. */
|
|
591
|
+
let connectFailures = 0;
|
|
592
|
+
/** Wall clock before which a new connect is refused. */
|
|
593
|
+
let retryAt = 0;
|
|
594
|
+
|
|
595
|
+
const delayFor = (failures: number): number =>
|
|
596
|
+
Math.min(backoff.maxDelayMs, backoff.initialDelayMs * backoff.factor ** Math.max(0, failures - 1));
|
|
597
|
+
|
|
598
|
+
/**
|
|
599
|
+
* One request, one connection.
|
|
600
|
+
*
|
|
601
|
+
* The id counter and the response-id check survive from the pending-map
|
|
602
|
+
* design because they still catch a server answering something other than
|
|
603
|
+
* what was asked, but there is no pending map: a connection carries exactly
|
|
604
|
+
* one outstanding call and is destroyed as soon as it settles.
|
|
605
|
+
*/
|
|
606
|
+
const call = async (method: string, callParams: Record<string, unknown>, timeoutMs?: number): Promise<unknown> => {
|
|
607
|
+
if (disposed) throw new MuxError("transport", "mux client is closed");
|
|
608
|
+
const waitMs = retryAt - Date.now();
|
|
609
|
+
if (waitMs > 0) {
|
|
610
|
+
throw new MuxError("transport", `mux socket ${socketPath} is in backoff for another ${waitMs}ms`);
|
|
611
|
+
}
|
|
612
|
+
let socket: net.Socket;
|
|
613
|
+
try {
|
|
614
|
+
socket = await connectSocket(socketPath, connectTimeoutMs);
|
|
615
|
+
} catch (error) {
|
|
616
|
+
connectFailures += 1;
|
|
617
|
+
retryAt = Date.now() + delayFor(connectFailures);
|
|
618
|
+
reachable = false;
|
|
619
|
+
throw error;
|
|
620
|
+
}
|
|
621
|
+
connectFailures = 0;
|
|
622
|
+
retryAt = 0;
|
|
623
|
+
nextId += 1;
|
|
624
|
+
const id = `clio-${nextId}`;
|
|
625
|
+
const budget = timeoutMs ?? requestTimeoutMs;
|
|
626
|
+
try {
|
|
627
|
+
const result = await new Promise<unknown>((resolve, reject) => {
|
|
628
|
+
let settled = false;
|
|
629
|
+
const finish = (settle: () => void): void => {
|
|
630
|
+
if (settled) return;
|
|
631
|
+
settled = true;
|
|
632
|
+
clearTimeout(timer);
|
|
633
|
+
socket.destroy();
|
|
634
|
+
settle();
|
|
635
|
+
};
|
|
636
|
+
const timer = setTimeout(() => finish(() => reject(new MuxRequestTimeout(method, budget))), budget);
|
|
637
|
+
timer.unref?.();
|
|
638
|
+
readJsonLines(
|
|
639
|
+
socket,
|
|
640
|
+
(line) => {
|
|
641
|
+
const responseId = line.id;
|
|
642
|
+
if (typeof responseId !== "string") return;
|
|
643
|
+
const error = asRecord(line.error);
|
|
644
|
+
// herdr answers a request it could not even parse with an empty id,
|
|
645
|
+
// so an empty-id error line on this connection is still ours.
|
|
646
|
+
if (responseId !== id && !(responseId === "" && error)) return;
|
|
647
|
+
if (error) {
|
|
648
|
+
const code = typeof error.code === "string" ? error.code : "unknown";
|
|
649
|
+
const message = typeof error.message === "string" ? error.message : code;
|
|
650
|
+
finish(() => reject(new MuxError(muxErrorKind(code), message, { wireCode: code, method })));
|
|
651
|
+
return;
|
|
652
|
+
}
|
|
653
|
+
finish(() => resolve(line.result));
|
|
654
|
+
},
|
|
655
|
+
() => finish(() => reject(new MuxError("protocol", `mux ${method} response line was oversized`, { method }))),
|
|
656
|
+
);
|
|
657
|
+
socket.on("error", (error: Error) =>
|
|
658
|
+
finish(() => reject(new MuxError("transport", `mux request ${method} failed: ${error.message}`, { method }))),
|
|
659
|
+
);
|
|
660
|
+
socket.on("close", () =>
|
|
661
|
+
finish(() => reject(new MuxError("transport", `mux request ${method} lost its connection`, { method }))),
|
|
662
|
+
);
|
|
663
|
+
socket.write(`${JSON.stringify({ id, method, params: callParams })}\n`, (error) => {
|
|
664
|
+
if (!error) return;
|
|
665
|
+
finish(() =>
|
|
666
|
+
reject(new MuxError("transport", `mux request ${method} failed to write: ${error.message}`, { method })),
|
|
667
|
+
);
|
|
668
|
+
});
|
|
669
|
+
});
|
|
670
|
+
reachable = true;
|
|
671
|
+
return result;
|
|
672
|
+
} catch (error) {
|
|
673
|
+
if (error instanceof MuxError && error.kind === "transport") reachable = false;
|
|
674
|
+
throw error;
|
|
675
|
+
}
|
|
676
|
+
};
|
|
677
|
+
|
|
678
|
+
const callObject = async (
|
|
679
|
+
method: string,
|
|
680
|
+
callParams: Record<string, unknown>,
|
|
681
|
+
timeoutMs?: number,
|
|
682
|
+
): Promise<Record<string, unknown>> => {
|
|
683
|
+
const result = asRecord(await call(method, callParams, timeoutMs));
|
|
684
|
+
if (!result) throw new MuxError("protocol", `mux ${method} returned a non-object result`, { method });
|
|
685
|
+
return result;
|
|
686
|
+
};
|
|
687
|
+
|
|
688
|
+
const snapshot = async (): Promise<MuxSnapshot> => {
|
|
689
|
+
const result = await callObject("session.snapshot", {});
|
|
690
|
+
const parsed = readSnapshot(result.snapshot);
|
|
691
|
+
snapshotCache = parsed;
|
|
692
|
+
serverInfo = parsed.server;
|
|
693
|
+
return parsed;
|
|
694
|
+
};
|
|
695
|
+
|
|
696
|
+
const subscribe = async (
|
|
697
|
+
kinds: ReadonlyArray<MuxEventKind>,
|
|
698
|
+
handler: (event: MuxEvent) => void,
|
|
699
|
+
subscribeOptions: MuxSubscribeOptions = {},
|
|
700
|
+
): Promise<MuxSubscription> => {
|
|
701
|
+
let closed = false;
|
|
702
|
+
let socket: net.Socket | null = null;
|
|
703
|
+
let retryTimer: NodeJS.Timeout | null = null;
|
|
704
|
+
let failures = 0;
|
|
705
|
+
|
|
706
|
+
const scheduleReopen = (): void => {
|
|
707
|
+
if (closed || disposed) return;
|
|
708
|
+
failures += 1;
|
|
709
|
+
const delay = delayFor(failures);
|
|
710
|
+
retryTimer = setTimeout(() => {
|
|
711
|
+
retryTimer = null;
|
|
712
|
+
void open(true);
|
|
713
|
+
}, delay);
|
|
714
|
+
retryTimer.unref?.();
|
|
715
|
+
};
|
|
716
|
+
|
|
717
|
+
const open = async (isReconnect: boolean): Promise<void> => {
|
|
718
|
+
if (closed || disposed) return;
|
|
719
|
+
let stream: net.Socket;
|
|
720
|
+
try {
|
|
721
|
+
stream = await connectSocket(socketPath, connectTimeoutMs);
|
|
722
|
+
} catch (error) {
|
|
723
|
+
log("debug", `mux event stream connect failed: ${error instanceof Error ? error.message : String(error)}`);
|
|
724
|
+
scheduleReopen();
|
|
725
|
+
return;
|
|
726
|
+
}
|
|
727
|
+
if (closed || disposed) {
|
|
728
|
+
stream.destroy();
|
|
729
|
+
return;
|
|
730
|
+
}
|
|
731
|
+
socket = stream;
|
|
732
|
+
let acknowledged = false;
|
|
733
|
+
readJsonLines(
|
|
734
|
+
stream,
|
|
735
|
+
(line) => {
|
|
736
|
+
if (!acknowledged && typeof line.id === "string") {
|
|
737
|
+
acknowledged = true;
|
|
738
|
+
failures = 0;
|
|
739
|
+
if (isReconnect) {
|
|
740
|
+
// Events dropped while the socket was down are gone. Take a
|
|
741
|
+
// fresh snapshot and let the caller rebuild from it.
|
|
742
|
+
void snapshot().then(
|
|
743
|
+
(fresh) => subscribeOptions.onResync?.(fresh),
|
|
744
|
+
(error) =>
|
|
745
|
+
log("debug", `mux snapshot re-bootstrap failed: ${error instanceof Error ? error.message : String(error)}`),
|
|
746
|
+
);
|
|
747
|
+
}
|
|
748
|
+
return;
|
|
749
|
+
}
|
|
750
|
+
const event = readEvent(line);
|
|
751
|
+
if (event) handler(event);
|
|
752
|
+
},
|
|
753
|
+
() => stream.destroy(),
|
|
754
|
+
);
|
|
755
|
+
const onGone = (): void => {
|
|
756
|
+
if (socket !== stream) return;
|
|
757
|
+
socket = null;
|
|
758
|
+
stream.destroy();
|
|
759
|
+
scheduleReopen();
|
|
760
|
+
};
|
|
761
|
+
stream.on("error", onGone);
|
|
762
|
+
stream.on("close", onGone);
|
|
763
|
+
stream.write(
|
|
764
|
+
`${JSON.stringify({
|
|
765
|
+
id: `clio-sub-${kinds.join("+")}`,
|
|
766
|
+
method: "events.subscribe",
|
|
767
|
+
params: { subscriptions: kinds.map((kind) => ({ type: kind })) },
|
|
768
|
+
})}\n`,
|
|
769
|
+
);
|
|
770
|
+
};
|
|
771
|
+
|
|
772
|
+
await open(false);
|
|
773
|
+
|
|
774
|
+
return {
|
|
775
|
+
close(): void {
|
|
776
|
+
closed = true;
|
|
777
|
+
if (retryTimer) clearTimeout(retryTimer);
|
|
778
|
+
retryTimer = null;
|
|
779
|
+
socket?.destroy();
|
|
780
|
+
socket = null;
|
|
781
|
+
},
|
|
782
|
+
};
|
|
783
|
+
};
|
|
784
|
+
|
|
785
|
+
return {
|
|
786
|
+
socketPath,
|
|
787
|
+
connected(): boolean {
|
|
788
|
+
return reachable;
|
|
789
|
+
},
|
|
790
|
+
server(): MuxServerInfo | null {
|
|
791
|
+
return serverInfo;
|
|
792
|
+
},
|
|
793
|
+
cachedSnapshot(): MuxSnapshot | null {
|
|
794
|
+
return snapshotCache;
|
|
795
|
+
},
|
|
796
|
+
async ping(pingOptions = {}): Promise<MuxServerInfo> {
|
|
797
|
+
const result = await callObject("ping", {}, pingOptions.timeoutMs);
|
|
798
|
+
const info = readServerInfo(result);
|
|
799
|
+
serverInfo = info;
|
|
800
|
+
return info;
|
|
801
|
+
},
|
|
802
|
+
snapshot,
|
|
803
|
+
async paneCurrent(callerPaneId?: string): Promise<MuxPane> {
|
|
804
|
+
const result = await callObject("pane.current", params({ caller_pane_id: callerPaneId }));
|
|
805
|
+
return readPane(result.pane);
|
|
806
|
+
},
|
|
807
|
+
async paneList(workspaceId?: string): Promise<ReadonlyArray<MuxPane>> {
|
|
808
|
+
const result = await callObject("pane.list", params({ workspace_id: workspaceId }));
|
|
809
|
+
return readArray(result, "panes").map(readPane);
|
|
810
|
+
},
|
|
811
|
+
async paneSplit(request: MuxSplitRequest): Promise<MuxPane> {
|
|
812
|
+
const result = await callObject(
|
|
813
|
+
"pane.split",
|
|
814
|
+
params({
|
|
815
|
+
direction: request.direction,
|
|
816
|
+
target_pane_id: request.targetPaneId,
|
|
817
|
+
workspace_id: request.workspaceId,
|
|
818
|
+
cwd: request.cwd,
|
|
819
|
+
env: request.env,
|
|
820
|
+
focus: request.focus ?? false,
|
|
821
|
+
ratio: request.ratio,
|
|
822
|
+
}),
|
|
823
|
+
);
|
|
824
|
+
return readPane(result.pane);
|
|
825
|
+
},
|
|
826
|
+
async paneRename(paneId: string, label: string): Promise<void> {
|
|
827
|
+
await call("pane.rename", { pane_id: paneId, label });
|
|
828
|
+
},
|
|
829
|
+
async paneClose(paneId: string): Promise<void> {
|
|
830
|
+
await call("pane.close", { pane_id: paneId });
|
|
831
|
+
},
|
|
832
|
+
async paneLayout(paneId?: string): Promise<MuxTabGeometry> {
|
|
833
|
+
const result = await callObject("pane.layout", params({ pane_id: paneId }));
|
|
834
|
+
return readTabGeometry(result.layout);
|
|
835
|
+
},
|
|
836
|
+
async paneFocus(paneId: string): Promise<void> {
|
|
837
|
+
await call("pane.focus", { pane_id: paneId });
|
|
838
|
+
},
|
|
839
|
+
async paneZoom(paneId: string, mode: "on" | "off" | "toggle"): Promise<{ changed: boolean; focusChanged: boolean }> {
|
|
840
|
+
const result = await callObject("pane.zoom", { pane_id: paneId, mode });
|
|
841
|
+
const zoom = asRecord(result.zoom);
|
|
842
|
+
if (!zoom) throw new MuxError("protocol", "mux pane.zoom returned no zoom result");
|
|
843
|
+
return { changed: zoom.changed === true, focusChanged: zoom.focus_changed === true };
|
|
844
|
+
},
|
|
845
|
+
async layoutExport(request = {}): Promise<MuxLayoutTree> {
|
|
846
|
+
const result = await callObject("layout.export", params({ tab_id: request.tabId, pane_id: request.paneId }));
|
|
847
|
+
return readLayoutTree(result.layout);
|
|
848
|
+
},
|
|
849
|
+
async layoutSetSplitRatio(request): Promise<MuxLayoutTree> {
|
|
850
|
+
const result = await callObject(
|
|
851
|
+
"layout.set_split_ratio",
|
|
852
|
+
params({ tab_id: request.tabId, pane_id: request.paneId, path: [...request.path], ratio: request.ratio }),
|
|
853
|
+
);
|
|
854
|
+
return readLayoutTree(result.layout);
|
|
855
|
+
},
|
|
856
|
+
async worktreeList(request = {}): Promise<MuxWorktreeListResult> {
|
|
857
|
+
const result = await callObject("worktree.list", params({ workspace_id: request.workspaceId, cwd: request.cwd }));
|
|
858
|
+
return { source: readWorktreeSource(result.source), worktrees: readArray(result, "worktrees").map(readWorktree) };
|
|
859
|
+
},
|
|
860
|
+
async worktreeCreate(request: MuxWorktreeCreateRequest): Promise<MuxWorktreeCreatedResult> {
|
|
861
|
+
const result = await callObject(
|
|
862
|
+
"worktree.create",
|
|
863
|
+
params({
|
|
864
|
+
workspace_id: request.workspaceId,
|
|
865
|
+
cwd: request.cwd,
|
|
866
|
+
branch: request.branch,
|
|
867
|
+
base: request.base,
|
|
868
|
+
path: request.path,
|
|
869
|
+
label: request.label,
|
|
870
|
+
focus: request.focus ?? false,
|
|
871
|
+
}),
|
|
872
|
+
);
|
|
873
|
+
const workspace = asRecord(result.workspace);
|
|
874
|
+
if (!workspace) throw new MuxError("protocol", "mux worktree.create returned no workspace");
|
|
875
|
+
return {
|
|
876
|
+
workspaceId: requireString(workspace, "workspace_id", "workspace"),
|
|
877
|
+
tab: readTab(result.tab),
|
|
878
|
+
rootPane: readPane(result.root_pane),
|
|
879
|
+
worktree: readWorktree(result.worktree),
|
|
880
|
+
};
|
|
881
|
+
},
|
|
882
|
+
async worktreeOpen(request: MuxWorktreeOpenRequest): Promise<MuxWorktreeOpenedResult> {
|
|
883
|
+
const result = await callObject(
|
|
884
|
+
"worktree.open",
|
|
885
|
+
params({
|
|
886
|
+
workspace_id: request.workspaceId,
|
|
887
|
+
cwd: request.cwd,
|
|
888
|
+
branch: request.branch,
|
|
889
|
+
path: request.path,
|
|
890
|
+
label: request.label,
|
|
891
|
+
focus: request.focus ?? false,
|
|
892
|
+
}),
|
|
893
|
+
);
|
|
894
|
+
const workspace = asRecord(result.workspace);
|
|
895
|
+
if (!workspace) throw new MuxError("protocol", "mux worktree.open returned no workspace");
|
|
896
|
+
return {
|
|
897
|
+
workspaceId: requireString(workspace, "workspace_id", "workspace"),
|
|
898
|
+
tab: readTab(result.tab),
|
|
899
|
+
rootPane: readPane(result.root_pane),
|
|
900
|
+
worktree: readWorktree(result.worktree),
|
|
901
|
+
alreadyOpen: result.already_open === true,
|
|
902
|
+
};
|
|
903
|
+
},
|
|
904
|
+
async worktreeRemove(workspaceId: string, removeOptions = {}): Promise<MuxWorktreeRemovedResult> {
|
|
905
|
+
const result = await callObject("worktree.remove", {
|
|
906
|
+
workspace_id: workspaceId,
|
|
907
|
+
force: removeOptions.force ?? false,
|
|
908
|
+
});
|
|
909
|
+
return {
|
|
910
|
+
workspaceId: requireString(result, "workspace_id", "worktree.remove"),
|
|
911
|
+
path: requireString(result, "path", "worktree.remove"),
|
|
912
|
+
forced: result.forced === true,
|
|
913
|
+
};
|
|
914
|
+
},
|
|
915
|
+
async paneSendText(paneId: string, text: string): Promise<void> {
|
|
916
|
+
await call("pane.send_text", { pane_id: paneId, text });
|
|
917
|
+
},
|
|
918
|
+
async paneReportAgent(request: MuxReportAgentRequest): Promise<void> {
|
|
919
|
+
await call(
|
|
920
|
+
"pane.report_agent",
|
|
921
|
+
params({
|
|
922
|
+
pane_id: request.paneId,
|
|
923
|
+
source: request.source,
|
|
924
|
+
agent: request.agent,
|
|
925
|
+
state: request.state,
|
|
926
|
+
message: request.message,
|
|
927
|
+
}),
|
|
928
|
+
);
|
|
929
|
+
},
|
|
930
|
+
async paneReportMetadata(request: MuxReportMetadataRequest): Promise<void> {
|
|
931
|
+
await call(
|
|
932
|
+
"pane.report_metadata",
|
|
933
|
+
params({
|
|
934
|
+
pane_id: request.paneId,
|
|
935
|
+
source: request.source,
|
|
936
|
+
agent: request.agent,
|
|
937
|
+
title: request.title,
|
|
938
|
+
display_agent: request.displayAgent,
|
|
939
|
+
tokens: request.tokens,
|
|
940
|
+
state_labels: request.stateLabels,
|
|
941
|
+
ttl_ms: request.ttlMs,
|
|
942
|
+
}),
|
|
943
|
+
);
|
|
944
|
+
},
|
|
945
|
+
async notificationShow(request: MuxNotificationRequest): Promise<MuxNotificationResult> {
|
|
946
|
+
const result = await callObject(
|
|
947
|
+
"notification.show",
|
|
948
|
+
params({ title: request.title, body: request.body, sound: request.sound }),
|
|
949
|
+
);
|
|
950
|
+
// `reason` is required on the wire, but a server that grows a new one
|
|
951
|
+
// must not turn a painted toast into a protocol error, so an unreadable
|
|
952
|
+
// reason degrades to the shown flag alone.
|
|
953
|
+
return {
|
|
954
|
+
shown: result.shown === true,
|
|
955
|
+
reason: optionalString(result, "reason") ?? (result.shown === true ? "shown" : "unknown"),
|
|
956
|
+
};
|
|
957
|
+
},
|
|
958
|
+
subscribe,
|
|
959
|
+
async close(): Promise<void> {
|
|
960
|
+
disposed = true;
|
|
961
|
+
reachable = false;
|
|
962
|
+
},
|
|
963
|
+
};
|
|
964
|
+
}
|