@iowarp/clio-coder 0.4.2 → 0.4.3
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 +35 -0
- package/CONTRIBUTING.md +86 -19
- package/README.md +35 -6
- package/dist/{acp-TMDQZDIG.js → acp-H2NGRPWO.js} +11 -11
- package/dist/{agents-5N5NG3XG.js → agents-TL5LLUQP.js} +54 -53
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-Z5CCBXKQ.js → auth-E5SW4HMS.js} +19 -16
- package/dist/{builtins-K6TNDT24.js → builtins-IA7V7FUC.js} +9 -4
- package/dist/{chunk-ZW4HH5JJ.js → chunk-2APPQIER.js} +6 -6
- package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
- package/dist/{chunk-UBRFI4HS.js → chunk-2UG5F4C5.js} +127 -47
- package/dist/{chunk-UH632ZYL.js → chunk-2UH2KFUP.js} +2 -2
- package/dist/{chunk-3F7VUY77.js → chunk-2VIKGWFZ.js} +2 -2
- package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
- package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
- package/dist/{chunk-2X4RYJTJ.js → chunk-4UVU7BJ5.js} +2 -2
- package/dist/{chunk-M2DAX4F6.js → chunk-4WR7VSYB.js} +2 -2
- package/dist/{chunk-5KW52TEP.js → chunk-54CBCGIR.js} +5 -5
- package/dist/{chunk-3KIPBMUA.js → chunk-5ICU3EUH.js} +2 -2
- package/dist/{chunk-77QIVUZB.js → chunk-5MEZN6CB.js} +4 -4
- package/dist/{chunk-O42A54GG.js → chunk-5OIVVPHF.js} +2 -2
- package/dist/{chunk-LJID3DYZ.js → chunk-64I3JVYM.js} +2 -2
- package/dist/{chunk-4JDLP6ZS.js → chunk-6PTFB5VS.js} +7 -7
- package/dist/{chunk-VN3SHNBN.js → chunk-7DICMOS6.js} +2 -2
- package/dist/{chunk-HLAFFSEK.js → chunk-7DRAWPTZ.js} +2 -2
- package/dist/chunk-7E7I3WLS.js +3762 -0
- package/dist/{chunk-YJISEZKC.js → chunk-7ZYNNDKC.js} +6 -6
- package/dist/{chunk-I66ZTYNP.js → chunk-AF4YM7Z4.js} +236 -101
- package/dist/{chunk-2HFQNRV3.js → chunk-AX2THNSA.js} +12 -12
- package/dist/{chunk-PGF63K6I.js → chunk-B4OAX3SI.js} +65 -3
- package/dist/{chunk-W6NIE6OW.js → chunk-B4VEBZKF.js} +3 -3
- package/dist/{chunk-JBCS7CRR.js → chunk-BEPZRGGU.js} +10 -10
- package/dist/{chunk-XGDPUNND.js → chunk-CE5AX47J.js} +2 -2
- package/dist/{chunk-I64IFBLB.js → chunk-DWUOQKRU.js} +17 -10
- package/dist/{chunk-DZAW46HP.js → chunk-E3TPLWFX.js} +3 -3
- package/dist/{chunk-HIICAHCJ.js → chunk-EKCHAPYA.js} +2 -2
- package/dist/{chunk-XE3PCIXH.js → chunk-F5JHEYZM.js} +7 -7
- package/dist/{chunk-5PFYMY2V.js → chunk-FTMGRKEF.js} +2 -2
- package/dist/{chunk-ZNT2M6TG.js → chunk-G76U63X4.js} +17 -17
- package/dist/{chunk-34BHNEE3.js → chunk-GHS5EBTQ.js} +58 -7
- package/dist/{chunk-2NHR3NAY.js → chunk-GI7YYQ3F.js} +40 -34
- package/dist/{chunk-DYHAXKHD.js → chunk-GWZNEVM2.js} +12 -8
- package/dist/chunk-GYV6VZOC.js +26 -0
- package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
- package/dist/{chunk-W4YEMFBX.js → chunk-HEQY7ZFI.js} +2 -2
- package/dist/{chunk-IKOZFYBN.js → chunk-I7ZPNEJM.js} +145 -102
- package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
- package/dist/{chunk-XQRY4DTA.js → chunk-IGLP3ODT.js} +10 -10
- package/dist/chunk-IJNZMHLA.js +101 -0
- package/dist/{chunk-JWJGP5DQ.js → chunk-INY6HTFL.js} +7 -7
- package/dist/{chunk-PBP4B7XR.js → chunk-IUE3Y34X.js} +2 -2
- package/dist/{chunk-B74PXLU7.js → chunk-IWT4SF4R.js} +3 -3
- package/dist/{chunk-B7HM5Z7T.js → chunk-JDAY6FIL.js} +5 -5
- package/dist/{chunk-PJX3WQUQ.js → chunk-JEQ3XTHC.js} +2 -2
- package/dist/{chunk-FSP7CMNU.js → chunk-JGRC33J2.js} +50 -4
- package/dist/{chunk-X7IARSHT.js → chunk-JKKCYP3C.js} +9 -9
- package/dist/{chunk-HJWWJ6IL.js → chunk-JSC3U7TI.js} +16 -4
- package/dist/{chunk-SSEYRH53.js → chunk-KK4JZPBQ.js} +19 -140
- package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
- package/dist/{chunk-Q4XWMHX6.js → chunk-L47TF46W.js} +2 -2
- package/dist/{chunk-O3YUNJZ2.js → chunk-LDJG7DW3.js} +81 -24
- package/dist/{chunk-CDNVLKUX.js → chunk-LLDJM5XK.js} +13 -7
- package/dist/{chunk-F2I26BDK.js → chunk-MUW2BDDH.js} +4 -4
- package/dist/{chunk-HKMD33FO.js → chunk-MWUZBSAQ.js} +79 -76
- package/dist/{chunk-QQLGQY2A.js → chunk-N2Z7HLVY.js} +20 -20
- package/dist/{chunk-DZEK6CJN.js → chunk-NIQJ66N4.js} +19 -19
- package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
- package/dist/{chunk-462T4EGZ.js → chunk-O5CVSAG5.js} +2 -2
- package/dist/{chunk-TPEQIQIE.js → chunk-OML5D5V5.js} +8 -8
- package/dist/{chunk-IKSLQ4XV.js → chunk-PAJQJ7BS.js} +558 -216
- package/dist/{chunk-ZW55JB7N.js → chunk-PUVDKJ2Y.js} +2 -2
- package/dist/{chunk-UH347SHR.js → chunk-QWGDJJYJ.js} +11 -11
- package/dist/chunk-R6Q67RJH.js +134 -0
- package/dist/{chunk-CRFOIAX3.js → chunk-RRNP2ANY.js} +6 -6
- package/dist/{chunk-IDNA72AH.js → chunk-RSJ25QSL.js} +2 -2
- package/dist/chunk-SKHCAU7K.js +385 -0
- package/dist/{chunk-RLYRBIYQ.js → chunk-TM6LQDI3.js} +20 -12
- package/dist/chunk-UOIZ7DA4.js +41 -0
- package/dist/{chunk-P75RZCJW.js → chunk-UPZU6GE4.js} +3 -3
- package/dist/{chunk-MCMZMDAC.js → chunk-V2ANDPVT.js} +4 -4
- package/dist/{chunk-AK5XEFVZ.js → chunk-VA5FNYMT.js} +26 -13
- package/dist/{chunk-IMXMHHMQ.js → chunk-VW6DOEDG.js} +332 -57
- package/dist/{chunk-XOXV5GKE.js → chunk-W6RRQCPQ.js} +16 -7
- package/dist/{chunk-CYZW7JHJ.js → chunk-WBKFA554.js} +8 -8
- package/dist/{chunk-BO7Y52RY.js → chunk-WCXUNS7U.js} +7 -7
- package/dist/{chunk-ZGNYYXQ6.js → chunk-WRBAGUNF.js} +3 -3
- package/dist/{chunk-FVDGR2ZL.js → chunk-XIVNBFZS.js} +85 -30
- package/dist/{chunk-BYMNWQ7O.js → chunk-XPWWI35G.js} +299 -58
- package/dist/{chunk-KPXDY6QF.js → chunk-XRZT5WY5.js} +2 -2
- package/dist/{chunk-AZ4WMN4W.js → chunk-Y3CBHOR6.js} +2 -2
- package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
- package/dist/{chunk-54ODD65L.js → chunk-YQWYVTMC.js} +4 -4
- package/dist/{chunk-M2WXEHER.js → chunk-ZA4VCIGV.js} +2 -2
- package/dist/{chunk-7BHIY2MW.js → chunk-ZDN3Y73Y.js} +6 -6
- package/dist/{chunk-E7GT7O5N.js → chunk-ZWPRK62N.js} +7 -4
- package/dist/cli/index.js +38 -37
- package/dist/{clio-7VB377CC.js → clio-CMMK4KRR.js} +7 -7
- package/dist/{code-nav-YVLCYA7V.js → code-nav-MDZNQS33.js} +7 -7
- package/dist/{components-UBWCQSRW.js → components-UCUQ4QXW.js} +4 -4
- package/dist/{config-4HVOS65E.js → config-SVM5P5YI.js} +76 -74
- package/dist/{configure-PIWO7B24.js → configure-LE3IK2TJ.js} +26 -24
- package/dist/{context-IYEHL3WQ.js → context-2OHRKS42.js} +66 -63
- package/dist/{context-N6ZE3LGJ.js → context-E3VC7RX5.js} +15 -11
- package/dist/{context-KQYIWPWT.js → context-VNCR7KAG.js} +60 -45
- package/dist/{context-clear-G4OGZJDS.js → context-clear-BW4O37TG.js} +61 -59
- package/dist/context-map-COB37XXN.js +505 -0
- package/dist/{context-working-set-BWLF6LJP.js → context-working-set-VDS25HXZ.js} +17 -16
- package/dist/{dispatch-runner-2QQAITS3.js → dispatch-runner-5AHT53RF.js} +85 -74
- package/dist/{doctor-LHBD36VU.js → doctor-WNNVO6FY.js} +37 -37
- package/dist/{eval-C45FYRJ6.js → eval-7G7SGAYO.js} +285 -114
- package/dist/{eval-inventory-6DEJPLBF.js → eval-inventory-Y6QRFOH5.js} +4 -4
- package/dist/{evidence-6SHONYAF.js → evidence-VD6736FQ.js} +63 -62
- package/dist/{evolve-KRKMV72X.js → evolve-AL3NGVRL.js} +62 -61
- package/dist/{extensions-KPZ2UHBB.js → extensions-MOVJ32NM.js} +7 -7
- package/dist/{fleet-IVTCKDHT.js → fleet-QZHUMAGI.js} +110 -108
- package/dist/{fleet-commands-EDWL3IT7.js → fleet-commands-BAYT5FJZ.js} +10 -10
- package/dist/{fleet-decisions-YP3YEFGK.js → fleet-decisions-IREVMRU4.js} +7 -6
- package/dist/{fleet-graph-ZFWKHY2M.js → fleet-graph-YCTT3HTI.js} +19 -18
- package/dist/{fleet-inspect-FVUNCBML.js → fleet-inspect-QVJTDAVB.js} +55 -54
- package/dist/{fleet-preflight-UN5XED4R.js → fleet-preflight-25QAFPK4.js} +4 -4
- package/dist/{fleet-validate-XOWC4HSX.js → fleet-validate-5O57AAJ7.js} +23 -22
- package/dist/{fleet-verify-UN3SODEL.js → fleet-verify-CPH2W2T6.js} +56 -55
- package/dist/{fleet-view-TWHJKCN6.js → fleet-view-SWBR3VGQ.js} +55 -54
- package/dist/{init-T2QORQ3Y.js → init-J477LKZH.js} +78 -76
- package/dist/{interop-IN5I2A66.js → interop-3FCM6XLG.js} +11 -11
- package/dist/{library-LSCATDLZ.js → library-QUQEIUG6.js} +28 -27
- package/dist/{memory-HYOKAGGJ.js → memory-SGGSEP65.js} +64 -63
- package/dist/{models-2GPMFYCM.js → models-HEKUAXXK.js} +49 -43
- package/dist/{monitor-E4ASVUJH.js → monitor-HKU57TYQ.js} +61 -60
- package/dist/{orchestrator-DDMPR3PY.js → orchestrator-VDFAEFAI.js} +919 -546
- package/dist/{panes-E3RUXOW5.js → panes-DN2SSFOH.js} +3 -3
- package/dist/{panes-IXKLOKA2.js → panes-TALGNPZT.js} +8 -8
- package/dist/{paths-L7LGY6RN.js → paths-NBMFAIEZ.js} +5 -5
- package/dist/reset-EAJFFJVB.js +344 -0
- package/dist/{resources-OTRSN34L.js → resources-OVKSEFVE.js} +27 -20
- package/dist/{run-5DEYH5QK.js → run-7DP7ZF2J.js} +113 -109
- package/dist/{share-IHWTLO3M.js → share-WML67FT3.js} +26 -25
- package/dist/{skills-IYMXMKW4.js → skills-SG662R2K.js} +39 -31
- package/dist/{skills-eval-DROHSJAR.js → skills-eval-VVZEUU46.js} +74 -73
- package/dist/{skills-inventory-D7X4L4ZX.js → skills-inventory-I2E23GET.js} +21 -20
- package/dist/{slash-commands-QBM7UZ3B.js → slash-commands-S7MBJDQK.js} +35 -34
- package/dist/{steer-Z5DO23FJ.js → steer-2LQOMCPB.js} +3 -3
- package/dist/{support-U7QOWY26.js → support-CC2UJBJ6.js} +6 -6
- package/dist/{targets-P2FUC4IL.js → targets-4QC3HIEW.js} +48 -45
- package/dist/{terminal-lease-YREJ3JX2.js → terminal-lease-TUHIJ6Y2.js} +2 -2
- package/dist/{tools-5B7RO6MV.js → tools-TFGJICCU.js} +8 -8
- package/dist/{trace-YMGMUM6A.js → trace-FXMXUZUF.js} +7 -7
- package/dist/uninstall-5PEVOE5B.js +408 -0
- package/dist/upgrade-M4WXY6KN.js +303 -0
- package/dist/{usage-ME5MPXGX.js → usage-N7ZNVLEM.js} +147 -102
- package/dist/{verifiers-BVZ7IWOO.js → verifiers-DJTP4XX6.js} +15 -15
- package/dist/{verify-5K7ZKQFC.js → verify-RWE4PPEK.js} +9 -9
- package/dist/{wiki-generate-F5W5QTYY.js → wiki-generate-C7IQOXSP.js} +84 -82
- package/dist/{with-panes-BYOJCLAM.js → with-panes-4GCGSL7J.js} +9 -9
- package/dist/worker/entry.js +61 -60
- package/docs/architecture/artifact-placement.md +1 -0
- package/docs/architecture/artifact-versions.md +1 -1
- package/docs/architecture/context-engine.md +4 -0
- package/docs/architecture/middleware-and-components.md +1 -1
- package/docs/architecture/model-catalog.md +21 -10
- package/docs/architecture/observability.md +12 -1
- package/docs/architecture/prompt-envelope-and-tools.md +2 -0
- package/docs/architecture/provider-adapter-cookbook.md +63 -0
- package/docs/architecture/safety-model.md +15 -5
- package/docs/guide/built-in-agents.md +17 -3
- package/docs/guide/commands-and-modes.md +1 -1
- package/docs/guide/configuration-and-targets.md +97 -9
- package/docs/guide/configuration-reference.md +7 -2
- package/docs/guide/environment-variables.md +2 -0
- package/docs/guide/installation-and-lifecycle.md +37 -4
- package/docs/guide/proactive-memory.md +66 -55
- package/docs/guide/skills-marketplace.md +18 -0
- package/docs/process/development-pipeline.md +34 -1
- package/docs/process/eval-runner.md +67 -3
- package/evals/behavioral-model.yaml +3 -2
- package/package.json +2 -2
- package/skills/README.md +7 -5
- package/skills/coding/ast-grep/SKILL.md +101 -30
- package/skills/coding/ast-grep/evals.md +26 -0
- package/skills/coding/coding-standards/SKILL.md +40 -5
- package/skills/coding/coding-standards/evals.md +23 -0
- package/skills/coding/prototype/SKILL.md +87 -28
- package/skills/coding/prototype/evals.md +19 -0
- package/skills/coding/tdd/SKILL.md +80 -53
- package/skills/coding/tdd/evals.md +20 -0
- package/skills/context/context-handoff/SKILL.md +43 -2
- package/skills/context/context-handoff/evals.md +44 -0
- package/skills/context/context-prime/SKILL.md +45 -15
- package/skills/context/context-prime/evals.md +45 -0
- package/skills/git/branch-closeout/SKILL.md +132 -0
- package/skills/git/branch-closeout/evals.md +133 -0
- package/skills/git/branch-closeout/references/closeout-checklist.md +81 -0
- package/skills/git/file-ticket/SKILL.md +77 -63
- package/skills/git/file-ticket/assets/issue-template.md +22 -0
- package/skills/git/file-ticket/evals.md +31 -26
- package/skills/git/file-ticket/references/issue-discovery.md +49 -0
- package/skills/git/fix-issue/SKILL.md +87 -64
- package/skills/git/fix-issue/evals.md +35 -31
- package/skills/git/fix-issue/references/diagnosis-and-rca.md +46 -0
- package/skills/git/resolve-merge-conflicts/SKILL.md +100 -51
- package/skills/git/resolve-merge-conflicts/evals.md +52 -25
- package/skills/git/resolve-merge-conflicts/references/conflict-matrix.md +126 -0
- package/skills/git/ship/SKILL.md +103 -67
- package/skills/git/ship/assets/pr-template.md +21 -0
- package/skills/git/ship/evals.md +44 -28
- package/skills/git/ship/references/remote-and-branch-policy.md +62 -0
- package/skills/git/worktree-create/SKILL.md +80 -50
- package/skills/git/worktree-create/evals.md +40 -33
- package/skills/git/worktree-create/references/worktree-setup.md +62 -66
- package/skills/git/worktree-merge/SKILL.md +112 -65
- package/skills/git/worktree-merge/evals.md +42 -34
- package/skills/git/worktree-merge/references/merge-strategies.md +52 -0
- package/skills/planning/archify/SKILL.md +196 -0
- package/skills/planning/archify/evals.md +65 -0
- package/skills/planning/architecture/SKILL.md +61 -12
- package/skills/planning/architecture/evals.md +65 -0
- package/skills/planning/backlog/SKILL.md +130 -14
- package/skills/planning/backlog/evals.md +142 -0
- package/skills/planning/prd/SKILL.md +46 -6
- package/skills/planning/prd/evals.md +54 -0
- package/skills/planning/product-intent/SKILL.md +57 -2
- package/skills/planning/product-intent/evals.md +70 -0
- package/skills/planning/tech-spec/SKILL.md +53 -2
- package/skills/planning/tech-spec/evals.md +73 -0
- package/skills/registry.yaml +58 -50
- package/skills/remote.yaml +13 -0
- package/skills/research/arxiv-literature/SKILL.md +76 -18
- package/skills/research/arxiv-literature/evals.md +50 -0
- package/skills/research/experiment-protocol/SKILL.md +20 -1
- package/skills/research/experiment-protocol/evals.md +23 -0
- package/skills/research/scientific-debugging/SKILL.md +23 -1
- package/skills/research/scientific-debugging/evals.md +18 -0
- package/skills/research/scientific-modernization/SKILL.md +26 -1
- package/skills/research/scientific-modernization/evals.md +27 -0
- package/skills/skill-marketplace.json +63 -28
- package/skills/workflow/cut-it/SKILL.md +65 -5
- package/skills/workflow/cut-it/evals.md +101 -0
- package/skills/workflow/design-council/SKILL.md +117 -27
- package/skills/workflow/design-council/evals.md +161 -0
- package/skills/workflow/grill-me/SKILL.md +86 -10
- package/skills/workflow/grill-me/evals.md +153 -0
- package/skills/workflow/workflow-distiller/SKILL.md +76 -17
- package/skills/workflow/workflow-distiller/evals.md +118 -0
- package/src/cli/configure-interop.ts +105 -13
- package/src/cli/configure-oauth.ts +57 -0
- package/src/cli/configure-onboarding.ts +980 -0
- package/src/cli/configure-target.ts +594 -0
- package/src/cli/configure.ts +1082 -528
- package/src/cli/context-map.ts +114 -0
- package/src/cli/context.ts +4 -0
- package/src/cli/index.ts +1 -0
- package/src/cli/lifecycle-presenter.ts +436 -0
- package/src/cli/models.ts +10 -2
- package/src/cli/modes/print.ts +5 -1
- package/src/cli/reset.ts +228 -106
- package/src/cli/run.ts +7 -2
- package/src/cli/select.ts +664 -0
- package/src/cli/skills.ts +9 -2
- package/src/cli/targets.ts +3 -0
- package/src/cli/uninstall.ts +233 -165
- package/src/cli/upgrade.ts +204 -149
- package/src/cli/usage.ts +86 -27
- package/src/cli/validate-model.ts +3 -3
- package/src/core/config.ts +56 -0
- package/src/core/external-diagnostic.ts +44 -0
- package/src/core/gateway-routing.ts +157 -0
- package/src/core/safe-exec.ts +17 -2
- package/src/core/skill-activation.ts +89 -2
- package/src/domains/agents/builtins/world-knowledge.md +31 -0
- package/src/domains/agents/catalog.ts +1 -1
- package/src/domains/agents/result-contract.ts +70 -0
- package/src/domains/context/wiki/map-seed.ts +589 -0
- package/src/domains/context/wiki/plan.ts +2 -2
- package/src/domains/dispatch/admission.ts +29 -0
- package/src/domains/dispatch/agent-candidates.ts +10 -0
- package/src/domains/dispatch/budget-envelope.ts +86 -1
- package/src/domains/dispatch/capability-match.ts +1 -0
- package/src/domains/dispatch/capacity-lease.ts +17 -0
- package/src/domains/dispatch/contract.ts +11 -1
- package/src/domains/dispatch/extension.ts +134 -29
- package/src/domains/dispatch/types.ts +3 -0
- package/src/domains/dispatch/worker-model-metadata.ts +38 -0
- package/src/domains/eval/metrics/call-ledger-stream.ts +34 -11
- package/src/domains/eval/metrics/token-stream.ts +201 -31
- package/src/domains/eval/metrics/tracked.ts +40 -4
- package/src/domains/eval/runners/clio-run.ts +5 -2
- package/src/domains/eval/schema/suite.ts +28 -0
- package/src/domains/eval/schema/verdict.ts +2 -2
- package/src/domains/eval/suites/resolve.ts +13 -1
- package/src/domains/eval/suites/run.ts +24 -3
- package/src/domains/interop/registry.ts +6 -2
- package/src/domains/interop/types.ts +4 -0
- package/src/domains/lifecycle/migrations/index.ts +4 -0
- package/src/domains/memory/task-memory-policy.ts +70 -26
- package/src/domains/memory/task-memory-telemetry.ts +1 -0
- package/src/domains/middleware/index.ts +0 -1
- package/src/domains/middleware/marketplace-offer.ts +3 -35
- package/src/domains/middleware/memory-intervention.ts +127 -32
- package/src/domains/middleware/memory-step-endpoint.ts +3 -2
- package/src/domains/middleware/skills-reminder.ts +31 -2
- package/src/domains/observability/compaction-usage.ts +118 -0
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/extension.ts +6 -1
- package/src/domains/observability/out-of-turn-usage.ts +52 -21
- package/src/domains/providers/contract.ts +4 -1
- package/src/domains/providers/extension.ts +40 -9
- package/src/domains/providers/model-capabilities.ts +9 -0
- package/src/domains/providers/model-discovery.ts +2 -0
- package/src/domains/providers/model-runtime-capabilities.ts +15 -5
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +32 -12
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
- package/src/domains/providers/runtimes/common/lmstudio-http.ts +6 -2
- package/src/domains/providers/runtimes/common/local-synth.ts +2 -0
- package/src/domains/providers/runtimes/protocol/litellm.ts +119 -29
- package/src/domains/providers/support.ts +11 -5
- package/src/domains/providers/target-model-cache.ts +25 -2
- package/src/domains/providers/types/capability-flags.ts +2 -0
- package/src/domains/providers/types/runtime-descriptor.ts +20 -1
- package/src/domains/providers/types/target-descriptor.ts +19 -0
- package/src/domains/resources/index.ts +3 -0
- package/src/domains/resources/skills/install.ts +72 -7
- package/src/domains/resources/skills/loader.ts +7 -0
- package/src/domains/resources/skills/marketplace.ts +63 -11
- package/src/domains/safety/autonomy.ts +15 -0
- package/src/domains/safety/index.ts +1 -0
- package/src/domains/safety/path-policy.ts +1 -1
- package/src/domains/safety/policy-engine.ts +34 -11
- package/src/domains/safety/protected-artifacts.ts +191 -88
- package/src/domains/safety/run-effects.ts +2 -22
- package/src/domains/safety/skill-authority.ts +55 -0
- package/src/domains/session/compaction/compact.ts +72 -22
- package/src/domains/session/entries.ts +6 -0
- package/src/domains/session/usage.ts +3 -3
- package/src/engine/agent.ts +13 -3
- package/src/engine/ai.ts +26 -8
- package/src/engine/antigravity/subprocess-runtime.ts +386 -120
- package/src/engine/api-registry.ts +3 -0
- package/src/engine/apis/openai-completions.ts +117 -14
- package/src/engine/external-subprocess.ts +114 -6
- package/src/entry/background-model-metadata.ts +18 -0
- package/src/entry/compaction-prompt.ts +57 -0
- package/src/entry/orchestrator.ts +405 -216
- package/src/entry/task-memory-lifecycle.ts +35 -0
- package/src/interactive/chat-loop-messages.ts +13 -4
- package/src/interactive/chat-loop.ts +65 -2
- package/src/interactive/chat-renderer.ts +1 -0
- package/src/interactive/cost-overlay.ts +26 -2
- package/src/interactive/interactive-slash-runtime.ts +2 -1
- package/src/interactive/renderers/worker-entry.ts +32 -0
- package/src/interactive/slash-commands.ts +24 -6
- package/src/interactive/theme/labels.ts +19 -13
- package/src/interactive/turn-context.ts +9 -5
- package/src/interactive/turn-recovery.ts +8 -0
- package/src/interactive/turn-runtime.ts +27 -11
- package/src/interactive/turn-state.ts +7 -0
- package/src/interactive/worker-receipts.ts +1 -0
- package/src/interactive/worker-stream.ts +6 -1
- package/src/tools/context/index.ts +30 -9
- package/src/tools/dispatch-arguments.ts +1 -0
- package/src/tools/dispatch-event-text.ts +10 -0
- package/src/tools/dispatch-plan.ts +1 -0
- package/src/tools/dispatch-runner.ts +12 -0
- package/src/tools/registry.ts +11 -5
- package/src/tools/worker-evidence.ts +3 -1
- package/src/worker/spec-contract.ts +4 -0
- package/dist/chunk-2Z2IKEXI.js +0 -1554
- package/dist/reset-OAQP3W4O.js +0 -230
- package/dist/uninstall-N34PCTGJ.js +0 -331
- package/dist/upgrade-PXK3S2YM.js +0 -325
|
@@ -17,6 +17,11 @@ import {
|
|
|
17
17
|
} from "@earendil-works/pi-ai";
|
|
18
18
|
import { openAICompletionsApi } from "@earendil-works/pi-ai/api/openai-completions.lazy";
|
|
19
19
|
import type { BackendCompletionTimings, BackendTimingsSource } from "../../core/cache-telemetry.js";
|
|
20
|
+
import {
|
|
21
|
+
type GatewayRoutingObservation,
|
|
22
|
+
liteLLMGatewayRoutingFromHeaders,
|
|
23
|
+
liteLLMRouteFailureMessage,
|
|
24
|
+
} from "../../core/gateway-routing.js";
|
|
20
25
|
import type { ResponseModelIdObservation } from "../../core/response-model-id.js";
|
|
21
26
|
import {
|
|
22
27
|
type AppliedThinking,
|
|
@@ -27,7 +32,7 @@ import {
|
|
|
27
32
|
import { lmStudioReasoningEffort } from "../../domains/providers/runtimes/common/lmstudio-http.js";
|
|
28
33
|
import type { ThinkingLevel } from "../../domains/providers/types/capability-flags.js";
|
|
29
34
|
import type { LocalModelQuirks, SamplingProfile } from "../../domains/providers/types/local-model-quirks.js";
|
|
30
|
-
import type { LmStudioTargetSettings } from "../../domains/providers/types/target-descriptor.js";
|
|
35
|
+
import type { LiteLLMTargetSettings, LmStudioTargetSettings } from "../../domains/providers/types/target-descriptor.js";
|
|
31
36
|
import { filterGemmaChannelStream, usesGemmaChannelMarkers } from "../gemma-channel-filter.js";
|
|
32
37
|
import { HarmonyResponseParser } from "../harmony-response.js";
|
|
33
38
|
import { createSentinelStripper, stripTokenizerSentinels } from "../strip-tokenizer-sentinels.js";
|
|
@@ -42,6 +47,8 @@ declare module "@earendil-works/pi-ai" {
|
|
|
42
47
|
interface AssistantMessage {
|
|
43
48
|
/** Direct observation of model-id presence in an OpenAI-compatible response. */
|
|
44
49
|
responseModelIdObservation?: ResponseModelIdObservation;
|
|
50
|
+
/** Route, fallback, retry, and proxy timing facts reported by LiteLLM. */
|
|
51
|
+
gatewayRouting?: GatewayRoutingObservation;
|
|
45
52
|
/** Backend-reported prefill and prediction timings when available. */
|
|
46
53
|
backendTimings?: BackendCompletionTimings;
|
|
47
54
|
}
|
|
@@ -69,6 +76,7 @@ interface ClioRuntimeMetadata {
|
|
|
69
76
|
quirks?: LocalModelQuirks;
|
|
70
77
|
chatTemplateKwargsUnsupported?: boolean;
|
|
71
78
|
lmstudio?: LmStudioTargetSettings;
|
|
79
|
+
litellm?: LiteLLMTargetSettings;
|
|
72
80
|
lmstudioReasoningOptions?: ReadonlyArray<string>;
|
|
73
81
|
lmstudioDefaultModel?: string;
|
|
74
82
|
};
|
|
@@ -101,6 +109,7 @@ interface ResponseModelIdCapture {
|
|
|
101
109
|
modelIdDone: boolean;
|
|
102
110
|
backendTimings: BackendCompletionTimings | null;
|
|
103
111
|
backendTimingsSource: BackendTimingsSource | null;
|
|
112
|
+
gatewayRouting: GatewayRoutingObservation | null;
|
|
104
113
|
buffer: string;
|
|
105
114
|
decoder: TextDecoder | null;
|
|
106
115
|
}
|
|
@@ -199,7 +208,10 @@ function observeResponseModelIdBytes(
|
|
|
199
208
|
if (captureCanStopEarly(capture) || flush) capture.decoder = null;
|
|
200
209
|
}
|
|
201
210
|
|
|
202
|
-
function captureResponseModelId(response: Response, capture: ResponseModelIdCapture): Response {
|
|
211
|
+
function captureResponseModelId(response: Response, capture: ResponseModelIdCapture, model: Model<Api>): Response {
|
|
212
|
+
if (runtimeMetadata(model)?.runtimeId === "litellm") {
|
|
213
|
+
capture.gatewayRouting = liteLLMGatewayRoutingFromHeaders(response.headers);
|
|
214
|
+
}
|
|
203
215
|
if (!response.body || !response.headers.get("content-type")?.toLowerCase().includes("text/event-stream")) {
|
|
204
216
|
return response;
|
|
205
217
|
}
|
|
@@ -234,6 +246,7 @@ function withResponseModelIdCapture<TOptions extends StreamOptions>(
|
|
|
234
246
|
modelIdDone: false,
|
|
235
247
|
backendTimings: null,
|
|
236
248
|
backendTimingsSource: backendTimingsSourceForModel(model),
|
|
249
|
+
gatewayRouting: null,
|
|
237
250
|
buffer: "",
|
|
238
251
|
decoder: new TextDecoder(),
|
|
239
252
|
};
|
|
@@ -241,7 +254,7 @@ function withResponseModelIdCapture<TOptions extends StreamOptions>(
|
|
|
241
254
|
options.fetch ?? ((input, init) => globalThis.fetch(input, init));
|
|
242
255
|
const capturedOptions = {
|
|
243
256
|
...options,
|
|
244
|
-
fetch: async (input, init) => captureResponseModelId(await fetchImpl(input, init), capture),
|
|
257
|
+
fetch: async (input, init) => captureResponseModelId(await fetchImpl(input, init), capture, model),
|
|
245
258
|
} as TOptions;
|
|
246
259
|
const source = sourceFactory(capturedOptions);
|
|
247
260
|
const annotated = createAssistantMessageEventStream();
|
|
@@ -255,9 +268,11 @@ function withResponseModelIdCapture<TOptions extends StreamOptions>(
|
|
|
255
268
|
: { state: "not-observed" };
|
|
256
269
|
if (event.type === "done") {
|
|
257
270
|
event.message.responseModelIdObservation = observation;
|
|
271
|
+
if (capture.gatewayRouting !== null) event.message.gatewayRouting = capture.gatewayRouting;
|
|
258
272
|
if (capture.backendTimings !== null) event.message.backendTimings = capture.backendTimings;
|
|
259
273
|
} else if (event.type === "error") {
|
|
260
274
|
event.error.responseModelIdObservation = observation;
|
|
275
|
+
if (capture.gatewayRouting !== null) event.error.gatewayRouting = capture.gatewayRouting;
|
|
261
276
|
if (capture.backendTimings !== null) event.error.backendTimings = capture.backendTimings;
|
|
262
277
|
}
|
|
263
278
|
annotated.push(event as AssistantMessageEvent);
|
|
@@ -271,6 +286,31 @@ function withResponseModelIdCapture<TOptions extends StreamOptions>(
|
|
|
271
286
|
return annotated;
|
|
272
287
|
}
|
|
273
288
|
|
|
289
|
+
/** Make a failed physical gateway route final and useful to an operator. */
|
|
290
|
+
function withLiteLLMRouteFailureAdvice(
|
|
291
|
+
model: Model<"openai-completions">,
|
|
292
|
+
source: AssistantMessageEventStream,
|
|
293
|
+
): AssistantMessageEventStream {
|
|
294
|
+
const metadata = runtimeMetadata(model);
|
|
295
|
+
if (metadata?.runtimeId !== "litellm") return source;
|
|
296
|
+
const advised = createAssistantMessageEventStream();
|
|
297
|
+
(async () => {
|
|
298
|
+
try {
|
|
299
|
+
for await (const event of source) {
|
|
300
|
+
if (event.type === "error") {
|
|
301
|
+
event.error.errorMessage = liteLLMRouteFailureMessage(event.error.errorMessage, metadata.targetId, model.id);
|
|
302
|
+
}
|
|
303
|
+
advised.push(event as AssistantMessageEvent);
|
|
304
|
+
}
|
|
305
|
+
advised.end();
|
|
306
|
+
} catch (err) {
|
|
307
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
308
|
+
throw new Error(liteLLMRouteFailureMessage(message, metadata.targetId, model.id));
|
|
309
|
+
}
|
|
310
|
+
})();
|
|
311
|
+
return advised;
|
|
312
|
+
}
|
|
313
|
+
|
|
274
314
|
function samplingParamsFromProfile(profile: SamplingProfile): Record<string, unknown> {
|
|
275
315
|
return {
|
|
276
316
|
...(profile.topP !== undefined ? { top_p: profile.topP } : {}),
|
|
@@ -395,6 +435,17 @@ function applyThinkingPayload(
|
|
|
395
435
|
) {
|
|
396
436
|
next.reasoning_effort = resolved.request.reasoningEffort;
|
|
397
437
|
}
|
|
438
|
+
// LiteLLM generic openai/<local model> routes otherwise drop this standard
|
|
439
|
+
// parameter. Allow only the effort this model/runtime actually resolved;
|
|
440
|
+
// unknown off controls and unrelated caller parameters gain no allowance.
|
|
441
|
+
if (
|
|
442
|
+
resolved.runtimeId === "litellm" &&
|
|
443
|
+
resolved.request.reasoningEffort &&
|
|
444
|
+
next.reasoning_effort === resolved.request.reasoningEffort
|
|
445
|
+
) {
|
|
446
|
+
const allowed = Array.isArray(next.allowed_openai_params) ? next.allowed_openai_params : [];
|
|
447
|
+
next.allowed_openai_params = [...new Set([...allowed, "reasoning_effort"])];
|
|
448
|
+
}
|
|
398
449
|
if (resolved.request.chatTemplateKwargs && !chatTemplateKwargsUnsupported(model)) {
|
|
399
450
|
const existing = isPlainRecord(next.chat_template_kwargs) ? next.chat_template_kwargs : {};
|
|
400
451
|
next.chat_template_kwargs = { ...existing, ...resolved.request.chatTemplateKwargs };
|
|
@@ -433,15 +484,15 @@ function applyLmStudioPayload(
|
|
|
433
484
|
if (request?.ttlSeconds !== undefined) next.ttl = request.ttlSeconds;
|
|
434
485
|
if (request?.draftModel !== undefined) next.draft_model = request.draftModel;
|
|
435
486
|
if (resolved.thinking.mechanism === "none" || resolved.thinking.mechanism === "always-on") return next;
|
|
436
|
-
const resolvedEffort =
|
|
437
|
-
resolved.
|
|
438
|
-
lmStudioReasoningEffort(resolved.thinking.effectiveLevel
|
|
487
|
+
const resolvedEffort = runtimeMetadata(model)?.lmstudioReasoningOptions
|
|
488
|
+
? lmStudioReasoningEffort(resolved.thinking.effectiveLevel, runtimeMetadata(model)?.lmstudioReasoningOptions)
|
|
489
|
+
: (resolved.request.reasoningEffort ?? lmStudioReasoningEffort(resolved.thinking.effectiveLevel));
|
|
439
490
|
switch (request?.reasoning) {
|
|
440
491
|
case "off":
|
|
441
|
-
next.reasoning_effort = "
|
|
492
|
+
next.reasoning_effort = lmStudioReasoningEffort("off", runtimeMetadata(model)?.lmstudioReasoningOptions);
|
|
442
493
|
break;
|
|
443
494
|
case "on":
|
|
444
|
-
next.reasoning_effort = "low";
|
|
495
|
+
next.reasoning_effort = lmStudioReasoningEffort("low", runtimeMetadata(model)?.lmstudioReasoningOptions);
|
|
445
496
|
break;
|
|
446
497
|
case "low":
|
|
447
498
|
case "medium":
|
|
@@ -584,6 +635,50 @@ function withRemainingContextBudget<TOptions extends StreamOptions>(
|
|
|
584
635
|
} as TOptions;
|
|
585
636
|
}
|
|
586
637
|
|
|
638
|
+
function hasHeader(headers: Readonly<Record<string, unknown>> | undefined, name: string): boolean {
|
|
639
|
+
if (!headers) return false;
|
|
640
|
+
const wanted = name.toLowerCase();
|
|
641
|
+
return Object.keys(headers).some((key) => key.toLowerCase() === wanted);
|
|
642
|
+
}
|
|
643
|
+
|
|
644
|
+
/**
|
|
645
|
+
* Apply LiteLLM's request-control headers at the final transport boundary.
|
|
646
|
+
*
|
|
647
|
+
* The OpenAI SDK otherwise retries twice below Clio's visible recovery loop and
|
|
648
|
+
* below LiteLLM's own router, multiplying a single failure into several hidden
|
|
649
|
+
* attempts. Gateway requests use zero client retries by default; optional
|
|
650
|
+
* `numRetries` controls the proxy router itself, where any configured attempts
|
|
651
|
+
* remain observable. A physical-routing gateway should leave it at zero.
|
|
652
|
+
*/
|
|
653
|
+
function withLiteLLMRequestOptions<TOptions extends StreamOptions>(
|
|
654
|
+
model: Model<"openai-completions">,
|
|
655
|
+
options: TOptions,
|
|
656
|
+
): TOptions {
|
|
657
|
+
const metadata = runtimeMetadata(model);
|
|
658
|
+
if (metadata?.runtimeId !== "litellm") return options;
|
|
659
|
+
const request = metadata.litellm?.request;
|
|
660
|
+
const modelHeaders = model.headers as Readonly<Record<string, unknown>> | undefined;
|
|
661
|
+
const optionHeaders = options.headers as Readonly<Record<string, unknown>> | undefined;
|
|
662
|
+
const headers: Record<string, string | null> = { ...(options.headers ?? {}) };
|
|
663
|
+
const setDefault = (name: string, value: string | undefined): void => {
|
|
664
|
+
if (value === undefined || hasHeader(modelHeaders, name) || hasHeader(optionHeaders, name)) return;
|
|
665
|
+
headers[name] = value;
|
|
666
|
+
};
|
|
667
|
+
setDefault("x-litellm-tags", ["clio-coder", ...(request?.tags ?? [])].join(","));
|
|
668
|
+
if (request?.sendSessionId !== false) setDefault("x-litellm-session-id", options.sessionId);
|
|
669
|
+
setDefault("x-litellm-timeout", request?.timeoutSeconds?.toString());
|
|
670
|
+
setDefault("x-litellm-stream-timeout", request?.streamTimeoutSeconds?.toString());
|
|
671
|
+
setDefault("x-litellm-num-retries", request?.numRetries?.toString());
|
|
672
|
+
return {
|
|
673
|
+
...options,
|
|
674
|
+
headers,
|
|
675
|
+
// Never hide duplicate attempts inside the OpenAI SDK beneath Clio's
|
|
676
|
+
// operator-visible failure. The gateway may still be configured to retry,
|
|
677
|
+
// but physical-routing deployments should keep that policy at zero too.
|
|
678
|
+
maxRetries: options.maxRetries ?? 0,
|
|
679
|
+
} as TOptions;
|
|
680
|
+
}
|
|
681
|
+
|
|
587
682
|
function requiredToolArguments(tool: Tool): ReadonlyArray<string> {
|
|
588
683
|
const schema = tool.parameters as unknown;
|
|
589
684
|
if (schema === null || typeof schema !== "object" || Array.isArray(schema)) return [];
|
|
@@ -921,15 +1016,18 @@ export const openAICompletionsApiProvider: EngineApiProvider<"openai-completions
|
|
|
921
1016
|
const resolved = resolvedCapabilitiesForModel(model, defaultLevel);
|
|
922
1017
|
const effectiveContext = stripsThinking(resolved) ? stripThinkingFromContext(context) : context;
|
|
923
1018
|
const withSamplers = withSamplingOverrides(model, options, resolved);
|
|
1019
|
+
const withGatewayOptions = withLiteLLMRequestOptions(
|
|
1020
|
+
model,
|
|
1021
|
+
withRemainingContextBudget(model, effectiveContext, withSamplers),
|
|
1022
|
+
);
|
|
924
1023
|
return guardMalformedToolCalls(
|
|
925
1024
|
withReasoningTokenEstimate(
|
|
926
1025
|
stripSentinelsFromStream(
|
|
927
1026
|
stripNeverReasoningFromStream(
|
|
928
1027
|
filterGemmaChannelStream(
|
|
929
|
-
|
|
1028
|
+
withLiteLLMRouteFailureAdvice(
|
|
930
1029
|
model,
|
|
931
|
-
|
|
932
|
-
(capturedOptions) =>
|
|
1030
|
+
withResponseModelIdCapture(model, withGatewayOptions, (capturedOptions) =>
|
|
933
1031
|
withLocalResidency(
|
|
934
1032
|
model,
|
|
935
1033
|
{
|
|
@@ -938,6 +1036,7 @@ export const openAICompletionsApiProvider: EngineApiProvider<"openai-completions
|
|
|
938
1036
|
},
|
|
939
1037
|
(requestModel) => piOpenAICompletions.stream(requestModel, effectiveContext, capturedOptions),
|
|
940
1038
|
),
|
|
1039
|
+
),
|
|
941
1040
|
),
|
|
942
1041
|
usesGemmaChannelMarkers(resolved.modelId),
|
|
943
1042
|
),
|
|
@@ -954,15 +1053,18 @@ export const openAICompletionsApiProvider: EngineApiProvider<"openai-completions
|
|
|
954
1053
|
const resolved = resolvedCapabilitiesForModel(model, thinkingLevelFromSimple(options));
|
|
955
1054
|
const effectiveContext = stripsThinking(resolved) ? stripThinkingFromContext(context) : context;
|
|
956
1055
|
const withSamplers = withSamplingOverrides(model, options, resolved);
|
|
1056
|
+
const withGatewayOptions = withLiteLLMRequestOptions(
|
|
1057
|
+
model,
|
|
1058
|
+
withRemainingContextBudget(model, effectiveContext, withSamplers),
|
|
1059
|
+
);
|
|
957
1060
|
return guardMalformedToolCalls(
|
|
958
1061
|
withReasoningTokenEstimate(
|
|
959
1062
|
stripSentinelsFromStream(
|
|
960
1063
|
stripNeverReasoningFromStream(
|
|
961
1064
|
filterGemmaChannelStream(
|
|
962
|
-
|
|
1065
|
+
withLiteLLMRouteFailureAdvice(
|
|
963
1066
|
model,
|
|
964
|
-
|
|
965
|
-
(capturedOptions) =>
|
|
1067
|
+
withResponseModelIdCapture(model, withGatewayOptions, (capturedOptions) =>
|
|
966
1068
|
withLocalResidency(
|
|
967
1069
|
model,
|
|
968
1070
|
{
|
|
@@ -971,6 +1073,7 @@ export const openAICompletionsApiProvider: EngineApiProvider<"openai-completions
|
|
|
971
1073
|
},
|
|
972
1074
|
(requestModel) => piOpenAICompletions.streamSimple(requestModel, effectiveContext, capturedOptions),
|
|
973
1075
|
),
|
|
1076
|
+
),
|
|
974
1077
|
),
|
|
975
1078
|
usesGemmaChannelMarkers(resolved.modelId),
|
|
976
1079
|
),
|
|
@@ -1,15 +1,117 @@
|
|
|
1
1
|
import type { ChildProcessByStdio } from "node:child_process";
|
|
2
2
|
import type { Readable } from "node:stream";
|
|
3
3
|
|
|
4
|
+
import { boundedExternalDiagnostic } from "../core/external-diagnostic.js";
|
|
5
|
+
|
|
4
6
|
export type SubprocessWithStdio = ChildProcessByStdio<null, Readable, Readable>;
|
|
5
7
|
|
|
8
|
+
export type BoundedLine = { kind: "line"; line: string } | { kind: "oversized" };
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Split a byte stream without ever retaining more than one bounded line.
|
|
12
|
+
* Node has already allocated each incoming chunk, but an unterminated provider
|
|
13
|
+
* line cannot make this decoder accumulate without limit.
|
|
14
|
+
*/
|
|
15
|
+
export async function* readBoundedLines(
|
|
16
|
+
readable: Readable,
|
|
17
|
+
options: { maxLineBytes: number; maxTotalBytes: number },
|
|
18
|
+
): AsyncGenerator<BoundedLine> {
|
|
19
|
+
let segments: Buffer[] = [];
|
|
20
|
+
let lineBytes = 0;
|
|
21
|
+
let totalBytes = 0;
|
|
22
|
+
let discarding = false;
|
|
23
|
+
const finishLine = (): BoundedLine | null => {
|
|
24
|
+
if (discarding) {
|
|
25
|
+
segments = [];
|
|
26
|
+
lineBytes = 0;
|
|
27
|
+
discarding = false;
|
|
28
|
+
return { kind: "oversized" };
|
|
29
|
+
}
|
|
30
|
+
if (lineBytes === 0) return { kind: "line", line: "" };
|
|
31
|
+
const joined = Buffer.concat(segments, lineBytes);
|
|
32
|
+
segments = [];
|
|
33
|
+
lineBytes = 0;
|
|
34
|
+
const end = joined.at(-1) === 0x0d ? joined.length - 1 : joined.length;
|
|
35
|
+
return { kind: "line", line: joined.subarray(0, end).toString("utf8") };
|
|
36
|
+
};
|
|
37
|
+
|
|
38
|
+
for await (const raw of readable) {
|
|
39
|
+
const chunk = Buffer.isBuffer(raw) ? raw : Buffer.from(String(raw));
|
|
40
|
+
totalBytes += chunk.byteLength;
|
|
41
|
+
if (totalBytes > options.maxTotalBytes) throw new Error("external stdout exceeded the cumulative output limit");
|
|
42
|
+
let offset = 0;
|
|
43
|
+
while (offset < chunk.length) {
|
|
44
|
+
const newline = chunk.indexOf(0x0a, offset);
|
|
45
|
+
const end = newline === -1 ? chunk.length : newline;
|
|
46
|
+
const piece = chunk.subarray(offset, end);
|
|
47
|
+
if (!discarding && piece.length > 0) {
|
|
48
|
+
if (lineBytes + piece.length > options.maxLineBytes) {
|
|
49
|
+
segments = [];
|
|
50
|
+
lineBytes = 0;
|
|
51
|
+
discarding = true;
|
|
52
|
+
} else {
|
|
53
|
+
segments.push(piece);
|
|
54
|
+
lineBytes += piece.length;
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
if (newline === -1) break;
|
|
58
|
+
const line = finishLine();
|
|
59
|
+
if (line) yield line;
|
|
60
|
+
offset = newline + 1;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
if (discarding || lineBytes > 0) {
|
|
64
|
+
const line = finishLine();
|
|
65
|
+
if (line) yield line;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
|
|
6
69
|
export async function readStderr(child: { stderr: Readable }): Promise<string> {
|
|
7
|
-
let
|
|
70
|
+
let tail = Buffer.alloc(0);
|
|
8
71
|
for await (const chunk of child.stderr) {
|
|
9
|
-
|
|
10
|
-
|
|
72
|
+
const bytes = Buffer.isBuffer(chunk) ? chunk : Buffer.from(String(chunk));
|
|
73
|
+
tail = Buffer.concat([tail, bytes]);
|
|
74
|
+
if (tail.byteLength > 8192) tail = tail.subarray(tail.byteLength - 8192);
|
|
11
75
|
}
|
|
12
|
-
return
|
|
76
|
+
return boundedExternalDiagnostic(tail.toString("utf8"));
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
export interface ProcessTreeTerminator {
|
|
80
|
+
terminate(): void;
|
|
81
|
+
cleanup(): void;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
/** POSIX process-group termination with a direct-child fallback; Windows is direct-child only. */
|
|
85
|
+
export function createProcessTreeTerminator(
|
|
86
|
+
child: { pid?: number | undefined; exitCode: number | null; kill(signal?: NodeJS.Signals): boolean },
|
|
87
|
+
graceMs = 1500,
|
|
88
|
+
): ProcessTreeTerminator {
|
|
89
|
+
let sent = false;
|
|
90
|
+
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
91
|
+
const signal = (name: NodeJS.Signals): void => {
|
|
92
|
+
if (child.exitCode !== null) return;
|
|
93
|
+
if (child.pid && process.platform !== "win32") {
|
|
94
|
+
try {
|
|
95
|
+
process.kill(-child.pid, name);
|
|
96
|
+
return;
|
|
97
|
+
} catch {
|
|
98
|
+
// The child may not have established its group yet.
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
child.kill(name);
|
|
102
|
+
};
|
|
103
|
+
return {
|
|
104
|
+
terminate() {
|
|
105
|
+
if (sent) return;
|
|
106
|
+
sent = true;
|
|
107
|
+
signal("SIGTERM");
|
|
108
|
+
timer = setTimeout(() => signal("SIGKILL"), graceMs);
|
|
109
|
+
},
|
|
110
|
+
cleanup() {
|
|
111
|
+
if (timer) clearTimeout(timer);
|
|
112
|
+
timer = null;
|
|
113
|
+
},
|
|
114
|
+
};
|
|
13
115
|
}
|
|
14
116
|
|
|
15
117
|
export function waitForClose(child: {
|
|
@@ -17,7 +119,13 @@ export function waitForClose(child: {
|
|
|
17
119
|
once(event: "close", listener: (code: number | null) => void): unknown;
|
|
18
120
|
}): Promise<number> {
|
|
19
121
|
return new Promise((resolve) => {
|
|
20
|
-
|
|
21
|
-
|
|
122
|
+
let settled = false;
|
|
123
|
+
const finish = (code: number): void => {
|
|
124
|
+
if (settled) return;
|
|
125
|
+
settled = true;
|
|
126
|
+
resolve(code);
|
|
127
|
+
};
|
|
128
|
+
child.once("error", () => finish(1));
|
|
129
|
+
child.once("close", (code: number | null) => finish(code ?? 1));
|
|
22
130
|
});
|
|
23
131
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import type { ProvidersContract } from "../domains/providers/contract.js";
|
|
2
|
+
|
|
3
|
+
/** Cold gateway roles need their own declared model controls before synthesis.
|
|
4
|
+
* Read metadata only; an unknown/mixed successful probe remains authoritative.
|
|
5
|
+
* Memory supplies its existing deadline/generation signal, including auth.
|
|
6
|
+
*/
|
|
7
|
+
export async function prepareBackgroundModelMetadata(
|
|
8
|
+
providers: ProvidersContract,
|
|
9
|
+
targetId: string,
|
|
10
|
+
signal?: AbortSignal,
|
|
11
|
+
): Promise<void> {
|
|
12
|
+
signal?.throwIfAborted();
|
|
13
|
+
const status = providers.list().find((entry) => entry.target.id === targetId);
|
|
14
|
+
if (status?.target.runtime === "litellm" && status.health.lastCheckAt === null) {
|
|
15
|
+
await providers.probeTarget(targetId, { reasoning: false, ...(signal ? { signal } : {}) });
|
|
16
|
+
}
|
|
17
|
+
signal?.throwIfAborted();
|
|
18
|
+
}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
import { constants } from "node:fs";
|
|
2
|
+
import { open } from "node:fs/promises";
|
|
3
|
+
import { resolve } from "node:path";
|
|
4
|
+
|
|
5
|
+
const MAX_PROMPT_BYTES = 64 * 1024;
|
|
6
|
+
|
|
7
|
+
/** Absolute paths remain supported; relative paths are based on the current session workspace. */
|
|
8
|
+
export async function readCompactionSystemPrompt(
|
|
9
|
+
path: string | null | undefined,
|
|
10
|
+
workspace: string,
|
|
11
|
+
): Promise<string | undefined> {
|
|
12
|
+
if (path === undefined || path === null) return undefined;
|
|
13
|
+
// Quote the configured path, not file contents. Escape invisible directional
|
|
14
|
+
// formatting too, and bound diagnostics for an invalid oversized filename.
|
|
15
|
+
const quotedPath = JSON.stringify(path).replace(
|
|
16
|
+
/[\p{Cc}\p{Cf}\p{Zl}\p{Zp}]/gu,
|
|
17
|
+
(character) => `\\u{${character.codePointAt(0)?.toString(16)}}`,
|
|
18
|
+
);
|
|
19
|
+
const displayPath = quotedPath.length <= 1024 ? quotedPath : `${quotedPath.slice(0, 1024)}...`;
|
|
20
|
+
const failure = (reason: string) =>
|
|
21
|
+
new Error(
|
|
22
|
+
`context.compaction.systemPrompt ${displayPath} ${reason}; set a readable, nonempty UTF-8 file of at most ${MAX_PROMPT_BYTES} bytes (relative to the session workspace), or unset the override`,
|
|
23
|
+
);
|
|
24
|
+
if (!path.trim()) throw failure("path is empty");
|
|
25
|
+
let file: Awaited<ReturnType<typeof open>>;
|
|
26
|
+
try {
|
|
27
|
+
// Nonblocking open prevents a named pipe from hanging compaction before stat.
|
|
28
|
+
file = await open(resolve(workspace, path), constants.O_RDONLY | constants.O_NONBLOCK);
|
|
29
|
+
} catch {
|
|
30
|
+
throw failure("cannot be opened");
|
|
31
|
+
}
|
|
32
|
+
try {
|
|
33
|
+
if (!(await file.stat()).isFile()) throw failure("must refer to a regular file");
|
|
34
|
+
// Read only limit + 1, even if the file grows after stat. No unbounded readFile.
|
|
35
|
+
const buffer = Buffer.alloc(MAX_PROMPT_BYTES + 1);
|
|
36
|
+
let length = 0;
|
|
37
|
+
while (length < buffer.length) {
|
|
38
|
+
const { bytesRead } = await file.read(buffer, length, buffer.length - length, null);
|
|
39
|
+
if (bytesRead === 0) break;
|
|
40
|
+
length += bytesRead;
|
|
41
|
+
}
|
|
42
|
+
if (length > MAX_PROMPT_BYTES) throw failure("file is oversized");
|
|
43
|
+
let text: string;
|
|
44
|
+
try {
|
|
45
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(buffer.subarray(0, length));
|
|
46
|
+
} catch {
|
|
47
|
+
throw failure("file is not valid UTF-8");
|
|
48
|
+
}
|
|
49
|
+
if (!text.trim()) throw failure("file is empty");
|
|
50
|
+
return text;
|
|
51
|
+
} catch (error) {
|
|
52
|
+
if (error instanceof Error && error.message.startsWith("context.compaction.systemPrompt ")) throw error;
|
|
53
|
+
throw failure("file cannot be read");
|
|
54
|
+
} finally {
|
|
55
|
+
await file.close();
|
|
56
|
+
}
|
|
57
|
+
}
|