@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
|
@@ -112,6 +112,7 @@ export function openSideQuestionOverlay(tui: TUI, options: OpenSideQuestionOverl
|
|
|
112
112
|
const handle = showClioOverlayFrame(tui, body, {
|
|
113
113
|
anchor: "center",
|
|
114
114
|
width: sideQuestionOverlayWidth(options.columns),
|
|
115
|
+
markerId: "side-question",
|
|
115
116
|
title: SIDE_QUESTION_OVERLAY_TITLE,
|
|
116
117
|
// Esc means two things here and the footer names the live one: it aborts a
|
|
117
118
|
// round that is still streaming, and it closes one that has settled.
|
|
@@ -26,6 +26,7 @@ import type { NoticeLevel } from "../command-output.js";
|
|
|
26
26
|
import { clioTheme, GLYPH } from "../theme/index.js";
|
|
27
27
|
import type { LibraryInstallConfirmSubject } from "./library-install-confirm.js";
|
|
28
28
|
import { openLibraryInstallConfirmOverlay } from "./library-install-confirm.js";
|
|
29
|
+
import { isLibraryTab, LIBRARY_TABS } from "./library-tabs.js";
|
|
29
30
|
import { type ListOverlayItem, type ListOverlayTab, openListOverlay } from "./list-overlay.js";
|
|
30
31
|
|
|
31
32
|
/**
|
|
@@ -53,23 +54,13 @@ const GROUP_DIAGNOSTICS = "Diagnostics";
|
|
|
53
54
|
const GROUP_INSTALLED = "Installed";
|
|
54
55
|
const GROUP_AVAILABLE = "Available";
|
|
55
56
|
|
|
56
|
-
|
|
57
|
-
export const LIBRARY_TABS: ReadonlyArray<{ id: LibraryEntryKind; label: string }> = [
|
|
58
|
-
{ id: "skill", label: "Skills" },
|
|
59
|
-
{ id: "agent", label: "Agents" },
|
|
60
|
-
{ id: "prompt", label: "Prompts" },
|
|
61
|
-
{ id: "fleet", label: "Fleets" },
|
|
62
|
-
];
|
|
57
|
+
export { isLibraryTab, LIBRARY_TABS };
|
|
63
58
|
|
|
64
59
|
export const SKILLS_HUB_TITLE = "Skills Hub";
|
|
65
60
|
|
|
66
61
|
/** Row id prefix for a library row, which is how an action tells the tabs apart. */
|
|
67
62
|
export const LIBRARY_ROW_PREFIX = "library:";
|
|
68
63
|
|
|
69
|
-
export function isLibraryTab(value: string): value is LibraryEntryKind {
|
|
70
|
-
return LIBRARY_TABS.some((tab) => tab.id === value);
|
|
71
|
-
}
|
|
72
|
-
|
|
73
64
|
/** @internal exported for contract tests */
|
|
74
65
|
export const SKILLS_HUB_EMPTY =
|
|
75
66
|
"no skills installed and no local marketplace configured. install one with `clio-coder skills install <path|github-url>`, or point CLIO_CODER_SKILL_CATALOG_DIR at a skills/ catalog.";
|
|
@@ -557,6 +548,7 @@ export function openSkillsHub(tui: TUI, deps: SkillsHubDeps): OverlayHandle {
|
|
|
557
548
|
};
|
|
558
549
|
|
|
559
550
|
handle = openListOverlay(tui, {
|
|
551
|
+
markerId: "skills-hub",
|
|
560
552
|
title: SKILLS_HUB_TITLE,
|
|
561
553
|
items: [],
|
|
562
554
|
tabs,
|
|
@@ -416,6 +416,7 @@ export function openTreeOverlay(tui: TUI, deps: OpenTreeOverlayDeps): OverlayHan
|
|
|
416
416
|
return showClioOverlayFrame(tui, box, {
|
|
417
417
|
anchor: "center",
|
|
418
418
|
width: TREE_OVERLAY_WIDTH,
|
|
419
|
+
markerId: "tree",
|
|
419
420
|
title: "Session Tree",
|
|
420
421
|
footerHint: () => view.getHint(),
|
|
421
422
|
});
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one decision function for opening a run-watching pane.
|
|
3
|
+
*
|
|
4
|
+
* Policy, stated whole: panes are pulled by the operator, never pushed by the
|
|
5
|
+
* fleet. A dispatch starting, detaching, backgrounding, or failing opens
|
|
6
|
+
* nothing; the native surfaces (transcript, Alt+W board, footer) already carry
|
|
7
|
+
* that state, and the v0.3/v0.4 behavior of opening a hidden viewer pane per
|
|
8
|
+
* dispatch produced panes nobody had asked for. A pane opens only when the
|
|
9
|
+
* operator names a run: Enter in the workers view, `/panes show`, or the
|
|
10
|
+
* `panes` tool acting on the conversation's behalf.
|
|
11
|
+
*
|
|
12
|
+
* The `dispatch` source is the seam for ever marking a dispatch watchable at
|
|
13
|
+
* enqueue time. It exists so the decision stays in this one function; today it
|
|
14
|
+
* always refuses, and any future exception must be argued here, not in a
|
|
15
|
+
* config key.
|
|
16
|
+
*
|
|
17
|
+
* This module is a leaf on purpose: `panes-runtime.ts` is a boundaries seam
|
|
18
|
+
* whose value closure must stay off the render graph, so the policy cannot
|
|
19
|
+
* live beside the dispatch board that shares its status vocabulary.
|
|
20
|
+
*/
|
|
21
|
+
|
|
22
|
+
export type PaneWatchSource = "workers-view" | "slash" | "tool" | "dispatch";
|
|
23
|
+
|
|
24
|
+
/** Statuses with a live process behind them, in the dispatch board's vocabulary. */
|
|
25
|
+
const WATCHABLE_STATUSES = new Set(["running", "stale", "cancelling", "enqueued", "retrying"]);
|
|
26
|
+
|
|
27
|
+
export interface PaneWatchRequest {
|
|
28
|
+
source: PaneWatchSource;
|
|
29
|
+
/** The run's lifecycle status; anything unrecognized reads as terminal. */
|
|
30
|
+
runStatus: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export type PaneWatchDecision = { open: true } | { open: false; reason: string };
|
|
34
|
+
|
|
35
|
+
export function paneWatchDecision(request: PaneWatchRequest): PaneWatchDecision {
|
|
36
|
+
if (request.source === "dispatch") {
|
|
37
|
+
return { open: false, reason: "dispatches run headless; watch a run from the workers view or /panes show" };
|
|
38
|
+
}
|
|
39
|
+
if (!WATCHABLE_STATUSES.has(request.runStatus)) {
|
|
40
|
+
return {
|
|
41
|
+
open: false,
|
|
42
|
+
reason: `run is ${request.runStatus}; use \`clio-coder fleet view <runId>\` for the post-mortem`,
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return { open: true };
|
|
46
|
+
}
|
|
@@ -0,0 +1,292 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The one implementation of `PanesOperations`, shared by `/panes` and the
|
|
3
|
+
* `panes` orchestrator tool.
|
|
4
|
+
*
|
|
5
|
+
* Two rules run through it. Presets probe their binary through the toolchain
|
|
6
|
+
* ladder *before* the pane is split: `openUtilityPane` delivers its command by
|
|
7
|
+
* sending `exec <argv>` into the pane's shell, so a binary that is not there
|
|
8
|
+
* kills the pane the instant it appears, and the operator sees a flicker
|
|
9
|
+
* instead of an install hint (phase 1 report, open question 3). And every
|
|
10
|
+
* mutation is scoped to panes Clio created, because the contract's registry
|
|
11
|
+
* refuses anything else.
|
|
12
|
+
*
|
|
13
|
+
* `show` targets running dispatches, not panes: it resolves a fuzzy agent id
|
|
14
|
+
* or run-id prefix against the live dispatch snapshot and points the shared
|
|
15
|
+
* watch pane at the match, under the one policy decision in
|
|
16
|
+
* `pane-policy.ts`. There is no per-run pane inventory to search any more.
|
|
17
|
+
*/
|
|
18
|
+
|
|
19
|
+
import type { ClioSettings } from "../core/config.js";
|
|
20
|
+
import type { DispatchSnapshot } from "../domains/dispatch/contract.js";
|
|
21
|
+
import {
|
|
22
|
+
newestRunEventJournalRunId,
|
|
23
|
+
runEventJournalPath,
|
|
24
|
+
runEventJournalRoot,
|
|
25
|
+
} from "../domains/dispatch/run-event-journal.js";
|
|
26
|
+
import type { MuxContract, MuxPaneRecord } from "../domains/mux/index.js";
|
|
27
|
+
import {
|
|
28
|
+
PANES_PRESETS,
|
|
29
|
+
type PanesCloseResult,
|
|
30
|
+
type PanesInventoryEntry,
|
|
31
|
+
type PanesOpenResult,
|
|
32
|
+
type PanesOperations,
|
|
33
|
+
type PanesShowResult,
|
|
34
|
+
type PanesStatus,
|
|
35
|
+
type PanesWatchController,
|
|
36
|
+
type PanesYaziController,
|
|
37
|
+
type PanesYaziStatus,
|
|
38
|
+
} from "../domains/mux/operations.js";
|
|
39
|
+
import { resolveBinary } from "../tools/executables.js";
|
|
40
|
+
import { type PaneWatchSource, paneWatchDecision } from "./pane-policy.js";
|
|
41
|
+
|
|
42
|
+
export interface PanesRuntimeDeps {
|
|
43
|
+
mux: MuxContract;
|
|
44
|
+
getSettings: () => Readonly<ClioSettings>;
|
|
45
|
+
/** Live dispatch state, used to turn a fuzzy agent id into a run id. */
|
|
46
|
+
getDispatchSnapshot: () => DispatchSnapshot;
|
|
47
|
+
getCwd: () => string;
|
|
48
|
+
/** Injection seam for tests; production uses the toolchain ladder. */
|
|
49
|
+
resolveBinaryPath?: (name: string) => string | null;
|
|
50
|
+
/** Journal root override for tests. */
|
|
51
|
+
journalRoot?: () => string;
|
|
52
|
+
/** Newest run whose journal exists, for the `logs` preset. */
|
|
53
|
+
newestJournalRunId?: () => string | null;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
const UNAVAILABLE = "the pane layer is not available in this session";
|
|
57
|
+
|
|
58
|
+
function inventory(records: ReadonlyArray<MuxPaneRecord>): ReadonlyArray<PanesInventoryEntry> {
|
|
59
|
+
return records.map((record) => ({
|
|
60
|
+
paneId: record.ref.paneId,
|
|
61
|
+
tabId: record.ref.tabId,
|
|
62
|
+
purpose: record.purpose,
|
|
63
|
+
label: record.label,
|
|
64
|
+
adopted: record.adopted === true,
|
|
65
|
+
}));
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export function createPanesRuntime(deps: PanesRuntimeDeps): PanesOperations {
|
|
69
|
+
const probe = deps.resolveBinaryPath ?? resolveBinary;
|
|
70
|
+
const journalRoot = deps.journalRoot ?? runEventJournalRoot;
|
|
71
|
+
let yaziController: PanesYaziController | null = null;
|
|
72
|
+
let watchController: PanesWatchController | null = null;
|
|
73
|
+
let nextPendingOpen = 0;
|
|
74
|
+
const pendingOpens = new Map<string, PanesInventoryEntry>();
|
|
75
|
+
const beginPendingOpen = (label: string): string => {
|
|
76
|
+
nextPendingOpen += 1;
|
|
77
|
+
const id = `pending:${nextPendingOpen}`;
|
|
78
|
+
pendingOpens.set(id, {
|
|
79
|
+
paneId: id,
|
|
80
|
+
tabId: "pending",
|
|
81
|
+
purpose: "utility",
|
|
82
|
+
label,
|
|
83
|
+
adopted: false,
|
|
84
|
+
pending: true,
|
|
85
|
+
});
|
|
86
|
+
return id;
|
|
87
|
+
};
|
|
88
|
+
const closedYaziStatus = (): PanesYaziStatus => ({
|
|
89
|
+
mode: "closed",
|
|
90
|
+
paneId: null,
|
|
91
|
+
paneCwd: null,
|
|
92
|
+
lastLineAt: null,
|
|
93
|
+
droppedLines: 0,
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Resolve one operator- or model-supplied target to a live dispatched run.
|
|
98
|
+
*
|
|
99
|
+
* Fuzzy agent id first, then runId prefix, most recent run winning: "the
|
|
100
|
+
* tester" is what an operator types; a run id is what a tool call carries.
|
|
101
|
+
* Retrying runs count as live; the watch pane shows them coming back.
|
|
102
|
+
*/
|
|
103
|
+
const matchRun = (target: string): { runId: string; agentId: string; status: string } | null => {
|
|
104
|
+
const needle = target.trim().toLowerCase();
|
|
105
|
+
if (needle.length === 0) return null;
|
|
106
|
+
const snapshot = deps.getDispatchSnapshot();
|
|
107
|
+
const live = [
|
|
108
|
+
...snapshot.running.map((run) => ({ runId: run.runId, agentId: run.agentId, status: "running" })),
|
|
109
|
+
...snapshot.retrying.map((run) => ({ runId: run.runId, agentId: run.agentId, status: "retrying" })),
|
|
110
|
+
];
|
|
111
|
+
// Newest first, so "the tester" means the tester the operator just started.
|
|
112
|
+
const newestFirst = [...live].reverse();
|
|
113
|
+
const byAgent = newestFirst.find((run) => run.agentId.toLowerCase().includes(needle));
|
|
114
|
+
if (byAgent) return byAgent;
|
|
115
|
+
return newestFirst.find((run) => run.runId.toLowerCase().startsWith(needle)) ?? null;
|
|
116
|
+
};
|
|
117
|
+
|
|
118
|
+
/** argv for one preset, once its binary has been found. */
|
|
119
|
+
const presetArgv = (presetId: string, binaryPath: string): ReadonlyArray<string> | null => {
|
|
120
|
+
if (presetId === "shell") return [binaryPath, "-l"];
|
|
121
|
+
if (presetId === "logs") {
|
|
122
|
+
const runId = (deps.newestJournalRunId ?? (() => newestRunEventJournalRunId(journalRoot())))();
|
|
123
|
+
if (runId === null) return null;
|
|
124
|
+
// `-F` rather than `-f`: the journal is recreated when its run's
|
|
125
|
+
// directory is pruned, and a viewer following an inode would silently
|
|
126
|
+
// stop at that point.
|
|
127
|
+
return [binaryPath, "-n", "200", "-F", runEventJournalPath(runId, journalRoot())];
|
|
128
|
+
}
|
|
129
|
+
return null;
|
|
130
|
+
};
|
|
131
|
+
|
|
132
|
+
const show = async (target: string, source: PaneWatchSource): Promise<PanesShowResult> => {
|
|
133
|
+
if (!deps.mux.available()) return { status: "unavailable", reason: UNAVAILABLE };
|
|
134
|
+
const match = matchRun(target);
|
|
135
|
+
if (match === null) {
|
|
136
|
+
// The candidate list is what turns a miss into a next step: it names
|
|
137
|
+
// the runs that are actually live right now.
|
|
138
|
+
const snapshot = deps.getDispatchSnapshot();
|
|
139
|
+
const candidates = [
|
|
140
|
+
...new Set([...snapshot.running.map((run) => run.agentId), ...snapshot.retrying.map((run) => run.agentId)]),
|
|
141
|
+
];
|
|
142
|
+
return { status: "not-found", target, candidates };
|
|
143
|
+
}
|
|
144
|
+
const decision = paneWatchDecision({ source, runStatus: match.status });
|
|
145
|
+
if (!decision.open) return { status: "refused", reason: decision.reason };
|
|
146
|
+
if (watchController === null) {
|
|
147
|
+
return { status: "unavailable", reason: "the watch pane is not wired in this session" };
|
|
148
|
+
}
|
|
149
|
+
const watched = await watchController.watch(match.runId);
|
|
150
|
+
if (watched.status !== "watching") return { status: "unavailable", reason: watched.reason };
|
|
151
|
+
return { status: "watching", runId: match.runId, agentId: match.agentId, opened: watched.opened };
|
|
152
|
+
};
|
|
153
|
+
|
|
154
|
+
return {
|
|
155
|
+
status(): PanesStatus {
|
|
156
|
+
const detection = deps.mux.detection();
|
|
157
|
+
const panes = deps.getSettings().panes;
|
|
158
|
+
return {
|
|
159
|
+
mode: deps.mux.mode,
|
|
160
|
+
available: deps.mux.available(),
|
|
161
|
+
reason: detection.reason,
|
|
162
|
+
socketPath: detection.socketPath,
|
|
163
|
+
server: detection.server,
|
|
164
|
+
settings: {
|
|
165
|
+
enabled: panes.enabled,
|
|
166
|
+
notifications: panes.notifications,
|
|
167
|
+
journal: panes.journal,
|
|
168
|
+
yazi: { ...panes.yazi },
|
|
169
|
+
},
|
|
170
|
+
yazi: yaziController?.status() ?? closedYaziStatus(),
|
|
171
|
+
panes: [...inventory(deps.mux.list()), ...pendingOpens.values()],
|
|
172
|
+
};
|
|
173
|
+
},
|
|
174
|
+
|
|
175
|
+
show(target: string): Promise<PanesShowResult> {
|
|
176
|
+
// The slash command and the tool share this implementation; the policy
|
|
177
|
+
// treats both as operator pull, so the source only matters for logs.
|
|
178
|
+
return show(target, "slash");
|
|
179
|
+
},
|
|
180
|
+
|
|
181
|
+
async open(request: { preset?: string; argv?: ReadonlyArray<string>; once?: boolean }): Promise<PanesOpenResult> {
|
|
182
|
+
const cwd = deps.getCwd();
|
|
183
|
+
if (request.preset !== undefined) {
|
|
184
|
+
const preset = PANES_PRESETS.find((entry) => entry.id === request.preset);
|
|
185
|
+
if (!preset) {
|
|
186
|
+
return { status: "refused", reason: `unknown preset: ${request.preset}` };
|
|
187
|
+
}
|
|
188
|
+
if (preset.id === "yazi") {
|
|
189
|
+
if (!deps.getSettings().panes.yazi.enabled) {
|
|
190
|
+
return { status: "refused", reason: "the files pane is disabled by panes.yazi.enabled" };
|
|
191
|
+
}
|
|
192
|
+
if (!yaziController) {
|
|
193
|
+
return { status: "unavailable", reason: "the files-pane return path is not ready" };
|
|
194
|
+
}
|
|
195
|
+
const pendingId = beginPendingOpen(preset.id);
|
|
196
|
+
try {
|
|
197
|
+
const result = await yaziController.open(request.once ? { once: true } : undefined);
|
|
198
|
+
if (result.status === "opened") {
|
|
199
|
+
return { status: "opened", label: preset.id, paneId: result.paneId };
|
|
200
|
+
}
|
|
201
|
+
if (result.status === "missing-binary") {
|
|
202
|
+
return {
|
|
203
|
+
status: "missing-binary",
|
|
204
|
+
preset: preset.id,
|
|
205
|
+
binary: result.binary,
|
|
206
|
+
installHint: preset.installHint,
|
|
207
|
+
detail: result.detail,
|
|
208
|
+
};
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
status: result.status === "profile-error" ? "refused" : "unavailable",
|
|
212
|
+
reason: result.reason,
|
|
213
|
+
};
|
|
214
|
+
} finally {
|
|
215
|
+
pendingOpens.delete(pendingId);
|
|
216
|
+
}
|
|
217
|
+
}
|
|
218
|
+
if (!deps.mux.available()) return { status: "unavailable", reason: UNAVAILABLE };
|
|
219
|
+
const binaryPath = probe(preset.binary);
|
|
220
|
+
if (binaryPath === null) {
|
|
221
|
+
return {
|
|
222
|
+
status: "missing-binary",
|
|
223
|
+
preset: preset.id,
|
|
224
|
+
binary: preset.binary,
|
|
225
|
+
installHint: preset.installHint,
|
|
226
|
+
detail: `${preset.binary} was not found (install with \`${preset.installHint}\`)`,
|
|
227
|
+
};
|
|
228
|
+
}
|
|
229
|
+
const argv = presetArgv(preset.id, binaryPath);
|
|
230
|
+
if (argv === null) {
|
|
231
|
+
return { status: "refused", reason: `preset ${preset.id} has nothing to show yet` };
|
|
232
|
+
}
|
|
233
|
+
const pendingId = beginPendingOpen(preset.id);
|
|
234
|
+
try {
|
|
235
|
+
const ref = await deps.mux.openUtilityPane({ argv, cwd, label: preset.id });
|
|
236
|
+
if (ref === null) return { status: "unavailable", reason: `pane host refused to open ${preset.id}` };
|
|
237
|
+
return { status: "opened", label: preset.id, paneId: ref.paneId };
|
|
238
|
+
} finally {
|
|
239
|
+
pendingOpens.delete(pendingId);
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
if (!deps.mux.available()) return { status: "unavailable", reason: UNAVAILABLE };
|
|
243
|
+
const argv = request.argv ?? [];
|
|
244
|
+
if (argv.length === 0) return { status: "refused", reason: "nothing to run" };
|
|
245
|
+
const label = argv[0] ?? "pane";
|
|
246
|
+
const pendingId = beginPendingOpen(label);
|
|
247
|
+
try {
|
|
248
|
+
const ref = await deps.mux.openUtilityPane({ argv, cwd, label });
|
|
249
|
+
if (ref === null) return { status: "unavailable", reason: `pane host refused to open ${label}` };
|
|
250
|
+
return { status: "opened", label, paneId: ref.paneId };
|
|
251
|
+
} finally {
|
|
252
|
+
pendingOpens.delete(pendingId);
|
|
253
|
+
}
|
|
254
|
+
},
|
|
255
|
+
|
|
256
|
+
async close(target: string): Promise<PanesCloseResult> {
|
|
257
|
+
if (!deps.mux.available()) return { status: "unavailable", reason: UNAVAILABLE };
|
|
258
|
+
const owned = deps.mux.list();
|
|
259
|
+
if (target === "all") {
|
|
260
|
+
const labels: string[] = [];
|
|
261
|
+
// Snapshot first: closing mutates the registry the list came from.
|
|
262
|
+
for (const record of [...owned]) {
|
|
263
|
+
if (await deps.mux.closePane(record.ref.paneId)) labels.push(record.label);
|
|
264
|
+
}
|
|
265
|
+
return { status: "closed", closed: labels.length, labels };
|
|
266
|
+
}
|
|
267
|
+
const needle = target.trim().toLowerCase();
|
|
268
|
+
const newestFirst = [...owned].reverse();
|
|
269
|
+
const match =
|
|
270
|
+
newestFirst.find((record) => record.ref.paneId.toLowerCase() === needle) ??
|
|
271
|
+
newestFirst.find((record) => record.label.toLowerCase().includes(needle)) ??
|
|
272
|
+
newestFirst.find((record) => record.purpose === needle);
|
|
273
|
+
if (!match) return { status: "not-found", target };
|
|
274
|
+
const closed = await deps.mux.closePane(match.ref.paneId);
|
|
275
|
+
return closed ? { status: "closed", closed: 1, labels: [match.label] } : { status: "not-found", target };
|
|
276
|
+
},
|
|
277
|
+
|
|
278
|
+
attachYazi(controller: PanesYaziController): () => void {
|
|
279
|
+
yaziController = controller;
|
|
280
|
+
return () => {
|
|
281
|
+
if (yaziController === controller) yaziController = null;
|
|
282
|
+
};
|
|
283
|
+
},
|
|
284
|
+
|
|
285
|
+
attachWatch(controller: PanesWatchController): () => void {
|
|
286
|
+
watchController = controller;
|
|
287
|
+
return () => {
|
|
288
|
+
if (watchController === controller) watchController = null;
|
|
289
|
+
};
|
|
290
|
+
},
|
|
291
|
+
};
|
|
292
|
+
}
|
|
@@ -1,5 +1,19 @@
|
|
|
1
1
|
import type { HintEntry } from "./overlay-frame.js";
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* The key that opens and closes local inspection of a parked mutation. It lives
|
|
5
|
+
* here rather than beside the preview builder so the composer rail can name it
|
|
6
|
+
* without pulling the diff machinery into the Stage 0 boot shell closure.
|
|
7
|
+
*/
|
|
8
|
+
export const MUTATION_PREVIEW_KEY = "v";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Whether this card has a mutation to read, and whether it is open.
|
|
12
|
+
* `none` covers every ask with nothing local to inspect, including a worker
|
|
13
|
+
* escalation, whose arguments never leave the worker.
|
|
14
|
+
*/
|
|
15
|
+
export type PermissionInspectionHint = "none" | "closed" | "open";
|
|
16
|
+
|
|
3
17
|
/**
|
|
4
18
|
* The keys that answer a parked call, as data, so the dialog footer and the
|
|
5
19
|
* composer rail render the same policy at any width.
|
|
@@ -16,17 +30,35 @@ import type { HintEntry } from "./overlay-frame.js";
|
|
|
16
30
|
*
|
|
17
31
|
* Esc says `deny`, not `close`: closing the dialog denies the call, and on the
|
|
18
32
|
* one surface where a misread is a wrong decision about a tool call the key
|
|
19
|
-
* names its effect.
|
|
33
|
+
* names its effect. It keeps that meaning while the mutation is open, so the
|
|
34
|
+
* inspect key is what puts the mutation away again.
|
|
20
35
|
*
|
|
21
36
|
* With a draft in the composer, Enter is inert (issue #186): the habitual send
|
|
22
37
|
* key must not resolve toward "allow" on a safety rail. The entry then says so
|
|
23
38
|
* and names the key that clears the draft, which the router passes through.
|
|
39
|
+
*
|
|
40
|
+
* A parked `write` or `edit` adds the inspect key (issue #254). It is
|
|
41
|
+
* droppable, and deliberately so: at 40 columns the four entries do not fit,
|
|
42
|
+
* and the three keys that answer the call outrank the one that reads it. The
|
|
43
|
+
* key keeps working at every width; the `/help` Autonomy & safety net topic is
|
|
44
|
+
* where it is documented for the widths that cannot show it.
|
|
24
45
|
*/
|
|
25
|
-
export function permissionHintEntries(
|
|
46
|
+
export function permissionHintEntries(
|
|
47
|
+
composerHasDraft = false,
|
|
48
|
+
inspection: PermissionInspectionHint = "none",
|
|
49
|
+
): HintEntry[] {
|
|
26
50
|
return [
|
|
27
51
|
composerHasDraft
|
|
28
52
|
? { key: "Backspace", verb: "clear the draft to allow", short: "clear draft", critical: true }
|
|
29
53
|
: { key: "Enter", verb: "allow once", short: "allow", critical: true },
|
|
54
|
+
...(inspection === "none"
|
|
55
|
+
? []
|
|
56
|
+
: inspection === "open"
|
|
57
|
+
? [
|
|
58
|
+
{ key: "↑↓", verb: "scroll", critical: false },
|
|
59
|
+
{ key: MUTATION_PREVIEW_KEY, verb: "hide mutation", short: "hide", critical: false },
|
|
60
|
+
]
|
|
61
|
+
: [{ key: MUTATION_PREVIEW_KEY, verb: "inspect mutation", short: "inspect", critical: false }]),
|
|
30
62
|
{ key: "s", verb: "stop turn", short: "stop", critical: true },
|
|
31
63
|
// With a draft, deny and stop are the only immediate answers, so Esc
|
|
32
64
|
// outranks the narrowing that would otherwise drop it first.
|
|
@@ -6,13 +6,21 @@ import {
|
|
|
6
6
|
decisionFactsForPermission,
|
|
7
7
|
} from "../domains/safety/decision-presentation.js";
|
|
8
8
|
import type { Component, OverlayOptions, TUI } from "../engine/tui.js";
|
|
9
|
+
import {
|
|
10
|
+
MUTATION_PREVIEW_VISIBLE_ROWS,
|
|
11
|
+
type MutationFacts,
|
|
12
|
+
type MutationInspector,
|
|
13
|
+
type MutationPreview,
|
|
14
|
+
mutationFactsLine,
|
|
15
|
+
mutationPreviewWindow,
|
|
16
|
+
} from "./mutation-preview.js";
|
|
9
17
|
import { fitHintEntries } from "./overlay-frame.js";
|
|
10
|
-
import { permissionHintEntries } from "./permission-hint.js";
|
|
18
|
+
import { MUTATION_PREVIEW_KEY, type PermissionInspectionHint, permissionHintEntries } from "./permission-hint.js";
|
|
11
19
|
import type { ClioToken } from "./theme/index.js";
|
|
12
20
|
|
|
13
21
|
export { type AskAxis, askAxis } from "../domains/safety/approval-axis.js";
|
|
14
22
|
export { describeCallTarget, sanitizeCallTargetText } from "../domains/safety/call-target.js";
|
|
15
|
-
export { permissionHintEntries } from "./permission-hint.js";
|
|
23
|
+
export { MUTATION_PREVIEW_KEY, type PermissionInspectionHint, permissionHintEntries } from "./permission-hint.js";
|
|
16
24
|
|
|
17
25
|
export interface ApprovalRequestView {
|
|
18
26
|
requestId: string;
|
|
@@ -34,6 +42,14 @@ export interface ApprovalRequestView {
|
|
|
34
42
|
* when nothing meaningful is derivable.
|
|
35
43
|
*/
|
|
36
44
|
target?: string;
|
|
45
|
+
/**
|
|
46
|
+
* Size and digest facts for a parked `write` or `edit`, and nothing else
|
|
47
|
+
* about it. The mutation text is deliberately absent: this view is what
|
|
48
|
+
* reaches the transcript row, the parked notice, and the approval-state
|
|
49
|
+
* event, so anything on it has already left the overlay. The text itself is
|
|
50
|
+
* held by the inspector the overlay opener is given (issue #254).
|
|
51
|
+
*/
|
|
52
|
+
mutation?: MutationFacts;
|
|
37
53
|
queueDepth?: number;
|
|
38
54
|
}
|
|
39
55
|
|
|
@@ -79,11 +95,59 @@ export function permissionOverlayPlacement(
|
|
|
79
95
|
};
|
|
80
96
|
}
|
|
81
97
|
|
|
82
|
-
|
|
83
|
-
|
|
98
|
+
/**
|
|
99
|
+
* The overlay body, plus the inspection state the key router drives. The
|
|
100
|
+
* preview is built on the first toggle rather than per frame, so the file read
|
|
101
|
+
* and the diff happen once when the operator asks for them.
|
|
102
|
+
*/
|
|
103
|
+
export interface PermissionOverlayBodyHandle extends Component {
|
|
104
|
+
/** Whether this card has a mutation the operator can read locally. */
|
|
105
|
+
canInspect(): boolean;
|
|
106
|
+
isInspecting(): boolean;
|
|
107
|
+
toggleInspect(): void;
|
|
108
|
+
scrollInspect(delta: number): void;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
class PermissionOverlayBody implements PermissionOverlayBodyHandle {
|
|
112
|
+
private preview: MutationPreview | null = null;
|
|
113
|
+
private scroll = 0;
|
|
114
|
+
private lastLineCount = 0;
|
|
115
|
+
|
|
116
|
+
constructor(
|
|
117
|
+
private readonly view: ApprovalRequestView,
|
|
118
|
+
private readonly inspect?: MutationInspector,
|
|
119
|
+
) {}
|
|
120
|
+
|
|
121
|
+
canInspect(): boolean {
|
|
122
|
+
return this.inspect !== undefined;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
isInspecting(): boolean {
|
|
126
|
+
return this.preview !== null;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
toggleInspect(): void {
|
|
130
|
+
if (this.inspect === undefined) return;
|
|
131
|
+
if (this.preview !== null) {
|
|
132
|
+
this.preview = null;
|
|
133
|
+
this.scroll = 0;
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
this.preview = this.inspect();
|
|
137
|
+
this.scroll = 0;
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
scrollInspect(delta: number): void {
|
|
141
|
+
if (this.preview === null) return;
|
|
142
|
+
const maxScroll = Math.max(0, this.lastLineCount - MUTATION_PREVIEW_VISIBLE_ROWS);
|
|
143
|
+
this.scroll = Math.max(0, Math.min(this.scroll + delta, maxScroll));
|
|
144
|
+
}
|
|
84
145
|
|
|
85
146
|
render(width: number): string[] {
|
|
86
|
-
return permissionOverlayLines(this.view, width);
|
|
147
|
+
if (this.preview === null) return permissionOverlayLines(this.view, width);
|
|
148
|
+
const rendered = permissionInspectionLines(this.view, this.preview, width, this.scroll);
|
|
149
|
+
this.lastLineCount = rendered.wrappedLineCount;
|
|
150
|
+
return rendered.lines;
|
|
87
151
|
}
|
|
88
152
|
|
|
89
153
|
invalidate(): void {}
|
|
@@ -167,14 +231,74 @@ export function permissionOverlayTone(view: ApprovalRequestView): ClioToken {
|
|
|
167
231
|
* three columns the bottom border spends on `─ ` and the trailing space come
|
|
168
232
|
* off the top, which is what `buildResponsiveHint` does for every other frame.
|
|
169
233
|
*/
|
|
170
|
-
export function permissionOverlayHint(
|
|
171
|
-
|
|
234
|
+
export function permissionOverlayHint(
|
|
235
|
+
innerWidth: number,
|
|
236
|
+
composerHasDraft = false,
|
|
237
|
+
inspection: PermissionInspectionHint = "none",
|
|
238
|
+
): string {
|
|
239
|
+
return fitHintEntries(permissionHintEntries(composerHasDraft, inspection), innerWidth - 3);
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
/** The tools whose parked call mutates a file, so a card without a preview owes the operator a reason. */
|
|
243
|
+
function isFileMutationTool(tool: string): boolean {
|
|
244
|
+
return tool === "write" || tool === "edit";
|
|
172
245
|
}
|
|
173
246
|
|
|
174
247
|
function actionConsequence(presentation: DecisionPresentation, id: "deny" | "stop"): string {
|
|
175
248
|
return presentation.requiredActions.find((action) => action.id === id)?.consequence ?? "";
|
|
176
249
|
}
|
|
177
250
|
|
|
251
|
+
/**
|
|
252
|
+
* Hard wrap for mutation text. Prose wraps on words; a proposed file line and a
|
|
253
|
+
* diff row do not, because the column a character sits in is part of what the
|
|
254
|
+
* operator is reading. The continuation marker says the row was folded rather
|
|
255
|
+
* than cut, which is the difference between a wrap and unmarked truncation.
|
|
256
|
+
*/
|
|
257
|
+
function wrapMutationLine(value: string, max: number): string[] {
|
|
258
|
+
if (max <= 1) return [value];
|
|
259
|
+
if (value.length <= max) return [value];
|
|
260
|
+
const lines: string[] = [];
|
|
261
|
+
let remaining = value;
|
|
262
|
+
while (remaining.length > max) {
|
|
263
|
+
lines.push(`${remaining.slice(0, max - 1)}↩`);
|
|
264
|
+
remaining = remaining.slice(max - 1);
|
|
265
|
+
}
|
|
266
|
+
lines.push(remaining);
|
|
267
|
+
return lines;
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
/**
|
|
271
|
+
* The card with the mutation open. The tool, target, and digest facts stay at
|
|
272
|
+
* the top so the bytes on screen remain tied to the call they belong to, and
|
|
273
|
+
* the standing safety prose gives way to the mutation itself: the operator
|
|
274
|
+
* opened this to read what changes, and the keys that answer the ask are on the
|
|
275
|
+
* footer throughout.
|
|
276
|
+
*/
|
|
277
|
+
function permissionInspectionLines(
|
|
278
|
+
view: ApprovalRequestView,
|
|
279
|
+
preview: MutationPreview,
|
|
280
|
+
width: number,
|
|
281
|
+
scroll: number,
|
|
282
|
+
): { lines: string[]; wrappedLineCount: number } {
|
|
283
|
+
const content = Math.max(8, Math.floor(width));
|
|
284
|
+
const wrapped = preview.body.flatMap((line) => wrapMutationLine(line, content));
|
|
285
|
+
const pane = mutationPreviewWindow(wrapped, scroll);
|
|
286
|
+
const notes: string[] = [];
|
|
287
|
+
if (preview.neutralized) notes.push("control characters shown as ·");
|
|
288
|
+
if (preview.tabsExpanded) notes.push("tabs shown as spaces");
|
|
289
|
+
const lines = [
|
|
290
|
+
field("Tool: ", `${view.tool} · Action: ${view.actionClass}`, content),
|
|
291
|
+
...(view.target !== undefined && view.target.length > 0 ? [field("Target: ", view.target, content)] : []),
|
|
292
|
+
...wrapSentence(`Mutation: ${mutationFactsLine(preview.facts)}`, content),
|
|
293
|
+
"",
|
|
294
|
+
...wrapSentence(preview.heading, content),
|
|
295
|
+
...pane.window,
|
|
296
|
+
...(pane.position === null ? [] : [pane.position]),
|
|
297
|
+
...(notes.length > 0 ? [`Rendered safely: ${notes.join(", ")}.`] : []),
|
|
298
|
+
];
|
|
299
|
+
return { lines, wrappedLineCount: wrapped.length };
|
|
300
|
+
}
|
|
301
|
+
|
|
178
302
|
/**
|
|
179
303
|
* The overlay's body, laid out for the width the frame gives it.
|
|
180
304
|
*
|
|
@@ -193,6 +317,24 @@ export function permissionOverlayLines(view: ApprovalRequestView, width: number)
|
|
|
193
317
|
const lines = [
|
|
194
318
|
field("Tool: ", `${view.tool} · Action: ${view.actionClass}`, content),
|
|
195
319
|
...(view.target !== undefined && view.target.length > 0 ? [field("Target: ", view.target, content)] : []),
|
|
320
|
+
// Size and digest stay on the collapsed card whether or not the operator
|
|
321
|
+
// opens the mutation, so the decision always carries the identity of the
|
|
322
|
+
// bytes it applies to.
|
|
323
|
+
// Wrapped, never ellipsized: at 40 columns the digest is the tail of the
|
|
324
|
+
// line, and ellipsizing it would drop the one fact that ties the decision
|
|
325
|
+
// to the bytes it applies to.
|
|
326
|
+
...(view.mutation !== undefined
|
|
327
|
+
? [
|
|
328
|
+
...wrapSentence(`Mutation: ${mutationFactsLine(view.mutation)}`, content),
|
|
329
|
+
...wrapSentence(`Press ${MUTATION_PREVIEW_KEY} to read it before deciding.`, content),
|
|
330
|
+
]
|
|
331
|
+
: []),
|
|
332
|
+
...(view.mutation === undefined && view.origin.kind === "worker" && isFileMutationTool(view.tool)
|
|
333
|
+
? wrapSentence(
|
|
334
|
+
"No local preview: this call's arguments stay inside the worker, so you are approving the target above without inspecting the mutation.",
|
|
335
|
+
content,
|
|
336
|
+
)
|
|
337
|
+
: []),
|
|
196
338
|
...wrapSentence(`Requested by: ${presentation.requestedByCopy}`, content),
|
|
197
339
|
...(view.artifact !== undefined
|
|
198
340
|
? [
|
|
@@ -215,6 +357,14 @@ export function permissionOverlayLines(view: ApprovalRequestView, width: number)
|
|
|
215
357
|
return lines;
|
|
216
358
|
}
|
|
217
359
|
|
|
218
|
-
|
|
219
|
-
|
|
360
|
+
/**
|
|
361
|
+
* The overlay body for one parked call. The inspector, when present, is the
|
|
362
|
+
* only path the mutation text takes: it is never placed on `view`, so nothing
|
|
363
|
+
* that renders or forwards the view can carry the bytes with it.
|
|
364
|
+
*/
|
|
365
|
+
export function createPermissionOverlayBody(
|
|
366
|
+
view: ApprovalRequestView,
|
|
367
|
+
inspect?: MutationInspector,
|
|
368
|
+
): PermissionOverlayBodyHandle {
|
|
369
|
+
return new PermissionOverlayBody(view, inspect);
|
|
220
370
|
}
|