@iowarp/clio-coder 0.4.2 → 0.4.4
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 +98 -0
- package/CONTRIBUTING.md +86 -19
- package/README.md +35 -6
- package/dist/{acp-TMDQZDIG.js → acp-WNAYYF4F.js} +12 -13
- package/dist/{agents-5N5NG3XG.js → agents-3OKXHLOI.js} +60 -57
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-Z5CCBXKQ.js → auth-VKNNMGPU.js} +21 -19
- package/dist/{builtins-K6TNDT24.js → builtins-WGALA46I.js} +9 -4
- package/dist/{chunk-XE3PCIXH.js → chunk-23L32XTI.js} +12 -9
- package/dist/{chunk-I64IFBLB.js → chunk-25QBEXRS.js} +18 -11
- package/dist/{chunk-CDNVLKUX.js → chunk-26QSH3EJ.js} +13 -7
- package/dist/{chunk-QQLGQY2A.js → chunk-2ASED4PZ.js} +22 -22
- package/dist/{chunk-MCEPRMZW.js → chunk-2CU2H6KE.js} +2 -2
- package/dist/chunk-2DSOYNFC.js +108 -0
- package/dist/{chunk-72GZI5EV.js → chunk-2JH2WHGE.js} +2 -2
- package/dist/{chunk-I66EAJFY.js → chunk-2WZ546HR.js} +267 -232
- package/dist/{chunk-O3YUNJZ2.js → chunk-2ZSONWVL.js} +82 -25
- package/dist/{chunk-2NHR3NAY.js → chunk-36CT5VVL.js} +331 -42
- package/dist/{chunk-2X4RYJTJ.js → chunk-3GY4F45V.js} +3 -3
- package/dist/{chunk-ZW55JB7N.js → chunk-3ODX73FK.js} +4 -6
- package/dist/{chunk-PBP4B7XR.js → chunk-3UNOLWNZ.js} +3 -3
- package/dist/{chunk-4JDLP6ZS.js → chunk-3UUXNFEX.js} +14 -10
- package/dist/{chunk-RKSR6VSF.js → chunk-4IUZQIJ3.js} +29 -1
- package/dist/{chunk-ZW4HH5JJ.js → chunk-4M6Z5QVF.js} +6 -6
- package/dist/{chunk-K6BSR66V.js → chunk-4NSRCOYP.js} +4 -1
- package/dist/{chunk-M2DAX4F6.js → chunk-4WR7VSYB.js} +2 -2
- package/dist/{chunk-FSP7CMNU.js → chunk-54X7T7DK.js} +61 -6
- package/dist/{chunk-54ODD65L.js → chunk-5636DCO5.js} +4 -4
- package/dist/chunk-57XXR6DR.js +3763 -0
- 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-YJISEZKC.js → chunk-5TUB6SLS.js} +6 -6
- package/dist/{chunk-IMXMHHMQ.js → chunk-6OSVSQL5.js} +341 -57
- package/dist/{chunk-Q4XWMHX6.js → chunk-6PAZTBPA.js} +14 -2
- package/dist/{chunk-FVDGR2ZL.js → chunk-6Q3CYFD3.js} +112 -39
- package/dist/{chunk-IDNA72AH.js → chunk-6QOTUPRG.js} +155 -36
- package/dist/{chunk-X7IARSHT.js → chunk-6UINWWS6.js} +16 -10
- package/dist/{chunk-CYZW7JHJ.js → chunk-72YIHOZQ.js} +9 -9
- package/dist/{chunk-IKSLQ4XV.js → chunk-75W7L2E2.js} +752 -861
- package/dist/{chunk-CRFOIAX3.js → chunk-7UGL4MB5.js} +6 -6
- package/dist/{chunk-HIICAHCJ.js → chunk-AUPNRN7C.js} +2 -2
- package/dist/{chunk-7BHIY2MW.js → chunk-BJVFZO5U.js} +8 -50
- package/dist/{chunk-B74PXLU7.js → chunk-CUSRQKPU.js} +65 -3
- package/dist/chunk-DQOVN6KV.js +386 -0
- package/dist/{chunk-E7GT7O5N.js → chunk-DT3LWJOB.js} +7 -4
- package/dist/chunk-DXKJURES.js +671 -0
- package/dist/{chunk-JBCS7CRR.js → chunk-EL24TAU4.js} +10 -10
- package/dist/{chunk-TPEQIQIE.js → chunk-ELWDPP3Y.js} +8 -8
- package/dist/{chunk-NDINPTJ4.js → chunk-ELZVTCGV.js} +5 -4
- package/dist/chunk-EXLD33WO.js +381 -0
- package/dist/chunk-FEAXX7B6.js +101 -0
- package/dist/{chunk-RLYRBIYQ.js → chunk-FFUPXJC4.js} +90 -331
- package/dist/{chunk-5PFYMY2V.js → chunk-FTMGRKEF.js} +2 -2
- package/dist/{chunk-34BHNEE3.js → chunk-GHS5EBTQ.js} +58 -7
- package/dist/{chunk-DYHAXKHD.js → chunk-GWZNEVM2.js} +12 -8
- package/dist/chunk-GX5WYQO4.js +59 -0
- package/dist/chunk-GYV6VZOC.js +26 -0
- package/dist/{chunk-MQXIVJ35.js → chunk-HAXOFFRH.js} +5 -5
- package/dist/chunk-I2DWJ4GM.js +390 -0
- package/dist/{chunk-TXOTCRLG.js → chunk-I5FWO7L5.js} +5 -5
- package/dist/{chunk-WNP7O5WZ.js → chunk-ID64D7PE.js} +4 -4
- package/dist/{chunk-XQRY4DTA.js → chunk-IGLP3ODT.js} +10 -10
- package/dist/chunk-IRXAATOX.js +539 -0
- package/dist/chunk-IXIY2H4R.js +44 -0
- package/dist/{chunk-SSEYRH53.js → chunk-IZXGRF7P.js} +92 -147
- package/dist/{chunk-5TSRNF4G.js → chunk-JCI2ROMZ.js} +164 -6
- package/dist/{chunk-JWJGP5DQ.js → chunk-JEIYHLOR.js} +7 -7
- package/dist/{chunk-F2I26BDK.js → chunk-JQLNNIKT.js} +4 -4
- package/dist/{chunk-BYMNWQ7O.js → chunk-JSD46VO2.js} +315 -63
- package/dist/{chunk-AK5XEFVZ.js → chunk-JT2RFCC5.js} +64 -14
- package/dist/{chunk-MCMZMDAC.js → chunk-K6T2ZAMZ.js} +168 -6
- package/dist/{chunk-PGF63K6I.js → chunk-KFV5L5SK.js} +73 -4
- package/dist/{chunk-IHXBNWMM.js → chunk-KXDSS5WJ.js} +7 -3
- package/dist/{chunk-PJX3WQUQ.js → chunk-LLXSDWXS.js} +3 -3
- package/dist/{chunk-DZAW46HP.js → chunk-LTIKRKFL.js} +3 -3
- package/dist/{chunk-DZEK6CJN.js → chunk-N56KALIC.js} +21 -21
- package/dist/{chunk-B7HM5Z7T.js → chunk-NAI6ZFCY.js} +9 -5
- package/dist/{chunk-I66ZTYNP.js → chunk-NRO2BJRH.js} +2656 -2213
- package/dist/{chunk-ZGNYYXQ6.js → chunk-NXIMQY5W.js} +3 -3
- package/dist/{chunk-IKOZFYBN.js → chunk-NXYCB2VD.js} +149 -106
- package/dist/{chunk-CWVRRIEI.js → chunk-NZMNUPZZ.js} +2 -2
- package/dist/{chunk-462T4EGZ.js → chunk-O5CVSAG5.js} +2 -2
- package/dist/chunk-ODGTEFFI.js +50 -0
- package/dist/{chunk-3F7VUY77.js → chunk-OEJSLEPW.js} +2 -2
- package/dist/{chunk-KKOJXO6R.js → chunk-OMQNJVKW.js} +4 -2
- package/dist/{chunk-5KW52TEP.js → chunk-Q4WO54TA.js} +132 -77
- package/dist/{chunk-W6NIE6OW.js → chunk-QUFRYSWI.js} +13 -7
- package/dist/{chunk-42FMPA75.js → chunk-QZWQA4DE.js} +2 -2
- package/dist/chunk-R6Q67RJH.js +134 -0
- package/dist/{chunk-W4YEMFBX.js → chunk-RAY4OVGZ.js} +3 -3
- package/dist/{chunk-ZNT2M6TG.js → chunk-RQCKCSRL.js} +17 -17
- package/dist/{chunk-LJID3DYZ.js → chunk-RXTN6AKH.js} +3 -3
- package/dist/{chunk-P75RZCJW.js → chunk-RZDWV63N.js} +3 -3
- package/dist/{chunk-UH632ZYL.js → chunk-S6PYF2XF.js} +2 -2
- package/dist/{chunk-HJWWJ6IL.js → chunk-TOIVGRUX.js} +17 -5
- package/dist/{chunk-HLAFFSEK.js → chunk-TQAHXW6Y.js} +2 -2
- package/dist/{chunk-JIEGK6UF.js → chunk-U6TMQNSI.js} +48 -4
- package/dist/{chunk-2HFQNRV3.js → chunk-UEPWCCTY.js} +12 -12
- package/dist/chunk-UOIZ7DA4.js +41 -0
- package/dist/{chunk-UH347SHR.js → chunk-USR47QNF.js} +11 -11
- package/dist/{chunk-AZ4WMN4W.js → chunk-V6HJFQZE.js} +2 -2
- package/dist/chunk-V76WTFTW.js +318 -0
- package/dist/{chunk-NMJXSHBJ.js → chunk-W54I7H25.js} +2 -2
- package/dist/{chunk-KPXDY6QF.js → chunk-XRZT5WY5.js} +2 -2
- package/dist/{chunk-UBRFI4HS.js → chunk-XULDXHTN.js} +142 -50
- package/dist/chunk-XXYSBZIQ.js +283 -0
- package/dist/{chunk-HKMD33FO.js → chunk-Y55JBDO5.js} +405 -122
- package/dist/{chunk-XOXV5GKE.js → chunk-YD5GIKET.js} +17 -8
- package/dist/{chunk-XGDPUNND.js → chunk-YECAMM3D.js} +2 -2
- package/dist/{chunk-BO7Y52RY.js → chunk-YNFKXPEC.js} +7 -7
- package/dist/{chunk-VXMFAE2W.js → chunk-YPC6ZR5L.js} +19 -6
- package/dist/{chunk-M2WXEHER.js → chunk-ZA4VCIGV.js} +2 -2
- package/dist/cli/index.js +42 -40
- package/dist/{clio-7VB377CC.js → clio-QLICPCF5.js} +7 -7
- package/dist/{code-nav-YVLCYA7V.js → code-nav-IJR2DBPR.js} +9 -9
- package/dist/{components-UBWCQSRW.js → components-2TGAI2RC.js} +5 -6
- package/dist/{config-4HVOS65E.js → config-IUA6OYNS.js} +88 -81
- package/dist/{configure-PIWO7B24.js → configure-VEPX4NMX.js} +26 -25
- package/dist/{context-KQYIWPWT.js → context-2DKHWH2T.js} +60 -45
- package/dist/{context-IYEHL3WQ.js → context-4MPR7WKB.js} +78 -69
- package/dist/{context-N6ZE3LGJ.js → context-BOYF5EJM.js} +15 -11
- package/dist/{context-clear-G4OGZJDS.js → context-clear-S4ZJCQUX.js} +73 -65
- package/dist/context-map-COB37XXN.js +505 -0
- package/dist/{context-working-set-BWLF6LJP.js → context-working-set-3I3FYX6Y.js} +18 -17
- package/dist/detail-A7JAVSIG.js +98 -0
- package/dist/{dispatch-runner-2QQAITS3.js → dispatch-runner-RJ5I2F2O.js} +99 -75
- package/dist/{docs-PD3EXDKU.js → docs-SPOV3BAN.js} +3 -5
- package/dist/{doctor-LHBD36VU.js → doctor-DKICC2SN.js} +71 -48
- package/dist/{eval-C45FYRJ6.js → eval-OQOQUDHK.js} +308 -146
- package/dist/{eval-inventory-6DEJPLBF.js → eval-inventory-Y6QRFOH5.js} +4 -4
- package/dist/{evidence-6SHONYAF.js → evidence-4DQ25GUQ.js} +79 -175
- package/dist/evidence-4F5USFKH.js +208 -0
- package/dist/{evolve-KRKMV72X.js → evolve-GSS52E5J.js} +71 -67
- package/dist/{extensions-KPZ2UHBB.js → extensions-G7MFLYHT.js} +8 -9
- package/dist/{fleet-IVTCKDHT.js → fleet-Q37YHHAQ.js} +126 -118
- package/dist/{fleet-commands-EDWL3IT7.js → fleet-commands-G7E4N7SM.js} +16 -13
- package/dist/{fleet-decisions-YP3YEFGK.js → fleet-decisions-O7M6QBA2.js} +9 -8
- package/dist/{fleet-graph-ZFWKHY2M.js → fleet-graph-TOUBW6OW.js} +21 -20
- package/dist/{fleet-inspect-FVUNCBML.js → fleet-inspect-SW33JJNI.js} +65 -60
- package/dist/{fleet-preflight-UN5XED4R.js → fleet-preflight-CV2655TW.js} +4 -5
- package/dist/{fleet-validate-XOWC4HSX.js → fleet-validate-KESZX2YH.js} +25 -24
- package/dist/{fleet-verify-UN3SODEL.js → fleet-verify-UQPMTVE3.js} +66 -61
- package/dist/{fleet-view-TWHJKCN6.js → fleet-view-MN2VG4MR.js} +65 -60
- package/dist/{init-T2QORQ3Y.js → init-PXEXQSBF.js} +90 -82
- package/dist/{interop-IN5I2A66.js → interop-ZG5T62U3.js} +12 -13
- package/dist/inventory-C26CFDRR.js +101 -0
- package/dist/{library-LSCATDLZ.js → library-B2W4N74O.js} +29 -29
- package/dist/{memory-HYOKAGGJ.js → memory-YCANYS5A.js} +73 -69
- package/dist/{models-2GPMFYCM.js → models-GERTU3YI.js} +51 -47
- package/dist/{monitor-E4ASVUJH.js → monitor-CPNIUULB.js} +74 -67
- package/dist/{orchestrator-DDMPR3PY.js → orchestrator-J4BSH4WQ.js} +1288 -1606
- package/dist/{panes-E3RUXOW5.js → panes-BOHAEGYC.js} +4 -4
- package/dist/{panes-IXKLOKA2.js → panes-NXSLDQZ2.js} +10 -11
- package/dist/{paths-L7LGY6RN.js → paths-VSUWNC22.js} +6 -7
- package/dist/reset-TNWTB5LU.js +343 -0
- package/dist/{resources-OTRSN34L.js → resources-4PXNMD5G.js} +29 -22
- package/dist/{run-5DEYH5QK.js → run-D6XJ34CN.js} +132 -132
- package/dist/{share-IHWTLO3M.js → share-2NWMJJEE.js} +27 -27
- package/dist/{skills-IYMXMKW4.js → skills-KR7WON5G.js} +40 -33
- package/dist/{skills-eval-DROHSJAR.js → skills-eval-O2ZNOLDS.js} +81 -77
- package/dist/{skills-inventory-D7X4L4ZX.js → skills-inventory-ZZOUBK7O.js} +23 -22
- package/dist/{slash-commands-QBM7UZ3B.js → slash-commands-ZXPJD64J.js} +47 -37
- package/dist/{steer-Z5DO23FJ.js → steer-XA25PSCS.js} +4 -4
- package/dist/{support-U7QOWY26.js → support-7EMVWYG2.js} +6 -6
- package/dist/{targets-P2FUC4IL.js → targets-OMH2XCSN.js} +50 -49
- package/dist/tasks-IPAGMEIX.js +36 -0
- package/dist/{terminal-lease-YREJ3JX2.js → terminal-lease-C2J3JYRE.js} +4 -4
- package/dist/{tools-5B7RO6MV.js → tools-EFFEAIDP.js} +8 -9
- package/dist/{trace-YMGMUM6A.js → trace-FXMXUZUF.js} +7 -7
- package/dist/uninstall-HALS6BLF.js +407 -0
- package/dist/upgrade-MS72RJEP.js +306 -0
- package/dist/{usage-ME5MPXGX.js → usage-NHG6MCJM.js} +162 -108
- package/dist/{verifiers-BVZ7IWOO.js → verifiers-7AUNVXDY.js} +155 -22
- package/dist/{verify-5K7ZKQFC.js → verify-FWYGPKMR.js} +14 -12
- package/dist/{web-fetch-MPARV2K7.js → web-fetch-V4FKSDAV.js} +4 -4
- package/dist/{wiki-generate-F5W5QTYY.js → wiki-generate-743CIGJW.js} +99 -90
- package/dist/{with-panes-BYOJCLAM.js → with-panes-BDQEWBRT.js} +10 -10
- package/dist/worker/entry.js +72 -68
- package/docs/README.md +3 -2
- package/docs/architecture/acp.md +17 -0
- package/docs/architecture/artifact-placement.md +1 -0
- package/docs/architecture/artifact-versions.md +2 -2
- package/docs/architecture/context-engine.md +4 -0
- package/docs/architecture/dispatch-typed-intent.md +1 -1
- package/docs/architecture/evidence-and-memory.md +1 -1
- package/docs/architecture/middleware-and-components.md +1 -1
- package/docs/architecture/model-catalog.md +21 -10
- package/docs/architecture/observability.md +19 -2
- package/docs/architecture/prompt-envelope-and-tools.md +17 -5
- package/docs/architecture/provider-adapter-cookbook.md +63 -0
- package/docs/architecture/safety-model.md +25 -22
- package/docs/architecture/tui-design.md +1 -1
- package/docs/guide/built-in-agents.md +25 -11
- package/docs/guide/commands-and-modes.md +18 -3
- package/docs/guide/configuration-and-targets.md +100 -10
- package/docs/guide/configuration-reference.md +17 -7
- package/docs/guide/environment-variables.md +4 -2
- 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/guide/tool-usage.md +78 -3
- package/docs/history/config-knobs-audit.md +2 -2
- package/docs/process/development-pipeline.md +40 -2
- package/docs/process/eval-runner.md +67 -3
- package/docs/process/git-commit-provenance.md +15 -0
- package/docs/process/release-cut-checklist.md +207 -0
- package/docs/process/scientific-validation.md +18 -17
- package/evals/behavioral-machinery-support.ts +1 -0
- package/evals/behavioral-machinery.yaml +1 -1
- 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 +47 -2
- 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 +47 -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 +24 -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 +64 -5
- package/skills/workflow/cut-it/evals.md +101 -0
- package/skills/workflow/design-council/SKILL.md +112 -27
- package/skills/workflow/design-council/evals.md +161 -0
- package/skills/workflow/grill-me/SKILL.md +85 -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/args.ts +0 -8
- 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 +1084 -529
- package/src/cli/context-map.ts +114 -0
- package/src/cli/context.ts +4 -0
- package/src/cli/doctor-state-size.ts +1 -12
- package/src/cli/doctor-validation-contract.ts +28 -0
- package/src/cli/doctor.ts +5 -0
- package/src/cli/evidence-detail.ts +1 -75
- package/src/cli/evidence-inventory.ts +1 -167
- package/src/cli/index.ts +3 -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 -4
- package/src/cli/select.ts +664 -0
- package/src/cli/skills.ts +9 -2
- package/src/cli/targets.ts +3 -0
- package/src/cli/tasks.ts +84 -0
- package/src/cli/uninstall.ts +233 -165
- package/src/cli/upgrade.ts +210 -150
- package/src/cli/usage.ts +92 -27
- package/src/cli/validate-model.ts +3 -3
- package/src/cli/verifiers.ts +147 -1
- package/src/cli/wiki-generate.ts +1 -0
- package/src/core/commit-attribution.ts +41 -1
- 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/git-commit-attribution.ts +46 -3
- package/src/core/run-overrides.ts +0 -5
- package/src/core/safe-exec.ts +17 -2
- package/src/core/skill-activation.ts +92 -2
- package/src/core/tool-names.ts +5 -2
- package/src/domains/agents/builtins/architect.md +1 -1
- package/src/domains/agents/builtins/coder.md +1 -1
- package/src/domains/agents/builtins/documenter.md +1 -1
- package/src/domains/agents/builtins/git-master.md +1 -1
- package/src/domains/agents/builtins/provenance.md +7 -7
- package/src/domains/agents/builtins/tester.md +1 -1
- package/src/domains/agents/builtins/verifier.md +2 -2
- package/src/domains/agents/builtins/wiki-writer.md +4 -3
- 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/extension.ts +31 -7
- package/src/domains/context/refresh.ts +3 -0
- package/src/domains/context/wiki/frontmatter.ts +5 -2
- package/src/domains/context/wiki/generate.ts +6 -0
- package/src/domains/context/wiki/map-seed.ts +589 -0
- package/src/domains/context/wiki/plan.ts +2 -2
- package/src/domains/context/wiki/prompts.ts +43 -0
- package/src/domains/dispatch/active-route-planner.ts +4 -0
- 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/code-step.ts +11 -4
- package/src/domains/dispatch/contract.ts +42 -8
- package/src/domains/dispatch/execution-scheduler.ts +2 -0
- package/src/domains/dispatch/extension.ts +184 -56
- package/src/domains/dispatch/fleet-commit-attribution.ts +5 -0
- package/src/domains/dispatch/fleet-run.ts +1 -0
- package/src/domains/dispatch/host-verification.ts +114 -13
- package/src/domains/dispatch/intent.ts +28 -18
- package/src/domains/dispatch/orphan-recovery.ts +2 -0
- package/src/domains/dispatch/receipt-integrity.ts +4 -0
- package/src/domains/dispatch/reservation-store.ts +5 -3
- package/src/domains/dispatch/state.ts +15 -2
- package/src/domains/dispatch/types.ts +20 -2
- 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 +17 -11
- package/src/domains/eval/runners/context-index.ts +2 -7
- package/src/domains/eval/runners/context-init.ts +3 -6
- package/src/domains/eval/runners/external-command.ts +29 -11
- 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/evidence/build.ts +102 -15
- package/src/domains/evidence/detail.ts +69 -0
- package/src/domains/evidence/eval.ts +13 -1
- package/src/domains/evidence/finish-contract-map.ts +5 -1
- package/src/domains/evidence/inventory.ts +167 -0
- package/src/domains/evidence/store.ts +16 -0
- package/src/domains/evidence/types.ts +12 -0
- package/src/domains/extensions/resources.ts +7 -0
- 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 +22 -35
- package/src/domains/middleware/memory-intervention.ts +127 -32
- package/src/domains/middleware/memory-step-endpoint.ts +3 -2
- package/src/domains/middleware/runtime.ts +7 -3
- package/src/domains/middleware/skills-reminder.ts +31 -2
- package/src/domains/mux/detect.ts +3 -6
- package/src/domains/observability/accountability.ts +15 -1
- package/src/domains/observability/compaction-usage.ts +118 -0
- package/src/domains/observability/contract.ts +52 -7
- package/src/domains/observability/cost.ts +1 -1
- package/src/domains/observability/evidence-index.ts +10 -0
- package/src/domains/observability/extension.ts +15 -6
- package/src/domains/observability/out-of-turn-usage.ts +52 -21
- package/src/domains/observability/projection.ts +394 -45
- package/src/{interactive → domains/observability}/worker-progress.ts +3 -3
- package/src/domains/prompts/fragments/operating/contract.md +2 -0
- package/src/domains/prompts/fragments/wiki/page.md +8 -0
- 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 +3 -4
- package/src/domains/providers/model-runtime-capabilities.ts +15 -5
- package/src/domains/providers/models/local-models/clio-coder-local-coding-targets.yaml +48 -26
- package/src/domains/providers/runtimes/antigravity/antigravity-code.ts +225 -45
- package/src/domains/providers/runtimes/claude/claude-code.ts +9 -0
- 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/action-classifier.ts +7 -0
- package/src/domains/safety/autonomy.ts +15 -0
- package/src/domains/safety/default-path-policy.ts +2 -0
- package/src/domains/safety/finish-contract-registration.ts +29 -14
- package/src/domains/safety/finish-contract.ts +252 -40
- package/src/domains/safety/index.ts +21 -1
- package/src/domains/safety/path-policy.ts +1 -1
- package/src/domains/safety/policy-engine.ts +60 -17
- package/src/domains/safety/protected-artifacts.ts +191 -88
- package/src/domains/safety/rigor.ts +53 -39
- package/src/domains/safety/run-effects.ts +2 -22
- package/src/domains/safety/skill-authority.ts +55 -0
- package/src/domains/safety/validation-contract.ts +388 -0
- package/src/domains/session/archive-readers.ts +10 -1
- package/src/domains/session/compaction/compact.ts +72 -22
- package/src/domains/session/decision-board.ts +101 -2
- package/src/domains/session/entries.ts +50 -7
- package/src/domains/session/extension.ts +4 -4
- package/src/domains/session/handoff.ts +2 -1
- package/src/domains/session/manager.ts +2 -3
- package/src/domains/session/task-board.ts +14 -1
- package/src/domains/session/tree/fork.ts +1 -2
- package/src/domains/session/tree/navigator.ts +1 -1
- package/src/domains/session/usage.ts +3 -3
- package/src/domains/user-tasks/acceptance.ts +56 -0
- package/src/domains/user-tasks/active-acceptance.ts +40 -0
- package/src/domains/user-tasks/store.ts +34 -3
- package/src/engine/acp/adapter.ts +24 -6
- package/src/engine/acp/server.ts +21 -4
- package/src/engine/acp/transport.ts +53 -8
- package/src/engine/acp/types.ts +4 -0
- 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/ollama-native.ts +15 -0
- package/src/engine/apis/openai-completions.ts +117 -14
- package/src/engine/claude/subprocess-runtime.ts +107 -60
- package/src/engine/external-subprocess.ts +122 -6
- package/src/entry/background-model-metadata.ts +18 -0
- package/src/entry/compaction-prompt.ts +57 -0
- package/src/entry/orchestrator.ts +416 -218
- 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/dispatch-board.ts +46 -717
- package/src/interactive/fleet-run-preview.ts +2 -1
- package/src/interactive/interactive-application.ts +3 -2
- package/src/interactive/interactive-presentation.ts +55 -12
- package/src/interactive/interactive-slash-runtime.ts +4 -2
- package/src/interactive/oracle.ts +5 -2
- package/src/interactive/overlays/fleet-run-approval.ts +3 -2
- package/src/interactive/overlays/message-picker.ts +2 -2
- package/src/interactive/overlays/settings.ts +2 -2
- package/src/interactive/overlays/tree-selector.ts +2 -2
- package/src/interactive/renderers/branch-summary.ts +1 -1
- package/src/interactive/renderers/worker-entry.ts +32 -0
- package/src/interactive/slash-autocomplete.ts +4 -6
- package/src/interactive/slash-commands.ts +49 -45
- package/src/interactive/slash-spec.ts +28 -0
- 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/view/artifacts.ts +2 -0
- package/src/interactive/worker-receipts.ts +1 -0
- package/src/interactive/worker-stream.ts +13 -4
- package/src/tools/bootstrap.ts +4 -0
- package/src/tools/builtin-tool-catalog.ts +31 -0
- package/src/tools/compete-worktrees.ts +7 -1
- package/src/tools/context/index.ts +30 -9
- package/src/tools/core-bootstrap.ts +16 -0
- package/src/tools/decide.ts +136 -0
- package/src/tools/dispatch-admission.ts +21 -0
- package/src/tools/dispatch-arguments.ts +1 -0
- package/src/tools/dispatch-event-text.ts +10 -0
- package/src/tools/dispatch-plan.ts +6 -2
- package/src/tools/dispatch-runner.ts +27 -1
- package/src/tools/dispatch-types.ts +6 -0
- package/src/tools/evidence.ts +96 -0
- package/src/tools/limitation.ts +76 -0
- package/src/tools/policy.ts +9 -0
- package/src/tools/presentation.ts +3 -0
- package/src/tools/registry.ts +11 -5
- package/src/tools/result-shaping.ts +17 -5
- package/src/tools/task-worktree.ts +13 -3
- package/src/tools/tasks.ts +10 -1
- package/src/tools/verify/authoring.ts +170 -83
- package/src/tools/verify/catalog.ts +122 -5
- package/src/tools/verify/index.ts +2 -1
- package/src/tools/verify/numeric.ts +298 -0
- package/src/tools/verify/perf.ts +143 -0
- package/src/tools/verify/scripts.ts +229 -2
- 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/chunk-RVG5JXAL.js +0 -41
- package/dist/chunk-T56WDKA5.js +0 -183
- package/dist/chunk-VN3SHNBN.js +0 -313
- package/dist/chunk-VPKWYKEY.js +0 -169
- package/dist/reset-OAQP3W4O.js +0 -230
- package/dist/uninstall-N34PCTGJ.js +0 -331
- package/dist/upgrade-PXK3S2YM.js +0 -325
|
@@ -1,36 +1,15 @@
|
|
|
1
|
-
import { performance } from "node:perf_hooks";
|
|
2
|
-
import {
|
|
3
|
-
BusChannels,
|
|
4
|
-
type DispatchCompletedPayload,
|
|
5
|
-
type DispatchFailedPayload,
|
|
6
|
-
type DispatchProgressPayload,
|
|
7
|
-
type DispatchRunIdentity,
|
|
8
|
-
} from "../core/bus-events.js";
|
|
9
|
-
import { resolveDispatchFailureStatus } from "../core/dispatch-outcome.js";
|
|
10
|
-
import type { SafeEventBus } from "../core/event-bus.js";
|
|
11
|
-
import { rawDurationMs } from "../core/timers.js";
|
|
12
1
|
import type { AgentAudience } from "../domains/agents/spec.js";
|
|
13
2
|
import {
|
|
14
|
-
cloneRunToolBudgetEnvelope,
|
|
15
3
|
formatBudgetPolicy,
|
|
16
4
|
formatBudgetReasons,
|
|
17
5
|
formatBudgetRequest,
|
|
18
6
|
formatEffectiveBudget,
|
|
19
7
|
type RunToolBudgetEnvelope,
|
|
20
8
|
} from "../domains/dispatch/budget-envelope.js";
|
|
21
|
-
import type
|
|
22
|
-
import {
|
|
23
|
-
type DispatchRequestOrigin,
|
|
24
|
-
type RunKind,
|
|
25
|
-
type RunStatus,
|
|
26
|
-
runKindSupportsLiveSteering,
|
|
27
|
-
} from "../domains/dispatch/types.js";
|
|
9
|
+
import { type DispatchRequestOrigin, type RunKind, runKindSupportsLiveSteering } from "../domains/dispatch/types.js";
|
|
28
10
|
import { describeWriteBoundaryAttributionDowngrade } from "../domains/dispatch/write-boundary.js";
|
|
29
|
-
import {
|
|
30
|
-
|
|
31
|
-
type TrustSummaryProjection,
|
|
32
|
-
type TrustVerdict,
|
|
33
|
-
} from "../domains/evidence/trust-projection.js";
|
|
11
|
+
import type { TrustSummaryProjection, TrustVerdict } from "../domains/evidence/trust-projection.js";
|
|
12
|
+
import type { ObservabilityContract, ObservabilityRunSummary } from "../domains/observability/contract.js";
|
|
34
13
|
import {
|
|
35
14
|
COST_NOT_MEASURED,
|
|
36
15
|
costAggregateForAmount,
|
|
@@ -38,7 +17,8 @@ import {
|
|
|
38
17
|
type ObservabilityNotice,
|
|
39
18
|
type ObservabilitySnapshot,
|
|
40
19
|
} from "../domains/observability/index.js";
|
|
41
|
-
import
|
|
20
|
+
import type { WorkerAction, WorkerProgressSnapshot } from "../domains/observability/worker-progress.js";
|
|
21
|
+
import { type CostProvenance, foregroundStreamUsage } from "../domains/providers/index.js";
|
|
42
22
|
import { sanitizeCallTargetText } from "../domains/safety/call-target.js";
|
|
43
23
|
import { type Component, truncateToWidth, visibleWidth, wrapTextWithAnsi } from "../engine/tui.js";
|
|
44
24
|
import { formatWorkerContextMeter } from "./context-meter.js";
|
|
@@ -59,20 +39,8 @@ import {
|
|
|
59
39
|
screenTitle,
|
|
60
40
|
spinnerFrame,
|
|
61
41
|
} from "./theme/index.js";
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
type WorkerAction,
|
|
65
|
-
type WorkerProgressFold,
|
|
66
|
-
type WorkerProgressSnapshot,
|
|
67
|
-
} from "./worker-progress.js";
|
|
68
|
-
import type { WorkerReceiptReader } from "./worker-stream.js";
|
|
69
|
-
|
|
70
|
-
export type DispatchBoardStatus =
|
|
71
|
-
| Extract<RunStatus, "running" | "completed" | "failed" | "stale" | "dead">
|
|
72
|
-
| "aborted"
|
|
73
|
-
| "cancelling"
|
|
74
|
-
| "enqueued"
|
|
75
|
-
| "retrying";
|
|
42
|
+
|
|
43
|
+
export type DispatchBoardStatus = ObservabilityRunSummary["status"];
|
|
76
44
|
|
|
77
45
|
export interface DispatchRetryPresentation {
|
|
78
46
|
attempt: number;
|
|
@@ -206,56 +174,9 @@ export function isDispatchBoardRowCancellable(row: DispatchBoardRow): boolean {
|
|
|
206
174
|
return row.status === "running" || row.status === "stale" || row.status === "enqueued" || row.status === "retrying";
|
|
207
175
|
}
|
|
208
176
|
|
|
209
|
-
interface DispatchBoardEntry
|
|
210
|
-
extends Omit<
|
|
211
|
-
DispatchBoardRow,
|
|
212
|
-
"elapsedMs" | "recentTools" | "lastContextTokens" | "currentTool" | "retry" | "progress"
|
|
213
|
-
> {
|
|
214
|
-
sequence: number;
|
|
215
|
-
enqueuedAtMs: number;
|
|
216
|
-
startedAtMs: number | null;
|
|
217
|
-
/**
|
|
218
|
-
* The monotonic twin of `startedAtMs`, set from the same observation. TTFT
|
|
219
|
-
* is a span, so it is measured against this and never against the wall
|
|
220
|
-
* stamps, which exist to order and label rows.
|
|
221
|
-
*/
|
|
222
|
-
startedAtClockMs: number | null;
|
|
223
|
-
finishedAtMs: number | null;
|
|
224
|
-
durationMs: number | null;
|
|
225
|
-
lastContextTokens: number;
|
|
226
|
-
/**
|
|
227
|
-
* The one fold that reads this run's worker events. Tool activity and the
|
|
228
|
-
* answer tail are its output, so the board no longer interprets the stream
|
|
229
|
-
* alongside the transcript.
|
|
230
|
-
*/
|
|
231
|
-
progress: WorkerProgressFold;
|
|
232
|
-
retry?: DispatchRetryPresentation;
|
|
233
|
-
}
|
|
234
|
-
|
|
235
|
-
/** Keep raw task text out of long-lived TUI rows and bound hostile/user-sized input. */
|
|
236
|
-
const TASK_SUMMARY_MAX_WIDTH = 240;
|
|
237
177
|
/** Rows of worker prose an expanded card shows before it defers to `/view`. */
|
|
238
178
|
const WORKER_PROGRESS_CARD_ROWS = 6;
|
|
239
179
|
|
|
240
|
-
interface WorkerEventShape {
|
|
241
|
-
type?: unknown;
|
|
242
|
-
message?: {
|
|
243
|
-
role?: unknown;
|
|
244
|
-
usage?: {
|
|
245
|
-
input?: unknown;
|
|
246
|
-
output?: unknown;
|
|
247
|
-
cacheRead?: unknown;
|
|
248
|
-
cacheWrite?: unknown;
|
|
249
|
-
};
|
|
250
|
-
};
|
|
251
|
-
messages?: unknown;
|
|
252
|
-
}
|
|
253
|
-
|
|
254
|
-
interface AssistantMessageShape {
|
|
255
|
-
role?: unknown;
|
|
256
|
-
stopReason?: unknown;
|
|
257
|
-
}
|
|
258
|
-
|
|
259
180
|
export const TASK_ISLAND_WIDTH = 44;
|
|
260
181
|
|
|
261
182
|
const STATUS_ORDER: Record<DispatchBoardStatus, number> = {
|
|
@@ -269,7 +190,6 @@ const STATUS_ORDER: Record<DispatchBoardStatus, number> = {
|
|
|
269
190
|
aborted: 7,
|
|
270
191
|
completed: 8,
|
|
271
192
|
};
|
|
272
|
-
const MAX_DISPATCH_BOARD_ROWS = 50;
|
|
273
193
|
|
|
274
194
|
/**
|
|
275
195
|
* The agent's own name, unadorned. Audience is carried by
|
|
@@ -511,16 +431,6 @@ function evidenceCardLine(theme: ClioTheme, evidence: RunEvidencePresentation, c
|
|
|
511
431
|
return cardUnitsLine(theme, "proof", units, contentWidth);
|
|
512
432
|
}
|
|
513
433
|
|
|
514
|
-
/** Sanitize lifecycle task text at the terminal boundary and collapse it to one bounded line. */
|
|
515
|
-
function sanitizeDispatchTaskSummary(value: unknown): string | undefined {
|
|
516
|
-
if (typeof value !== "string") return undefined;
|
|
517
|
-
const sanitized = sanitizeCallTargetText(value);
|
|
518
|
-
if (sanitized.length === 0) return undefined;
|
|
519
|
-
// pi-tui's truncator appends reset sequences when it elides. Strip those
|
|
520
|
-
// again so the stored projection remains plain text, not terminal styling.
|
|
521
|
-
return sanitizeCallTargetText(truncateToWidth(sanitized, TASK_SUMMARY_MAX_WIDTH, "…", false));
|
|
522
|
-
}
|
|
523
|
-
|
|
524
434
|
function retryCountdown(retry: DispatchRetryPresentation, now = Date.now()): string {
|
|
525
435
|
const remainingMs = Math.max(0, retry.dueAtMs - now);
|
|
526
436
|
return remainingMs === 0 ? "now" : `in ${formatCompactMs(remainingMs)}`;
|
|
@@ -1154,87 +1064,6 @@ export function formatTaskIslandLines(rows: ReadonlyArray<DispatchBoardRow>, max
|
|
|
1154
1064
|
return frame(clioTheme(), "Fleet runs", body, TASK_ISLAND_WIDTH + 4);
|
|
1155
1065
|
}
|
|
1156
1066
|
|
|
1157
|
-
function parseRunId(value: unknown): string | null {
|
|
1158
|
-
return typeof value === "string" && value.length > 0 ? value : null;
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
function parseText(value: unknown, fallback: string): string {
|
|
1162
|
-
return typeof value === "string" && value.length > 0 ? value : fallback;
|
|
1163
|
-
}
|
|
1164
|
-
|
|
1165
|
-
function parseRuntimeKind(value: unknown): RunKind {
|
|
1166
|
-
if (value === "sdk" || value === "subprocess" || value === "acp-delegation") return value;
|
|
1167
|
-
return "http";
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
function parseAgentAudience(value: unknown, fallback: AgentAudience | undefined): AgentAudience | undefined {
|
|
1171
|
-
if (value === "base" || value === "shadow" || value === "custom" || value === "internal") return value;
|
|
1172
|
-
return fallback;
|
|
1173
|
-
}
|
|
1174
|
-
|
|
1175
|
-
function parseRequestOrigin(
|
|
1176
|
-
value: unknown,
|
|
1177
|
-
fallback: DispatchRequestOrigin | undefined,
|
|
1178
|
-
): DispatchRequestOrigin | undefined {
|
|
1179
|
-
if (value === "user" || value === "agent" || value === "internal") return value;
|
|
1180
|
-
return fallback;
|
|
1181
|
-
}
|
|
1182
|
-
|
|
1183
|
-
function parseFiniteNumber(value: unknown, fallback: number): number {
|
|
1184
|
-
return typeof value === "number" && Number.isFinite(value) ? value : fallback;
|
|
1185
|
-
}
|
|
1186
|
-
|
|
1187
|
-
function parseNonEmptyString(value: unknown): string | undefined {
|
|
1188
|
-
return typeof value === "string" && value.length > 0 ? value : undefined;
|
|
1189
|
-
}
|
|
1190
|
-
|
|
1191
|
-
function parseTaskSummary(
|
|
1192
|
-
raw: Partial<DispatchRunIdentity> & { task?: unknown; taskSummary?: unknown },
|
|
1193
|
-
fallback: string | undefined,
|
|
1194
|
-
): string | undefined {
|
|
1195
|
-
return sanitizeDispatchTaskSummary(raw.task) ?? sanitizeDispatchTaskSummary(raw.taskSummary) ?? fallback;
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
function parsePositiveInt(value: unknown): number | undefined {
|
|
1199
|
-
return typeof value === "number" && Number.isFinite(value) && value > 0 ? Math.floor(value) : undefined;
|
|
1200
|
-
}
|
|
1201
|
-
|
|
1202
|
-
function parseGateBadge(value: unknown): { role: string; cycle: number } | undefined {
|
|
1203
|
-
if (typeof value !== "object" || value === null) return undefined;
|
|
1204
|
-
const record = value as { role?: unknown; cycle?: unknown };
|
|
1205
|
-
if (typeof record.role !== "string" || record.role.length === 0) return undefined;
|
|
1206
|
-
const cycle = parsePositiveInt(record.cycle) ?? 1;
|
|
1207
|
-
return { role: record.role, cycle };
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
function parseEndpointCapacity(value: unknown): DispatchBoardRow["endpoint"] | undefined {
|
|
1211
|
-
if (typeof value !== "object" || value === null) return undefined;
|
|
1212
|
-
const record = value as { key?: unknown; label?: unknown; limit?: unknown };
|
|
1213
|
-
const key = parseNonEmptyString(record.key);
|
|
1214
|
-
const label = parseNonEmptyString(record.label);
|
|
1215
|
-
const limit = parsePositiveInt(record.limit);
|
|
1216
|
-
return key === undefined || label === undefined || limit === undefined ? undefined : { key, label, limit };
|
|
1217
|
-
}
|
|
1218
|
-
|
|
1219
|
-
function parseCouncilBadge(value: unknown): DispatchBoardRow["council"] | undefined {
|
|
1220
|
-
if (typeof value !== "object" || value === null) return undefined;
|
|
1221
|
-
const record = value as { group?: unknown; label?: unknown; color?: unknown; round?: unknown };
|
|
1222
|
-
const group = parseNonEmptyString(record.group);
|
|
1223
|
-
const label = parseNonEmptyString(record.label);
|
|
1224
|
-
const round = parsePositiveInt(record.round);
|
|
1225
|
-
if (group === undefined || label === undefined || round === undefined) return undefined;
|
|
1226
|
-
return {
|
|
1227
|
-
group,
|
|
1228
|
-
label,
|
|
1229
|
-
...(typeof record.color === "string" && record.color.length > 0 ? { color: record.color } : {}),
|
|
1230
|
-
round,
|
|
1231
|
-
};
|
|
1232
|
-
}
|
|
1233
|
-
|
|
1234
|
-
function parseFiniteNumberOrZero(value: unknown): number {
|
|
1235
|
-
return typeof value === "number" && Number.isFinite(value) ? value : 0;
|
|
1236
|
-
}
|
|
1237
|
-
|
|
1238
1067
|
function parseOptionalDetail(value: unknown): string | null {
|
|
1239
1068
|
if (typeof value !== "string") return null;
|
|
1240
1069
|
const detail = value.replace(/\s+/g, " ").trim();
|
|
@@ -1273,150 +1102,34 @@ function terminalDetail(row: DispatchBoardRow): string | null {
|
|
|
1273
1102
|
return parseOptionalDetail(row.outcomeDetail);
|
|
1274
1103
|
}
|
|
1275
1104
|
|
|
1276
|
-
function resolveAgentEndStatus(rawMessages: unknown): DispatchBoardStatus | null {
|
|
1277
|
-
if (!Array.isArray(rawMessages)) return null;
|
|
1278
|
-
for (let index = rawMessages.length - 1; index >= 0; index -= 1) {
|
|
1279
|
-
const message = (rawMessages[index] ?? {}) as AssistantMessageShape;
|
|
1280
|
-
if (message.role !== "assistant") continue;
|
|
1281
|
-
if (message.stopReason === "stop") return "completed";
|
|
1282
|
-
if (message.stopReason === "error") return "failed";
|
|
1283
|
-
if (message.stopReason === "aborted") return "aborted";
|
|
1284
|
-
return null;
|
|
1285
|
-
}
|
|
1286
|
-
return null;
|
|
1287
|
-
}
|
|
1288
|
-
|
|
1289
|
-
function resolveFailureDetail(
|
|
1290
|
-
payload: Partial<DispatchFailedPayload>,
|
|
1291
|
-
fallback: string | null | undefined,
|
|
1292
|
-
): string | null {
|
|
1293
|
-
const detail = parseOptionalDetail(payload.outcomeDetail);
|
|
1294
|
-
if (detail !== null) return detail;
|
|
1295
|
-
if (payload.reason === "timed_out") return "turn timeout exceeded";
|
|
1296
|
-
return fallback ?? null;
|
|
1297
|
-
}
|
|
1298
|
-
|
|
1299
|
-
function resolveHeartbeatStatus(status: unknown): DispatchBoardStatus | null {
|
|
1300
|
-
if (status === "alive") return "running";
|
|
1301
|
-
if (status === "stale" || status === "dead") return status;
|
|
1302
|
-
return null;
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
1105
|
function isTerminalStatus(status: DispatchBoardStatus): boolean {
|
|
1306
1106
|
return status === "completed" || status === "failed" || status === "aborted" || status === "dead";
|
|
1307
1107
|
}
|
|
1308
1108
|
|
|
1309
|
-
function
|
|
1310
|
-
const attempt = parsePositiveInt(value.attempt);
|
|
1311
|
-
const dueAtMs = Date.parse(value.dueAt);
|
|
1312
|
-
if (attempt === undefined || !Number.isFinite(dueAtMs)) return null;
|
|
1313
|
-
return {
|
|
1314
|
-
attempt,
|
|
1315
|
-
dueAtMs,
|
|
1316
|
-
reason: sanitizeCallTargetText(value.reason),
|
|
1317
|
-
};
|
|
1318
|
-
}
|
|
1319
|
-
|
|
1320
|
-
function readRetrySnapshot(
|
|
1321
|
-
snapshot: DispatchSnapshot,
|
|
1322
|
-
): Map<string, { agentId: string; taskSummary?: string; retry: DispatchRetryPresentation }> {
|
|
1323
|
-
const retrying = new Map<string, { agentId: string; taskSummary?: string; retry: DispatchRetryPresentation }>();
|
|
1324
|
-
try {
|
|
1325
|
-
for (const value of snapshot.retrying) {
|
|
1326
|
-
const runId = parseRunId(value.runId);
|
|
1327
|
-
const agentId = parseNonEmptyString(value.agentId);
|
|
1328
|
-
const retry = parseRetrySnapshot(value);
|
|
1329
|
-
const taskSummary = sanitizeDispatchTaskSummary(value.task);
|
|
1330
|
-
if (runId && agentId && retry) {
|
|
1331
|
-
retrying.set(runId, {
|
|
1332
|
-
agentId,
|
|
1333
|
-
...(taskSummary !== undefined ? { taskSummary } : {}),
|
|
1334
|
-
retry,
|
|
1335
|
-
});
|
|
1336
|
-
}
|
|
1337
|
-
}
|
|
1338
|
-
} catch {
|
|
1339
|
-
// The board remains lifecycle-event driven if an optional snapshot fails.
|
|
1340
|
-
}
|
|
1341
|
-
return retrying;
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
function readRunningSnapshot(snapshot: DispatchSnapshot): Map<
|
|
1345
|
-
string,
|
|
1346
|
-
{
|
|
1347
|
-
inputTokens: number;
|
|
1348
|
-
outputTokens: number;
|
|
1349
|
-
tokenCount: number;
|
|
1350
|
-
costUsd: number;
|
|
1351
|
-
costProvenance: CostProvenance;
|
|
1352
|
-
outcomePhase: string;
|
|
1353
|
-
budget?: RunToolBudgetEnvelope;
|
|
1354
|
-
}
|
|
1355
|
-
> {
|
|
1356
|
-
const running = new Map<
|
|
1357
|
-
string,
|
|
1358
|
-
{
|
|
1359
|
-
inputTokens: number;
|
|
1360
|
-
outputTokens: number;
|
|
1361
|
-
tokenCount: number;
|
|
1362
|
-
costUsd: number;
|
|
1363
|
-
costProvenance: CostProvenance;
|
|
1364
|
-
outcomePhase: string;
|
|
1365
|
-
budget?: RunToolBudgetEnvelope;
|
|
1366
|
-
}
|
|
1367
|
-
>();
|
|
1368
|
-
try {
|
|
1369
|
-
for (const value of snapshot.running) {
|
|
1370
|
-
const runId = parseRunId(value.runId);
|
|
1371
|
-
if (!runId) continue;
|
|
1372
|
-
const budget = cloneRunToolBudgetEnvelope(value.budget);
|
|
1373
|
-
running.set(runId, {
|
|
1374
|
-
inputTokens: parseFiniteNumberOrZero(value.tokens.input),
|
|
1375
|
-
outputTokens: parseFiniteNumberOrZero(value.tokens.output),
|
|
1376
|
-
tokenCount: parseFiniteNumberOrZero(value.tokens.total),
|
|
1377
|
-
costUsd: parseFiniteNumberOrZero(value.costUsd),
|
|
1378
|
-
costProvenance: value.costProvenance ?? "unknown",
|
|
1379
|
-
outcomePhase: value.outcomePhase,
|
|
1380
|
-
...(budget !== undefined ? { budget } : {}),
|
|
1381
|
-
});
|
|
1382
|
-
}
|
|
1383
|
-
} catch {
|
|
1384
|
-
// Lifecycle/progress events remain authoritative if the optional snapshot fails.
|
|
1385
|
-
}
|
|
1386
|
-
return running;
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
function resolveElapsedMs(entry: DispatchBoardEntry, now: number): number {
|
|
1390
|
-
const startedAtMs = entry.startedAtMs ?? entry.enqueuedAtMs;
|
|
1391
|
-
if (entry.durationMs !== null) return entry.durationMs;
|
|
1392
|
-
const endMs = entry.finishedAtMs ?? now;
|
|
1393
|
-
return Math.max(0, rawDurationMs(startedAtMs, endMs));
|
|
1394
|
-
}
|
|
1395
|
-
|
|
1396
|
-
function toRow(entry: DispatchBoardEntry, now: number): DispatchBoardRow {
|
|
1109
|
+
function toRow(entry: ObservabilityRunSummary, now: number): DispatchBoardRow {
|
|
1397
1110
|
const retry = entry.retry;
|
|
1398
|
-
const progress = entry.progress
|
|
1111
|
+
const progress = entry.progress;
|
|
1399
1112
|
return {
|
|
1400
|
-
progress,
|
|
1113
|
+
...(progress !== undefined ? { progress } : {}),
|
|
1401
1114
|
runId: entry.runId,
|
|
1402
1115
|
agentId: entry.agentId,
|
|
1403
1116
|
...(entry.agentAudience !== undefined ? { agentAudience: entry.agentAudience } : {}),
|
|
1404
1117
|
...(entry.requestOrigin !== undefined ? { requestOrigin: entry.requestOrigin } : {}),
|
|
1405
|
-
runtimeKind: entry.runtimeKind,
|
|
1406
|
-
runtimeId: entry.runtimeId,
|
|
1407
|
-
targetId: entry.targetId,
|
|
1408
|
-
wireModelId: entry.
|
|
1118
|
+
runtimeKind: entry.runtimeKind ?? "http",
|
|
1119
|
+
runtimeId: entry.runtimeId ?? "-",
|
|
1120
|
+
targetId: entry.targetId ?? "-",
|
|
1121
|
+
wireModelId: entry.modelId ?? "-",
|
|
1409
1122
|
...(entry.endpoint !== undefined ? { endpoint: { ...entry.endpoint } } : {}),
|
|
1410
1123
|
...(entry.taskSummary !== undefined ? { taskSummary: entry.taskSummary } : {}),
|
|
1411
1124
|
...(entry.budget !== undefined ? { budget: entry.budget } : {}),
|
|
1412
|
-
status:
|
|
1413
|
-
elapsedMs:
|
|
1414
|
-
tokenCount: entry.
|
|
1125
|
+
status: entry.status,
|
|
1126
|
+
elapsedMs: entry.durationMs ?? Math.max(0, (entry.finishedAtMs ?? now) - entry.startedAtMs),
|
|
1127
|
+
tokenCount: entry.tokens.total,
|
|
1415
1128
|
costUsd: entry.costUsd,
|
|
1416
1129
|
...(entry.costProvenance !== undefined ? { costProvenance: entry.costProvenance } : {}),
|
|
1417
|
-
inputTokens: entry.
|
|
1418
|
-
outputTokens: entry.
|
|
1419
|
-
ttftMs: entry.ttftMs,
|
|
1130
|
+
inputTokens: entry.tokens.input,
|
|
1131
|
+
outputTokens: entry.tokens.output,
|
|
1132
|
+
ttftMs: entry.ttftMs ?? null,
|
|
1420
1133
|
...(entry.outcomeDetail !== undefined ? { outcomeDetail: entry.outcomeDetail } : {}),
|
|
1421
1134
|
...(entry.node !== undefined ? { node: entry.node } : {}),
|
|
1422
1135
|
...(entry.gate !== undefined ? { gate: { ...entry.gate } } : {}),
|
|
@@ -1426,439 +1139,55 @@ function toRow(entry: DispatchBoardEntry, now: number): DispatchBoardRow {
|
|
|
1426
1139
|
...(entry.rerouteCount !== undefined ? { rerouteCount: entry.rerouteCount } : {}),
|
|
1427
1140
|
...(entry.failoverHops !== undefined ? { failoverHops: entry.failoverHops } : {}),
|
|
1428
1141
|
...(entry.contextWindow !== undefined ? { contextWindow: entry.contextWindow } : {}),
|
|
1429
|
-
lastContextTokens: entry.lastContextTokens,
|
|
1142
|
+
lastContextTokens: entry.lastContextTokens ?? 0,
|
|
1430
1143
|
...(entry.receiptId !== undefined ? { receiptId: entry.receiptId } : {}),
|
|
1431
1144
|
...(entry.phase !== undefined ? { phase: { ...entry.phase } } : {}),
|
|
1432
1145
|
// Both tool fields are views of the one projection, so the compact card and
|
|
1433
1146
|
// the expanded detail can never disagree about what is running.
|
|
1434
|
-
currentTool: retry ? null : (progress
|
|
1435
|
-
recentTools: progress
|
|
1147
|
+
currentTool: retry ? null : (progress?.currentAction?.tool ?? null),
|
|
1148
|
+
recentTools: progress?.recentActions.map((action) => action.tool) ?? [],
|
|
1436
1149
|
...(retry ? { retry: { ...retry } } : {}),
|
|
1437
1150
|
...(entry.steerAcknowledgement ? { steerAcknowledgement: { ...entry.steerAcknowledgement } } : {}),
|
|
1438
1151
|
...(entry.writeRecordDowngrade ? { writeRecordDowngrade: { ...entry.writeRecordDowngrade } } : {}),
|
|
1439
1152
|
};
|
|
1440
1153
|
}
|
|
1441
1154
|
|
|
1442
|
-
|
|
1443
|
-
const aStatus = a.retry ? "retrying" : a.status;
|
|
1444
|
-
const bStatus = b.retry ? "retrying" : b.status;
|
|
1445
|
-
const rank = STATUS_ORDER[aStatus] - STATUS_ORDER[bStatus];
|
|
1446
|
-
if (rank !== 0) return rank;
|
|
1447
|
-
const aTime = a.finishedAtMs ?? a.startedAtMs ?? a.enqueuedAtMs;
|
|
1448
|
-
const bTime = b.finishedAtMs ?? b.startedAtMs ?? b.enqueuedAtMs;
|
|
1449
|
-
if (aTime !== bTime) return bTime - aTime;
|
|
1450
|
-
return a.sequence - b.sequence;
|
|
1451
|
-
}
|
|
1452
|
-
|
|
1453
|
-
function pruneEntries(entries: Map<string, DispatchBoardEntry>, onEvict?: (runId: string) => void): void {
|
|
1454
|
-
if (entries.size <= MAX_DISPATCH_BOARD_ROWS) return;
|
|
1455
|
-
const terminalEntries = [...entries.values()]
|
|
1456
|
-
.filter((entry) => !entry.retry && isTerminalStatus(entry.status))
|
|
1457
|
-
.sort((a, b) => a.sequence - b.sequence);
|
|
1458
|
-
const evictionQueue =
|
|
1459
|
-
terminalEntries.length > 0 ? terminalEntries : [...entries.values()].sort((a, b) => a.sequence - b.sequence);
|
|
1460
|
-
for (const entry of evictionQueue) {
|
|
1461
|
-
if (entries.size <= MAX_DISPATCH_BOARD_ROWS) break;
|
|
1462
|
-
entries.delete(entry.runId);
|
|
1463
|
-
onEvict?.(entry.runId);
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
|
|
1155
|
+
/** The board keeps display order and reads every run fact from observability. */
|
|
1467
1156
|
export function createDispatchBoardStore(
|
|
1468
|
-
|
|
1469
|
-
snapshot?: () => DispatchSnapshot,
|
|
1470
|
-
/**
|
|
1471
|
-
* Sealed terminal facts for a finished run. Settlement replaces the
|
|
1472
|
-
* provisional live tail with the receipt's answer where one can be read; the
|
|
1473
|
-
* run's own durable message stands in where it cannot.
|
|
1474
|
-
*/
|
|
1475
|
-
readReceipt?: WorkerReceiptReader,
|
|
1157
|
+
projection: Pick<ObservabilityContract, "snapshot" | "subscribe" | "reconcileRuns" | "setFleetPhase">,
|
|
1476
1158
|
): {
|
|
1477
1159
|
rows(): ReadonlyArray<DispatchBoardRow>;
|
|
1478
1160
|
activeRows(): ReadonlyArray<DispatchBoardRow>;
|
|
1479
1161
|
reconcile(): void;
|
|
1480
|
-
/**
|
|
1481
|
-
* Record the fleet-plan position of a run the caller just dispatched. The
|
|
1482
|
-
* board never infers a position: a run carries one only because whoever
|
|
1483
|
-
* dispatched the plan said so, which is why a non-fleet run can never grow
|
|
1484
|
-
* a phase cell.
|
|
1485
|
-
*/
|
|
1486
1162
|
setFleetPhase(runId: string, phase: DispatchBoardPhase): void;
|
|
1487
1163
|
unsubscribe(): void;
|
|
1488
1164
|
} {
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
let nextSequence = 0;
|
|
1494
|
-
let reconciledAtMs = Date.now();
|
|
1495
|
-
|
|
1496
|
-
/**
|
|
1497
|
-
* Seal a run's projection on the sealed receipt's answer. Only for the
|
|
1498
|
-
* terminal bus events: the dispatch domain writes `receipts/<runId>.json`
|
|
1499
|
-
* before it publishes one, so this is the first moment the file exists.
|
|
1500
|
-
*/
|
|
1501
|
-
const settleFromReceipt = (entry: DispatchBoardEntry): void => {
|
|
1502
|
-
const facts = readReceipt?.(entry.runId);
|
|
1503
|
-
const text = facts?.text;
|
|
1504
|
-
entry.progress.settle(typeof text === "string" && text.trim().length > 0 ? text : undefined);
|
|
1505
|
-
if (facts?.trust !== undefined) entry.trust = summarizeTrustStatus(facts.trust);
|
|
1506
|
-
};
|
|
1507
|
-
|
|
1508
|
-
// Payloads arrive typed off the bus, but the board keeps its runtime
|
|
1509
|
-
// parsing (parse* helpers) because events are not validated at runtime.
|
|
1510
|
-
const upsertBase = (
|
|
1511
|
-
raw: Partial<DispatchRunIdentity>,
|
|
1512
|
-
status: DispatchBoardStatus,
|
|
1513
|
-
now: number,
|
|
1514
|
-
): DispatchBoardEntry | null => {
|
|
1515
|
-
const runId = parseRunId(raw.runId);
|
|
1516
|
-
if (!runId) return null;
|
|
1517
|
-
const previous = entries.get(runId);
|
|
1518
|
-
const agentAudience = parseAgentAudience(raw.agentAudience, previous?.agentAudience);
|
|
1519
|
-
const requestOrigin = parseRequestOrigin(raw.requestOrigin, previous?.requestOrigin);
|
|
1520
|
-
const node = parseNonEmptyString(raw.node) ?? previous?.node;
|
|
1521
|
-
const endpoint = parseEndpointCapacity(raw.endpoint) ?? previous?.endpoint;
|
|
1522
|
-
const gate = parseGateBadge(raw.gate) ?? previous?.gate;
|
|
1523
|
-
const council = parseCouncilBadge(raw.council) ?? previous?.council;
|
|
1524
|
-
const rerouteCount = parsePositiveInt(raw.rerouteCount) ?? previous?.rerouteCount;
|
|
1525
|
-
const contextWindow = parsePositiveInt(raw.contextWindow) ?? previous?.contextWindow;
|
|
1526
|
-
const taskSummary = parseTaskSummary(raw, previous?.taskSummary);
|
|
1527
|
-
const budget = cloneRunToolBudgetEnvelope(raw.budget) ?? previous?.budget;
|
|
1528
|
-
const phase = fleetPhases.get(runId) ?? previous?.phase;
|
|
1529
|
-
const entry: DispatchBoardEntry = {
|
|
1530
|
-
runId,
|
|
1531
|
-
agentId: parseText(raw.agentId, previous?.agentId ?? "-"),
|
|
1532
|
-
...(agentAudience !== undefined ? { agentAudience } : {}),
|
|
1533
|
-
...(requestOrigin !== undefined ? { requestOrigin } : {}),
|
|
1534
|
-
runtimeKind: parseRuntimeKind(raw.runtimeKind ?? previous?.runtimeKind),
|
|
1535
|
-
runtimeId: parseText(raw.runtimeId, previous?.runtimeId ?? "-"),
|
|
1536
|
-
targetId: parseText(raw.targetId, previous?.targetId ?? "-"),
|
|
1537
|
-
wireModelId: parseText(raw.wireModelId, previous?.wireModelId ?? "-"),
|
|
1538
|
-
...(endpoint !== undefined ? { endpoint } : {}),
|
|
1539
|
-
...(taskSummary !== undefined ? { taskSummary } : {}),
|
|
1540
|
-
...(budget !== undefined ? { budget } : {}),
|
|
1541
|
-
status,
|
|
1542
|
-
tokenCount: previous?.tokenCount ?? 0,
|
|
1543
|
-
costUsd: previous?.costUsd ?? 0,
|
|
1544
|
-
costProvenance: previous?.costProvenance ?? "unknown",
|
|
1545
|
-
sequence: previous?.sequence ?? nextSequence++,
|
|
1546
|
-
enqueuedAtMs: previous?.enqueuedAtMs ?? now,
|
|
1547
|
-
startedAtMs: previous?.startedAtMs ?? null,
|
|
1548
|
-
startedAtClockMs: previous?.startedAtClockMs ?? null,
|
|
1549
|
-
finishedAtMs: previous?.finishedAtMs ?? null,
|
|
1550
|
-
durationMs: previous?.durationMs ?? null,
|
|
1551
|
-
inputTokens: previous?.inputTokens ?? 0,
|
|
1552
|
-
outputTokens: previous?.outputTokens ?? 0,
|
|
1553
|
-
ttftMs: previous?.ttftMs ?? null,
|
|
1554
|
-
outcomeDetail: previous?.outcomeDetail ?? null,
|
|
1555
|
-
...(node !== undefined ? { node } : {}),
|
|
1556
|
-
...(gate !== undefined ? { gate } : {}),
|
|
1557
|
-
...(council !== undefined ? { council } : {}),
|
|
1558
|
-
...(previous?.hostVerification !== undefined ? { hostVerification: previous.hostVerification } : {}),
|
|
1559
|
-
...(rerouteCount !== undefined ? { rerouteCount } : {}),
|
|
1560
|
-
...(contextWindow !== undefined ? { contextWindow } : {}),
|
|
1561
|
-
lastContextTokens: previous?.lastContextTokens ?? 0,
|
|
1562
|
-
...(previous?.receiptId !== undefined ? { receiptId: previous.receiptId } : {}),
|
|
1563
|
-
...(phase !== undefined ? { phase } : {}),
|
|
1564
|
-
progress: previous?.progress ?? createWorkerProgressFold(),
|
|
1565
|
-
...(previous?.retry ? { retry: { ...previous.retry } } : {}),
|
|
1566
|
-
...(previous?.steerAcknowledgement ? { steerAcknowledgement: { ...previous.steerAcknowledgement } } : {}),
|
|
1567
|
-
...(previous?.writeRecordDowngrade ? { writeRecordDowngrade: { ...previous.writeRecordDowngrade } } : {}),
|
|
1568
|
-
};
|
|
1569
|
-
entries.set(runId, entry);
|
|
1570
|
-
pruneEntries(entries, (evicted) => fleetPhases.delete(evicted));
|
|
1571
|
-
return entry;
|
|
1572
|
-
};
|
|
1573
|
-
|
|
1574
|
-
const unsubscribers = [
|
|
1575
|
-
bus.on(BusChannels.DispatchEnqueued, (raw) => {
|
|
1576
|
-
const entry = upsertBase(raw ?? {}, "enqueued", Date.now());
|
|
1577
|
-
if (entry) delete entry.retry;
|
|
1578
|
-
}),
|
|
1579
|
-
bus.on(BusChannels.DispatchStarted, (raw) => {
|
|
1580
|
-
const now = Date.now();
|
|
1581
|
-
const entry = upsertBase(raw ?? {}, "running", now);
|
|
1582
|
-
if (!entry) return;
|
|
1583
|
-
entry.startedAtMs ??= now;
|
|
1584
|
-
entry.startedAtClockMs ??= performance.now();
|
|
1585
|
-
entry.finishedAtMs = null;
|
|
1586
|
-
entry.durationMs = null;
|
|
1587
|
-
delete entry.retry;
|
|
1588
|
-
}),
|
|
1589
|
-
bus.on(BusChannels.DispatchCompleted, (raw) => {
|
|
1590
|
-
const now = Date.now();
|
|
1591
|
-
const payload: Partial<DispatchCompletedPayload> = raw ?? {};
|
|
1592
|
-
const entry = upsertBase(payload, "completed", now);
|
|
1593
|
-
if (!entry) return;
|
|
1594
|
-
entry.startedAtMs ??= entry.enqueuedAtMs;
|
|
1595
|
-
entry.finishedAtMs = now;
|
|
1596
|
-
entry.durationMs = parseFiniteNumber(payload.durationMs, Math.max(0, rawDurationMs(entry.startedAtMs, now)));
|
|
1597
|
-
entry.tokenCount = parseFiniteNumber(payload.tokenCount, entry.tokenCount);
|
|
1598
|
-
entry.costUsd = parseFiniteNumber(payload.costUsd, entry.costUsd);
|
|
1599
|
-
entry.costProvenance = resolveCostProvenance(payload.costProvenance, entry.costProvenance ?? "unknown");
|
|
1600
|
-
entry.outcomeDetail = null;
|
|
1601
|
-
if (payload.hostVerification !== undefined) entry.hostVerification = payload.hostVerification;
|
|
1602
|
-
settleFromReceipt(entry);
|
|
1603
|
-
// A terminal dispatch event is published only after the run's receipt is
|
|
1604
|
-
// sealed at receipts/<runId>.json, so the run id is the receipt id here.
|
|
1605
|
-
entry.receiptId = entry.runId;
|
|
1606
|
-
delete entry.retry;
|
|
1607
|
-
if (typeof payload.inputTokenCount === "number") {
|
|
1608
|
-
entry.inputTokens = payload.inputTokenCount + parseFiniteNumberOrZero(payload.cacheReadTokenCount);
|
|
1609
|
-
}
|
|
1610
|
-
if (typeof payload.outputTokenCount === "number") {
|
|
1611
|
-
entry.outputTokens = payload.outputTokenCount;
|
|
1612
|
-
}
|
|
1613
|
-
}),
|
|
1614
|
-
bus.on(BusChannels.DispatchFailed, (raw) => {
|
|
1615
|
-
const now = Date.now();
|
|
1616
|
-
const payload: Partial<DispatchFailedPayload> = raw ?? {};
|
|
1617
|
-
const runId = parseRunId(payload.runId);
|
|
1618
|
-
const previousStatus = runId !== null ? entries.get(runId)?.status : undefined;
|
|
1619
|
-
const resolvedStatus = resolveDispatchFailureStatus(payload.reason);
|
|
1620
|
-
const status = previousStatus === "dead" && resolvedStatus === "failed" ? "dead" : resolvedStatus;
|
|
1621
|
-
const entry = upsertBase(payload, status, now);
|
|
1622
|
-
if (!entry) return;
|
|
1623
|
-
entry.startedAtMs ??= entry.enqueuedAtMs;
|
|
1624
|
-
entry.finishedAtMs = now;
|
|
1625
|
-
entry.durationMs = parseFiniteNumber(payload.durationMs, Math.max(0, rawDurationMs(entry.startedAtMs, now)));
|
|
1626
|
-
entry.tokenCount = parseFiniteNumber(payload.tokenCount, entry.tokenCount);
|
|
1627
|
-
entry.costUsd = parseFiniteNumber(payload.costUsd, entry.costUsd);
|
|
1628
|
-
entry.costProvenance = resolveCostProvenance(payload.costProvenance, entry.costProvenance ?? "unknown");
|
|
1629
|
-
entry.outcomeDetail = resolveFailureDetail(payload, entry.outcomeDetail);
|
|
1630
|
-
if (payload.hostVerification !== undefined) entry.hostVerification = payload.hostVerification;
|
|
1631
|
-
settleFromReceipt(entry);
|
|
1632
|
-
// A denied retry never reached a run, so no receipt was sealed for it;
|
|
1633
|
-
// every other failure finalized through recordReceipt like a success.
|
|
1634
|
-
if (payload.reason !== "retry_denied") entry.receiptId = entry.runId;
|
|
1635
|
-
delete entry.retry;
|
|
1636
|
-
if (typeof payload.inputTokenCount === "number") {
|
|
1637
|
-
entry.inputTokens = payload.inputTokenCount + parseFiniteNumberOrZero(payload.cacheReadTokenCount);
|
|
1638
|
-
}
|
|
1639
|
-
if (typeof payload.outputTokenCount === "number") {
|
|
1640
|
-
entry.outputTokens = payload.outputTokenCount;
|
|
1641
|
-
}
|
|
1642
|
-
}),
|
|
1643
|
-
bus.on(BusChannels.RunAborted, (raw) => {
|
|
1644
|
-
const runId = parseRunId(raw?.runId);
|
|
1645
|
-
if (!runId) return;
|
|
1646
|
-
const entry = entries.get(runId);
|
|
1647
|
-
if (!entry) return;
|
|
1648
|
-
const wasRetrying = entry.retry !== undefined;
|
|
1649
|
-
delete entry.retry;
|
|
1650
|
-
if (wasRetrying && raw?.startedAt === null) {
|
|
1651
|
-
// Canceling a retry timer is synchronous: there is no worker left to
|
|
1652
|
-
// wind down, so the history row can become terminal immediately.
|
|
1653
|
-
entry.status = "aborted";
|
|
1654
|
-
entry.finishedAtMs = Date.now();
|
|
1655
|
-
entry.progress.settle();
|
|
1656
|
-
} else {
|
|
1657
|
-
if (isTerminalStatus(entry.status) && !wasRetrying) return;
|
|
1658
|
-
entry.status = "cancelling";
|
|
1659
|
-
}
|
|
1660
|
-
entry.outcomeDetail = parseOptionalDetail(raw?.reason) ?? entry.outcomeDetail ?? null;
|
|
1661
|
-
}),
|
|
1662
|
-
bus.on(BusChannels.DispatchProgress, (raw) => {
|
|
1663
|
-
const payload: Partial<DispatchProgressPayload> = raw ?? {};
|
|
1664
|
-
const runId = parseRunId(payload.runId);
|
|
1665
|
-
if (!runId) return;
|
|
1666
|
-
const entry = entries.get(runId);
|
|
1667
|
-
if (!entry) return;
|
|
1668
|
-
const workerEvent = (payload.event ?? {}) as WorkerEventShape;
|
|
1669
|
-
const type = typeof workerEvent.type === "string" ? workerEvent.type : "";
|
|
1670
|
-
if (type === "heartbeat_status") {
|
|
1671
|
-
if (isTerminalStatus(entry.status) || entry.status === "cancelling") return;
|
|
1672
|
-
const status = resolveHeartbeatStatus((workerEvent as { status?: unknown }).status);
|
|
1673
|
-
if (!status) return;
|
|
1674
|
-
entry.status = status;
|
|
1675
|
-
if (status === "dead") {
|
|
1676
|
-
entry.finishedAtMs ??= Date.now();
|
|
1677
|
-
// A worker-side terminal signal arrives before any receipt is
|
|
1678
|
-
// sealed, so the run's own last durable message is the best truth
|
|
1679
|
-
// there is; the terminal bus event replaces it with the sealed one.
|
|
1680
|
-
entry.progress.settle();
|
|
1681
|
-
delete entry.retry;
|
|
1682
|
-
}
|
|
1683
|
-
return;
|
|
1684
|
-
}
|
|
1685
|
-
if (type === "attempt_start") {
|
|
1686
|
-
// The assignment stream hands the root run a failover hop: a later
|
|
1687
|
-
// attempt took over, so the row is live again on the new route.
|
|
1688
|
-
entry.failoverHops = (entry.failoverHops ?? 0) + 1;
|
|
1689
|
-
entry.status = "running";
|
|
1690
|
-
entry.finishedAtMs = null;
|
|
1691
|
-
// The projection keeps the tail the operator is reading and drops the
|
|
1692
|
-
// finished attempt's live state, exactly as the transcript block does.
|
|
1693
|
-
entry.progress.restart();
|
|
1694
|
-
delete entry.retry;
|
|
1695
|
-
return;
|
|
1696
|
-
}
|
|
1697
|
-
if (type === "agent_start") {
|
|
1698
|
-
entry.startedAtMs = Date.now();
|
|
1699
|
-
entry.startedAtClockMs = performance.now();
|
|
1700
|
-
}
|
|
1701
|
-
if (type === "message_update") {
|
|
1702
|
-
const assistantEvent =
|
|
1703
|
-
"assistantMessageEvent" in workerEvent &&
|
|
1704
|
-
typeof workerEvent.assistantMessageEvent === "object" &&
|
|
1705
|
-
workerEvent.assistantMessageEvent !== null
|
|
1706
|
-
? (workerEvent.assistantMessageEvent as { type?: unknown })
|
|
1707
|
-
: {};
|
|
1708
|
-
const hasDelta =
|
|
1709
|
-
assistantEvent.type === "text_delta" ||
|
|
1710
|
-
assistantEvent.type === "thinking_delta" ||
|
|
1711
|
-
assistantEvent.type === "toolcall_start" ||
|
|
1712
|
-
assistantEvent.type === "toolcall_delta";
|
|
1713
|
-
if (hasDelta && entry.ttftMs === null && entry.startedAtClockMs !== null) {
|
|
1714
|
-
entry.ttftMs = Math.round(performance.now() - entry.startedAtClockMs);
|
|
1715
|
-
}
|
|
1716
|
-
}
|
|
1717
|
-
if (type === "clio_coder_write_record_downgraded") {
|
|
1718
|
-
const rawPayload = (workerEvent as { payload?: unknown }).payload;
|
|
1719
|
-
const payload =
|
|
1720
|
-
typeof rawPayload === "object" && rawPayload !== null ? (rawPayload as Record<string, unknown>) : null;
|
|
1721
|
-
const tool = payload === null ? undefined : parseNonEmptyString(payload.tool);
|
|
1722
|
-
const toolCallId = payload === null ? undefined : parseNonEmptyString(payload.toolCallId);
|
|
1723
|
-
if (payload?.reason === "opaque_tool_succeeded" && tool !== undefined && toolCallId !== undefined) {
|
|
1724
|
-
entry.writeRecordDowngrade = {
|
|
1725
|
-
reason: "opaque_tool_succeeded",
|
|
1726
|
-
tool: sanitizeCallTargetText(tool),
|
|
1727
|
-
toolCallId: sanitizeCallTargetText(toolCallId),
|
|
1728
|
-
};
|
|
1729
|
-
}
|
|
1730
|
-
}
|
|
1731
|
-
// The one fold that reads worker prose and tool activity. Everything the
|
|
1732
|
-
// board says about what a worker is saying or touching comes from here,
|
|
1733
|
-
// so the board and the transcript block cannot tell two stories.
|
|
1734
|
-
entry.progress.observe(payload.event);
|
|
1735
|
-
if (type === "clio_coder_steer_received") {
|
|
1736
|
-
const steerPayload = (workerEvent as { payload?: { chars?: unknown } }).payload;
|
|
1737
|
-
entry.steerAcknowledgement = {
|
|
1738
|
-
receivedAtMs: Date.now(),
|
|
1739
|
-
chars: Math.max(0, Math.floor(parseFiniteNumberOrZero(steerPayload?.chars))),
|
|
1740
|
-
};
|
|
1741
|
-
}
|
|
1742
|
-
if (isTerminalStatus(entry.status)) return;
|
|
1743
|
-
if (type === "message_end" && workerEvent.message?.role === "assistant") {
|
|
1744
|
-
const usage = workerEvent.message.usage;
|
|
1745
|
-
const input = parseFiniteNumberOrZero(usage?.input) + parseFiniteNumberOrZero(usage?.cacheRead);
|
|
1746
|
-
const output = parseFiniteNumberOrZero(usage?.output);
|
|
1747
|
-
entry.inputTokens += input;
|
|
1748
|
-
entry.outputTokens += output;
|
|
1749
|
-
entry.tokenCount += input + output + parseFiniteNumberOrZero(usage?.cacheWrite);
|
|
1750
|
-
// The last assistant message's input+cacheRead+output approximates the
|
|
1751
|
-
// worker's current context occupancy for the per-worker meter.
|
|
1752
|
-
entry.lastContextTokens = input + output;
|
|
1753
|
-
}
|
|
1754
|
-
if (type === "agent_end") {
|
|
1755
|
-
const status = resolveAgentEndStatus(workerEvent.messages);
|
|
1756
|
-
if (!status) return;
|
|
1757
|
-
entry.status = status;
|
|
1758
|
-
entry.finishedAtMs ??= Date.now();
|
|
1759
|
-
// The worker says it is done before the domain seals its receipt. Settle
|
|
1760
|
-
// on the durable message now so the card stops reading as live; the
|
|
1761
|
-
// terminal bus event seals it on the receipt shortly after.
|
|
1762
|
-
entry.progress.settle();
|
|
1763
|
-
delete entry.retry;
|
|
1764
|
-
}
|
|
1765
|
-
}),
|
|
1766
|
-
];
|
|
1767
|
-
|
|
1768
|
-
let closed = false;
|
|
1769
|
-
const reconcile = (): void => {
|
|
1770
|
-
const now = Date.now();
|
|
1771
|
-
if (!snapshot) {
|
|
1772
|
-
reconciledAtMs = now;
|
|
1773
|
-
return;
|
|
1774
|
-
}
|
|
1775
|
-
let currentSnapshot: DispatchSnapshot;
|
|
1776
|
-
try {
|
|
1777
|
-
currentSnapshot = snapshot();
|
|
1778
|
-
} catch {
|
|
1779
|
-
// Lifecycle and progress events remain authoritative if snapshot polling fails.
|
|
1780
|
-
return;
|
|
1781
|
-
}
|
|
1782
|
-
if (!Array.isArray(currentSnapshot?.retrying) || !Array.isArray(currentSnapshot?.running)) return;
|
|
1783
|
-
reconciledAtMs = now;
|
|
1784
|
-
const retrying = readRetrySnapshot(currentSnapshot);
|
|
1785
|
-
const running = readRunningSnapshot(currentSnapshot);
|
|
1786
|
-
for (const entry of entries.values()) {
|
|
1787
|
-
if (entry.retry && !retrying.has(entry.runId)) {
|
|
1788
|
-
// The timer left the queue (launched or was otherwise consumed). The
|
|
1789
|
-
// parent attempt's original terminal state becomes visible again; the
|
|
1790
|
-
// successor gets its own row.
|
|
1791
|
-
delete entry.retry;
|
|
1792
|
-
}
|
|
1793
|
-
}
|
|
1794
|
-
for (const [runId, projection] of retrying) {
|
|
1795
|
-
const existing = entries.get(runId);
|
|
1796
|
-
if (existing && existing.status !== "failed" && existing.status !== "dead") {
|
|
1797
|
-
continue;
|
|
1798
|
-
}
|
|
1799
|
-
const entry =
|
|
1800
|
-
existing ??
|
|
1801
|
-
upsertBase(
|
|
1802
|
-
{
|
|
1803
|
-
runId,
|
|
1804
|
-
agentId: projection.agentId,
|
|
1805
|
-
...(projection.taskSummary !== undefined ? { task: projection.taskSummary } : {}),
|
|
1806
|
-
},
|
|
1807
|
-
"failed",
|
|
1808
|
-
now,
|
|
1809
|
-
);
|
|
1810
|
-
if (entry) {
|
|
1811
|
-
// A waiting retry has no live worker; the row projection already
|
|
1812
|
-
// renders a retrying row with no current tool.
|
|
1813
|
-
entry.retry = { ...projection.retry };
|
|
1814
|
-
if (entry.taskSummary === undefined && projection.taskSummary !== undefined) {
|
|
1815
|
-
entry.taskSummary = projection.taskSummary;
|
|
1816
|
-
}
|
|
1817
|
-
}
|
|
1818
|
-
}
|
|
1819
|
-
for (const [runId, live] of running) {
|
|
1820
|
-
const entry = entries.get(runId);
|
|
1821
|
-
if (!entry) continue;
|
|
1822
|
-
if (isTerminalStatus(entry.status) && live.outcomePhase !== "aborting") continue;
|
|
1823
|
-
entry.inputTokens = live.inputTokens;
|
|
1824
|
-
entry.outputTokens = live.outputTokens;
|
|
1825
|
-
entry.tokenCount = live.tokenCount;
|
|
1826
|
-
entry.costUsd = live.costUsd;
|
|
1827
|
-
entry.costProvenance = live.costProvenance;
|
|
1828
|
-
if (live.budget !== undefined) entry.budget = live.budget;
|
|
1829
|
-
if (live.outcomePhase === "aborting") {
|
|
1830
|
-
if (entry.status !== "completed" && entry.status !== "aborted") {
|
|
1831
|
-
entry.status = "cancelling";
|
|
1832
|
-
delete entry.retry;
|
|
1833
|
-
}
|
|
1834
|
-
}
|
|
1835
|
-
}
|
|
1836
|
-
};
|
|
1837
|
-
|
|
1165
|
+
let current = projection.snapshot();
|
|
1166
|
+
const unsubscribe = projection.subscribe((snapshot) => {
|
|
1167
|
+
current = snapshot;
|
|
1168
|
+
});
|
|
1838
1169
|
const projectRows = (activeOnly: boolean): ReadonlyArray<DispatchBoardRow> => {
|
|
1839
|
-
return [...
|
|
1840
|
-
.
|
|
1841
|
-
.
|
|
1170
|
+
return [...current.runs]
|
|
1171
|
+
.reverse()
|
|
1172
|
+
.sort(
|
|
1173
|
+
(a, b) =>
|
|
1174
|
+
STATUS_ORDER[a.status] - STATUS_ORDER[b.status] ||
|
|
1175
|
+
(b.finishedAtMs ?? b.startedAtMs) - (a.finishedAtMs ?? a.startedAtMs),
|
|
1176
|
+
)
|
|
1177
|
+
.map((run) => toRow(run, current.generatedAt))
|
|
1842
1178
|
.filter((row) => !activeOnly || !isTerminalStatus(row.status));
|
|
1843
1179
|
};
|
|
1844
|
-
|
|
1845
1180
|
return {
|
|
1846
|
-
rows()
|
|
1847
|
-
|
|
1848
|
-
|
|
1849
|
-
|
|
1850
|
-
|
|
1851
|
-
},
|
|
1852
|
-
reconcile,
|
|
1853
|
-
setFleetPhase(runId: string, phase: DispatchBoardPhase): void {
|
|
1854
|
-
fleetPhases.set(runId, phase);
|
|
1855
|
-
const entry = entries.get(runId);
|
|
1856
|
-
if (entry) entry.phase = { ...phase };
|
|
1181
|
+
rows: () => projectRows(false),
|
|
1182
|
+
activeRows: () => projectRows(true),
|
|
1183
|
+
reconcile() {
|
|
1184
|
+
projection.reconcileRuns();
|
|
1185
|
+
current = projection.snapshot();
|
|
1857
1186
|
},
|
|
1858
|
-
|
|
1859
|
-
|
|
1860
|
-
|
|
1861
|
-
for (const unsubscribe of unsubscribers) unsubscribe();
|
|
1187
|
+
setFleetPhase(runId, phase) {
|
|
1188
|
+
projection.setFleetPhase(runId, phase);
|
|
1189
|
+
current = projection.snapshot();
|
|
1862
1190
|
},
|
|
1191
|
+
unsubscribe,
|
|
1863
1192
|
};
|
|
1864
1193
|
}
|