@iowarp/clio-coder 0.3.8 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +102 -0
- package/NOTICE +33 -0
- package/README.md +12 -3
- package/dist/{acp-U67UHUK2.js → acp-G5WJBNCT.js} +13 -12
- package/dist/{agents-YU6SGALZ.js → agents-FMV2Q5G4.js} +41 -36
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-5ZPJOIVG.js → auth-3IDSJEIK.js} +18 -18
- package/dist/{builtins-C6JMZVV6.js → builtins-XCZWXSC7.js} +5 -5
- package/dist/{chunk-IFBNV6H6.js → chunk-2ANTL7MR.js} +3 -3
- package/dist/{chunk-5FR74PWO.js → chunk-2JDWVJND.js} +2 -2
- package/dist/{chunk-XWSF374K.js → chunk-2OQE55CK.js} +3 -3
- package/dist/{chunk-5H3GB5BO.js → chunk-32KWKNSF.js} +8 -384
- package/dist/{chunk-KTYTFRMB.js → chunk-36EJLSQQ.js} +34 -36
- package/dist/{chunk-FHJEP5SW.js → chunk-3BT2XMV4.js} +19 -13
- package/dist/chunk-3DPEIQKN.js +113 -0
- package/dist/{chunk-GU2UIAFZ.js → chunk-3URVFKWK.js} +7 -7
- package/dist/{chunk-WEH5XRJQ.js → chunk-3XML7CDN.js} +3 -3
- package/dist/chunk-42FMPA75.js +101 -0
- package/dist/{chunk-A2NJGIB3.js → chunk-5LXZXPKX.js} +2 -2
- package/dist/{chunk-VCBR6CU7.js → chunk-5PSMVOLM.js} +2 -2
- package/dist/{chunk-NMPKI6XL.js → chunk-6DB53AJS.js} +203 -25
- package/dist/{chunk-3BINW3FP.js → chunk-76ONBSIA.js} +2 -2
- package/dist/{chunk-26LEYJZH.js → chunk-7MCTRUCE.js} +2 -2
- package/dist/{chunk-TYPGUK6W.js → chunk-AB44T6BB.js} +111 -5
- package/dist/{chunk-K4XHGFR5.js → chunk-B7OBL7PK.js} +317 -721
- package/dist/{chunk-B5CSFE7B.js → chunk-BBVJUZHB.js} +2 -2
- package/dist/{chunk-EQ63NRB7.js → chunk-BBVYXMFO.js} +2 -2
- package/dist/{chunk-ZVJ5BLO2.js → chunk-BKFJHQCA.js} +154 -16
- package/dist/chunk-BKFM6EJV.js +462 -0
- package/dist/chunk-BMS5RKQY.js +27 -0
- package/dist/{chunk-ZNLWCMVZ.js → chunk-BPKCPIL7.js} +2 -2
- package/dist/{chunk-TLQJPP24.js → chunk-BUMFYQFY.js} +1394 -1349
- package/dist/{chunk-BNAZZHFG.js → chunk-BYP5D4HI.js} +1 -1
- package/dist/chunk-C2LTL2W6.js +2447 -0
- package/dist/{chunk-ME6CCNFO.js → chunk-CODPRO7Q.js} +8 -8
- package/dist/{chunk-E77JEWSD.js → chunk-CTJ4RNAA.js} +7 -37
- package/dist/{chunk-ODFEOB4F.js → chunk-CY6FY24N.js} +26 -8
- package/dist/{chunk-7RFXX52T.js → chunk-DQITNCXG.js} +642 -172
- package/dist/{chunk-TTHACPOM.js → chunk-DYJP44XW.js} +578 -117
- package/dist/{chunk-2HFZQUHL.js → chunk-F4CKPOEQ.js} +18 -8
- package/dist/{chunk-DGSYXYMX.js → chunk-FEFIFZTL.js} +3 -3
- package/dist/{chunk-GWS3VEIW.js → chunk-FWDFM5ZU.js} +24 -3
- package/dist/{chunk-MV3K5QF2.js → chunk-GCSMB2KY.js} +2 -2
- package/dist/chunk-GKF55TAZ.js +391 -0
- package/dist/{chunk-VWZOAB7K.js → chunk-GR5G2PVF.js} +9 -8
- package/dist/{chunk-4DGYLA73.js → chunk-GXNLGKAB.js} +80 -9
- package/dist/chunk-HHV2GANA.js +88 -0
- package/dist/{chunk-IIZWH4XA.js → chunk-HI63TFOG.js} +5 -4
- package/dist/{chunk-WLFILSD5.js → chunk-HJJTYUHX.js} +113 -83
- package/dist/{chunk-TT36MB5S.js → chunk-HLW2MRKE.js} +3 -1
- package/dist/{chunk-PMDBGQSJ.js → chunk-HWHKMHUA.js} +7 -7
- package/dist/chunk-HZHHCK24.js +1631 -0
- package/dist/{chunk-WSB3FPX7.js → chunk-I5VEOC6I.js} +39 -143
- package/dist/chunk-IBEBSCYA.js +564 -0
- package/dist/chunk-IQ7KR472.js +362 -0
- package/dist/{chunk-A3WNZD3P.js → chunk-J4W7KFM7.js} +949 -972
- package/dist/{chunk-TB5666IT.js → chunk-JDG2WCRO.js} +5 -5
- package/dist/{chunk-N22QMJKY.js → chunk-K5C3NCBD.js} +4 -4
- package/dist/{chunk-CGKSTWHD.js → chunk-K6BSR66V.js} +2 -1
- package/dist/{chunk-5C3AQNDW.js → chunk-KFZI4NIL.js} +216 -38
- package/dist/chunk-KMVISBZR.js +132 -0
- package/dist/{chunk-WXY7KU3G.js → chunk-LDQ2ZF2M.js} +2 -2
- package/dist/{chunk-XN3L4EYL.js → chunk-LQ3DZAMX.js} +3 -3
- package/dist/{chunk-U6MBIEMB.js → chunk-LY4S7GJC.js} +173 -144
- package/dist/{chunk-4SPRNWDE.js → chunk-MLKNTWH2.js} +19 -19
- package/dist/{chunk-MVVUPGPW.js → chunk-MXHC5QYU.js} +6 -6
- package/dist/chunk-NEKRRTYW.js +56 -0
- package/dist/{chunk-SPULKLCF.js → chunk-NHCZP4K7.js} +3 -3
- package/dist/chunk-NHLBIGRH.js +1506 -0
- package/dist/chunk-NQQH3YT7.js +302 -0
- package/dist/chunk-NYS75XW5.js +15 -0
- package/dist/{chunk-GN57SG4G.js → chunk-O4XIVISU.js} +10 -8
- package/dist/{chunk-EMYUUSFG.js → chunk-O6TL7WWY.js} +6 -6
- package/dist/chunk-OQBA45DZ.js +97 -0
- package/dist/{chunk-LU7P4LHA.js → chunk-P3FOHJT4.js} +2 -2
- package/dist/chunk-PMZCIOCJ.js +25 -0
- package/dist/{chunk-I4HZDVNP.js → chunk-PQEFIJ36.js} +2 -2
- package/dist/{chunk-J3YUBZWY.js → chunk-QBJA7R7N.js} +62 -6
- package/dist/chunk-QDC3K2U3.js +262 -0
- package/dist/{chunk-2HEJ2F35.js → chunk-QLFS5GO2.js} +22 -10
- package/dist/{chunk-7RGZWPB6.js → chunk-QLL7ILRG.js} +95 -32
- package/dist/{chunk-YS5VLNH5.js → chunk-QREDIESB.js} +6 -6
- package/dist/chunk-QSNYB6ZV.js +195 -0
- package/dist/{chunk-GOXNB3AO.js → chunk-RAPCMZL4.js} +75 -4
- package/dist/chunk-RKKLTLYB.js +45 -0
- package/dist/{chunk-P43ETTHK.js → chunk-SJ5ZKQ4S.js} +2 -2
- package/dist/{chunk-GPIEI3LY.js → chunk-SP2RXXYO.js} +6 -54
- package/dist/chunk-SUCTJL45.js +45 -0
- package/dist/{chunk-DYIM5TJT.js → chunk-SUW5DORT.js} +263 -7
- package/dist/chunk-T56WDKA5.js +183 -0
- package/dist/chunk-TVHHYFHE.js +255 -0
- package/dist/{chunk-FJ3H4MN5.js → chunk-TZ3SGWZZ.js} +3 -3
- package/dist/{chunk-MXKJU4JB.js → chunk-U77AMWDL.js} +91 -10
- package/dist/{chunk-5DHKRSMQ.js → chunk-ULC6OTWO.js} +11 -7
- package/dist/{chunk-RWSI4YD7.js → chunk-UM7N4G5A.js} +33 -12
- package/dist/{chunk-FCSXB6T2.js → chunk-UOSL25KY.js} +14 -2
- package/dist/{chunk-IGWKHNIQ.js → chunk-UXMFQ54G.js} +44 -37
- package/dist/{chunk-HFSBBKSQ.js → chunk-V5DHCITQ.js} +171 -3
- package/dist/{chunk-5WIGXA4T.js → chunk-VAZSBTKF.js} +111 -4
- package/dist/{chunk-VHN4MY6O.js → chunk-VEO4AP2K.js} +2 -2
- package/dist/{chunk-IJ7RPIYJ.js → chunk-VFA6GDY5.js} +65 -4
- package/dist/{chunk-PT7HYKEM.js → chunk-VO2LKSTM.js} +2 -2
- package/dist/chunk-VO67MWHC.js +75 -0
- package/dist/{chunk-XK56QHLX.js → chunk-VPKWYKEY.js} +19 -5
- package/dist/{chunk-TANS5ZJS.js → chunk-VYMXRQI6.js} +36 -22
- package/dist/{chunk-WWCZ5F23.js → chunk-W5VSYASO.js} +77 -16
- package/dist/{chunk-WNIJTQQK.js → chunk-WZR7K7ZX.js} +72 -116
- package/dist/{chunk-5Q2VVUKB.js → chunk-X3YGUTOB.js} +4 -4
- package/dist/chunk-X75E3D2N.js +686 -0
- package/dist/{chunk-VAWNZU7Z.js → chunk-YDFRH54B.js} +4 -4
- package/dist/chunk-YJX4SHTD.js +40 -0
- package/dist/{chunk-ZI647VB5.js → chunk-YPI3QQCF.js} +2 -2
- package/dist/chunk-Z2RR6MAK.js +127 -0
- package/dist/{chunk-FBVTI2TJ.js → chunk-Z4TXYIEG.js} +12 -131
- package/dist/cli/index.js +47 -36
- package/dist/{clio-QVTYJ57A.js → clio-2JXHBBY5.js} +7 -7
- package/dist/{code-nav-FGGFIE7L.js → code-nav-3YYRMYNF.js} +8 -8
- package/dist/{compile-cache-CVJMMODC.js → compile-cache-7FPE6PS3.js} +3 -3
- package/dist/{components-ZFA3SAER.js → components-RYZV4JGP.js} +5 -5
- package/dist/{config-LW5IJFQN.js → config-QZPCMYSO.js} +99 -63
- package/dist/{configure-7XIZCOU4.js → configure-TEGEBYCA.js} +23 -22
- package/dist/{context-Y6Y7QPR6.js → context-AV7OEZ4D.js} +12 -12
- package/dist/{context-L3WL3X7K.js → context-E6H5RNMC.js} +56 -47
- package/dist/{context-N52ZA626.js → context-GSXUE4CT.js} +29 -27
- package/dist/{context-clear-MBQRLSDQ.js → context-clear-SHIBYK6T.js} +55 -46
- package/dist/{context-index-HVMFQHK3.js → context-index-HNG3MOME.js} +2 -2
- package/dist/{context-working-set-GS6DSO7F.js → context-working-set-5ZGKPGZQ.js} +13 -13
- package/dist/{dispatch-runner-22ZCNOM3.js → dispatch-runner-EFMJT4LD.js} +93 -64
- package/dist/{docs-7LQ23DLM.js → docs-23KQS3XK.js} +5 -5
- package/dist/doctor-QOA5FNY5.js +313 -0
- package/dist/{eval-BEC2WHDA.js → eval-TFBYQH4H.js} +2032 -156
- package/dist/eval-inventory-SXH7PDKX.js +316 -0
- package/dist/{evidence-REJUMSKM.js → evidence-ERGESKGN.js} +203 -48
- package/dist/{evolve-PY5ZBA5K.js → evolve-VDXTSYCJ.js} +52 -43
- package/dist/{extensions-HVKU65YU.js → extensions-7BGBHN57.js} +13 -7
- package/dist/{fleet-7WZEWRFA.js → fleet-2RRVDF2V.js} +228 -108
- package/dist/{fleet-commands-UVHWM76J.js → fleet-commands-VJ726XIA.js} +11 -11
- package/dist/fleet-decisions-EPAPM3XJ.js +157 -0
- package/dist/{fleet-graph-6ULH7PES.js → fleet-graph-JF5QOATM.js} +18 -15
- package/dist/fleet-inspect-VLY4S7QM.js +442 -0
- package/dist/{fleet-preflight-J53T6CCE.js → fleet-preflight-AIZUEJOY.js} +5 -5
- package/dist/{fleet-validate-72PC4SLA.js → fleet-validate-AJRPDMDV.js} +22 -19
- package/dist/fleet-verify-JFEL2L3H.js +175 -0
- package/dist/fleet-view-ZCON35AG.js +102 -0
- package/dist/{init-OG3TPGQG.js → init-DN2WWLFE.js} +72 -62
- package/dist/install-XGLBQY5E.js +13 -0
- package/dist/interop-OZBKXAYL.js +114 -0
- package/dist/{library-CNTMPLRF.js → library-YWZG7IMW.js} +21 -18
- package/dist/{memory-6IS7F275.js → memory-I4C4HMLW.js} +54 -45
- package/dist/{models-ENRJDA5W.js → models-CEYXJBO6.js} +33 -30
- package/dist/{monitor-XLDVO7TN.js → monitor-NZ6GCI3P.js} +59 -52
- package/dist/{orchestrator-6KSPYRHA.js → orchestrator-GCGQ4N5I.js} +7827 -7328
- package/dist/panes-HMABYVO4.js +58 -0
- package/dist/panes-KY6W3V2E.js +103 -0
- package/dist/{paths-DBXMZMDU.js → paths-II4K7DNR.js} +5 -5
- package/dist/{reset-RZ4ER727.js → reset-DQ6FGCSH.js} +13 -11
- package/dist/resources-BB3MVJMD.js +111 -0
- package/dist/{run-Y2CNK5RU.js → run-H2GQDUER.js} +119 -87
- package/dist/{share-A55GYP6Z.js → share-GTJN6A5O.js} +20 -17
- package/dist/{skills-ALC5J6AT.js → skills-L55TEW6R.js} +33 -24
- package/dist/{skills-eval-JPBEBYQU.js → skills-eval-XVXPH2JI.js} +67 -56
- package/dist/skills-inventory-S4MXPJFV.js +126 -0
- package/dist/slash-commands-ZSGASKJC.js +77 -0
- package/dist/{steer-GGWFUJUD.js → steer-RZGSCY4R.js} +4 -4
- package/dist/{support-MIETYA5E.js → support-PKEUNNQL.js} +6 -6
- package/dist/{targets-VGNXIR3S.js → targets-NCPZ644J.js} +68 -40
- package/dist/{terminal-lease-WOBR64YA.js → terminal-lease-44SV3YCN.js} +6 -4
- package/dist/tools-DAF3DI3C.js +27 -0
- package/dist/{trace-PNCASAXC.js → trace-FYVW2MQA.js} +207 -10
- package/dist/tui-primitives-2AKXQNZK.js +13 -0
- package/dist/{uninstall-ZJF5H5ZN.js → uninstall-DW2PNOIC.js} +5 -5
- package/dist/{upgrade-FUSUAGHR.js → upgrade-3XPP6OQL.js} +27 -24
- package/dist/{usage-N4MKVHKD.js → usage-3NLHGTU2.js} +114 -62
- package/dist/{verifiers-YAWOJ3H2.js → verifiers-SSQONKRT.js} +172 -13
- package/dist/{verify-LTDHYBGY.js → verify-3U6J7FZI.js} +10 -10
- package/dist/{web-fetch-2YHJ3KTG.js → web-fetch-S7RR6GZ7.js} +3 -3
- package/dist/{wiki-generate-6M7GHTBJ.js → wiki-generate-CEHYGPGQ.js} +75 -65
- package/dist/with-panes-MKB46MPQ.js +782 -0
- package/dist/worker/entry.js +106 -75
- package/docs/README.md +3 -2
- package/docs/acp.md +24 -3
- package/docs/alcf-provider.md +1 -1
- package/docs/architecture.md +2 -2
- package/docs/artifact-versions.md +9 -1
- package/docs/built-in-agents.md +1 -1
- package/docs/capacity-and-scheduling.md +62 -3
- package/docs/commands-and-modes.md +31 -2
- package/docs/configuration-and-targets.md +69 -12
- package/docs/context-engine.md +63 -4
- package/docs/development-pipeline.md +19 -0
- package/docs/dispatch-typed-intent.md +385 -0
- package/docs/documentation-coverage.md +5 -5
- package/docs/documentation-guide.md +1 -1
- package/docs/environment-variables.md +3 -0
- package/docs/eval-runner.md +262 -11
- package/docs/evals-internal.md +72 -2
- package/docs/evidence-and-memory.md +12 -11
- package/docs/evolution.md +1 -1
- package/docs/exit-codes-and-output.md +1 -1
- package/docs/extensions-and-sharing.md +27 -1
- package/docs/fleet-dispatch.md +25 -4
- package/docs/installation-and-lifecycle.md +15 -2
- package/docs/middleware-and-components.md +1 -1
- package/docs/model-catalog.md +10 -1
- package/docs/observability.md +55 -4
- package/docs/proactive-memory.md +127 -14
- package/docs/prompt-envelope-and-tools.md +19 -1
- package/docs/provider-adapter-cookbook.md +1 -1
- package/docs/release-cut-checklist.md +19 -3
- 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 +1 -1
- package/docs/troubleshooting.md +88 -1
- package/docs/tui-design.md +1 -1
- package/docs/worker-dispatch-mechanics.md +1 -1
- package/package.json +5 -2
- package/src/cli/acp.ts +6 -2
- package/src/cli/agents.ts +1 -1
- package/src/cli/argv.ts +25 -0
- package/src/cli/config-inspect.ts +33 -6
- package/src/cli/config.ts +1 -1
- package/src/cli/configure.ts +23 -21
- package/src/cli/doctor-panes.ts +124 -0
- package/src/cli/doctor-state-size.ts +82 -0
- package/src/cli/doctor-toolchain.ts +57 -0
- package/src/cli/doctor.ts +22 -1
- package/src/cli/eval-inventory.ts +436 -0
- package/src/cli/eval.ts +93 -16
- 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/extensions.ts +5 -1
- package/src/cli/fleet-decisions.ts +69 -0
- package/src/cli/fleet-inspect.ts +334 -0
- package/src/cli/fleet-verify.ts +133 -0
- package/src/cli/fleet-view.ts +810 -0
- package/src/cli/fleet.ts +179 -39
- 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/panes.ts +35 -0
- package/src/cli/reset.ts +5 -2
- package/src/cli/run.ts +58 -0
- package/src/cli/skills-inventory.ts +185 -0
- package/src/cli/skills.ts +16 -13
- package/src/cli/targets.ts +44 -13
- package/src/cli/tools.ts +321 -0
- package/src/cli/trace-inspect.ts +252 -0
- package/src/cli/trace.ts +85 -5
- package/src/cli/usage.ts +63 -14
- package/src/cli/verifiers-inspect.ts +347 -0
- package/src/cli/verifiers.ts +9 -0
- package/src/core/bus-events.ts +33 -1
- package/src/core/cache-telemetry.ts +42 -0
- package/src/core/config.ts +67 -0
- package/src/core/defaults.ts +124 -8
- package/src/core/endpoint-key.ts +27 -0
- package/src/core/residency-target-key.ts +25 -0
- package/src/core/response-schema.ts +80 -6
- package/src/core/theme-token-hex.ts +43 -0
- package/src/core/tool-names.ts +2 -1
- package/src/core/xdg.ts +1 -1
- package/src/domains/agents/fleets/build-review.md +0 -3
- package/src/domains/agents/fleets/build-test.md +0 -3
- package/src/domains/agents/result-contract-filesystem.ts +32 -0
- package/src/domains/agents/result-contract.ts +164 -35
- package/src/domains/config/classify.ts +6 -0
- package/src/domains/context/codewiki/coordinator.ts +12 -4
- package/src/domains/dispatch/admission-error.ts +9 -0
- package/src/domains/dispatch/admission.ts +52 -14
- package/src/domains/dispatch/capacity-lease.ts +118 -9
- package/src/domains/dispatch/contract.ts +11 -0
- package/src/domains/dispatch/council-topology.ts +398 -0
- package/src/domains/dispatch/execution-plan.ts +44 -4
- package/src/domains/dispatch/extension.ts +378 -82
- package/src/domains/dispatch/fleet-node-prompt.ts +62 -0
- package/src/domains/dispatch/fleet-plan.ts +7 -2
- package/src/domains/dispatch/fleet-run.ts +87 -4
- package/src/domains/dispatch/gate-decisions.ts +11 -1
- package/src/domains/dispatch/gate-role-prompts.ts +9 -0
- package/src/domains/dispatch/gate-topology.ts +289 -0
- package/src/domains/dispatch/heartbeat.ts +32 -8
- package/src/domains/dispatch/index.ts +22 -0
- package/src/domains/dispatch/intent-compatibility.ts +330 -0
- package/src/domains/dispatch/intent.ts +85 -1
- package/src/domains/dispatch/orphan-recovery.ts +5 -0
- package/src/domains/dispatch/reservation-store.ts +139 -11
- package/src/domains/dispatch/run-event-journal-bridge.ts +149 -0
- package/src/domains/dispatch/run-event-journal.ts +598 -0
- package/src/domains/dispatch/state.ts +49 -1
- package/src/domains/dispatch/types.ts +13 -0
- package/src/domains/dispatch/validation.ts +33 -8
- package/src/domains/dispatch/worker-spawn.ts +25 -11
- package/src/domains/dispatch/write-boundary-enforcer.ts +20 -3
- package/src/domains/dispatch/write-boundary.ts +62 -1
- package/src/domains/eval/artifacts/store.ts +62 -0
- package/src/domains/eval/compare/behavioral.ts +224 -0
- package/src/domains/eval/compare/compare.ts +342 -2
- package/src/domains/eval/compare/envelope.ts +128 -0
- package/src/domains/eval/compare/gates.ts +24 -6
- package/src/domains/eval/compare/thresholds.ts +30 -3
- package/src/domains/eval/execution-provenance.ts +240 -0
- package/src/domains/eval/inventory.ts +113 -0
- package/src/domains/eval/metrics/aggregate.ts +136 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +112 -0
- package/src/domains/eval/metrics/tracked.ts +413 -0
- package/src/domains/eval/provenance.ts +117 -0
- package/src/domains/eval/reports/comparison.ts +128 -0
- package/src/domains/eval/reports/junit.ts +17 -3
- package/src/domains/eval/reports/markdown.ts +3 -3
- package/src/domains/eval/reports/text.ts +14 -0
- package/src/domains/eval/run-compare.ts +20 -0
- package/src/domains/eval/runners/clio-run.ts +127 -0
- package/src/domains/eval/runners/external-command.ts +28 -3
- package/src/domains/eval/schema/adapter.ts +111 -0
- package/src/domains/eval/schema/artifact.ts +20 -0
- package/src/domains/eval/schema/behavioral-metrics.ts +204 -0
- package/src/domains/eval/schema/behavioral.ts +520 -0
- package/src/domains/eval/schema/execution-envelope.ts +194 -0
- package/src/domains/eval/schema/serving.ts +105 -0
- package/src/domains/eval/schema/suite.ts +38 -8
- package/src/domains/eval/schema/validate.ts +58 -3
- package/src/domains/eval/schema/verdict.ts +237 -0
- package/src/domains/eval/suites/resolve.ts +2 -0
- package/src/domains/eval/suites/run.ts +264 -33
- package/src/domains/eval/verifiers/command.ts +2 -1
- package/src/domains/eval/workspaces/temp-copy.ts +145 -13
- package/src/domains/evidence/build.ts +2 -13
- package/src/domains/evidence/eval.ts +2 -12
- package/src/domains/evidence/findings-markdown.ts +33 -0
- package/src/domains/evidence/run-trust.ts +7 -113
- package/src/domains/evidence/store.ts +6 -0
- package/src/domains/evidence/trust-projection.ts +2 -2
- package/src/domains/extensions/compatibility.ts +285 -0
- package/src/domains/extensions/discovery.ts +38 -3
- package/src/domains/extensions/resources.ts +1 -1
- package/src/domains/extensions/state.ts +12 -3
- package/src/domains/extensions/types.ts +2 -0
- package/src/domains/lifecycle/doctor.ts +69 -1
- package/src/domains/memory/index.ts +14 -1
- package/src/domains/memory/task-bank-promotion.ts +64 -0
- package/src/domains/memory/task-memory-policy.ts +82 -17
- package/src/domains/memory/task-memory-spend.ts +131 -0
- package/src/domains/memory/task-memory-status.ts +7 -0
- package/src/domains/memory/task-memory-telemetry.ts +3 -0
- package/src/domains/middleware/index.ts +1 -0
- package/src/domains/middleware/memory-intervention.ts +97 -21
- package/src/domains/middleware/memory-step-endpoint.ts +71 -0
- package/src/domains/mux/contract.ts +434 -0
- package/src/domains/mux/detect.ts +158 -0
- package/src/domains/mux/extension.ts +47 -0
- package/src/domains/mux/index.ts +96 -0
- package/src/domains/mux/manifest.ts +6 -0
- package/src/domains/mux/operations.ts +164 -0
- package/src/domains/mux/pane-registry.ts +90 -0
- package/src/domains/mux/protocol.ts +49 -0
- package/src/domains/mux/socket-client.ts +816 -0
- package/src/domains/mux/types.ts +222 -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 +180 -0
- package/src/domains/mux/yazi/profile.ts +299 -0
- package/src/domains/mux/yazi/session.ts +228 -0
- package/src/domains/mux/yazi/theme.ts +30 -0
- package/src/domains/observability/background-memory-usage.ts +140 -0
- package/src/domains/observability/cost.ts +22 -1
- package/src/domains/observability/index.ts +9 -0
- package/src/domains/observability/out-of-turn-usage.ts +51 -2
- package/src/domains/observability/trace-store.ts +234 -2
- package/src/domains/prompts/compiler.ts +100 -13
- package/src/domains/providers/endpoint-capacity.ts +228 -0
- package/src/domains/providers/endpoint-slots-store.ts +189 -0
- package/src/domains/providers/extension.ts +20 -3
- package/src/domains/providers/index.ts +32 -0
- package/src/domains/providers/model-runtime-capabilities.ts +32 -0
- package/src/domains/providers/models/local-models/clio-local-coding-targets.yaml +243 -1
- package/src/domains/providers/runtime-resolution.ts +8 -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/common/probe-helpers.ts +31 -9
- package/src/domains/providers/runtimes/local-native/llamacpp-anthropic.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-completion.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-embed.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp-rerank.ts +1 -1
- package/src/domains/providers/runtimes/local-native/llamacpp.ts +4 -1
- package/src/domains/providers/runtimes/local-native/lmstudio.ts +4 -1
- package/src/domains/providers/runtimes/local-native/ollama-native.ts +6 -1
- package/src/domains/providers/runtimes/protocol/litellm.ts +375 -0
- package/src/domains/providers/support.ts +1 -0
- package/src/domains/providers/target-model-cache.ts +124 -0
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/target-descriptor.ts +2 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/prompts/loader.ts +95 -33
- package/src/domains/resources/skills/loader.ts +33 -0
- package/src/domains/safety/action-classifier.ts +6 -0
- package/src/domains/safety/call-target.ts +52 -0
- package/src/domains/safety/run-effects.ts +35 -4
- package/src/domains/session/context-accounting.ts +52 -1
- package/src/domains/session/context-ledger.ts +37 -13
- package/src/domains/session/index.ts +6 -0
- package/src/domains/session/prompt-cache.ts +140 -0
- package/src/domains/session/prompt-manifest.ts +42 -0
- 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 +18 -3
- package/src/engine/acp/server.ts +413 -70
- package/src/engine/acp/types.ts +19 -1
- package/src/engine/ai.ts +35 -0
- package/src/engine/apis/llamacpp-residency.ts +55 -3
- package/src/engine/apis/lmstudio.ts +25 -5
- package/src/engine/apis/ollama-native.ts +2 -1
- package/src/engine/apis/openai-completions.ts +80 -17
- package/src/engine/apis/residency-lock.ts +3 -1
- package/src/engine/apis/residency.ts +34 -1
- package/src/engine/claude/sdk-module.ts +98 -0
- package/src/engine/claude/sdk-runtime.ts +19 -11
- package/src/engine/provider-payload.ts +29 -1
- package/src/engine/tui-primitives.ts +21 -0
- package/src/engine/tui.ts +1 -0
- package/src/engine/worker-runtime.ts +2 -13
- package/src/entry/boot-options.ts +2 -0
- package/src/entry/orchestrator.ts +279 -35
- package/src/entry/panes-activation.ts +31 -0
- package/src/entry/with-panes.ts +20 -0
- package/src/interactive/chat-loop-messages.ts +26 -7
- package/src/interactive/chat-loop.ts +318 -41
- package/src/interactive/chat-panel.ts +62 -8
- package/src/interactive/clio-editor.ts +45 -8
- package/src/interactive/context-activity.ts +5 -1
- package/src/interactive/context-meter.ts +1 -1
- package/src/interactive/context-overlay.ts +41 -10
- package/src/interactive/cost-overlay.ts +66 -6
- package/src/interactive/council-grid.ts +1 -3
- package/src/interactive/council.ts +11 -0
- package/src/interactive/dispatch-board.ts +102 -20
- package/src/interactive/fleet-run-preview.ts +41 -15
- package/src/interactive/handoff-round.ts +41 -2
- package/src/interactive/interactive-application.ts +177 -7
- package/src/interactive/interactive-input-runtime.ts +15 -0
- package/src/interactive/interactive-presentation.ts +4 -0
- package/src/interactive/interactive-shell.ts +20 -17
- package/src/interactive/interactive-slash-runtime.ts +63 -10
- package/src/interactive/memory-overlay.ts +9 -0
- package/src/interactive/modal-marker.ts +170 -0
- package/src/interactive/mutation-preview.ts +295 -0
- package/src/interactive/mux-bridge.ts +214 -0
- package/src/interactive/overlay-frame.ts +58 -2
- package/src/interactive/overlay-general-openers.ts +17 -0
- package/src/interactive/overlay-key-routing.ts +52 -3
- package/src/interactive/overlay-lifecycle.ts +56 -7
- package/src/interactive/overlay-model-selectors.ts +40 -3
- package/src/interactive/overlay-permission-lifecycle.ts +112 -24
- package/src/interactive/overlay-session-lifecycle.ts +73 -9
- package/src/interactive/overlay-transitions.ts +18 -4
- package/src/interactive/overlays/agents.ts +1 -0
- package/src/interactive/overlays/ask-user.ts +227 -49
- package/src/interactive/overlays/auth-dialog.ts +1 -0
- package/src/interactive/overlays/context-reset.ts +1 -0
- package/src/interactive/overlays/cwd-fallback.ts +1 -0
- package/src/interactive/overlays/decisions.ts +11 -11
- package/src/interactive/overlays/extensions.ts +1 -0
- package/src/interactive/overlays/fleet-run-approval.ts +1 -0
- package/src/interactive/overlays/handoff-review.ts +1 -0
- package/src/interactive/overlays/help-reference.ts +6 -0
- package/src/interactive/overlays/interop.ts +1 -0
- package/src/interactive/overlays/library-install-confirm.ts +1 -0
- 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 +1 -0
- package/src/interactive/overlays/model-scope.ts +86 -0
- package/src/interactive/overlays/model-selector.ts +1 -0
- package/src/interactive/overlays/prompts.ts +12 -1
- package/src/interactive/overlays/session-selector.ts +1 -0
- package/src/interactive/overlays/settings-sections.ts +30 -0
- package/src/interactive/overlays/settings.ts +614 -45
- package/src/interactive/overlays/side-question.ts +1 -0
- package/src/interactive/overlays/skills-hub.ts +3 -11
- package/src/interactive/overlays/tree-selector.ts +1 -0
- package/src/interactive/pane-policy.ts +46 -0
- package/src/interactive/panes-runtime.ts +292 -0
- package/src/interactive/permission-hint.ts +34 -2
- package/src/interactive/permission-overlay.ts +159 -9
- package/src/interactive/prewarm.ts +197 -0
- package/src/interactive/render-trace.ts +162 -15
- package/src/interactive/renderers/compaction-summary.ts +29 -0
- package/src/interactive/renderers/tool-execution.ts +4 -0
- package/src/interactive/renderers/worker-entry.ts +122 -14
- package/src/interactive/side-question.ts +58 -1
- package/src/interactive/slash-commands.ts +251 -15
- package/src/interactive/status/controller.ts +11 -0
- package/src/interactive/status/state-machine.ts +54 -2
- package/src/interactive/status/types.ts +7 -0
- package/src/interactive/tasks-overlay.ts +1 -0
- package/src/interactive/terminal-lease.ts +2 -0
- package/src/interactive/theme/tokens.ts +3 -14
- package/src/interactive/turn-context.ts +346 -33
- package/src/interactive/turn-persistence.ts +14 -4
- package/src/interactive/turn-prewarm.ts +364 -0
- package/src/interactive/turn-queues.ts +7 -4
- package/src/interactive/turn-runtime.ts +8 -1
- package/src/interactive/turn-state.ts +23 -0
- package/src/interactive/view/artifacts.ts +109 -1
- package/src/interactive/view/view-overlay.ts +29 -3
- package/src/interactive/watch-pane.ts +152 -0
- package/src/interactive/worker-progress.ts +7 -1
- package/src/interactive/worker-receipts.ts +19 -1
- package/src/interactive/worker-stream.ts +5 -0
- package/src/interactive/yazi-bridge.ts +444 -0
- package/src/tools/ask-user.ts +43 -2
- package/src/tools/bootstrap.ts +26 -2
- package/src/tools/builtin-tool-catalog.ts +15 -0
- package/src/tools/compete-worktrees.ts +83 -2
- package/src/tools/core-bootstrap.ts +2 -1
- package/src/tools/dispatch-admission.ts +14 -3
- package/src/tools/dispatch-arguments.ts +20 -20
- package/src/tools/dispatch-plan.ts +17 -9
- package/src/tools/dispatch-run-events.ts +134 -19
- package/src/tools/dispatch-runner.ts +29 -7
- package/src/tools/dispatch-scout.ts +1 -1
- package/src/tools/dispatch-types.ts +15 -3
- package/src/tools/dispatch.ts +1 -1
- package/src/tools/executables.ts +17 -14
- package/src/tools/observation.ts +54 -4
- 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/registry.ts +16 -0
- package/dist/chunk-AOCYTWAV.js +0 -449
- package/dist/chunk-HLE42MG7.js +0 -37
- package/dist/chunk-HWUFFB6L.js +0 -83
- package/dist/chunk-JOZYP4GM.js +0 -279
- package/dist/doctor-M7YEDGAE.js +0 -91
|
@@ -4,7 +4,7 @@ import {
|
|
|
4
4
|
sanitizeToolResultDigest,
|
|
5
5
|
type ToolResultDigest,
|
|
6
6
|
} from "../../tools/result-disposition.js";
|
|
7
|
-
import { TASK_MEMORY_DEFAULT_PROCEDURAL_CAP, type TaskMemoryBank } from "../memory/task-bank.js";
|
|
7
|
+
import { TASK_MEMORY_DEFAULT_PROCEDURAL_CAP, type TaskMemoryBank, type TaskMemoryEntry } from "../memory/task-bank.js";
|
|
8
8
|
import {
|
|
9
9
|
runTaskMemoryPolicy,
|
|
10
10
|
TASK_MEMORY_POLICY_DEFAULT_TIMEOUT_MS,
|
|
@@ -12,6 +12,7 @@ import {
|
|
|
12
12
|
type TaskMemoryModelClient,
|
|
13
13
|
type TaskMemoryPolicyReason,
|
|
14
14
|
type TaskMemoryPolicyResult,
|
|
15
|
+
type TaskMemoryStepUsage,
|
|
15
16
|
type TaskMemoryTrajectoryStep,
|
|
16
17
|
} from "../memory/task-memory-policy.js";
|
|
17
18
|
import type { TaskMemoryActivityEvent } from "../memory/task-memory-status.js";
|
|
@@ -30,8 +31,10 @@ import type { MiddlewareEffect, MiddlewareHookInput } from "./types.js";
|
|
|
30
31
|
|
|
31
32
|
export const MEMORY_INTERVENTION_REGISTRATION_ID = "observer.memory-intervention";
|
|
32
33
|
export const MEMORY_INTERVENTION_DEFAULT_WINDOW_STEPS = 8;
|
|
33
|
-
export const MEMORY_INTERVENTION_DEFAULT_MAX_TOKENS =
|
|
34
|
+
export const MEMORY_INTERVENTION_DEFAULT_MAX_TOKENS = 2_000;
|
|
34
35
|
export const MEMORY_INTERVENTION_DEFAULT_EVERY_N_TOOLS = 10;
|
|
36
|
+
/** Two full deadlines are enough evidence to stop spending this session's endpoint. */
|
|
37
|
+
export const MEMORY_INTERVENTION_TIMEOUT_BACKOFF_THRESHOLD = 2;
|
|
35
38
|
|
|
36
39
|
export const MEMORY_INTERVENTION_ACTIVITY_LIMIT = 20;
|
|
37
40
|
|
|
@@ -75,6 +78,27 @@ export interface MemoryInterventionDeps {
|
|
|
75
78
|
everyNTools?: number;
|
|
76
79
|
/** Lazily resolves the explicitly configured background role. Null means rules-only. */
|
|
77
80
|
getModelClient?: () => TaskMemoryModelClient | null;
|
|
81
|
+
/** Completion budget derived from the resolved background model capability. */
|
|
82
|
+
getModelMaxTokens?: (configuredMaxTokens: number) => number;
|
|
83
|
+
/**
|
|
84
|
+
* True when the background target's inference endpoint is already serving the
|
|
85
|
+
* chat target's stream. A memory step then either queues behind the operator's
|
|
86
|
+
* own turn on a single-slot server or makes the server evict the resident
|
|
87
|
+
* model to serve it, so the boundary is skipped and the skip is recorded.
|
|
88
|
+
*/
|
|
89
|
+
backgroundEndpointBusy?: () => boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Provider-reported spend for one completed model step. The composition root
|
|
92
|
+
* routes it to the cost ledger; the middleware never prices anything.
|
|
93
|
+
*/
|
|
94
|
+
onStepUsage?: (usage: TaskMemoryStepUsage) => void;
|
|
95
|
+
/**
|
|
96
|
+
* Bank entries an llm-tier reminder cited when it reached the operator. The
|
|
97
|
+
* composition root proposes them into the durable memory store, which is what
|
|
98
|
+
* connects the session bank to the records `/memory` and `clio-coder memory`
|
|
99
|
+
* read. Best effort and content-bearing, exactly like `onEnvelope`.
|
|
100
|
+
*/
|
|
101
|
+
onInjectedEntries?: (entries: ReadonlyArray<TaskMemoryEntry>) => void;
|
|
78
102
|
/** Live next-turn settings view; individual fields above remain test-friendly fallbacks. */
|
|
79
103
|
getSettings?: () => Readonly<MemoryInterventionSettings>;
|
|
80
104
|
/** Best-effort content-free telemetry; sink failures never affect intervention. */
|
|
@@ -167,6 +191,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
167
191
|
let outstandingStep: Promise<void> = Promise.resolve();
|
|
168
192
|
let rulesInjectedSincePromptedStep = false;
|
|
169
193
|
let annotatedSinceTurnEnd = false;
|
|
194
|
+
let consecutiveLlmTimeouts = 0;
|
|
170
195
|
|
|
171
196
|
return {
|
|
172
197
|
id: MEMORY_INTERVENTION_REGISTRATION_ID,
|
|
@@ -348,6 +373,7 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
348
373
|
reminder: null,
|
|
349
374
|
inputTokens: 0,
|
|
350
375
|
outputTokens: 0,
|
|
376
|
+
usage: null,
|
|
351
377
|
effects: NO_EFFECTS,
|
|
352
378
|
});
|
|
353
379
|
const live = settings();
|
|
@@ -361,23 +387,38 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
361
387
|
let tier: TaskMemoryTelemetryTier = "rules";
|
|
362
388
|
promptedStepTier = tier;
|
|
363
389
|
let promptedResult: TaskMemoryPolicyResult;
|
|
390
|
+
// A boundary that never reached the model is a skipped boundary rather than
|
|
391
|
+
// a policy decision, and `dropped` is the telemetry outcome for exactly
|
|
392
|
+
// that. The returned decision stays `silent`, since no reminder was
|
|
393
|
+
// produced and the policy vocabulary has no value for a step that never ran.
|
|
394
|
+
let telemetryDecision: TaskMemoryTelemetryDecision | null = null;
|
|
364
395
|
try {
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
promptedResult = silent("no_client");
|
|
396
|
+
if (consecutiveLlmTimeouts >= MEMORY_INTERVENTION_TIMEOUT_BACKOFF_THRESHOLD) {
|
|
397
|
+
promptedResult = silent("llm_timeout_backoff");
|
|
368
398
|
} else {
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
399
|
+
const client = deps.getModelClient?.() ?? null;
|
|
400
|
+
if (client === null) {
|
|
401
|
+
promptedResult = silent("no_client");
|
|
402
|
+
} else if (deps.backgroundEndpointBusy?.() === true) {
|
|
403
|
+
tier = "llm";
|
|
404
|
+
promptedStepTier = tier;
|
|
405
|
+
promptedResult = silent("endpoint_busy");
|
|
406
|
+
telemetryDecision = "dropped";
|
|
407
|
+
} else {
|
|
408
|
+
tier = "llm";
|
|
409
|
+
promptedStepTier = tier;
|
|
410
|
+
promptedResult = await runTaskMemoryPolicy(deps.bank, client, {
|
|
411
|
+
task: input.task?.trim() || currentTask,
|
|
412
|
+
trajectory: [...trajectory],
|
|
413
|
+
deterministicTrigger: input.deterministicTrigger,
|
|
414
|
+
maxTokens: live.maxTokens,
|
|
415
|
+
modelMaxTokens: positiveInteger(deps.getModelMaxTokens?.(live.maxTokens), live.maxTokens),
|
|
416
|
+
...(input.suppressIntervention === undefined ? {} : { suppressIntervention: input.suppressIntervention }),
|
|
417
|
+
previousReminder: lastInjectedMessage,
|
|
418
|
+
timeoutMs: live.timeoutMs,
|
|
419
|
+
...(deps.onEnvelope === undefined ? {} : { onEnvelope: deps.onEnvelope }),
|
|
420
|
+
});
|
|
421
|
+
}
|
|
381
422
|
}
|
|
382
423
|
} catch (error) {
|
|
383
424
|
// runTaskMemoryPolicy resolves its own failures, so reaching here means
|
|
@@ -395,11 +436,21 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
395
436
|
error: error instanceof Error ? error.message : "resolving the background model client failed",
|
|
396
437
|
});
|
|
397
438
|
}
|
|
439
|
+
if (tier === "llm" && promptedResult.decision === "timeout") consecutiveLlmTimeouts += 1;
|
|
440
|
+
else if (tier === "llm" && telemetryDecision !== "dropped") consecutiveLlmTimeouts = 0;
|
|
398
441
|
lastDecision = promptedResult.decision;
|
|
442
|
+
if (promptedResult.usage !== null) {
|
|
443
|
+
try {
|
|
444
|
+
deps.onStepUsage?.(promptedResult.usage);
|
|
445
|
+
} catch {
|
|
446
|
+
// Accounting is bookkeeping. A failing sink never changes memory behavior.
|
|
447
|
+
}
|
|
448
|
+
}
|
|
449
|
+
if (promptedResult.decision === "injected") reportInjectedEntries(promptedResult.reminder);
|
|
399
450
|
emitTelemetry(
|
|
400
451
|
triggers,
|
|
401
452
|
tier,
|
|
402
|
-
promptedResult.decision,
|
|
453
|
+
telemetryDecision ?? promptedResult.decision,
|
|
403
454
|
promptedResult.reason,
|
|
404
455
|
citedEntryCount(promptedResult.reminder),
|
|
405
456
|
promptedResult.inputTokens,
|
|
@@ -462,10 +513,35 @@ export function createMemoryInterventionRegistration(deps: MemoryInterventionDep
|
|
|
462
513
|
if (activity.length > MEMORY_INTERVENTION_ACTIVITY_LIMIT) activity.length = MEMORY_INTERVENTION_ACTIVITY_LIMIT;
|
|
463
514
|
}
|
|
464
515
|
|
|
465
|
-
function
|
|
466
|
-
if (message === null) return
|
|
516
|
+
function citedEntries(message: string | null): TaskMemoryEntry[] {
|
|
517
|
+
if (message === null) return [];
|
|
467
518
|
const snapshot = deps.bank.snapshot();
|
|
468
|
-
return [...snapshot.knowledge, ...snapshot.procedural].filter((entry) => message.includes(`[${entry.id}]`))
|
|
519
|
+
return [...snapshot.knowledge, ...snapshot.procedural].filter((entry) => message.includes(`[${entry.id}]`));
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
function citedEntryCount(message: string | null): number {
|
|
523
|
+
return citedEntries(message).length;
|
|
524
|
+
}
|
|
525
|
+
|
|
526
|
+
/**
|
|
527
|
+
* Hand the cited entries to the durable store.
|
|
528
|
+
*
|
|
529
|
+
* Only the model tier reports here. A rules-tier reminder cites an entry this
|
|
530
|
+
* middleware wrote itself out of one repeated tool failure, and proposing
|
|
531
|
+
* every one of those as a durable lesson would fill the operator's review
|
|
532
|
+
* queue with rows nobody asked for. The model tier's entries are the ones the
|
|
533
|
+
* background plane produced, which is what #229 asks to be reviewable.
|
|
534
|
+
*/
|
|
535
|
+
function reportInjectedEntries(reminder: string | null): void {
|
|
536
|
+
if (deps.onInjectedEntries === undefined) return;
|
|
537
|
+
const entries = citedEntries(reminder);
|
|
538
|
+
if (entries.length === 0) return;
|
|
539
|
+
try {
|
|
540
|
+
deps.onInjectedEntries(entries);
|
|
541
|
+
} catch {
|
|
542
|
+
// A failing store is the composition root's problem to report, never a
|
|
543
|
+
// reason to fail the step that produced the reminder.
|
|
544
|
+
}
|
|
469
545
|
}
|
|
470
546
|
|
|
471
547
|
function observeBeforeTool(input: MiddlewareHookInput): void {
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Publishing and accounting for the endpoint a background memory step uses.
|
|
3
|
+
*
|
|
4
|
+
* A proactive-memory step that runs on the chat target's own endpoint moves
|
|
5
|
+
* that server's prefix cache, so the next turn is cold for a reason Clio caused
|
|
6
|
+
* and can name. The turn context turns {@link BusChannels.MemoryStepCompleted}
|
|
7
|
+
* into the `background_memory` expected-cold reason; without it `/context`
|
|
8
|
+
* reports the turn as an unexplained provider re-prefill.
|
|
9
|
+
*
|
|
10
|
+
* The disturbance is a property of the request having left the process, not of
|
|
11
|
+
* the answer coming back. A step that times out still had its whole trajectory
|
|
12
|
+
* prefilled into the single prefix slot, because aborting the HTTP request does
|
|
13
|
+
* not stop a llama.cpp prefill (the measurement is recorded in
|
|
14
|
+
* `src/interactive/turn-prewarm.ts`). Publishing from the usage sink instead
|
|
15
|
+
* missed exactly that case, since usage is only assigned once the call resolves.
|
|
16
|
+
*
|
|
17
|
+
* The same request also occupies real endpoint capacity. Both responsibilities
|
|
18
|
+
* live here around the client's `complete`: the slot is registered only after
|
|
19
|
+
* the middleware's `endpoint_busy` admission check, so a step never sees its
|
|
20
|
+
* own slot, then released in the `finally` that also announces the disturbance.
|
|
21
|
+
* Both happen on resolve, timeout, and transport throw, and neither happens for
|
|
22
|
+
* a boundary that skipped the model altogether (`endpoint_busy`, no configured
|
|
23
|
+
* route), because those never call `complete`.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import { BusChannels } from "../../core/bus-events.js";
|
|
27
|
+
import type { SafeEventBus } from "../../core/event-bus.js";
|
|
28
|
+
import { registerForegroundStream } from "../providers/endpoint-capacity.js";
|
|
29
|
+
|
|
30
|
+
/** What the announcer needs: somewhere to publish, and the route to name. */
|
|
31
|
+
export interface MemoryStepEndpointAnnouncerDeps {
|
|
32
|
+
bus: Pick<SafeEventBus, "emit"> | null;
|
|
33
|
+
/** Canonical endpoint the step calls, or null when the route has none. */
|
|
34
|
+
endpointKey: string | null;
|
|
35
|
+
targetId: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/**
|
|
39
|
+
* Wrap one background memory `complete` so every request that leaves the
|
|
40
|
+
* process holds one endpoint slot and publishes its endpoint exactly once,
|
|
41
|
+
* whatever the call does next.
|
|
42
|
+
*
|
|
43
|
+
* A route with no canonical endpoint key is unchanged. A null bus suppresses
|
|
44
|
+
* the announcement but still counts capacity for a route whose key is known.
|
|
45
|
+
*/
|
|
46
|
+
export function announceMemoryStepEndpoint<Request, Response>(
|
|
47
|
+
deps: MemoryStepEndpointAnnouncerDeps,
|
|
48
|
+
complete: (request: Request) => Promise<Response>,
|
|
49
|
+
): (request: Request) => Promise<Response> {
|
|
50
|
+
const { bus, endpointKey, targetId } = deps;
|
|
51
|
+
if (endpointKey === null) return complete;
|
|
52
|
+
return async (request: Request): Promise<Response> => {
|
|
53
|
+
// `runPromptedStep` performs its busy check before it invokes `complete`,
|
|
54
|
+
// so this registration counts the outgoing request without self-refusing.
|
|
55
|
+
const releaseEndpointSlot = registerForegroundStream(endpointKey);
|
|
56
|
+
try {
|
|
57
|
+
return await complete(request);
|
|
58
|
+
} finally {
|
|
59
|
+
releaseEndpointSlot();
|
|
60
|
+
// Bookkeeping never changes memory behavior, and a crashing subscriber
|
|
61
|
+
// must not turn a resolved step into a failed one.
|
|
62
|
+
if (bus !== null) {
|
|
63
|
+
try {
|
|
64
|
+
bus.emit(BusChannels.MemoryStepCompleted, { endpointKey, targetId });
|
|
65
|
+
} catch {
|
|
66
|
+
// The safe bus already contains listener errors; this covers the rest.
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
};
|
|
71
|
+
}
|
|
@@ -0,0 +1,434 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The pane layer's cross-domain surface.
|
|
3
|
+
*
|
|
4
|
+
* Every method is best-effort. A mux failure never fails a dispatch, never
|
|
5
|
+
* throws at a caller, and never blocks the event loop on a dead socket: it logs
|
|
6
|
+
* and degrades to `available() === false`, which the consumers read as "use the
|
|
7
|
+
* native fleet surfaces instead". That is why every method here returns a
|
|
8
|
+
* fallback value rather than rejecting.
|
|
9
|
+
*
|
|
10
|
+
* Two ownership rules run through the whole file. Clio acts only on panes it
|
|
11
|
+
* created, tracked in `pane-registry.ts` and tagged with the `clio_owner`
|
|
12
|
+
* metadata token so `clio doctor` can find orphans. The one documented
|
|
13
|
+
* exception is Clio's own hosting pane in guest mode, which `reportSelf`
|
|
14
|
+
* writes to under SA-3 of the v0.4.0 cycle plan.
|
|
15
|
+
*
|
|
16
|
+
* What is deliberately absent: per-run viewer panes. The v0.4.0 phase 3/4
|
|
17
|
+
* integration opened a pane per dispatched run in a hidden Fleet tab, with a
|
|
18
|
+
* focus ladder, run-state reporting, and resume adoption keyed on run ids. All
|
|
19
|
+
* of that projected fleet state the native surfaces already show onto panes
|
|
20
|
+
* nobody had asked for. The one run-viewing surface is now the workers-view
|
|
21
|
+
* watch pane (src/interactive/watch-pane.ts): a single utility pane following
|
|
22
|
+
* a selection file, opened on operator demand and retargeted by file writes
|
|
23
|
+
* that never touch this socket.
|
|
24
|
+
*/
|
|
25
|
+
|
|
26
|
+
import type { DomainContract } from "../../core/domain-loader.js";
|
|
27
|
+
import type { MuxDetection } from "./detect.js";
|
|
28
|
+
import { createPaneRegistry, type MuxPaneRegistry, paneRecord } from "./pane-registry.js";
|
|
29
|
+
import { muxSupportsMethod } from "./protocol.js";
|
|
30
|
+
import type {
|
|
31
|
+
MuxClient,
|
|
32
|
+
MuxSubscription,
|
|
33
|
+
MuxWorktreeCreatedResult,
|
|
34
|
+
MuxWorktreeCreateRequest,
|
|
35
|
+
} from "./socket-client.js";
|
|
36
|
+
import {
|
|
37
|
+
MuxError,
|
|
38
|
+
type MuxEvent,
|
|
39
|
+
type MuxLog,
|
|
40
|
+
type MuxMode,
|
|
41
|
+
type MuxNotificationSound,
|
|
42
|
+
type MuxPanePurpose,
|
|
43
|
+
type MuxPaneRecord,
|
|
44
|
+
type MuxPaneRef,
|
|
45
|
+
type MuxSelfReport,
|
|
46
|
+
} from "./types.js";
|
|
47
|
+
|
|
48
|
+
/** Metadata source for everything Clio's pane layer writes. */
|
|
49
|
+
const METADATA_SOURCE = "clio:mux";
|
|
50
|
+
/** Agent-authority source for Clio's own hosting pane, per SA-3. */
|
|
51
|
+
const SELF_AGENT_SOURCE = "clio:coder";
|
|
52
|
+
/** Token every Clio-created pane carries so orphans are findable. */
|
|
53
|
+
const OWNER_TOKEN_KEY = "clio_owner";
|
|
54
|
+
const OWNER_TOKEN_VALUE = "clio:mux";
|
|
55
|
+
/** herdr caps a metadata token value at 80 characters. */
|
|
56
|
+
const TOKEN_VALUE_MAX = 80;
|
|
57
|
+
/** How long `available()` stays false after a transport failure before probing again. */
|
|
58
|
+
const DEGRADE_COOLDOWN_MS = 5_000;
|
|
59
|
+
|
|
60
|
+
export interface MuxOpenUtilityPaneRequest {
|
|
61
|
+
argv: ReadonlyArray<string>;
|
|
62
|
+
cwd: string;
|
|
63
|
+
label: string;
|
|
64
|
+
/** Operator-facing pane title. Omitted when the caller wants the shell default. */
|
|
65
|
+
title?: string;
|
|
66
|
+
purpose?: MuxPanePurpose;
|
|
67
|
+
direction?: "right" | "down";
|
|
68
|
+
env?: Readonly<Record<string, string>>;
|
|
69
|
+
/**
|
|
70
|
+
* Absolute path the pane's stdout is redirected into. Full-screen programs
|
|
71
|
+
* such as Yazi reopen `/dev/tty` for their interface when stdout is not a tty.
|
|
72
|
+
*/
|
|
73
|
+
stdoutPath?: string;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
export interface MuxNotifyRequest {
|
|
77
|
+
title: string;
|
|
78
|
+
body?: string;
|
|
79
|
+
sound?: MuxNotificationSound;
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export interface MuxContract extends DomainContract {
|
|
83
|
+
readonly mode: MuxMode;
|
|
84
|
+
/** `mode !== "none"` and the socket is currently healthy. */
|
|
85
|
+
available(): boolean;
|
|
86
|
+
/**
|
|
87
|
+
* The rung detection resolved to, with the socket it answered on and the
|
|
88
|
+
* protocol recorded from the handshake. `/panes` and `clio-coder doctor`
|
|
89
|
+
* print it; the notify and worktree paths gate on its protocol.
|
|
90
|
+
*/
|
|
91
|
+
detection(): Readonly<MuxDetection>;
|
|
92
|
+
openUtilityPane(request: MuxOpenUtilityPaneRequest): Promise<MuxPaneRef | null>;
|
|
93
|
+
/** Close one Clio-created pane by pane id. Refuses a pane Clio did not create. */
|
|
94
|
+
closePane(paneId: string): Promise<boolean>;
|
|
95
|
+
/**
|
|
96
|
+
* Re-adopt one pane of the given purpose that outlived the process that made
|
|
97
|
+
* it. A fresh `session.snapshot` is scanned for a pane carrying Clio's owner
|
|
98
|
+
* token and a matching `role` token; the first hit is recorded and returned.
|
|
99
|
+
* This is what stops a restarted session's Enter-in-the-workers-view from
|
|
100
|
+
* opening a second watch pane beside the surviving one.
|
|
101
|
+
*/
|
|
102
|
+
adoptPane(request: { purpose: MuxPanePurpose; label: string }): Promise<MuxPaneRef | null>;
|
|
103
|
+
notify(request: MuxNotifyRequest): Promise<void>;
|
|
104
|
+
/** Optional compete storage route. Protocol-gated with a native Git fallback at the caller. */
|
|
105
|
+
worktreeCreate(request: MuxWorktreeCreateRequest): Promise<MuxWorktreeCreatedResult | null>;
|
|
106
|
+
/** Remove a herdr worktree workspace. False tells the caller to use native Git cleanup. */
|
|
107
|
+
worktreeRemove(workspaceId: string, options?: { force?: boolean }): Promise<boolean>;
|
|
108
|
+
/**
|
|
109
|
+
* Called when a pane Clio owns leaves, whether the user closed it or the
|
|
110
|
+
* program in it exited. Callers record it and do not reopen: a closed pane
|
|
111
|
+
* is a decision, not a fault.
|
|
112
|
+
*/
|
|
113
|
+
onPaneGone(handler: (record: MuxPaneRecord) => void): () => void;
|
|
114
|
+
/** Panes Clio created, with their purpose. */
|
|
115
|
+
list(): ReadonlyArray<MuxPaneRecord>;
|
|
116
|
+
/**
|
|
117
|
+
* Report Clio's own state on its hosting pane (SA-3). Returns false when
|
|
118
|
+
* there is no pane to report on, which is every mode but guest.
|
|
119
|
+
*/
|
|
120
|
+
reportSelf(report: MuxSelfReport): Promise<boolean>;
|
|
121
|
+
shutdown(): Promise<void>;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export interface MuxRuntimeOptions {
|
|
125
|
+
detection: MuxDetection;
|
|
126
|
+
client: MuxClient | null;
|
|
127
|
+
log?: MuxLog;
|
|
128
|
+
now?: () => number;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** The contract plus the lifecycle handles the domain extension drives. */
|
|
132
|
+
export interface MuxRuntime {
|
|
133
|
+
contract: MuxContract;
|
|
134
|
+
start(): Promise<void>;
|
|
135
|
+
stop(): Promise<void>;
|
|
136
|
+
/** Test seam: the registry the contract reconciles against. */
|
|
137
|
+
registry: MuxPaneRegistry;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/** POSIX single-quoting, so an argv element with spaces or quotes survives the shell. */
|
|
141
|
+
function shellQuote(argv: ReadonlyArray<string>): string {
|
|
142
|
+
return argv.map((arg) => `'${arg.replaceAll("'", `'\\''`)}'`).join(" ");
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
function token(value: string | undefined | null): string | null {
|
|
146
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
147
|
+
return value.length > TOKEN_VALUE_MAX ? value.slice(0, TOKEN_VALUE_MAX) : value;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
export function createMuxRuntime(options: MuxRuntimeOptions): MuxRuntime {
|
|
151
|
+
const { detection, client } = options;
|
|
152
|
+
const log = options.log ?? ((): void => undefined);
|
|
153
|
+
const now = options.now ?? Date.now;
|
|
154
|
+
const registry = createPaneRegistry();
|
|
155
|
+
|
|
156
|
+
let healthy = client !== null;
|
|
157
|
+
let probeHealthAt = 0;
|
|
158
|
+
let stopped = false;
|
|
159
|
+
let subscription: MuxSubscription | null = null;
|
|
160
|
+
const paneGoneHandlers = new Set<(record: MuxPaneRecord) => void>();
|
|
161
|
+
|
|
162
|
+
const degrade = (what: string, error: unknown): void => {
|
|
163
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
164
|
+
const transport = error instanceof MuxError && (error.kind === "transport" || error.kind === "timeout");
|
|
165
|
+
if (transport) {
|
|
166
|
+
healthy = false;
|
|
167
|
+
probeHealthAt = now() + DEGRADE_COOLDOWN_MS;
|
|
168
|
+
}
|
|
169
|
+
log(transport ? "warning" : "debug", `mux ${what} failed: ${message}`);
|
|
170
|
+
};
|
|
171
|
+
|
|
172
|
+
const usable = (): boolean => {
|
|
173
|
+
if (stopped || client === null || detection.mode === "none") return false;
|
|
174
|
+
return healthy || now() >= probeHealthAt;
|
|
175
|
+
};
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Runs one mux interaction and swallows everything it can throw. The fallback
|
|
179
|
+
* is what the caller sees when the pane layer is not there, which is the same
|
|
180
|
+
* value it sees in `none` mode.
|
|
181
|
+
*/
|
|
182
|
+
const attempt = async <T>(what: string, run: (live: MuxClient) => Promise<T>, fallback: T): Promise<T> => {
|
|
183
|
+
if (!usable() || client === null) return fallback;
|
|
184
|
+
try {
|
|
185
|
+
const value = await run(client);
|
|
186
|
+
healthy = true;
|
|
187
|
+
return value;
|
|
188
|
+
} catch (error) {
|
|
189
|
+
degrade(what, error);
|
|
190
|
+
return fallback;
|
|
191
|
+
}
|
|
192
|
+
};
|
|
193
|
+
|
|
194
|
+
const tagOwner = async (
|
|
195
|
+
live: MuxClient,
|
|
196
|
+
paneId: string,
|
|
197
|
+
tokens: Readonly<Record<string, string | null>>,
|
|
198
|
+
title?: string,
|
|
199
|
+
): Promise<void> => {
|
|
200
|
+
await live.paneReportMetadata({
|
|
201
|
+
paneId,
|
|
202
|
+
source: METADATA_SOURCE,
|
|
203
|
+
...(title === undefined ? {} : { title }),
|
|
204
|
+
tokens: { [OWNER_TOKEN_KEY]: OWNER_TOKEN_VALUE, ...tokens },
|
|
205
|
+
});
|
|
206
|
+
};
|
|
207
|
+
|
|
208
|
+
const onEvent = (event: MuxEvent): void => {
|
|
209
|
+
const dropped = registry.forget(event.paneId);
|
|
210
|
+
if (dropped) {
|
|
211
|
+
log("debug", `mux pane ${event.paneId} left on ${event.kind}; dropped from the registry`);
|
|
212
|
+
for (const handler of paneGoneHandlers) {
|
|
213
|
+
try {
|
|
214
|
+
handler(dropped);
|
|
215
|
+
} catch (error) {
|
|
216
|
+
log("debug", `mux pane-gone handler threw: ${error instanceof Error ? error.message : String(error)}`);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
};
|
|
221
|
+
|
|
222
|
+
const contract: MuxContract = {
|
|
223
|
+
mode: detection.mode,
|
|
224
|
+
|
|
225
|
+
available(): boolean {
|
|
226
|
+
return usable();
|
|
227
|
+
},
|
|
228
|
+
|
|
229
|
+
detection(): Readonly<MuxDetection> {
|
|
230
|
+
return detection;
|
|
231
|
+
},
|
|
232
|
+
|
|
233
|
+
async openUtilityPane(request: MuxOpenUtilityPaneRequest): Promise<MuxPaneRef | null> {
|
|
234
|
+
return await attempt(
|
|
235
|
+
"openUtilityPane",
|
|
236
|
+
async (live) => {
|
|
237
|
+
const anchor = detection.self.paneId ?? (await live.paneCurrent()).paneId;
|
|
238
|
+
const pane = await live.paneSplit({
|
|
239
|
+
direction: request.direction ?? "right",
|
|
240
|
+
targetPaneId: anchor,
|
|
241
|
+
cwd: request.cwd,
|
|
242
|
+
focus: false,
|
|
243
|
+
...(request.env ? { env: request.env } : {}),
|
|
244
|
+
});
|
|
245
|
+
const ref: MuxPaneRef = { paneId: pane.paneId, tabId: pane.tabId, workspaceId: pane.workspaceId };
|
|
246
|
+
const purpose = request.purpose ?? "utility";
|
|
247
|
+
registry.record(paneRecord(ref, { purpose, label: request.label, openedAt: now() }));
|
|
248
|
+
const title = request.title;
|
|
249
|
+
const titleSupported = title !== undefined && muxSupportsMethod(detection.server, "pane.rename");
|
|
250
|
+
if (titleSupported) {
|
|
251
|
+
try {
|
|
252
|
+
await live.paneRename(pane.paneId, title);
|
|
253
|
+
} catch {
|
|
254
|
+
// Presentation is optional. A server that advertises the floor but
|
|
255
|
+
// lacks or refuses rename must not strand an otherwise healthy pane.
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
// The `role` token is what adoptPane finds again after a restart.
|
|
259
|
+
await tagOwner(live, pane.paneId, { role: token(purpose) }, titleSupported ? title : undefined);
|
|
260
|
+
if (request.argv.length > 0) {
|
|
261
|
+
// herdr has no argv parameter on pane.split, so the command goes in
|
|
262
|
+
// through the pane's shell. `exec` replaces the shell so the pane
|
|
263
|
+
// exits with the program and emits pane.exited for reconciliation.
|
|
264
|
+
const redirect = request.stdoutPath ? ` > ${shellQuote([request.stdoutPath])}` : "";
|
|
265
|
+
await live.paneSendText(pane.paneId, `exec ${shellQuote(request.argv)}${redirect}\n`);
|
|
266
|
+
}
|
|
267
|
+
return ref;
|
|
268
|
+
},
|
|
269
|
+
null,
|
|
270
|
+
);
|
|
271
|
+
},
|
|
272
|
+
|
|
273
|
+
async closePane(paneId: string): Promise<boolean> {
|
|
274
|
+
// The ownership rule, restated for the operator-facing path: `/panes
|
|
275
|
+
// close` addresses panes by id and must refuse anything the registry
|
|
276
|
+
// does not hold.
|
|
277
|
+
if (!registry.owns(paneId)) return false;
|
|
278
|
+
return await attempt(
|
|
279
|
+
"closePane",
|
|
280
|
+
async (live) => {
|
|
281
|
+
await live.paneClose(paneId);
|
|
282
|
+
registry.forget(paneId);
|
|
283
|
+
return true;
|
|
284
|
+
},
|
|
285
|
+
false,
|
|
286
|
+
);
|
|
287
|
+
},
|
|
288
|
+
|
|
289
|
+
async adoptPane(request: { purpose: MuxPanePurpose; label: string }): Promise<MuxPaneRef | null> {
|
|
290
|
+
const existing = registry.byPurpose(request.purpose);
|
|
291
|
+
if (existing) return existing.ref;
|
|
292
|
+
return await attempt(
|
|
293
|
+
"adoptPane",
|
|
294
|
+
async (live) => {
|
|
295
|
+
const snapshot = await live.snapshot();
|
|
296
|
+
for (const pane of snapshot.panes) {
|
|
297
|
+
if (pane.tokens[OWNER_TOKEN_KEY] !== OWNER_TOKEN_VALUE) continue;
|
|
298
|
+
if (pane.tokens.role !== request.purpose) continue;
|
|
299
|
+
if (registry.owns(pane.paneId)) continue;
|
|
300
|
+
// Another workspace's pane belongs to another session's screen;
|
|
301
|
+
// adopting it would retarget a surface the operator cannot see.
|
|
302
|
+
if (detection.self.workspaceId !== null && pane.workspaceId !== detection.self.workspaceId) continue;
|
|
303
|
+
const ref: MuxPaneRef = { paneId: pane.paneId, tabId: pane.tabId, workspaceId: pane.workspaceId };
|
|
304
|
+
registry.record(
|
|
305
|
+
paneRecord(ref, { purpose: request.purpose, label: request.label, openedAt: now(), adopted: true }),
|
|
306
|
+
);
|
|
307
|
+
log("info", `mux adopted a ${request.purpose} pane left open by a previous session`);
|
|
308
|
+
return ref;
|
|
309
|
+
}
|
|
310
|
+
return null;
|
|
311
|
+
},
|
|
312
|
+
null,
|
|
313
|
+
);
|
|
314
|
+
},
|
|
315
|
+
|
|
316
|
+
async notify(request: MuxNotifyRequest): Promise<void> {
|
|
317
|
+
if (!muxSupportsMethod(detection.server, "notification.show")) {
|
|
318
|
+
log("debug", `mux notify skipped, server protocol is below the notification.show floor: ${request.title}`);
|
|
319
|
+
return;
|
|
320
|
+
}
|
|
321
|
+
await attempt(
|
|
322
|
+
"notify",
|
|
323
|
+
async (live) => {
|
|
324
|
+
const result = await live.notificationShow({
|
|
325
|
+
title: request.title,
|
|
326
|
+
...(request.body ? { body: request.body } : {}),
|
|
327
|
+
...(request.sound ? { sound: request.sound } : {}),
|
|
328
|
+
});
|
|
329
|
+
// A suppressed toast is the operator's own herdr config talking
|
|
330
|
+
// (disabled, rate limited, no foreground client). Reporting it as a
|
|
331
|
+
// warning would turn their setting into Clio's error.
|
|
332
|
+
if (!result.shown) log("debug", `mux notify not shown (${result.reason}): ${request.title}`);
|
|
333
|
+
return undefined;
|
|
334
|
+
},
|
|
335
|
+
undefined,
|
|
336
|
+
);
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
async worktreeCreate(request: MuxWorktreeCreateRequest): Promise<MuxWorktreeCreatedResult | null> {
|
|
340
|
+
if (!muxSupportsMethod(detection.server, "worktree.create")) {
|
|
341
|
+
log("debug", "mux worktree.create skipped, server protocol is below the worktree floor");
|
|
342
|
+
return null;
|
|
343
|
+
}
|
|
344
|
+
return await attempt("worktreeCreate", (live) => live.worktreeCreate(request), null);
|
|
345
|
+
},
|
|
346
|
+
|
|
347
|
+
async worktreeRemove(workspaceId: string, removeOptions = {}): Promise<boolean> {
|
|
348
|
+
if (!muxSupportsMethod(detection.server, "worktree.remove")) {
|
|
349
|
+
log("debug", "mux worktree.remove skipped, server protocol is below the worktree floor");
|
|
350
|
+
return false;
|
|
351
|
+
}
|
|
352
|
+
return await attempt(
|
|
353
|
+
"worktreeRemove",
|
|
354
|
+
async (live) => {
|
|
355
|
+
await live.worktreeRemove(workspaceId, removeOptions);
|
|
356
|
+
return true;
|
|
357
|
+
},
|
|
358
|
+
false,
|
|
359
|
+
);
|
|
360
|
+
},
|
|
361
|
+
|
|
362
|
+
onPaneGone(handler: (record: MuxPaneRecord) => void): () => void {
|
|
363
|
+
paneGoneHandlers.add(handler);
|
|
364
|
+
return () => {
|
|
365
|
+
paneGoneHandlers.delete(handler);
|
|
366
|
+
};
|
|
367
|
+
},
|
|
368
|
+
|
|
369
|
+
list(): ReadonlyArray<MuxPaneRecord> {
|
|
370
|
+
return registry.list();
|
|
371
|
+
},
|
|
372
|
+
|
|
373
|
+
async reportSelf(report: MuxSelfReport): Promise<boolean> {
|
|
374
|
+
const paneId = detection.self.paneId;
|
|
375
|
+
if (detection.mode !== "guest" || !paneId) return false;
|
|
376
|
+
return await attempt(
|
|
377
|
+
"reportSelf",
|
|
378
|
+
async (live) => {
|
|
379
|
+
await live.paneReportAgent({
|
|
380
|
+
paneId,
|
|
381
|
+
source: SELF_AGENT_SOURCE,
|
|
382
|
+
agent: "clio-coder",
|
|
383
|
+
state: report.state,
|
|
384
|
+
...(report.message ? { message: report.message } : {}),
|
|
385
|
+
});
|
|
386
|
+
if (report.tokens || report.stateLabels || report.ttlMs !== undefined) {
|
|
387
|
+
await live.paneReportMetadata({
|
|
388
|
+
paneId,
|
|
389
|
+
source: METADATA_SOURCE,
|
|
390
|
+
...(report.tokens ? { tokens: report.tokens } : {}),
|
|
391
|
+
...(report.stateLabels ? { stateLabels: report.stateLabels } : {}),
|
|
392
|
+
...(report.ttlMs !== undefined ? { ttlMs: report.ttlMs } : {}),
|
|
393
|
+
});
|
|
394
|
+
}
|
|
395
|
+
return true;
|
|
396
|
+
},
|
|
397
|
+
false,
|
|
398
|
+
);
|
|
399
|
+
},
|
|
400
|
+
|
|
401
|
+
async shutdown(): Promise<void> {
|
|
402
|
+
if (stopped) return;
|
|
403
|
+
stopped = true;
|
|
404
|
+
subscription?.close();
|
|
405
|
+
subscription = null;
|
|
406
|
+
paneGoneHandlers.clear();
|
|
407
|
+
// Pane ownership is server-side and intentionally survives process
|
|
408
|
+
// shutdown. Keep the local snapshot too so the contract itself proves
|
|
409
|
+
// shutdown tears down sockets, never panes.
|
|
410
|
+
if (client) await client.close().catch(() => undefined);
|
|
411
|
+
},
|
|
412
|
+
};
|
|
413
|
+
|
|
414
|
+
const start = async (): Promise<void> => {
|
|
415
|
+
if (detection.mode === "none" || client === null) return;
|
|
416
|
+
try {
|
|
417
|
+
subscription = await client.subscribe(["pane.closed", "pane.exited"], onEvent, {
|
|
418
|
+
onResync: (snapshot) => {
|
|
419
|
+
// A reconnect means events were missed. The snapshot is the authority
|
|
420
|
+
// on which panes still exist, so anything Clio thinks it owns that is
|
|
421
|
+
// absent from it is gone.
|
|
422
|
+
const dropped = registry.reconcile(snapshot.panes.map((pane) => pane.paneId));
|
|
423
|
+
if (dropped.length > 0) {
|
|
424
|
+
log("info", `mux reconciled ${dropped.length} pane(s) closed while the socket was down`);
|
|
425
|
+
}
|
|
426
|
+
},
|
|
427
|
+
});
|
|
428
|
+
} catch (error) {
|
|
429
|
+
degrade("event subscription", error);
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
|
|
433
|
+
return { contract, start, stop: contract.shutdown, registry };
|
|
434
|
+
}
|