@iowarp/clio-coder 0.5.0 → 0.5.2
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/.claude-plugin/marketplace.json +4 -4
- package/CHANGELOG.md +35 -0
- package/CONTRIBUTING.md +9 -0
- package/README.md +12 -9
- package/ROADMAP.md +30 -5
- package/dist/{acp-KS7ARGV6.js → acp-F6PGOFZ4.js} +2 -2
- package/dist/{agents-YOGJ2YEJ.js → agents-ZHP4R6EX.js} +22 -21
- package/dist/assets/codewiki.json +1 -1
- package/dist/{auth-CEDCO6O6.js → auth-N75U2H3Z.js} +4 -4
- package/dist/{chunk-D3KWFOUT.js → chunk-23UIXH6Z.js} +3 -3
- package/dist/{chunk-ZR5YA6ZF.js → chunk-36XVK5P5.js} +5 -5
- package/dist/{chunk-AVSR2HKI.js → chunk-3DZ4LPLS.js} +6 -6
- package/dist/{chunk-LYJJ6546.js → chunk-3GSPCWFX.js} +12 -12
- package/dist/{chunk-CRHPCPZP.js → chunk-4KC4CHKJ.js} +2 -2
- package/dist/{chunk-4VDHLCF5.js → chunk-4WJBWKMI.js} +2 -2
- package/dist/{chunk-KBUTSJSR.js → chunk-4XBYHXGK.js} +2 -2
- package/dist/{chunk-6W75D37F.js → chunk-53P775GE.js} +6 -3
- package/dist/{chunk-XZWSP67B.js → chunk-5APYAXCB.js} +2 -2
- package/dist/{chunk-D65E25JG.js → chunk-67HPYNTJ.js} +2 -2
- package/dist/{chunk-5JQR5B4D.js → chunk-6KV4KCQZ.js} +4 -4
- package/dist/{chunk-V4XJWDHR.js → chunk-6UKFRTXI.js} +2 -1
- package/dist/{chunk-NDPF2N2L.js → chunk-7DW7CJW2.js} +2 -2
- package/dist/{chunk-5KQEUIWM.js → chunk-7LUEQODV.js} +4 -4
- package/dist/{chunk-LNOXCGN2.js → chunk-7UFDIOBT.js} +3 -3
- package/dist/{chunk-DXSETN72.js → chunk-7WUGNN43.js} +2 -2
- package/dist/{chunk-V35KZDUZ.js → chunk-AA3GRZWS.js} +2 -2
- package/dist/{chunk-X4CEFOSG.js → chunk-ADO3OQIC.js} +4 -4
- package/dist/{chunk-UX2L5CUD.js → chunk-AI36V3ON.js} +3 -3
- package/dist/{chunk-B7GY6QER.js → chunk-B26OUMJW.js} +2 -2
- package/dist/{chunk-LAR7DX5E.js → chunk-B5TASTCK.js} +153 -62
- package/dist/{chunk-TGWZXJ7L.js → chunk-BEMQK5Q7.js} +92 -84
- package/dist/{chunk-RNDCROSG.js → chunk-CNXU7TR2.js} +3 -3
- package/dist/{chunk-3JLTRPN7.js → chunk-CVMUXT64.js} +35 -66
- package/dist/{chunk-733ZBT5P.js → chunk-E74MJF6G.js} +4 -4
- package/dist/{chunk-T2MDZES3.js → chunk-EBMTBE76.js} +3 -3
- package/dist/{chunk-OZ76TLGU.js → chunk-EEITU7S6.js} +2 -2
- package/dist/{chunk-GRHOXDKB.js → chunk-ELDJWJKM.js} +97 -14
- package/dist/{chunk-GCQFN7YI.js → chunk-EMYEQLWO.js} +2 -2
- package/dist/{chunk-LTWH2ACR.js → chunk-EQPFEDFV.js} +222 -127
- package/dist/{chunk-TDGYTWM6.js → chunk-F4I3H56H.js} +2 -2
- package/dist/chunk-F6KCJO3U.js +523 -0
- package/dist/{chunk-FGSQHUCK.js → chunk-F6VKWTTY.js} +5 -5
- package/dist/{chunk-UJD5MPP6.js → chunk-FLNXQQ5B.js} +2 -2
- package/dist/{chunk-EX57VVWW.js → chunk-FOSRJ2VZ.js} +4 -4
- package/dist/{chunk-ZARZ4POR.js → chunk-G5ZDQQE3.js} +3 -3
- package/dist/{chunk-HQVN7G4F.js → chunk-G62JBPXN.js} +7 -7
- package/dist/{chunk-ZJPORZTC.js → chunk-GIAI7A2K.js} +2 -2
- package/dist/chunk-GPTR6OTU.js +2551 -0
- package/dist/{chunk-EZD2BXGP.js → chunk-GUFQPTQK.js} +2 -2
- package/dist/{chunk-OPD7GL6F.js → chunk-H6FQVNZC.js} +8 -7
- package/dist/chunk-H7REJ7L5.js +80 -0
- package/dist/{chunk-EYTLV3W3.js → chunk-HTWTORF7.js} +2 -2
- package/dist/{chunk-DF6PI6GN.js → chunk-I6UKQPGS.js} +3 -3
- package/dist/{chunk-ISHUS7HC.js → chunk-JRW236JT.js} +3 -3
- package/dist/{chunk-DE2LU267.js → chunk-KKAJGT3B.js} +3 -2
- package/dist/{chunk-OV62D6KO.js → chunk-KQMYL5GR.js} +3 -3
- package/dist/{chunk-QDUUOZ3S.js → chunk-KWMFC7FN.js} +3 -3
- package/dist/{chunk-R7FGRZNF.js → chunk-LXYHCCIZ.js} +9 -9
- package/dist/{chunk-NFSK2VNU.js → chunk-LZMTVVN4.js} +2 -2
- package/dist/{chunk-62UK7AGW.js → chunk-M5PMRZSR.js} +397 -44
- package/dist/chunk-MMZMM6SW.js +131 -0
- package/dist/{chunk-FFYTC2KQ.js → chunk-MNABNEBX.js} +2 -2
- package/dist/{chunk-XMDBTYCH.js → chunk-N3CWOGVF.js} +3 -3
- package/dist/{chunk-VYRQHORQ.js → chunk-NMQSO6Z6.js} +4 -3
- package/dist/{chunk-R2UUNSNQ.js → chunk-O3ZAF7UY.js} +18 -5
- package/dist/{chunk-4SYHGVDE.js → chunk-OQNCLZI4.js} +4 -4
- package/dist/{chunk-EG4ARXPC.js → chunk-OX6QTA4N.js} +3 -3
- package/dist/{chunk-P4GNZPXO.js → chunk-OYUS3UZP.js} +2 -2
- package/dist/{chunk-OQ2EOAHA.js → chunk-PF36KOGI.js} +291 -112
- package/dist/{chunk-55RMDDFM.js → chunk-PGQG7ZMW.js} +2 -2
- package/dist/{chunk-CBAQPTDU.js → chunk-PIU6BXXW.js} +2 -2
- package/dist/{chunk-EKV4UBCM.js → chunk-PZBQUJ2F.js} +2 -2
- package/dist/{chunk-7RET77VB.js → chunk-Q2HKY32Y.js} +2 -2
- package/dist/{chunk-U6YTUVOX.js → chunk-Q4RMNWMZ.js} +4 -4
- package/dist/chunk-Q6FRR3AQ.js +48 -0
- package/dist/{chunk-6RJMYYIE.js → chunk-QJSIAJBY.js} +3 -3
- package/dist/{chunk-DOUISWEE.js → chunk-QOJ4ERMU.js} +5 -5
- package/dist/{chunk-IFPDAD7R.js → chunk-RWSRKXLT.js} +3 -3
- package/dist/{chunk-T33IYTZM.js → chunk-SAASVMIY.js} +3 -3
- package/dist/{chunk-2DTIWSAW.js → chunk-SEQDH6JC.js} +3 -3
- package/dist/{chunk-BRCOSE7O.js → chunk-SZUO5BSE.js} +2 -2
- package/dist/{chunk-HOEDA42N.js → chunk-T7HZ7KJF.js} +2 -2
- package/dist/{chunk-OJXOA6YU.js → chunk-TL6LNERH.js} +2 -2
- package/dist/{chunk-UCINIRHW.js → chunk-TPCZXWLT.js} +3 -3
- package/dist/{chunk-ZUKUCZYZ.js → chunk-TQ2KTH4A.js} +2 -2
- package/dist/{chunk-4WOOTKFD.js → chunk-U3FETNQB.js} +341 -20
- package/dist/{chunk-5B3RTYAK.js → chunk-UGDSB4AN.js} +2 -2
- package/dist/{chunk-VKHLUZNO.js → chunk-UZ7YBL43.js} +3 -3
- package/dist/{chunk-QNUQ7K7D.js → chunk-VKMSEO7Y.js} +4 -4
- package/dist/{chunk-IN7DGBVS.js → chunk-VLX5VZ35.js} +5 -5
- package/dist/{chunk-SJGS3GDI.js → chunk-WAGBMMNX.js} +5 -5
- package/dist/{chunk-BFOSV5EZ.js → chunk-WX2YCH7F.js} +2 -2
- package/dist/{chunk-3LT34CAM.js → chunk-XBIGUILU.js} +32 -17
- package/dist/{chunk-XDHUDE5K.js → chunk-XKYBFRWR.js} +5 -5
- package/dist/{chunk-U5QU5ZOD.js → chunk-XYPWFSU5.js} +3 -3
- package/dist/{chunk-YBUECLAF.js → chunk-YEJQDODA.js} +2 -2
- package/dist/{chunk-YQ6XEFVK.js → chunk-Z74OGONW.js} +39 -7
- package/dist/{chunk-I4ELN5BX.js → chunk-ZTNOEJRI.js} +2 -2
- package/dist/cli/index.js +26 -26
- package/dist/{clio-K2PBVCEM.js → clio-4IKFE25F.js} +2 -2
- package/dist/{clio-context-tools-GR4OHFSO.js → clio-context-tools-OHJXYX4R.js} +25 -23
- package/dist/{code-nav-4X3OI6DK.js → code-nav-XPM3MY5I.js} +7 -7
- package/dist/{config-Q5J7UBAB.js → config-343YS25T.js} +43 -41
- package/dist/{config-graph-P3555574.js → config-graph-WI263KDX.js} +43 -41
- package/dist/{configure-KIJ32ZO6.js → configure-GZDG4HER.js} +21 -21
- package/dist/{context-LFBQOSXT.js → context-4OFO7N7Y.js} +12 -12
- package/dist/{context-WBH3KSVR.js → context-JLK2RLOG.js} +42 -40
- package/dist/{context-NNLBES2Y.js → context-O6DIWCF6.js} +23 -21
- package/dist/{context-clear-YOHMQ6SQ.js → context-clear-MR7KOGQI.js} +42 -40
- package/dist/{context-working-set-MRAEVDNV.js → context-working-set-YZAD3KWO.js} +14 -13
- package/dist/{data-tool-JJPBGMQJ.js → data-tool-EKD7DFHG.js} +7 -7
- package/dist/{detail-RHJOTGN4.js → detail-YZPHFEVJ.js} +43 -41
- package/dist/{dispatch-runner-NC7PYNIO.js → dispatch-runner-VKVXVTWJ.js} +44 -42
- package/dist/{doctor-S5KZ2GTN.js → doctor-53AVQXAO.js} +17 -16
- package/dist/{doctor-deep-2EJQSHIZ.js → doctor-deep-BLRB2NCG.js} +5 -5
- package/dist/{eval-3D6M36N7.js → eval-P3BQSLQE.js} +21 -20
- package/dist/{evidence-XNVPPLVK.js → evidence-6LLI6SZH.js} +44 -42
- package/dist/{evidence-6IYN52ET.js → evidence-HTN3JLUO.js} +42 -40
- package/dist/{evidence-JVECPI3F.js → evidence-NJRE3R5H.js} +42 -40
- package/dist/{evolve-TLPUDJDM.js → evolve-WWZHJVJP.js} +42 -40
- package/dist/{fleet-WKVBF5SZ.js → fleet-GGZ4BVJE.js} +64 -62
- package/dist/{fleet-6RJWIOEO.js → fleet-QG3IIWWM.js} +44 -42
- package/dist/{fleet-commands-L6WFT7KZ.js → fleet-commands-J2ZIKISQ.js} +7 -7
- package/dist/{fleet-decisions-BTQMWU5A.js → fleet-decisions-Y2Q7375Q.js} +8 -8
- package/dist/{fleet-graph-553DZ67Q.js → fleet-graph-TCBCCCBP.js} +11 -11
- package/dist/{fleet-inspect-236FZPRB.js → fleet-inspect-KOLKBC56.js} +44 -42
- package/dist/{fleet-preflight-NZQHABWO.js → fleet-preflight-44UNCC4Y.js} +27 -25
- package/dist/{fleet-validate-7NLAE26R.js → fleet-validate-K2FXRZVA.js} +13 -13
- package/dist/{fleet-verify-E3RO6A5W.js → fleet-verify-AS444WDW.js} +42 -40
- package/dist/{fleet-view-KMZQY7YJ.js → fleet-view-X4JU4J6O.js} +43 -41
- package/dist/gui/ops-worker.js +9 -9
- package/dist/gui/reads-worker.js +9 -8
- package/dist/{init-DV5B6HQG.js → init-VSOWFHVL.js} +54 -52
- package/dist/{interactive-OXGYZYAS.js → interactive-JRCBENLZ.js} +1733 -577
- package/dist/{interop-J7UOBOSF.js → interop-JR6BCY7R.js} +10 -10
- package/dist/{inventory-OEGIL6PY.js → inventory-3JUGLVJI.js} +43 -41
- package/dist/{library-ROZAMUIL.js → library-7BOH3Y7N.js} +15 -15
- package/dist/{library-B3UPGY4V.js → library-7PFONXUI.js} +9 -9
- package/dist/{library-MXQA5DLT.js → library-TUYZMFIA.js} +7 -7
- package/dist/{library-import-2LTWOVBD.js → library-import-TJVXKLDK.js} +10 -10
- package/dist/{library-inventory-LJ3XHLWO.js → library-inventory-MD3AYTP4.js} +9 -9
- package/dist/{library-validation-DARHHUNW.js → library-validation-ZDLITEA3.js} +7 -7
- package/dist/{mcp-2GSPYQ54.js → mcp-EFCWUPUR.js} +3 -3
- package/dist/{memory-J3STUUIK.js → memory-Q2YVOKK5.js} +42 -40
- package/dist/{models-Y3GMFJ2V.js → models-M7BOCW7F.js} +17 -16
- package/dist/{monitor-LHNH577J.js → monitor-2HD3MC67.js} +47 -45
- package/dist/{orchestrator-DTAPXULA.js → orchestrator-OUW3ZN6Y.js} +1894 -226
- package/dist/{panes-A743ONZ5.js → panes-TTPPSYCL.js} +3 -3
- package/dist/{preload-OJBMAIXF.js → preload-A47C2NUF.js} +42 -40
- package/dist/{providers-CMETPZNS.js → providers-T43W7EL4.js} +4 -4
- package/dist/{resources-FY6XYFN2.js → resources-TP6X2V6W.js} +20 -11
- package/dist/{run-H64MEVTA.js → run-LDSBPMCS.js} +61 -59
- package/dist/{share-CAFMMQLM.js → share-URHKKMHR.js} +9 -9
- package/dist/{skills-ERKQUC7L.js → skills-E477MOOO.js} +13 -11
- package/dist/{skills-eval-CQ23MYQK.js → skills-eval-AIBR2L7H.js} +583 -93
- package/dist/{skills-inventory-TVUYJDVN.js → skills-inventory-HLMKY3R5.js} +13 -11
- package/dist/{slash-commands-ROG3KIFJ.js → slash-commands-LIIZKA5Y.js} +28 -26
- package/dist/{startup-background-KDWCQMWT.js → startup-background-JR2KDK6R.js} +43 -41
- package/dist/{steer-KKYXJSH4.js → steer-D7RTAPCM.js} +3 -3
- package/dist/{system-ZDW44ZGX.js → system-X2P5N4IY.js} +14 -13
- package/dist/{targets-AJWA6E7Z.js → targets-VFFAKUFM.js} +25 -24
- package/dist/{tasks-6L2JJRC5.js → tasks-ERAWZA22.js} +6 -6
- package/dist/{terminal-lease-YFUSDPAD.js → terminal-lease-V2N2BIKQ.js} +2 -2
- package/dist/{trace-LA5MVR4Y.js → trace-MA5BT7XY.js} +3 -3
- package/dist/{usage-XSILDHKF.js → usage-WYFY2L6M.js} +50 -48
- package/dist/{verifiers-ECA5GIHL.js → verifiers-TYIW2XKF.js} +7 -7
- package/dist/{verify-R6QQCCEB.js → verify-242UFYTP.js} +6 -6
- package/dist/{web-fetch-PVZNMBOB.js → web-fetch-LRAGYU6Y.js} +3 -3
- package/dist/{wiki-generate-RP22WP5K.js → wiki-generate-OFKOX2T6.js} +53 -51
- package/dist/worker/entry.js +31 -29
- package/docs/architecture/architecture.md +1 -0
- package/docs/architecture/context-engine.md +4 -2
- package/docs/architecture/observability.md +6 -4
- package/docs/architecture/prompt-envelope-and-tools.md +1 -1
- package/docs/architecture/session-lifecycle.md +1 -1
- package/docs/architecture/tui-design.md +12 -9
- package/docs/gui/parity/02-slash-and-surfaces.md +1 -1
- package/docs/guide/commands-and-modes.md +91 -5
- package/docs/guide/configuration-and-targets.md +2 -2
- package/docs/guide/context-continuity.md +49 -0
- package/docs/guide/proactive-memory.md +6 -3
- package/library/registry.yaml +292 -32
- package/library/skills/README.md +27 -2
- package/library/skills/context/context-handoff/SKILL.md +10 -4
- package/library/skills/meta/clio-coder-dev/SKILL.md +92 -88
- package/library/skills/meta/clio-coder-dev/evals.md +51 -46
- package/library/skills/meta/clio-coder-dev/plugin.json +2 -2
- package/library/skills/meta/clio-coder-dev/references/change-map.md +49 -0
- package/library/skills/meta/clio-coder-test/SKILL.md +89 -142
- package/library/skills/meta/clio-coder-test/evals.md +58 -62
- package/library/skills/meta/clio-coder-test/plugin.json +2 -2
- package/library/skills/meta/clio-coder-test/references/harness.md +3 -3
- package/library/skills/meta/clio-coder-test/references/lifecycle-validation.md +30 -0
- package/library/skills/meta/clio-coder-test/references/test-map.md +60 -89
- package/library/skills/registry.yaml +5 -5
- package/library/skills/skill-marketplace.json +12 -14
- package/package.json +1 -1
- package/src/cli/skills-eval.ts +1064 -54
- package/src/cli/usage.ts +2 -2
- package/src/core/clio-repo.ts +3 -0
- package/src/core/tool-names.ts +1 -0
- package/src/domains/context/budget/inspection.ts +9 -0
- package/src/domains/context/budget/live-view.ts +418 -0
- package/src/domains/context/budget/pressure.ts +393 -0
- package/src/domains/context/budget/request-fit.ts +15 -0
- package/src/domains/evidence/build.ts +24 -0
- package/src/domains/gateway/mcp/client.ts +1 -1
- package/src/domains/memory/commit-state.ts +160 -0
- package/src/domains/memory/operations.ts +18 -10
- package/src/domains/memory/prompt-cache.ts +95 -0
- package/src/domains/memory/prompt-section.ts +50 -7
- package/src/domains/memory/relevance.ts +93 -0
- package/src/domains/memory/restoration.ts +78 -0
- package/src/domains/memory/store.ts +39 -1
- package/src/domains/middleware/memory-intervention.ts +116 -24
- package/src/domains/observability/background-memory-usage.ts +1 -1
- package/src/domains/observability/cost.ts +3 -3
- package/src/domains/observability/extension.ts +1 -1
- package/src/domains/observability/metrics.ts +1 -1
- package/src/domains/prompts/compiler.ts +1 -1
- package/src/domains/prompts/extension.ts +38 -1
- package/src/domains/quota/anthropic-max-provider.ts +134 -0
- package/src/domains/quota/anthropic-usage.ts +220 -0
- package/src/domains/quota/antigravity-provider.ts +339 -0
- package/src/domains/quota/cache.ts +87 -0
- package/src/domains/quota/claude-code-provider.ts +169 -0
- package/src/domains/quota/codex-provider.ts +237 -0
- package/src/domains/quota/presentation.ts +240 -0
- package/src/domains/quota/registry.ts +23 -0
- package/src/domains/quota/service.ts +93 -0
- package/src/domains/quota/summary-feed.ts +86 -0
- package/src/domains/quota/types.ts +84 -0
- package/src/domains/resources/index.ts +11 -0
- package/src/domains/resources/skills/catalog-view.ts +571 -0
- package/src/domains/resources/skills/lexical-match.ts +136 -0
- package/src/domains/resources/skills/loader.ts +38 -0
- package/src/domains/resources/skills/promotion.ts +1 -55
- package/src/domains/resources/skills/provenance-pin.ts +50 -20
- package/src/domains/safety/action-classifier.ts +1 -0
- package/src/domains/session/compaction/branch-summary.ts +4 -1
- package/src/domains/session/compaction/compact.ts +18 -2
- package/src/domains/session/compaction/cut-point.ts +20 -1
- package/src/domains/session/compaction/tokens.ts +48 -3
- package/src/domains/session/context-accounting.ts +8 -1
- package/src/domains/session/continuity/carry.ts +59 -0
- package/src/domains/session/continuity/contract.ts +592 -0
- package/src/domains/session/continuity/evidence.ts +290 -0
- package/src/domains/session/continuity/fold.ts +1075 -0
- package/src/domains/session/continuity/note.ts +79 -0
- package/src/domains/session/continuity/operator-request.ts +104 -0
- package/src/domains/session/continuity/persistence.ts +408 -0
- package/src/domains/session/continuity/ports.ts +231 -0
- package/src/domains/session/continuity/projection.ts +538 -0
- package/src/domains/session/continuity/validate.ts +352 -0
- package/src/domains/session/entries.ts +50 -3
- package/src/domains/session/index.ts +48 -0
- package/src/domains/session/migrations/index.ts +7 -3
- package/src/domains/session/tree/fork.ts +15 -1
- package/src/domains/session/usage.ts +2 -2
- package/src/engine/acp/commands.ts +1 -1
- package/src/engine/agent.ts +133 -9
- package/src/engine/session.ts +13 -6
- package/src/entry/orchestrator.ts +116 -33
- package/src/interactive/chat-loop-messages.ts +2 -2
- package/src/interactive/chat-loop.ts +219 -63
- package/src/interactive/chat-renderer.ts +99 -8
- package/src/interactive/context-overlay.ts +24 -3
- package/src/interactive/continuity-controller.ts +526 -0
- package/src/interactive/dispatch-board.ts +21 -3
- package/src/interactive/footer/dashboard.ts +25 -1
- package/src/interactive/footer/key-hints.ts +2 -2
- package/src/interactive/footer/pages.ts +70 -27
- package/src/interactive/footer/widgets.ts +32 -7
- package/src/interactive/footer-panel.ts +1 -1
- package/src/interactive/interactive-application.ts +7 -2
- package/src/interactive/interactive-input-runtime.ts +2 -2
- package/src/interactive/interactive-presentation.ts +15 -0
- package/src/interactive/interactive-slash-runtime.ts +45 -8
- package/src/interactive/interactive-tickers.ts +7 -1
- package/src/interactive/model-session-replay.ts +130 -3
- package/src/interactive/output-reserve.ts +35 -0
- package/src/interactive/overlay-general-openers.ts +12 -8
- package/src/interactive/overlay-key-routing.ts +6 -9
- package/src/interactive/overlay-lifecycle.ts +10 -6
- package/src/interactive/overlay-session-lifecycle.ts +21 -14
- package/src/interactive/quota-view.ts +229 -0
- package/src/interactive/session-last-turn.ts +1 -1
- package/src/interactive/session-transcript.ts +2 -1
- package/src/interactive/session-usage-reseed.ts +2 -2
- package/src/interactive/side-question.ts +2 -2
- package/src/interactive/slash-commands.ts +28 -9
- package/src/interactive/turn-context.ts +686 -63
- package/src/interactive/turn-middleware.ts +39 -6
- package/src/interactive/turn-persistence.ts +15 -2
- package/src/interactive/turn-prewarm.ts +1 -1
- package/src/interactive/turn-runtime.ts +48 -5
- package/src/interactive/{cost-overlay.ts → usage-overlay.ts} +121 -33
- package/src/interactive/welcome-dashboard.ts +26 -3
- package/src/tools/agent-tools.ts +3 -1
- package/src/tools/bootstrap.ts +6 -0
- package/src/tools/builtin-tool-catalog.ts +9 -0
- package/src/tools/context/index.ts +148 -113
- package/src/tools/context/surface.ts +11 -7
- package/src/tools/core-bootstrap.ts +4 -0
- package/src/tools/observation.ts +8 -2
- package/src/tools/policy.ts +3 -0
- package/src/tools/self-compact.ts +31 -0
- package/src/tools/surface.ts +1 -0
- package/src/tools/tasks.ts +1 -1
- package/dist/chunk-CTFPFW3H.js +0 -44
- package/dist/chunk-EOJPDNUP.js +0 -1325
- package/dist/chunk-I4Y4WKZR.js +0 -386
|
@@ -11,7 +11,7 @@ import {
|
|
|
11
11
|
parseEditorBashCommand,
|
|
12
12
|
unguardPastedEditorOperator,
|
|
13
13
|
writeInputWedgeDump
|
|
14
|
-
} from "./chunk-
|
|
14
|
+
} from "./chunk-O3ZAF7UY.js";
|
|
15
15
|
import {
|
|
16
16
|
OperatorExtensionRuntime
|
|
17
17
|
} from "./chunk-C7AQTPCE.js";
|
|
@@ -39,7 +39,10 @@ import {
|
|
|
39
39
|
clockLocal,
|
|
40
40
|
compactReasoningTokens,
|
|
41
41
|
contextCategorySwatch,
|
|
42
|
+
contextOccupancyBar,
|
|
42
43
|
contextQuadrant,
|
|
44
|
+
contextUsageText,
|
|
45
|
+
continuityContextFromSession,
|
|
43
46
|
createAssistantGenerationTiming,
|
|
44
47
|
createCoalescingChatRenderer,
|
|
45
48
|
createDefaultArtifactProviders,
|
|
@@ -68,6 +71,7 @@ import {
|
|
|
68
71
|
isDispatchBoardRowSteerable,
|
|
69
72
|
listRecentModels,
|
|
70
73
|
listViewArtifacts,
|
|
74
|
+
localQuotaSnapshot,
|
|
71
75
|
loopBlockedAuditReason,
|
|
72
76
|
loopBlockedStopReason,
|
|
73
77
|
mergeHandoffDecisions,
|
|
@@ -83,23 +87,27 @@ import {
|
|
|
83
87
|
previewBudget,
|
|
84
88
|
previewRows,
|
|
85
89
|
providerErrorEvidence,
|
|
90
|
+
quotaMeter,
|
|
91
|
+
quotaSummaryLine,
|
|
86
92
|
readWorkerReceiptFacts,
|
|
87
93
|
reasoningFromTally,
|
|
88
94
|
rehydrateChatPanelFromTurns,
|
|
89
95
|
relative,
|
|
90
96
|
renderBashTranscriptExecution,
|
|
91
|
-
renderContextMeterBar,
|
|
92
97
|
renderContextMeterGrid,
|
|
93
98
|
renderDispatchActivity,
|
|
94
99
|
renderEvictedTokensLine,
|
|
95
100
|
renderHandoffDocument,
|
|
101
|
+
renderQuotaAccounts,
|
|
96
102
|
renderRetryStatus,
|
|
97
103
|
renderToolArguments,
|
|
98
104
|
renderToolAwaitingApproval,
|
|
99
105
|
renderToolExecution,
|
|
100
106
|
renderToolPreview,
|
|
107
|
+
renderWorkerUsage,
|
|
101
108
|
resolveFooterVerb,
|
|
102
109
|
restartRequiredNotice,
|
|
110
|
+
routeWeeklyQuota,
|
|
103
111
|
safeWorkerAnswerText,
|
|
104
112
|
safetyBlockedNotice,
|
|
105
113
|
sessionQuadrant,
|
|
@@ -114,18 +122,19 @@ import {
|
|
|
114
122
|
validateHandoffFiles,
|
|
115
123
|
validateHandoffGoal,
|
|
116
124
|
verifyReceiptFileReport,
|
|
125
|
+
withContinuityReplay,
|
|
117
126
|
workerEscalationNotice,
|
|
118
127
|
workerRunEntryFields,
|
|
119
128
|
workspaceQuadrant,
|
|
120
129
|
zipColumnBlocks,
|
|
121
130
|
zipColumns
|
|
122
|
-
} from "./chunk-
|
|
123
|
-
import "./chunk-
|
|
131
|
+
} from "./chunk-M5PMRZSR.js";
|
|
132
|
+
import "./chunk-Z74OGONW.js";
|
|
124
133
|
import {
|
|
125
134
|
extractText,
|
|
126
135
|
isSelfExplainingAbort
|
|
127
|
-
} from "./chunk-
|
|
128
|
-
import "./chunk-
|
|
136
|
+
} from "./chunk-36XVK5P5.js";
|
|
137
|
+
import "./chunk-GIAI7A2K.js";
|
|
129
138
|
import {
|
|
130
139
|
CLIO_APP_KEYBINDINGS,
|
|
131
140
|
CLIO_APP_KEYBINDING_IDS,
|
|
@@ -181,7 +190,7 @@ import {
|
|
|
181
190
|
planLibraryImport,
|
|
182
191
|
releaseLibraryImport,
|
|
183
192
|
renderProposalEntry
|
|
184
|
-
} from "./chunk-
|
|
193
|
+
} from "./chunk-EBMTBE76.js";
|
|
185
194
|
import {
|
|
186
195
|
detectInteropAgents
|
|
187
196
|
} from "./chunk-4A6YRGV4.js";
|
|
@@ -199,23 +208,23 @@ import {
|
|
|
199
208
|
parseSlashCommand,
|
|
200
209
|
renderArgsSpec,
|
|
201
210
|
workerAskedByModel
|
|
202
|
-
} from "./chunk-
|
|
211
|
+
} from "./chunk-XBIGUILU.js";
|
|
203
212
|
import "./chunk-DGC6X6XR.js";
|
|
204
213
|
import {
|
|
205
214
|
resolveExtensionCommands
|
|
206
215
|
} from "./chunk-RFCKPS2V.js";
|
|
207
216
|
import "./chunk-QUIJZSDW.js";
|
|
208
|
-
import "./chunk-
|
|
209
|
-
import "./chunk-
|
|
217
|
+
import "./chunk-TPCZXWLT.js";
|
|
218
|
+
import "./chunk-TL6LNERH.js";
|
|
210
219
|
import "./chunk-GGPF6LLE.js";
|
|
211
220
|
import {
|
|
212
221
|
formatUserTaskHandoff
|
|
213
|
-
} from "./chunk-
|
|
214
|
-
import "./chunk-
|
|
222
|
+
} from "./chunk-JRW236JT.js";
|
|
223
|
+
import "./chunk-G62JBPXN.js";
|
|
215
224
|
import {
|
|
216
225
|
appendOutOfTurnUsageRow
|
|
217
|
-
} from "./chunk-
|
|
218
|
-
import "./chunk-
|
|
226
|
+
} from "./chunk-AA3GRZWS.js";
|
|
227
|
+
import "./chunk-T7HZ7KJF.js";
|
|
219
228
|
import {
|
|
220
229
|
SETTINGS_DESCRIPTIONS_BY_ID,
|
|
221
230
|
SETTINGS_HELP_BY_ID,
|
|
@@ -233,10 +242,10 @@ import {
|
|
|
233
242
|
recallErrorMessage,
|
|
234
243
|
recallParentTurnId,
|
|
235
244
|
resolveRecall
|
|
236
|
-
} from "./chunk-
|
|
245
|
+
} from "./chunk-OX6QTA4N.js";
|
|
237
246
|
import {
|
|
238
247
|
foldWorkingSet
|
|
239
|
-
} from "./chunk-
|
|
248
|
+
} from "./chunk-GUFQPTQK.js";
|
|
240
249
|
import {
|
|
241
250
|
getAtPath,
|
|
242
251
|
isRoutingPath,
|
|
@@ -248,7 +257,7 @@ import {
|
|
|
248
257
|
settingsGroupForPath,
|
|
249
258
|
settingsSectionForPath
|
|
250
259
|
} from "./chunk-LJRBX7QR.js";
|
|
251
|
-
import "./chunk-
|
|
260
|
+
import "./chunk-U3FETNQB.js";
|
|
252
261
|
import "./chunk-Y3JU5RPK.js";
|
|
253
262
|
import {
|
|
254
263
|
CombinedAutocompleteProvider,
|
|
@@ -287,20 +296,20 @@ import {
|
|
|
287
296
|
loadMemoryRecordsSync,
|
|
288
297
|
proposeMemoryPromotion,
|
|
289
298
|
renderCostAggregate
|
|
290
|
-
} from "./chunk-
|
|
299
|
+
} from "./chunk-EQPFEDFV.js";
|
|
291
300
|
import "./chunk-PECBKCDK.js";
|
|
292
|
-
import "./chunk-
|
|
293
|
-
import "./chunk-
|
|
301
|
+
import "./chunk-KQMYL5GR.js";
|
|
302
|
+
import "./chunk-ZTNOEJRI.js";
|
|
294
303
|
import {
|
|
295
304
|
preflightWriteBoundaries
|
|
296
|
-
} from "./chunk-
|
|
305
|
+
} from "./chunk-7WUGNN43.js";
|
|
297
306
|
import {
|
|
298
307
|
bindExecutionPlanEndpoints,
|
|
299
308
|
compileFleetExecutionPlan
|
|
300
|
-
} from "./chunk-
|
|
309
|
+
} from "./chunk-LZMTVVN4.js";
|
|
301
310
|
import {
|
|
302
311
|
trustStateWord
|
|
303
|
-
} from "./chunk-
|
|
312
|
+
} from "./chunk-EEITU7S6.js";
|
|
304
313
|
import {
|
|
305
314
|
addResponseModelIdObservationCount,
|
|
306
315
|
addResponseModelIdObservationCounts,
|
|
@@ -309,12 +318,12 @@ import {
|
|
|
309
318
|
ledgerUsageCalls,
|
|
310
319
|
responseModelIdObservationCountsLabel,
|
|
311
320
|
responseModelIdObservationFromRecord
|
|
312
|
-
} from "./chunk-
|
|
321
|
+
} from "./chunk-GPTR6OTU.js";
|
|
313
322
|
import "./chunk-BOBCCDJ6.js";
|
|
314
323
|
import {
|
|
315
324
|
describeLocalCapacity
|
|
316
325
|
} from "./chunk-E6IPKW2E.js";
|
|
317
|
-
import "./chunk-
|
|
326
|
+
import "./chunk-N3CWOGVF.js";
|
|
318
327
|
import "./chunk-UQIVHSE4.js";
|
|
319
328
|
import "./chunk-BYFHHCFV.js";
|
|
320
329
|
import {
|
|
@@ -325,7 +334,7 @@ import "./chunk-LQTKDAUO.js";
|
|
|
325
334
|
import "./chunk-ZU4JPCPR.js";
|
|
326
335
|
import {
|
|
327
336
|
foldDecisionBoard
|
|
328
|
-
} from "./chunk-
|
|
337
|
+
} from "./chunk-XYPWFSU5.js";
|
|
329
338
|
import {
|
|
330
339
|
emptyWorkspaceSnapshot,
|
|
331
340
|
probeGitStatusAsync,
|
|
@@ -334,9 +343,9 @@ import {
|
|
|
334
343
|
import {
|
|
335
344
|
filterEntriesToActivePath
|
|
336
345
|
} from "./chunk-O5F25NIE.js";
|
|
337
|
-
import "./chunk-
|
|
346
|
+
import "./chunk-Q4RMNWMZ.js";
|
|
338
347
|
import "./chunk-SD7SHNDW.js";
|
|
339
|
-
import "./chunk-
|
|
348
|
+
import "./chunk-Q2HKY32Y.js";
|
|
340
349
|
import "./chunk-YQ3GFEUY.js";
|
|
341
350
|
import "./chunk-WTQGRBHV.js";
|
|
342
351
|
import "./chunk-GLIQT7SU.js";
|
|
@@ -351,23 +360,23 @@ import {
|
|
|
351
360
|
} from "./chunk-XISLDHEL.js";
|
|
352
361
|
import {
|
|
353
362
|
collectSessionEntries
|
|
354
|
-
} from "./chunk-
|
|
363
|
+
} from "./chunk-CNXU7TR2.js";
|
|
355
364
|
import {
|
|
356
365
|
applyLibraryLifecycle,
|
|
357
366
|
libraryImportOutcome,
|
|
358
367
|
planLibraryLifecycle,
|
|
359
368
|
releaseLibraryLifecycle,
|
|
360
369
|
retryLibraryRefresh
|
|
361
|
-
} from "./chunk-
|
|
370
|
+
} from "./chunk-7LUEQODV.js";
|
|
362
371
|
import {
|
|
363
372
|
inspectLibraryCopy,
|
|
364
373
|
readLibraryInventory
|
|
365
|
-
} from "./chunk-
|
|
366
|
-
import "./chunk-
|
|
367
|
-
import "./chunk-
|
|
374
|
+
} from "./chunk-6KV4KCQZ.js";
|
|
375
|
+
import "./chunk-G5ZDQQE3.js";
|
|
376
|
+
import "./chunk-AI36V3ON.js";
|
|
368
377
|
import {
|
|
369
378
|
installSkill
|
|
370
|
-
} from "./chunk-
|
|
379
|
+
} from "./chunk-B5TASTCK.js";
|
|
371
380
|
import "./chunk-DNCE23JJ.js";
|
|
372
381
|
import "./chunk-CDQ2UC6W.js";
|
|
373
382
|
import {
|
|
@@ -381,11 +390,11 @@ import {
|
|
|
381
390
|
validateFleetGraph
|
|
382
391
|
} from "./chunk-5LP5FNNR.js";
|
|
383
392
|
import "./chunk-NVPXXW2H.js";
|
|
384
|
-
import "./chunk-
|
|
385
|
-
import "./chunk-
|
|
393
|
+
import "./chunk-LXYHCCIZ.js";
|
|
394
|
+
import "./chunk-QOJ4ERMU.js";
|
|
386
395
|
import {
|
|
387
396
|
retiredIntegrityVersionOf
|
|
388
|
-
} from "./chunk-
|
|
397
|
+
} from "./chunk-UZ7YBL43.js";
|
|
389
398
|
import {
|
|
390
399
|
askAxis,
|
|
391
400
|
askUserExposure,
|
|
@@ -396,14 +405,14 @@ import {
|
|
|
396
405
|
decisionFactsForAnswer,
|
|
397
406
|
openDetachedBatchViews,
|
|
398
407
|
runBashCommand
|
|
399
|
-
} from "./chunk-
|
|
408
|
+
} from "./chunk-PF36KOGI.js";
|
|
400
409
|
import {
|
|
401
410
|
foldSessionTaskHistory,
|
|
402
411
|
foldTaskBoard,
|
|
403
412
|
taskBoardCounts
|
|
404
|
-
} from "./chunk-
|
|
413
|
+
} from "./chunk-7DW7CJW2.js";
|
|
405
414
|
import "./chunk-7QXCO3AF.js";
|
|
406
|
-
import "./chunk-
|
|
415
|
+
import "./chunk-SAASVMIY.js";
|
|
407
416
|
import "./chunk-OH3YYA3B.js";
|
|
408
417
|
import {
|
|
409
418
|
extensionPanelText
|
|
@@ -416,31 +425,32 @@ import {
|
|
|
416
425
|
sanitizeCallTargetText,
|
|
417
426
|
sanitizeMultilineDisplayText
|
|
418
427
|
} from "./chunk-XNIZBOFV.js";
|
|
419
|
-
import "./chunk-
|
|
428
|
+
import "./chunk-5APYAXCB.js";
|
|
420
429
|
import {
|
|
421
430
|
agentRoleFactsResolver,
|
|
422
431
|
requestExecutionRole,
|
|
423
432
|
withAttemptRole
|
|
424
|
-
} from "./chunk-
|
|
425
|
-
import "./chunk-
|
|
433
|
+
} from "./chunk-SZUO5BSE.js";
|
|
434
|
+
import "./chunk-PGQG7ZMW.js";
|
|
426
435
|
import "./chunk-L4N3DWNW.js";
|
|
427
|
-
import "./chunk-
|
|
428
|
-
import "./chunk-
|
|
429
|
-
import "./chunk-
|
|
436
|
+
import "./chunk-F4I3H56H.js";
|
|
437
|
+
import "./chunk-Q6FRR3AQ.js";
|
|
438
|
+
import "./chunk-KKAJGT3B.js";
|
|
439
|
+
import "./chunk-H7REJ7L5.js";
|
|
430
440
|
import "./chunk-YYLCPDCC.js";
|
|
431
441
|
import {
|
|
432
442
|
redactSecretString
|
|
433
443
|
} from "./chunk-EFSEIZE6.js";
|
|
434
|
-
import "./chunk-
|
|
444
|
+
import "./chunk-4XBYHXGK.js";
|
|
435
445
|
import {
|
|
436
446
|
expandInlineFileReferencesAsync
|
|
437
|
-
} from "./chunk-
|
|
438
|
-
import "./chunk-
|
|
439
|
-
import "./chunk-
|
|
440
|
-
import "./chunk-
|
|
447
|
+
} from "./chunk-YEJQDODA.js";
|
|
448
|
+
import "./chunk-4KC4CHKJ.js";
|
|
449
|
+
import "./chunk-MNABNEBX.js";
|
|
450
|
+
import "./chunk-FLNXQQ5B.js";
|
|
441
451
|
import "./chunk-DZLR4UEH.js";
|
|
442
|
-
import "./chunk-
|
|
443
|
-
import "./chunk-
|
|
452
|
+
import "./chunk-H6FQVNZC.js";
|
|
453
|
+
import "./chunk-E74MJF6G.js";
|
|
444
454
|
import "./chunk-GHXGMFQ5.js";
|
|
445
455
|
import "./chunk-KECNXMDE.js";
|
|
446
456
|
import "./chunk-WXA2CFJO.js";
|
|
@@ -456,7 +466,7 @@ import {
|
|
|
456
466
|
resolveRuntimeTarget,
|
|
457
467
|
thinkingLevelChoiceLabel,
|
|
458
468
|
thinkingLevelFromChoiceLabel
|
|
459
|
-
} from "./chunk-
|
|
469
|
+
} from "./chunk-HTWTORF7.js";
|
|
460
470
|
import "./chunk-MCJKEGHO.js";
|
|
461
471
|
import "./chunk-DVTBERFY.js";
|
|
462
472
|
import {
|
|
@@ -472,7 +482,7 @@ import {
|
|
|
472
482
|
ceilChars,
|
|
473
483
|
contentChars,
|
|
474
484
|
extractReasoningTokens
|
|
475
|
-
} from "./chunk-
|
|
485
|
+
} from "./chunk-53P775GE.js";
|
|
476
486
|
import {
|
|
477
487
|
formatContextWindowSlots
|
|
478
488
|
} from "./chunk-77DCC6JZ.js";
|
|
@@ -480,6 +490,7 @@ import {
|
|
|
480
490
|
resolveProviderReference
|
|
481
491
|
} from "./chunk-SYF7FVBL.js";
|
|
482
492
|
import {
|
|
493
|
+
openAuthStorage,
|
|
483
494
|
targetRequiresAuth
|
|
484
495
|
} from "./chunk-Z4GLJ6J4.js";
|
|
485
496
|
import "./chunk-VNBICSS2.js";
|
|
@@ -494,25 +505,26 @@ import "./chunk-L7G7K4I2.js";
|
|
|
494
505
|
import "./chunk-ALJWT6O6.js";
|
|
495
506
|
import "./chunk-4WV4PI66.js";
|
|
496
507
|
import "./chunk-HMN2C6YL.js";
|
|
508
|
+
import "./chunk-F6KCJO3U.js";
|
|
509
|
+
import "./chunk-UZVYEF57.js";
|
|
497
510
|
import {
|
|
498
511
|
SKILL_SUGGESTION_PREFIX
|
|
499
|
-
} from "./chunk-
|
|
500
|
-
import "./chunk-UZVYEF57.js";
|
|
512
|
+
} from "./chunk-MMZMM6SW.js";
|
|
501
513
|
import "./chunk-O3VV6IVK.js";
|
|
502
514
|
import {
|
|
503
515
|
openSession,
|
|
504
516
|
sessionPaths
|
|
505
|
-
} from "./chunk-
|
|
517
|
+
} from "./chunk-PZBQUJ2F.js";
|
|
506
518
|
import "./chunk-UHW5V7HC.js";
|
|
507
519
|
import {
|
|
508
520
|
isUserVisibleAgent
|
|
509
|
-
} from "./chunk-
|
|
521
|
+
} from "./chunk-7UFDIOBT.js";
|
|
510
522
|
import "./chunk-BJH6WFIB.js";
|
|
511
523
|
import {
|
|
512
524
|
interopAgentKind
|
|
513
525
|
} from "./chunk-5EQO5NWP.js";
|
|
514
|
-
import "./chunk-
|
|
515
|
-
import "./chunk-
|
|
526
|
+
import "./chunk-NMQSO6Z6.js";
|
|
527
|
+
import "./chunk-OYUS3UZP.js";
|
|
516
528
|
import "./chunk-R2P2U3ZS.js";
|
|
517
529
|
import "./chunk-NTTS3O53.js";
|
|
518
530
|
import "./chunk-C2CPOIH2.js";
|
|
@@ -520,7 +532,7 @@ import "./chunk-MGLRTOCK.js";
|
|
|
520
532
|
import "./chunk-M4KFUXS7.js";
|
|
521
533
|
import {
|
|
522
534
|
ToolNames
|
|
523
|
-
} from "./chunk-
|
|
535
|
+
} from "./chunk-6UKFRTXI.js";
|
|
524
536
|
import {
|
|
525
537
|
SettingsValidationError,
|
|
526
538
|
bindAgentProfileInSettings,
|
|
@@ -3113,12 +3125,32 @@ function renderContextLedgerLines(ledger, contentWidth, workingSet, workingSetCo
|
|
|
3113
3125
|
var STREAMING_FALLBACK_TICK_MS = 1e3;
|
|
3114
3126
|
function openContextOverlay(tui, getLedger, options) {
|
|
3115
3127
|
let contentWidth = DEFAULT_CONTENT_WIDTH;
|
|
3116
|
-
const render2 = () =>
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3128
|
+
const render2 = () => {
|
|
3129
|
+
const lines = renderContextLedgerLines(
|
|
3130
|
+
getLedger(),
|
|
3131
|
+
contentWidth,
|
|
3132
|
+
options?.getWorkingSet?.() ?? null,
|
|
3133
|
+
options?.getWorkingSetConfig?.() ?? null
|
|
3134
|
+
);
|
|
3135
|
+
const inspection = options?.chat?.inspectLiveBudget?.();
|
|
3136
|
+
if (inspection?.status === "available") {
|
|
3137
|
+
const view = inspection.view;
|
|
3138
|
+
const count = (value) => value === null ? "unknown" : formatTokens(value);
|
|
3139
|
+
lines.push(
|
|
3140
|
+
"",
|
|
3141
|
+
`Next request: ${count(view.inputTokens)} input + ${count(view.outputReserveTokens)} output`,
|
|
3142
|
+
`Headroom: ${count(view.headroomTokens)} \xB7 ${view.phase}`
|
|
3143
|
+
);
|
|
3144
|
+
if (view.pendingHandoff) {
|
|
3145
|
+
lines.push(
|
|
3146
|
+
`Handoff: ${view.lastOutcome?.outcome ?? "pending"}`,
|
|
3147
|
+
view.pendingHandoff.id,
|
|
3148
|
+
`/context recover ${view.pendingHandoff.id} reduce|deliver`
|
|
3149
|
+
);
|
|
3150
|
+
} else if (view.lastOutcome) lines.push(`Last handoff: ${view.lastOutcome.outcome}`);
|
|
3151
|
+
}
|
|
3152
|
+
return lines.join("\n");
|
|
3153
|
+
};
|
|
3122
3154
|
const text = new Text(render2(), 0, 0);
|
|
3123
3155
|
const body = {
|
|
3124
3156
|
render(width) {
|
|
@@ -3188,273 +3220,6 @@ function openContextOverlay(tui, getLedger, options) {
|
|
|
3188
3220
|
};
|
|
3189
3221
|
}
|
|
3190
3222
|
|
|
3191
|
-
// src/interactive/cost-overlay.ts
|
|
3192
|
-
init_esm_shims();
|
|
3193
|
-
var DEFAULT_CONTENT_WIDTH2 = 80;
|
|
3194
|
-
var COST_OVERLAY_WIDTH = DEFAULT_CONTENT_WIDTH2 + 4;
|
|
3195
|
-
function formatTokens2(n) {
|
|
3196
|
-
return n.toLocaleString("en-US");
|
|
3197
|
-
}
|
|
3198
|
-
function aggregateCostEntries(entries) {
|
|
3199
|
-
const grouped = /* @__PURE__ */ new Map();
|
|
3200
|
-
for (const entry of entries) {
|
|
3201
|
-
const key = `${entry.providerId}::${entry.attributedModelId}`;
|
|
3202
|
-
const existing = grouped.get(key);
|
|
3203
|
-
if (existing) {
|
|
3204
|
-
existing.row.runs += 1;
|
|
3205
|
-
existing.row.tokens += entry.tokens;
|
|
3206
|
-
existing.row.input += entry.input;
|
|
3207
|
-
existing.row.output += entry.output;
|
|
3208
|
-
existing.row.cacheRead += entry.cacheRead;
|
|
3209
|
-
existing.row.cacheWrite += entry.cacheWrite;
|
|
3210
|
-
existing.row.reasoningTokens += entry.reasoningTokens;
|
|
3211
|
-
existing.row.apiCalls += entry.apiCalls ?? 1;
|
|
3212
|
-
if (entry.label === "side-question") existing.row.sideQuestions += 1;
|
|
3213
|
-
if (entry.label === "handoff") existing.row.handoffs += 1;
|
|
3214
|
-
if (entry.label === "prewarm") existing.row.prewarms += 1;
|
|
3215
|
-
if (entry.label === "background-memory") existing.row.backgroundMemory += 1;
|
|
3216
|
-
if (entry.label === "failed-compaction") existing.row.failedCompaction += 1;
|
|
3217
|
-
for (const requestedModelId of entry.requestedModelIds) existing.requestedModelIds.add(requestedModelId);
|
|
3218
|
-
addResponseModelIdObservationCounts(
|
|
3219
|
-
existing.responseModelIdObservationCounts,
|
|
3220
|
-
entry.responseModelIdObservationCounts
|
|
3221
|
-
);
|
|
3222
|
-
existing.entries.push(entry);
|
|
3223
|
-
continue;
|
|
3224
|
-
}
|
|
3225
|
-
grouped.set(key, {
|
|
3226
|
-
row: {
|
|
3227
|
-
providerId: entry.providerId,
|
|
3228
|
-
attributedModelId: entry.attributedModelId,
|
|
3229
|
-
runs: 1,
|
|
3230
|
-
tokens: entry.tokens,
|
|
3231
|
-
input: entry.input,
|
|
3232
|
-
output: entry.output,
|
|
3233
|
-
cacheRead: entry.cacheRead,
|
|
3234
|
-
cacheWrite: entry.cacheWrite,
|
|
3235
|
-
reasoningTokens: entry.reasoningTokens,
|
|
3236
|
-
apiCalls: entry.apiCalls ?? 1,
|
|
3237
|
-
sideQuestions: entry.label === "side-question" ? 1 : 0,
|
|
3238
|
-
handoffs: entry.label === "handoff" ? 1 : 0,
|
|
3239
|
-
prewarms: entry.label === "prewarm" ? 1 : 0,
|
|
3240
|
-
backgroundMemory: entry.label === "background-memory" ? 1 : 0,
|
|
3241
|
-
failedCompaction: entry.label === "failed-compaction" ? 1 : 0
|
|
3242
|
-
},
|
|
3243
|
-
requestedModelIds: new Set(entry.requestedModelIds),
|
|
3244
|
-
responseModelIdObservationCounts: { ...entry.responseModelIdObservationCounts },
|
|
3245
|
-
entries: [entry]
|
|
3246
|
-
});
|
|
3247
|
-
}
|
|
3248
|
-
const rows = Array.from(grouped.values(), ({ row: row2, entries: entries2, requestedModelIds, responseModelIdObservationCounts }) => ({
|
|
3249
|
-
...row2,
|
|
3250
|
-
requestedModelIds: [...requestedModelIds].sort(),
|
|
3251
|
-
responseModelIdObservationCounts,
|
|
3252
|
-
cost: aggregateCostAmounts(entries2.map((entry) => ({ usd: entry.usd, provenance: entry.provenance })))
|
|
3253
|
-
}));
|
|
3254
|
-
rows.sort((a, b) => {
|
|
3255
|
-
if (a.providerId !== b.providerId) return a.providerId < b.providerId ? -1 : 1;
|
|
3256
|
-
if (a.attributedModelId !== b.attributedModelId) return a.attributedModelId < b.attributedModelId ? -1 : 1;
|
|
3257
|
-
return 0;
|
|
3258
|
-
});
|
|
3259
|
-
return rows;
|
|
3260
|
-
}
|
|
3261
|
-
function sumRows(rows) {
|
|
3262
|
-
return rows.reduce(
|
|
3263
|
-
(acc, row2) => ({
|
|
3264
|
-
runs: acc.runs + row2.runs,
|
|
3265
|
-
tokens: acc.tokens + row2.tokens,
|
|
3266
|
-
input: acc.input + row2.input,
|
|
3267
|
-
output: acc.output + row2.output,
|
|
3268
|
-
cacheRead: acc.cacheRead + row2.cacheRead,
|
|
3269
|
-
cacheWrite: acc.cacheWrite + row2.cacheWrite,
|
|
3270
|
-
reasoningTokens: acc.reasoningTokens + row2.reasoningTokens,
|
|
3271
|
-
apiCalls: acc.apiCalls + row2.apiCalls,
|
|
3272
|
-
sideQuestions: acc.sideQuestions + row2.sideQuestions,
|
|
3273
|
-
handoffs: acc.handoffs + row2.handoffs,
|
|
3274
|
-
prewarms: acc.prewarms + row2.prewarms,
|
|
3275
|
-
backgroundMemory: acc.backgroundMemory + row2.backgroundMemory,
|
|
3276
|
-
failedCompaction: acc.failedCompaction + row2.failedCompaction
|
|
3277
|
-
}),
|
|
3278
|
-
{
|
|
3279
|
-
runs: 0,
|
|
3280
|
-
tokens: 0,
|
|
3281
|
-
input: 0,
|
|
3282
|
-
output: 0,
|
|
3283
|
-
cacheRead: 0,
|
|
3284
|
-
cacheWrite: 0,
|
|
3285
|
-
reasoningTokens: 0,
|
|
3286
|
-
apiCalls: 0,
|
|
3287
|
-
sideQuestions: 0,
|
|
3288
|
-
handoffs: 0,
|
|
3289
|
-
prewarms: 0,
|
|
3290
|
-
backgroundMemory: 0,
|
|
3291
|
-
failedCompaction: 0
|
|
3292
|
-
}
|
|
3293
|
-
);
|
|
3294
|
-
}
|
|
3295
|
-
function cacheReadValue(cacheRead, apiCalls) {
|
|
3296
|
-
if (apiCalls > 1 && cacheRead > 0) {
|
|
3297
|
-
return [formatTokens2(cacheRead), `(avg/call ${formatTokens2(Math.round(cacheRead / apiCalls))})`];
|
|
3298
|
-
}
|
|
3299
|
-
return [formatTokens2(cacheRead)];
|
|
3300
|
-
}
|
|
3301
|
-
function reasoningValue(reasoningTokens) {
|
|
3302
|
-
return [formatTokens2(reasoningTokens), "provider-reported only"];
|
|
3303
|
-
}
|
|
3304
|
-
function kvBlock(entries) {
|
|
3305
|
-
const theme2 = clioTheme();
|
|
3306
|
-
const keyWidth = entries.reduce((max, [key]) => Math.max(max, key.length), 0);
|
|
3307
|
-
const valueWidth = entries.reduce((max, [, value]) => Math.max(max, value.length), 0);
|
|
3308
|
-
return entries.map(([key, value, annotation]) => {
|
|
3309
|
-
const row2 = `${theme2.fg("dim", key.padEnd(keyWidth))} ${theme2.fg("muted", value.padStart(valueWidth))}`;
|
|
3310
|
-
return annotation ? `${row2} ${theme2.fg("dim", annotation)}` : row2;
|
|
3311
|
-
});
|
|
3312
|
-
}
|
|
3313
|
-
function summaryBlock(totalCost, totalTokens, rows, promptCache) {
|
|
3314
|
-
const totals = sumRows(rows);
|
|
3315
|
-
const resolvedTotal = totalTokens > 0 ? totalTokens : totals.tokens;
|
|
3316
|
-
const cost = formatCostAggregate(totalCost);
|
|
3317
|
-
const cacheRows = promptCache !== null && hasPromptCacheTelemetry(promptCache) ? [
|
|
3318
|
-
[
|
|
3319
|
-
"uncached prefill",
|
|
3320
|
-
promptCache.uncachedPrefillTokens === null ? "not reported" : formatTokens2(promptCache.uncachedPrefillTokens)
|
|
3321
|
-
],
|
|
3322
|
-
[
|
|
3323
|
-
"cache verdicts",
|
|
3324
|
-
`hot ${promptCache.verdictCounts.hot} \xB7 partial ${promptCache.verdictCounts.partial} \xB7 cold ${promptCache.verdictCounts.cold} \xB7 small ${promptCache.verdictCounts.small} \xB7 unknown ${promptCache.verdictCounts.unknown}`
|
|
3325
|
-
]
|
|
3326
|
-
] : [];
|
|
3327
|
-
return kvBlock([
|
|
3328
|
-
[
|
|
3329
|
-
"turns",
|
|
3330
|
-
formatTokens2(
|
|
3331
|
-
totals.runs - totals.sideQuestions - totals.handoffs - totals.prewarms - totals.backgroundMemory - totals.failedCompaction
|
|
3332
|
-
)
|
|
3333
|
-
],
|
|
3334
|
-
["model calls", formatTokens2(totals.apiCalls)],
|
|
3335
|
-
...totals.sideQuestions > 0 ? [["side questions", formatTokens2(totals.sideQuestions)]] : [],
|
|
3336
|
-
...totals.handoffs > 0 ? [["handoffs", formatTokens2(totals.handoffs)]] : [],
|
|
3337
|
-
...totals.prewarms > 0 ? [["pre-warms", formatTokens2(totals.prewarms)]] : [],
|
|
3338
|
-
...totals.backgroundMemory > 0 ? [["memory steps", formatTokens2(totals.backgroundMemory)]] : [],
|
|
3339
|
-
...totals.failedCompaction > 0 ? [
|
|
3340
|
-
["failed compaction calls", formatTokens2(totals.failedCompaction)],
|
|
3341
|
-
["compaction usage", "known subtotals; missing usage is unknown"]
|
|
3342
|
-
] : [],
|
|
3343
|
-
...cost === null ? [] : [["cost", cost]],
|
|
3344
|
-
["input", formatTokens2(totals.input)],
|
|
3345
|
-
["output", formatTokens2(totals.output)],
|
|
3346
|
-
["reasoning", ...reasoningValue(totals.reasoningTokens)],
|
|
3347
|
-
["cache read", ...cacheReadValue(totals.cacheRead, totals.apiCalls)],
|
|
3348
|
-
["cache write", formatTokens2(totals.cacheWrite)],
|
|
3349
|
-
...cacheRows,
|
|
3350
|
-
["processed", `${formatTokens2(resolvedTotal)} tokens`]
|
|
3351
|
-
]);
|
|
3352
|
-
}
|
|
3353
|
-
function modelBlock(row2) {
|
|
3354
|
-
const cost = formatCostAggregate(row2.cost);
|
|
3355
|
-
return kvBlock([
|
|
3356
|
-
["requested model ids", row2.requestedModelIds.join(", ")],
|
|
3357
|
-
["response model id observation", responseModelIdObservationCountsLabel(row2.responseModelIdObservationCounts)],
|
|
3358
|
-
[
|
|
3359
|
-
"turns",
|
|
3360
|
-
formatTokens2(
|
|
3361
|
-
row2.runs - row2.sideQuestions - row2.handoffs - row2.prewarms - row2.backgroundMemory - row2.failedCompaction
|
|
3362
|
-
)
|
|
3363
|
-
],
|
|
3364
|
-
["model calls", formatTokens2(row2.apiCalls)],
|
|
3365
|
-
...row2.sideQuestions > 0 ? [["side questions", formatTokens2(row2.sideQuestions)]] : [],
|
|
3366
|
-
...row2.handoffs > 0 ? [["handoffs", formatTokens2(row2.handoffs)]] : [],
|
|
3367
|
-
...row2.prewarms > 0 ? [["pre-warms", formatTokens2(row2.prewarms)]] : [],
|
|
3368
|
-
...row2.backgroundMemory > 0 ? [["memory steps", formatTokens2(row2.backgroundMemory)]] : [],
|
|
3369
|
-
...row2.failedCompaction > 0 ? [["failed compaction calls", formatTokens2(row2.failedCompaction)]] : [],
|
|
3370
|
-
...cost === null ? [] : [["cost", cost]],
|
|
3371
|
-
["input", formatTokens2(row2.input)],
|
|
3372
|
-
["output", formatTokens2(row2.output)],
|
|
3373
|
-
["reasoning", ...reasoningValue(row2.reasoningTokens)],
|
|
3374
|
-
["cache read", ...cacheReadValue(row2.cacheRead, row2.apiCalls)],
|
|
3375
|
-
["cache write", formatTokens2(row2.cacheWrite)],
|
|
3376
|
-
["processed", `${formatTokens2(row2.tokens)} tokens`]
|
|
3377
|
-
]);
|
|
3378
|
-
}
|
|
3379
|
-
function formatCostOverlayBodyLines(totalCost, totalTokens, rows, contentWidth, promptCache = null) {
|
|
3380
|
-
const theme2 = clioTheme();
|
|
3381
|
-
const lines = [];
|
|
3382
|
-
for (const line of summaryBlock(totalCost, totalTokens, rows, promptCache)) {
|
|
3383
|
-
lines.push(line);
|
|
3384
|
-
}
|
|
3385
|
-
lines.push(rule(theme2, contentWidth));
|
|
3386
|
-
if (rows.length === 0) {
|
|
3387
|
-
lines.push(theme2.fg("muted", "no token usage recorded for this session"));
|
|
3388
|
-
} else {
|
|
3389
|
-
for (const [index, row2] of rows.entries()) {
|
|
3390
|
-
if (index > 0) lines.push("");
|
|
3391
|
-
lines.push(theme2.style("accent", `${row2.providerId} \xB7 attributed model ${row2.attributedModelId}`, { bold: true }));
|
|
3392
|
-
for (const line of modelBlock(row2)) {
|
|
3393
|
-
lines.push(line);
|
|
3394
|
-
}
|
|
3395
|
-
}
|
|
3396
|
-
}
|
|
3397
|
-
return lines;
|
|
3398
|
-
}
|
|
3399
|
-
function buildCostSnapshot(observability, sessionId, snapshot, getSessionEntries) {
|
|
3400
|
-
const entries = observability.costEntries();
|
|
3401
|
-
const rows = aggregateCostEntries(entries);
|
|
3402
|
-
const totalTokens = rows.reduce((sum, r) => sum + r.tokens, 0);
|
|
3403
|
-
return {
|
|
3404
|
-
sessionId,
|
|
3405
|
-
totalCost: snapshot?.session.cost ?? observability.sessionCostSummary(),
|
|
3406
|
-
totalTokens,
|
|
3407
|
-
rows,
|
|
3408
|
-
promptCache: getSessionEntries ? foldPromptCacheTelemetry(getSessionEntries()) : null
|
|
3409
|
-
};
|
|
3410
|
-
}
|
|
3411
|
-
var CostOverlayBody = class {
|
|
3412
|
-
constructor(getSnapshot) {
|
|
3413
|
-
this.getSnapshot = getSnapshot;
|
|
3414
|
-
}
|
|
3415
|
-
getSnapshot;
|
|
3416
|
-
render(width) {
|
|
3417
|
-
const contentWidth = Math.max(1, Math.floor(width));
|
|
3418
|
-
const snapshot = this.getSnapshot();
|
|
3419
|
-
return formatCostOverlayBodyLines(
|
|
3420
|
-
snapshot.totalCost,
|
|
3421
|
-
snapshot.totalTokens,
|
|
3422
|
-
snapshot.rows,
|
|
3423
|
-
contentWidth,
|
|
3424
|
-
snapshot.promptCache
|
|
3425
|
-
);
|
|
3426
|
-
}
|
|
3427
|
-
invalidate() {
|
|
3428
|
-
}
|
|
3429
|
-
};
|
|
3430
|
-
function openCostOverlay(tui, observability, options) {
|
|
3431
|
-
const sessionId = options?.sessionId ?? null;
|
|
3432
|
-
let latest = observability.snapshot();
|
|
3433
|
-
const body = new CostOverlayBody(
|
|
3434
|
-
() => buildCostSnapshot(observability, sessionId, latest, options?.getSessionEntries)
|
|
3435
|
-
);
|
|
3436
|
-
const handle = showClioOverlayFrame(tui, body, {
|
|
3437
|
-
anchor: "center",
|
|
3438
|
-
width: COST_OVERLAY_WIDTH,
|
|
3439
|
-
// Not derived from the title: that one carries the session id.
|
|
3440
|
-
markerId: "cost",
|
|
3441
|
-
title: sessionId && sessionId.length > 0 ? `Session usage (${sessionId})` : "Session usage",
|
|
3442
|
-
footerHint: buildHint([])
|
|
3443
|
-
});
|
|
3444
|
-
const unsubscribe = observability.subscribe((snapshot) => {
|
|
3445
|
-
latest = snapshot;
|
|
3446
|
-
body.invalidate();
|
|
3447
|
-
tui.requestRender();
|
|
3448
|
-
});
|
|
3449
|
-
return {
|
|
3450
|
-
...handle,
|
|
3451
|
-
hide() {
|
|
3452
|
-
unsubscribe();
|
|
3453
|
-
handle.hide();
|
|
3454
|
-
}
|
|
3455
|
-
};
|
|
3456
|
-
}
|
|
3457
|
-
|
|
3458
3223
|
// src/interactive/fleet-run-preview.ts
|
|
3459
3224
|
init_esm_shims();
|
|
3460
3225
|
function defaultLoad(workspaceRoot, name) {
|
|
@@ -4338,9 +4103,9 @@ function openListOverlay(tui, options) {
|
|
|
4338
4103
|
}
|
|
4339
4104
|
|
|
4340
4105
|
// src/interactive/memory-overlay.ts
|
|
4341
|
-
var
|
|
4106
|
+
var DEFAULT_CONTENT_WIDTH2 = 96;
|
|
4342
4107
|
var REFRESH_MS = 1e3;
|
|
4343
|
-
var MEMORY_OVERLAY_WIDTH =
|
|
4108
|
+
var MEMORY_OVERLAY_WIDTH = DEFAULT_CONTENT_WIDTH2 + 4;
|
|
4344
4109
|
var EMPTY_MESSAGE = "no approved lessons, task-bank entries, or memory steps captured yet.";
|
|
4345
4110
|
function formatMemoryStatusLine(status, contentWidth) {
|
|
4346
4111
|
const theme2 = clioTheme();
|
|
@@ -4707,8 +4472,8 @@ function openContextResetOverlay(tui, deps) {
|
|
|
4707
4472
|
|
|
4708
4473
|
// src/interactive/overlays/decisions.ts
|
|
4709
4474
|
init_esm_shims();
|
|
4710
|
-
var
|
|
4711
|
-
var DECISIONS_OVERLAY_WIDTH =
|
|
4475
|
+
var DEFAULT_CONTENT_WIDTH3 = 88;
|
|
4476
|
+
var DECISIONS_OVERLAY_WIDTH = DEFAULT_CONTENT_WIDTH3 + 4;
|
|
4712
4477
|
function formatDecisionCorrectionTurn(selection, correction) {
|
|
4713
4478
|
return `Decision "${selection.label}" (previously: ${selection.value}) is superseded by the operator. New direction: ${correction}. Acknowledge and adjust the plan.`;
|
|
4714
4479
|
}
|
|
@@ -4772,7 +4537,7 @@ function decisionLines(decision, selected, expanded, width) {
|
|
|
4772
4537
|
}
|
|
4773
4538
|
return lines;
|
|
4774
4539
|
}
|
|
4775
|
-
function formatDecisionsOverlayBodyLines(interviews, selectedIndex = 0, expandedKey = null, contentWidth =
|
|
4540
|
+
function formatDecisionsOverlayBodyLines(interviews, selectedIndex = 0, expandedKey = null, contentWidth = DEFAULT_CONTENT_WIDTH3, now = Date.now()) {
|
|
4776
4541
|
const width = Math.max(1, Math.floor(contentWidth));
|
|
4777
4542
|
const theme2 = clioTheme();
|
|
4778
4543
|
if (interviews.length === 0) {
|
|
@@ -5171,9 +4936,9 @@ function openSideQuestionOverlay(tui, options) {
|
|
|
5171
4936
|
// src/interactive/tasks-overlay.ts
|
|
5172
4937
|
init_esm_shims();
|
|
5173
4938
|
import { isAbsolute, relative as relative3, resolve } from "node:path";
|
|
5174
|
-
var
|
|
4939
|
+
var DEFAULT_CONTENT_WIDTH4 = 84;
|
|
5175
4940
|
var REFRESH_MS2 = 1e3;
|
|
5176
|
-
var TASKS_OVERLAY_WIDTH =
|
|
4941
|
+
var TASKS_OVERLAY_WIDTH = DEFAULT_CONTENT_WIDTH4 + 4;
|
|
5177
4942
|
var STATUS_PRESENTATION = {
|
|
5178
4943
|
pending: { glyph: GLYPH.queued, token: "dim", label: "pending" },
|
|
5179
4944
|
active: { glyph: GLYPH.running, token: "accent", label: "active" },
|
|
@@ -5243,7 +5008,7 @@ function taskReceiptRows(task, width) {
|
|
|
5243
5008
|
}
|
|
5244
5009
|
return [];
|
|
5245
5010
|
}
|
|
5246
|
-
function formatTasksOverlayBodyLines(board, contentWidth =
|
|
5011
|
+
function formatTasksOverlayBodyLines(board, contentWidth = DEFAULT_CONTENT_WIDTH4, selectedTaskId) {
|
|
5247
5012
|
const theme2 = clioTheme();
|
|
5248
5013
|
const width = Math.max(1, Math.floor(contentWidth));
|
|
5249
5014
|
if (!board || board.tasks.length === 0) {
|
|
@@ -5326,7 +5091,7 @@ var USER_TASK_PRESENTATION = {
|
|
|
5326
5091
|
done: { glyph: GLYPH.ok, token: "success" },
|
|
5327
5092
|
dropped: { glyph: GLYPH.cancelled, token: "dim" }
|
|
5328
5093
|
};
|
|
5329
|
-
function formatCompositeTasksOverlayBodyLines(state, contentWidth =
|
|
5094
|
+
function formatCompositeTasksOverlayBodyLines(state, contentWidth = DEFAULT_CONTENT_WIDTH4) {
|
|
5330
5095
|
const width = Math.max(1, Math.floor(contentWidth));
|
|
5331
5096
|
const theme2 = clioTheme();
|
|
5332
5097
|
const rows = selectableRows2(state);
|
|
@@ -5541,40 +5306,391 @@ var TasksOverlayBody = class {
|
|
|
5541
5306
|
this.status = "";
|
|
5542
5307
|
this.requestRender();
|
|
5543
5308
|
}
|
|
5544
|
-
mutateUserTask(status, id, mutation) {
|
|
5545
|
-
if (!mutation) {
|
|
5546
|
-
this.status = "Operator task actions are unavailable.";
|
|
5547
|
-
this.requestRender();
|
|
5548
|
-
return;
|
|
5549
|
-
}
|
|
5550
|
-
try {
|
|
5551
|
-
mutation(id);
|
|
5552
|
-
this.refreshUserTasks();
|
|
5553
|
-
this.status = `Operator task ${id} ${status}.`;
|
|
5554
|
-
} catch (error) {
|
|
5555
|
-
this.status = error instanceof Error ? error.message : String(error);
|
|
5309
|
+
mutateUserTask(status, id, mutation) {
|
|
5310
|
+
if (!mutation) {
|
|
5311
|
+
this.status = "Operator task actions are unavailable.";
|
|
5312
|
+
this.requestRender();
|
|
5313
|
+
return;
|
|
5314
|
+
}
|
|
5315
|
+
try {
|
|
5316
|
+
mutation(id);
|
|
5317
|
+
this.refreshUserTasks();
|
|
5318
|
+
this.status = `Operator task ${id} ${status}.`;
|
|
5319
|
+
} catch (error) {
|
|
5320
|
+
this.status = error instanceof Error ? error.message : String(error);
|
|
5321
|
+
}
|
|
5322
|
+
this.requestRender();
|
|
5323
|
+
}
|
|
5324
|
+
requestRender() {
|
|
5325
|
+
this.options.requestRender?.();
|
|
5326
|
+
}
|
|
5327
|
+
};
|
|
5328
|
+
function openTasksOverlay(tui, getBoard, options = {}) {
|
|
5329
|
+
const body = new TasksOverlayBody(getBoard, options);
|
|
5330
|
+
const handle = showClioOverlayFrame(tui, body, {
|
|
5331
|
+
anchor: "center",
|
|
5332
|
+
width: TASKS_OVERLAY_WIDTH,
|
|
5333
|
+
markerId: "tasks",
|
|
5334
|
+
title: () => "Tasks",
|
|
5335
|
+
footerHint: () => body.footerHint()
|
|
5336
|
+
});
|
|
5337
|
+
const timer = setInterval(() => tui.requestRender(), REFRESH_MS2);
|
|
5338
|
+
timer.unref?.();
|
|
5339
|
+
return {
|
|
5340
|
+
...handle,
|
|
5341
|
+
hide() {
|
|
5342
|
+
clearInterval(timer);
|
|
5343
|
+
handle.hide();
|
|
5344
|
+
}
|
|
5345
|
+
};
|
|
5346
|
+
}
|
|
5347
|
+
|
|
5348
|
+
// src/interactive/usage-overlay.ts
|
|
5349
|
+
init_esm_shims();
|
|
5350
|
+
var DEFAULT_CONTENT_WIDTH5 = 104;
|
|
5351
|
+
var USAGE_OVERLAY_WIDTH = DEFAULT_CONTENT_WIDTH5 + 4;
|
|
5352
|
+
function formatTokens2(n) {
|
|
5353
|
+
return n.toLocaleString("en-US");
|
|
5354
|
+
}
|
|
5355
|
+
function aggregateCostEntries(entries) {
|
|
5356
|
+
const grouped = /* @__PURE__ */ new Map();
|
|
5357
|
+
for (const entry of entries) {
|
|
5358
|
+
const key = `${entry.providerId}::${entry.attributedModelId}`;
|
|
5359
|
+
const existing = grouped.get(key);
|
|
5360
|
+
if (existing) {
|
|
5361
|
+
existing.row.runs += 1;
|
|
5362
|
+
existing.row.tokens += entry.tokens;
|
|
5363
|
+
existing.row.input += entry.input;
|
|
5364
|
+
existing.row.output += entry.output;
|
|
5365
|
+
existing.row.cacheRead += entry.cacheRead;
|
|
5366
|
+
existing.row.cacheWrite += entry.cacheWrite;
|
|
5367
|
+
existing.row.reasoningTokens += entry.reasoningTokens;
|
|
5368
|
+
existing.row.apiCalls += entry.apiCalls ?? 1;
|
|
5369
|
+
if (entry.label === "side-question") existing.row.sideQuestions += 1;
|
|
5370
|
+
if (entry.label === "handoff") existing.row.handoffs += 1;
|
|
5371
|
+
if (entry.label === "prewarm") existing.row.prewarms += 1;
|
|
5372
|
+
if (entry.label === "background-memory") existing.row.backgroundMemory += 1;
|
|
5373
|
+
if (entry.label === "failed-compaction") existing.row.failedCompaction += 1;
|
|
5374
|
+
for (const requestedModelId of entry.requestedModelIds) existing.requestedModelIds.add(requestedModelId);
|
|
5375
|
+
addResponseModelIdObservationCounts(
|
|
5376
|
+
existing.responseModelIdObservationCounts,
|
|
5377
|
+
entry.responseModelIdObservationCounts
|
|
5378
|
+
);
|
|
5379
|
+
existing.entries.push(entry);
|
|
5380
|
+
continue;
|
|
5381
|
+
}
|
|
5382
|
+
grouped.set(key, {
|
|
5383
|
+
row: {
|
|
5384
|
+
providerId: entry.providerId,
|
|
5385
|
+
attributedModelId: entry.attributedModelId,
|
|
5386
|
+
runs: 1,
|
|
5387
|
+
tokens: entry.tokens,
|
|
5388
|
+
input: entry.input,
|
|
5389
|
+
output: entry.output,
|
|
5390
|
+
cacheRead: entry.cacheRead,
|
|
5391
|
+
cacheWrite: entry.cacheWrite,
|
|
5392
|
+
reasoningTokens: entry.reasoningTokens,
|
|
5393
|
+
apiCalls: entry.apiCalls ?? 1,
|
|
5394
|
+
sideQuestions: entry.label === "side-question" ? 1 : 0,
|
|
5395
|
+
handoffs: entry.label === "handoff" ? 1 : 0,
|
|
5396
|
+
prewarms: entry.label === "prewarm" ? 1 : 0,
|
|
5397
|
+
backgroundMemory: entry.label === "background-memory" ? 1 : 0,
|
|
5398
|
+
failedCompaction: entry.label === "failed-compaction" ? 1 : 0
|
|
5399
|
+
},
|
|
5400
|
+
requestedModelIds: new Set(entry.requestedModelIds),
|
|
5401
|
+
responseModelIdObservationCounts: { ...entry.responseModelIdObservationCounts },
|
|
5402
|
+
entries: [entry]
|
|
5403
|
+
});
|
|
5404
|
+
}
|
|
5405
|
+
const rows = Array.from(grouped.values(), ({ row: row2, entries: entries2, requestedModelIds, responseModelIdObservationCounts }) => ({
|
|
5406
|
+
...row2,
|
|
5407
|
+
requestedModelIds: [...requestedModelIds].sort(),
|
|
5408
|
+
responseModelIdObservationCounts,
|
|
5409
|
+
cost: aggregateCostAmounts(entries2.map((entry) => ({ usd: entry.usd, provenance: entry.provenance })))
|
|
5410
|
+
}));
|
|
5411
|
+
rows.sort((a, b) => {
|
|
5412
|
+
if (a.providerId !== b.providerId) return a.providerId < b.providerId ? -1 : 1;
|
|
5413
|
+
if (a.attributedModelId !== b.attributedModelId) return a.attributedModelId < b.attributedModelId ? -1 : 1;
|
|
5414
|
+
return 0;
|
|
5415
|
+
});
|
|
5416
|
+
return rows;
|
|
5417
|
+
}
|
|
5418
|
+
function sumRows(rows) {
|
|
5419
|
+
return rows.reduce(
|
|
5420
|
+
(acc, row2) => ({
|
|
5421
|
+
runs: acc.runs + row2.runs,
|
|
5422
|
+
tokens: acc.tokens + row2.tokens,
|
|
5423
|
+
input: acc.input + row2.input,
|
|
5424
|
+
output: acc.output + row2.output,
|
|
5425
|
+
cacheRead: acc.cacheRead + row2.cacheRead,
|
|
5426
|
+
cacheWrite: acc.cacheWrite + row2.cacheWrite,
|
|
5427
|
+
reasoningTokens: acc.reasoningTokens + row2.reasoningTokens,
|
|
5428
|
+
apiCalls: acc.apiCalls + row2.apiCalls,
|
|
5429
|
+
sideQuestions: acc.sideQuestions + row2.sideQuestions,
|
|
5430
|
+
handoffs: acc.handoffs + row2.handoffs,
|
|
5431
|
+
prewarms: acc.prewarms + row2.prewarms,
|
|
5432
|
+
backgroundMemory: acc.backgroundMemory + row2.backgroundMemory,
|
|
5433
|
+
failedCompaction: acc.failedCompaction + row2.failedCompaction
|
|
5434
|
+
}),
|
|
5435
|
+
{
|
|
5436
|
+
runs: 0,
|
|
5437
|
+
tokens: 0,
|
|
5438
|
+
input: 0,
|
|
5439
|
+
output: 0,
|
|
5440
|
+
cacheRead: 0,
|
|
5441
|
+
cacheWrite: 0,
|
|
5442
|
+
reasoningTokens: 0,
|
|
5443
|
+
apiCalls: 0,
|
|
5444
|
+
sideQuestions: 0,
|
|
5445
|
+
handoffs: 0,
|
|
5446
|
+
prewarms: 0,
|
|
5447
|
+
backgroundMemory: 0,
|
|
5448
|
+
failedCompaction: 0
|
|
5449
|
+
}
|
|
5450
|
+
);
|
|
5451
|
+
}
|
|
5452
|
+
function cacheReadValue(cacheRead, apiCalls) {
|
|
5453
|
+
if (apiCalls > 1 && cacheRead > 0) {
|
|
5454
|
+
return [formatTokens2(cacheRead), `(avg/call ${formatTokens2(Math.round(cacheRead / apiCalls))})`];
|
|
5455
|
+
}
|
|
5456
|
+
return [formatTokens2(cacheRead)];
|
|
5457
|
+
}
|
|
5458
|
+
function reasoningValue(reasoningTokens) {
|
|
5459
|
+
return [formatTokens2(reasoningTokens), "provider-reported only"];
|
|
5460
|
+
}
|
|
5461
|
+
function kvBlock(entries) {
|
|
5462
|
+
const theme2 = clioTheme();
|
|
5463
|
+
const keyWidth = entries.reduce((max, [key]) => Math.max(max, key.length), 0);
|
|
5464
|
+
const valueWidth = entries.reduce((max, [, value]) => Math.max(max, value.length), 0);
|
|
5465
|
+
return entries.map(([key, value, annotation]) => {
|
|
5466
|
+
const row2 = `${theme2.fg("dim", key.padEnd(keyWidth))} ${theme2.fg("muted", value.padStart(valueWidth))}`;
|
|
5467
|
+
return annotation ? `${row2} ${theme2.fg("dim", annotation)}` : row2;
|
|
5468
|
+
});
|
|
5469
|
+
}
|
|
5470
|
+
function summaryBlock(totalCost, totalTokens, rows, promptCache) {
|
|
5471
|
+
const totals = sumRows(rows);
|
|
5472
|
+
const resolvedTotal = totalTokens > 0 ? totalTokens : totals.tokens;
|
|
5473
|
+
const cost = formatCostAggregate(totalCost);
|
|
5474
|
+
const cacheRows = promptCache !== null && hasPromptCacheTelemetry(promptCache) ? [
|
|
5475
|
+
[
|
|
5476
|
+
"uncached prefill",
|
|
5477
|
+
promptCache.uncachedPrefillTokens === null ? "not reported" : formatTokens2(promptCache.uncachedPrefillTokens)
|
|
5478
|
+
],
|
|
5479
|
+
[
|
|
5480
|
+
"cache verdicts",
|
|
5481
|
+
`hot ${promptCache.verdictCounts.hot} \xB7 partial ${promptCache.verdictCounts.partial} \xB7 cold ${promptCache.verdictCounts.cold} \xB7 small ${promptCache.verdictCounts.small} \xB7 unknown ${promptCache.verdictCounts.unknown}`
|
|
5482
|
+
]
|
|
5483
|
+
] : [];
|
|
5484
|
+
return kvBlock([
|
|
5485
|
+
[
|
|
5486
|
+
"turns",
|
|
5487
|
+
formatTokens2(
|
|
5488
|
+
totals.runs - totals.sideQuestions - totals.handoffs - totals.prewarms - totals.backgroundMemory - totals.failedCompaction
|
|
5489
|
+
)
|
|
5490
|
+
],
|
|
5491
|
+
["model calls", formatTokens2(totals.apiCalls)],
|
|
5492
|
+
...totals.sideQuestions > 0 ? [["side questions", formatTokens2(totals.sideQuestions)]] : [],
|
|
5493
|
+
...totals.handoffs > 0 ? [["handoffs", formatTokens2(totals.handoffs)]] : [],
|
|
5494
|
+
...totals.prewarms > 0 ? [["pre-warms", formatTokens2(totals.prewarms)]] : [],
|
|
5495
|
+
...totals.backgroundMemory > 0 ? [["memory steps", formatTokens2(totals.backgroundMemory)]] : [],
|
|
5496
|
+
...totals.failedCompaction > 0 ? [
|
|
5497
|
+
["failed compaction calls", formatTokens2(totals.failedCompaction)],
|
|
5498
|
+
["compaction usage", "known subtotals; missing usage is unknown"]
|
|
5499
|
+
] : [],
|
|
5500
|
+
...cost === null ? [] : [["cost", cost]],
|
|
5501
|
+
["input", formatTokens2(totals.input)],
|
|
5502
|
+
["output", formatTokens2(totals.output)],
|
|
5503
|
+
["reasoning", ...reasoningValue(totals.reasoningTokens)],
|
|
5504
|
+
["cache read", ...cacheReadValue(totals.cacheRead, totals.apiCalls)],
|
|
5505
|
+
["cache write", formatTokens2(totals.cacheWrite)],
|
|
5506
|
+
...cacheRows,
|
|
5507
|
+
["processed", `${formatTokens2(resolvedTotal)} tokens`]
|
|
5508
|
+
]);
|
|
5509
|
+
}
|
|
5510
|
+
function modelBlock(row2) {
|
|
5511
|
+
const cost = formatCostAggregate(row2.cost);
|
|
5512
|
+
return kvBlock([
|
|
5513
|
+
["requested model ids", row2.requestedModelIds.join(", ")],
|
|
5514
|
+
["response model id observation", responseModelIdObservationCountsLabel(row2.responseModelIdObservationCounts)],
|
|
5515
|
+
[
|
|
5516
|
+
"turns",
|
|
5517
|
+
formatTokens2(
|
|
5518
|
+
row2.runs - row2.sideQuestions - row2.handoffs - row2.prewarms - row2.backgroundMemory - row2.failedCompaction
|
|
5519
|
+
)
|
|
5520
|
+
],
|
|
5521
|
+
["model calls", formatTokens2(row2.apiCalls)],
|
|
5522
|
+
...row2.sideQuestions > 0 ? [["side questions", formatTokens2(row2.sideQuestions)]] : [],
|
|
5523
|
+
...row2.handoffs > 0 ? [["handoffs", formatTokens2(row2.handoffs)]] : [],
|
|
5524
|
+
...row2.prewarms > 0 ? [["pre-warms", formatTokens2(row2.prewarms)]] : [],
|
|
5525
|
+
...row2.backgroundMemory > 0 ? [["memory steps", formatTokens2(row2.backgroundMemory)]] : [],
|
|
5526
|
+
...row2.failedCompaction > 0 ? [["failed compaction calls", formatTokens2(row2.failedCompaction)]] : [],
|
|
5527
|
+
...cost === null ? [] : [["cost", cost]],
|
|
5528
|
+
["input", formatTokens2(row2.input)],
|
|
5529
|
+
["output", formatTokens2(row2.output)],
|
|
5530
|
+
["reasoning", ...reasoningValue(row2.reasoningTokens)],
|
|
5531
|
+
["cache read", ...cacheReadValue(row2.cacheRead, row2.apiCalls)],
|
|
5532
|
+
["cache write", formatTokens2(row2.cacheWrite)],
|
|
5533
|
+
["processed", `${formatTokens2(row2.tokens)} tokens`]
|
|
5534
|
+
]);
|
|
5535
|
+
}
|
|
5536
|
+
function modelDetailLines(rows, contentWidth) {
|
|
5537
|
+
const theme2 = clioTheme();
|
|
5538
|
+
const lines = [rule(theme2, contentWidth)];
|
|
5539
|
+
if (rows.length === 0) {
|
|
5540
|
+
lines.push(theme2.fg("muted", "no token usage recorded for this session"));
|
|
5541
|
+
} else {
|
|
5542
|
+
for (const [index, row2] of rows.entries()) {
|
|
5543
|
+
if (index > 0) lines.push("");
|
|
5544
|
+
lines.push(theme2.style("accent", `${row2.providerId} \xB7 attributed model ${row2.attributedModelId}`, { bold: true }));
|
|
5545
|
+
for (const line of modelBlock(row2)) {
|
|
5546
|
+
lines.push(line);
|
|
5547
|
+
}
|
|
5548
|
+
}
|
|
5549
|
+
}
|
|
5550
|
+
return lines;
|
|
5551
|
+
}
|
|
5552
|
+
function buildCostSnapshot(observability, sessionId, snapshot, getSessionEntries) {
|
|
5553
|
+
const entries = observability.costEntries();
|
|
5554
|
+
const rows = aggregateCostEntries(entries);
|
|
5555
|
+
const totalTokens = rows.reduce((sum, r) => sum + r.tokens, 0);
|
|
5556
|
+
return {
|
|
5557
|
+
sessionId,
|
|
5558
|
+
totalCost: snapshot?.session.cost ?? observability.sessionCostSummary(),
|
|
5559
|
+
totalTokens,
|
|
5560
|
+
rows,
|
|
5561
|
+
promptCache: getSessionEntries ? foldPromptCacheTelemetry(getSessionEntries()) : null
|
|
5562
|
+
};
|
|
5563
|
+
}
|
|
5564
|
+
var USAGE_TABS = ["Accounts", "Session", "Models", "Workers"];
|
|
5565
|
+
var UsageOverlayBody = class {
|
|
5566
|
+
constructor(getSnapshot, getQuotaSnapshots, getDispatchRows, requestRender) {
|
|
5567
|
+
this.getSnapshot = getSnapshot;
|
|
5568
|
+
this.getQuotaSnapshots = getQuotaSnapshots;
|
|
5569
|
+
this.getDispatchRows = getDispatchRows;
|
|
5570
|
+
this.requestRender = requestRender;
|
|
5571
|
+
}
|
|
5572
|
+
getSnapshot;
|
|
5573
|
+
getQuotaSnapshots;
|
|
5574
|
+
getDispatchRows;
|
|
5575
|
+
requestRender;
|
|
5576
|
+
tab = 0;
|
|
5577
|
+
offsets = [0, 0, 0, 0];
|
|
5578
|
+
height = 20;
|
|
5579
|
+
pageHeight = 16;
|
|
5580
|
+
lineCount = 0;
|
|
5581
|
+
setHeight(rows) {
|
|
5582
|
+
this.height = Math.max(1, rows - 3);
|
|
5583
|
+
}
|
|
5584
|
+
handleInput(data) {
|
|
5585
|
+
const selected = ["1", "2", "3", "4"].findIndex((key) => matchesKey(data, key));
|
|
5586
|
+
if (selected >= 0) this.tab = selected;
|
|
5587
|
+
else if (matchesKey(data, "tab") || matchesKey(data, "right")) this.tab = (this.tab + 1) % USAGE_TABS.length;
|
|
5588
|
+
else if (matchesKey(data, "shift+tab") || matchesKey(data, "left"))
|
|
5589
|
+
this.tab = (this.tab + USAGE_TABS.length - 1) % USAGE_TABS.length;
|
|
5590
|
+
else {
|
|
5591
|
+
let offset = this.offsets[this.tab] ?? 0;
|
|
5592
|
+
if (matchesKey(data, "up")) offset--;
|
|
5593
|
+
else if (matchesKey(data, "down")) offset++;
|
|
5594
|
+
else if (matchesKey(data, "pageUp")) offset -= this.pageHeight;
|
|
5595
|
+
else if (matchesKey(data, "pageDown")) offset += this.pageHeight;
|
|
5596
|
+
else if (matchesKey(data, "home") || matchesKey(data, "ctrl+home")) offset = 0;
|
|
5597
|
+
else if (matchesKey(data, "end") || matchesKey(data, "ctrl+end")) offset = this.lineCount;
|
|
5598
|
+
else return;
|
|
5599
|
+
this.offsets[this.tab] = Math.max(0, Math.min(offset, this.lineCount - this.pageHeight));
|
|
5556
5600
|
}
|
|
5557
5601
|
this.requestRender();
|
|
5558
5602
|
}
|
|
5559
|
-
|
|
5560
|
-
|
|
5603
|
+
render(width) {
|
|
5604
|
+
const contentWidth = Math.max(1, Math.floor(width));
|
|
5605
|
+
const snapshot = this.getSnapshot();
|
|
5606
|
+
const quota = this.getQuotaSnapshots();
|
|
5607
|
+
const theme2 = clioTheme();
|
|
5608
|
+
const tabs = wrapTextWithAnsi(
|
|
5609
|
+
USAGE_TABS.map(
|
|
5610
|
+
(name, index) => index === this.tab ? theme2.style("accent", `${index + 1} ${name}`, { bold: true, underline: true }) : theme2.fg("dim", `${index + 1} ${name}`)
|
|
5611
|
+
).join(" "),
|
|
5612
|
+
contentWidth
|
|
5613
|
+
);
|
|
5614
|
+
let body;
|
|
5615
|
+
if (this.tab === 0)
|
|
5616
|
+
body = [
|
|
5617
|
+
theme2.fg("dim", "Account-wide limits \xB7 filled = used \xB7 shared across sessions and devices"),
|
|
5618
|
+
"",
|
|
5619
|
+
...renderQuotaAccounts(quota, contentWidth)
|
|
5620
|
+
];
|
|
5621
|
+
else if (this.tab === 1)
|
|
5622
|
+
body = [
|
|
5623
|
+
theme2.style("accent", "Session tokens & cost", { bold: true }),
|
|
5624
|
+
theme2.fg("dim", "Recorded calls in this session \xB7 estimates are marked in the cost totals"),
|
|
5625
|
+
"",
|
|
5626
|
+
...summaryBlock(snapshot.totalCost, snapshot.totalTokens, snapshot.rows, snapshot.promptCache),
|
|
5627
|
+
"",
|
|
5628
|
+
rule(theme2, contentWidth),
|
|
5629
|
+
theme2.fg("dim", "Session tokens cannot be converted to subscription percentages."),
|
|
5630
|
+
...snapshot.rows.length ? [] : ["no token usage recorded for this session"]
|
|
5631
|
+
];
|
|
5632
|
+
else if (this.tab === 2) {
|
|
5633
|
+
body = [
|
|
5634
|
+
theme2.style("accent", "Model activity \xB7 this session", { bold: true }),
|
|
5635
|
+
theme2.fg("dim", "Share of recorded processed tokens, including cache traffic; not account quota."),
|
|
5636
|
+
""
|
|
5637
|
+
];
|
|
5638
|
+
for (const row2 of [...snapshot.rows].sort((a, b) => b.tokens - a.tokens)) {
|
|
5639
|
+
const share = snapshot.totalTokens > 0 ? row2.tokens / snapshot.totalTokens * 100 : 0;
|
|
5640
|
+
body.push(
|
|
5641
|
+
`${row2.providerId} \xB7 ${row2.attributedModelId}`,
|
|
5642
|
+
`${quotaMeter(share, Math.min(24, contentWidth), "normal")} ${share.toFixed(1)}% \xB7 ${formatTokens2(row2.tokens)} tokens`
|
|
5643
|
+
);
|
|
5644
|
+
}
|
|
5645
|
+
body.push("", ...modelDetailLines(snapshot.rows, contentWidth));
|
|
5646
|
+
} else body = renderWorkerUsage(this.getDispatchRows(), quota, contentWidth);
|
|
5647
|
+
const lines = body.flatMap((line) => wrapTextWithAnsi(line, contentWidth));
|
|
5648
|
+
this.lineCount = lines.length;
|
|
5649
|
+
this.pageHeight = Math.max(1, this.height - tabs.length - 1);
|
|
5650
|
+
const offset = Math.max(0, Math.min(this.offsets[this.tab] ?? 0, lines.length - this.pageHeight));
|
|
5651
|
+
this.offsets[this.tab] = offset;
|
|
5652
|
+
const visible = [...tabs, "", ...lines.slice(offset, offset + this.pageHeight)];
|
|
5653
|
+
if (lines.length > this.pageHeight)
|
|
5654
|
+
visible.push(theme2.fg("dim", `${offset + 1}\u2013${Math.min(lines.length, offset + this.pageHeight)} / ${lines.length}`));
|
|
5655
|
+
return visible;
|
|
5656
|
+
}
|
|
5657
|
+
invalidate() {
|
|
5561
5658
|
}
|
|
5562
5659
|
};
|
|
5563
|
-
function
|
|
5564
|
-
const
|
|
5660
|
+
function openUsageOverlay(tui, observability, options) {
|
|
5661
|
+
const sessionId = options?.sessionId ?? null;
|
|
5662
|
+
let latest = observability.snapshot();
|
|
5663
|
+
const body = new UsageOverlayBody(
|
|
5664
|
+
() => buildCostSnapshot(observability, sessionId, latest, options?.getSessionEntries),
|
|
5665
|
+
options?.getQuotaSnapshots ?? (() => []),
|
|
5666
|
+
options?.getDispatchRows ?? (() => []),
|
|
5667
|
+
() => tui.requestRender()
|
|
5668
|
+
);
|
|
5565
5669
|
const handle = showClioOverlayFrame(tui, body, {
|
|
5566
5670
|
anchor: "center",
|
|
5567
|
-
width:
|
|
5568
|
-
|
|
5569
|
-
|
|
5570
|
-
|
|
5671
|
+
width: USAGE_OVERLAY_WIDTH,
|
|
5672
|
+
// Not derived from the title: that one carries the session id.
|
|
5673
|
+
markerId: "usage",
|
|
5674
|
+
title: sessionId && sessionId.length > 0 ? `Usage (${sessionId})` : "Usage",
|
|
5675
|
+
footerHint: buildResponsiveHint([
|
|
5676
|
+
{ key: "1\u20134 / Tab", verb: "view", critical: true },
|
|
5677
|
+
{ key: "\u2191\u2193", verb: "scroll" },
|
|
5678
|
+
{ key: "PgUp/PgDn", verb: "page" }
|
|
5679
|
+
]),
|
|
5680
|
+
visible: (_width, height) => {
|
|
5681
|
+
body.setHeight(height);
|
|
5682
|
+
return true;
|
|
5683
|
+
}
|
|
5684
|
+
});
|
|
5685
|
+
const unsubscribe = observability.subscribe((snapshot) => {
|
|
5686
|
+
latest = snapshot;
|
|
5687
|
+
body.invalidate();
|
|
5688
|
+
tui.requestRender();
|
|
5571
5689
|
});
|
|
5572
|
-
const timer = setInterval(() => tui.requestRender(), REFRESH_MS2);
|
|
5573
|
-
timer.unref?.();
|
|
5574
5690
|
return {
|
|
5575
5691
|
...handle,
|
|
5576
5692
|
hide() {
|
|
5577
|
-
|
|
5693
|
+
unsubscribe();
|
|
5578
5694
|
handle.hide();
|
|
5579
5695
|
}
|
|
5580
5696
|
};
|
|
@@ -5582,7 +5698,7 @@ function openTasksOverlay(tui, getBoard, options = {}) {
|
|
|
5582
5698
|
|
|
5583
5699
|
// src/interactive/overlay-general-openers.ts
|
|
5584
5700
|
function createOverlayGeneralOpeners(deps) {
|
|
5585
|
-
const
|
|
5701
|
+
const openUsageOverlayFactory = deps.openUsageOverlay ?? openUsageOverlay;
|
|
5586
5702
|
const openContextOverlayFactory = deps.openContextOverlay ?? openContextOverlay;
|
|
5587
5703
|
const openContextResetOverlayFactory = deps.openContextResetOverlay ?? openContextResetOverlay;
|
|
5588
5704
|
const openTasksOverlayFactory = deps.openTasksOverlay ?? openTasksOverlay;
|
|
@@ -5591,11 +5707,13 @@ function createOverlayGeneralOpeners(deps) {
|
|
|
5591
5707
|
const openViewOverlayFactory = deps.openViewOverlay ?? openViewOverlay;
|
|
5592
5708
|
const showOverlayFrameFactory = deps.showOverlayFrame ?? showClioOverlayFrame;
|
|
5593
5709
|
const openSideQuestionOverlayFactory = deps.openSideQuestionOverlay ?? openSideQuestionOverlay;
|
|
5594
|
-
const
|
|
5710
|
+
const openUsage = () => {
|
|
5595
5711
|
if (deps.transitions.state !== "closed") return;
|
|
5596
|
-
deps.transitions.state = "
|
|
5597
|
-
deps.transitions.handle =
|
|
5712
|
+
deps.transitions.state = "usage";
|
|
5713
|
+
deps.transitions.handle = openUsageOverlayFactory(deps.tui, deps.observability, {
|
|
5598
5714
|
sessionId: deps.getSessionId?.() ?? null,
|
|
5715
|
+
...deps.getQuotaSnapshots ? { getQuotaSnapshots: deps.getQuotaSnapshots } : {},
|
|
5716
|
+
...deps.getDispatchRows ? { getDispatchRows: deps.getDispatchRows } : {},
|
|
5599
5717
|
...deps.readSessionEntries ? {
|
|
5600
5718
|
getSessionEntries: () => deps.readSessionEntries?.() ?? []
|
|
5601
5719
|
} : {}
|
|
@@ -5805,16 +5923,16 @@ function createOverlayGeneralOpeners(deps) {
|
|
|
5805
5923
|
});
|
|
5806
5924
|
deps.transitions.handle = session;
|
|
5807
5925
|
deps.requestRender();
|
|
5808
|
-
void ask(question, { signal: controller.signal, onDelta: (partialText) => session.setAnswer(partialText) }).then((
|
|
5809
|
-
if (
|
|
5810
|
-
session.settle({ kind: "answered", text:
|
|
5926
|
+
void ask(question, { signal: controller.signal, onDelta: (partialText) => session.setAnswer(partialText) }).then((outcome2) => {
|
|
5927
|
+
if (outcome2.status === "answered") {
|
|
5928
|
+
session.settle({ kind: "answered", text: outcome2.text });
|
|
5811
5929
|
return;
|
|
5812
5930
|
}
|
|
5813
|
-
if (
|
|
5814
|
-
session.settle({ kind: "aborted", text:
|
|
5931
|
+
if (outcome2.status === "aborted") {
|
|
5932
|
+
session.settle({ kind: "aborted", text: outcome2.text });
|
|
5815
5933
|
return;
|
|
5816
5934
|
}
|
|
5817
|
-
session.settle({ kind: "error", reason:
|
|
5935
|
+
session.settle({ kind: "error", reason: outcome2.reason });
|
|
5818
5936
|
}).catch((error) => {
|
|
5819
5937
|
session.settle({ kind: "error", reason: error instanceof Error ? error.message : String(error) });
|
|
5820
5938
|
});
|
|
@@ -5905,13 +6023,13 @@ function createOverlayGeneralOpeners(deps) {
|
|
|
5905
6023
|
},
|
|
5906
6024
|
onNotice: (text) => deps.stderr(`[fleet ${preview.name}] ${text}
|
|
5907
6025
|
`)
|
|
5908
|
-
}).then((
|
|
6026
|
+
}).then((outcome2) => {
|
|
5909
6027
|
deps.notify(
|
|
5910
|
-
|
|
6028
|
+
outcome2.cleanRun ? "success" : "warning",
|
|
5911
6029
|
// `totalCost` rather than the bare `totalCostUsd` sum: a run whose
|
|
5912
6030
|
// receipts were all unpriced reads as not measured instead of as a
|
|
5913
6031
|
// measured $0.0000 nobody put a number on.
|
|
5914
|
-
`fleet ${preview.name}: ${
|
|
6032
|
+
`fleet ${preview.name}: ${outcome2.succeededStepCount}/${outcome2.requiredStepCount} steps succeeded, cost ${renderCostAggregate(outcome2.totalCost)}`,
|
|
5915
6033
|
"fleet-run:settled"
|
|
5916
6034
|
);
|
|
5917
6035
|
}).catch((error) => {
|
|
@@ -5923,7 +6041,7 @@ function createOverlayGeneralOpeners(deps) {
|
|
|
5923
6041
|
});
|
|
5924
6042
|
};
|
|
5925
6043
|
return {
|
|
5926
|
-
|
|
6044
|
+
openUsage,
|
|
5927
6045
|
openContextView,
|
|
5928
6046
|
openContextReset,
|
|
5929
6047
|
toggleFooter,
|
|
@@ -7033,13 +7151,13 @@ function editNumberSubmenu(title, id) {
|
|
|
7033
7151
|
numberSettingNote(rule2)
|
|
7034
7152
|
);
|
|
7035
7153
|
input.onSubmit = (val) => {
|
|
7036
|
-
const
|
|
7037
|
-
if ("refusal" in
|
|
7038
|
-
wrapper.setProblem(
|
|
7154
|
+
const outcome2 = parseNumberSetting(val, rule2);
|
|
7155
|
+
if ("refusal" in outcome2) {
|
|
7156
|
+
wrapper.setProblem(outcome2.refusal);
|
|
7039
7157
|
return;
|
|
7040
7158
|
}
|
|
7041
7159
|
wrapper.setProblem(null);
|
|
7042
|
-
done(
|
|
7160
|
+
done(outcome2.value === null ? "" : val.trim());
|
|
7043
7161
|
};
|
|
7044
7162
|
input.onEscape = () => done();
|
|
7045
7163
|
return wrapper;
|
|
@@ -7067,13 +7185,13 @@ function editEnumListSubmenu(title, legal) {
|
|
|
7067
7185
|
`Comma-separated, from ${legal.join(", ")}; blank activates none.`
|
|
7068
7186
|
);
|
|
7069
7187
|
input.onSubmit = (val) => {
|
|
7070
|
-
const
|
|
7071
|
-
if ("refusal" in
|
|
7072
|
-
wrapper.setProblem(
|
|
7188
|
+
const outcome2 = parseEnumListSetting(val, legal);
|
|
7189
|
+
if ("refusal" in outcome2) {
|
|
7190
|
+
wrapper.setProblem(outcome2.refusal);
|
|
7073
7191
|
return;
|
|
7074
7192
|
}
|
|
7075
7193
|
wrapper.setProblem(null);
|
|
7076
|
-
done(
|
|
7194
|
+
done(outcome2.values.join(", "));
|
|
7077
7195
|
};
|
|
7078
7196
|
input.onEscape = () => done();
|
|
7079
7197
|
return wrapper;
|
|
@@ -7289,12 +7407,12 @@ function scopedModelsSubmenu(selectedRefs, providers) {
|
|
|
7289
7407
|
"Target entries cycle by target, using its default model when switching targets. Model entries pin one exact target/model reference."
|
|
7290
7408
|
);
|
|
7291
7409
|
}
|
|
7292
|
-
function chainSubmenus(first, second,
|
|
7410
|
+
function chainSubmenus(first, second, join6) {
|
|
7293
7411
|
return (_currentValue, done) => {
|
|
7294
7412
|
let active = first("", (head) => {
|
|
7295
7413
|
const trimmed = head?.trim() ?? "";
|
|
7296
7414
|
if (!trimmed) return done();
|
|
7297
|
-
active = second(trimmed)("", (tail) => done(tail?.trim() ?
|
|
7415
|
+
active = second(trimmed)("", (tail) => done(tail?.trim() ? join6(trimmed, tail.trim()) : void 0));
|
|
7298
7416
|
});
|
|
7299
7417
|
return {
|
|
7300
7418
|
render: (width) => active.render(width),
|
|
@@ -8277,9 +8395,9 @@ function applyNonNegativeInteger(value, set) {
|
|
|
8277
8395
|
if (Number.isFinite(parsed) && parsed >= 0) set(Math.floor(parsed));
|
|
8278
8396
|
}
|
|
8279
8397
|
function applyNumberSetting(id, value, set) {
|
|
8280
|
-
const
|
|
8281
|
-
if ("refusal" in
|
|
8282
|
-
set(
|
|
8398
|
+
const outcome2 = parseNumberSetting(value, NUMBER_SETTING_RULES[id]);
|
|
8399
|
+
if ("refusal" in outcome2) return;
|
|
8400
|
+
set(outcome2.value);
|
|
8283
8401
|
}
|
|
8284
8402
|
function applyDelegationAgentChange(settings, value) {
|
|
8285
8403
|
if (value.startsWith(DELEGATION_REMOVE_PREFIX)) {
|
|
@@ -8567,13 +8685,13 @@ function applySettingChange(settings, id, value) {
|
|
|
8567
8685
|
});
|
|
8568
8686
|
return;
|
|
8569
8687
|
case "routing.activeRoles": {
|
|
8570
|
-
const
|
|
8571
|
-
if ("values" in
|
|
8688
|
+
const outcome2 = parseEnumListSetting(value, ACTIVE_ROUTING_ROLES);
|
|
8689
|
+
if ("values" in outcome2) settings.fleet.adaptiveRouting.roles = outcome2.values;
|
|
8572
8690
|
return;
|
|
8573
8691
|
}
|
|
8574
8692
|
case "routing.activePostures": {
|
|
8575
|
-
const
|
|
8576
|
-
if ("values" in
|
|
8693
|
+
const outcome2 = parseEnumListSetting(value, ACTIVE_ROUTING_POSTURES);
|
|
8694
|
+
if ("values" in outcome2) settings.fleet.adaptiveRouting.postures = outcome2.values;
|
|
8577
8695
|
return;
|
|
8578
8696
|
}
|
|
8579
8697
|
case "prewarm.enabled":
|
|
@@ -8692,12 +8810,12 @@ function applyEntrySettingChange(settings, id, value) {
|
|
|
8692
8810
|
}
|
|
8693
8811
|
function changedLeafPaths(before, after) {
|
|
8694
8812
|
const out = [];
|
|
8695
|
-
const
|
|
8813
|
+
const isRecord6 = (v) => v !== null && typeof v === "object" && !Array.isArray(v);
|
|
8696
8814
|
const visit = (a, b, path) => {
|
|
8697
8815
|
if (a === b) return;
|
|
8698
8816
|
const profileLeaf = path.startsWith("fleet.profiles.") && path.split(".").length === 3;
|
|
8699
8817
|
const collectionLeaf = path === "interface.keybindings" || path === "fleet.rosters";
|
|
8700
|
-
if (!
|
|
8818
|
+
if (!isRecord6(a) || !isRecord6(b) || profileLeaf || collectionLeaf) {
|
|
8701
8819
|
if (JSON.stringify(a) !== JSON.stringify(b)) out.push(path);
|
|
8702
8820
|
return;
|
|
8703
8821
|
}
|
|
@@ -11435,28 +11553,28 @@ function evidenceLabel(evidence, refresh) {
|
|
|
11435
11553
|
return "resource evidence from before refresh; current session admission is unverified because refresh failed";
|
|
11436
11554
|
return "resource evidence from before refresh; no session refresh applied";
|
|
11437
11555
|
}
|
|
11438
|
-
function outcomeLines(
|
|
11556
|
+
function outcomeLines(outcome2, width, refresh) {
|
|
11439
11557
|
const theme2 = clioTheme();
|
|
11440
|
-
const token =
|
|
11558
|
+
const token = outcome2.status === "committed" ? "success" : outcome2.status === "failed" ? "error" : "dim";
|
|
11441
11559
|
const rows = wrap(
|
|
11442
|
-
theme2.fg(token, `${
|
|
11560
|
+
theme2.fg(token, `${outcome2.status}: ${outcome2.operation} ${outcome2.identity.ref} (${outcome2.identity.scope})`),
|
|
11443
11561
|
width
|
|
11444
11562
|
);
|
|
11445
|
-
if (
|
|
11446
|
-
rows.push(...wrap(theme2.fg("error", `${
|
|
11447
|
-
if (
|
|
11563
|
+
if (outcome2.error) {
|
|
11564
|
+
rows.push(...wrap(theme2.fg("error", `${outcome2.error.code}: ${outcome2.error.message}`), width));
|
|
11565
|
+
if (outcome2.error.changed)
|
|
11448
11566
|
rows.push(
|
|
11449
11567
|
...wrap(
|
|
11450
11568
|
theme2.fg(
|
|
11451
11569
|
"dim",
|
|
11452
|
-
`changed fact ${
|
|
11570
|
+
`changed fact ${outcome2.error.changed.fact}: reviewed ${JSON.stringify(outcome2.error.changed.expected)}, observed ${JSON.stringify(outcome2.error.changed.observed)}`
|
|
11453
11571
|
),
|
|
11454
11572
|
width
|
|
11455
11573
|
)
|
|
11456
11574
|
);
|
|
11457
|
-
rows.push(...wrap(theme2.fg("info",
|
|
11575
|
+
rows.push(...wrap(theme2.fg("info", outcome2.error.next), width));
|
|
11458
11576
|
}
|
|
11459
|
-
const verification =
|
|
11577
|
+
const verification = outcome2.verification;
|
|
11460
11578
|
if (verification) {
|
|
11461
11579
|
rows.push(...wrap(theme2.fg("dim", `disk: tree ${verification.tree}, record ${verification.record}`), width));
|
|
11462
11580
|
rows.push(
|
|
@@ -11480,11 +11598,11 @@ function outcomeLines(outcome, width, refresh) {
|
|
|
11480
11598
|
)
|
|
11481
11599
|
);
|
|
11482
11600
|
}
|
|
11483
|
-
if (
|
|
11484
|
-
rows.push(...wrap(theme2.fg("info", `recovered content: ${
|
|
11485
|
-
if (
|
|
11486
|
-
rows.push(...wrap(theme2.fg("dim", `state backup: ${
|
|
11487
|
-
for (const diagnostic of
|
|
11601
|
+
if (outcome2.recovery?.packageBackup)
|
|
11602
|
+
rows.push(...wrap(theme2.fg("info", `recovered content: ${outcome2.recovery.packageBackup}`), width));
|
|
11603
|
+
if (outcome2.recovery?.stateBackup)
|
|
11604
|
+
rows.push(...wrap(theme2.fg("dim", `state backup: ${outcome2.recovery.stateBackup}`), width));
|
|
11605
|
+
for (const diagnostic of outcome2.diagnostics) rows.push(...wrap(theme2.fg("dim", diagnostic), width));
|
|
11488
11606
|
return rows;
|
|
11489
11607
|
}
|
|
11490
11608
|
function formatLibraryOutcome(result, width) {
|
|
@@ -11497,7 +11615,7 @@ function formatLibraryOutcome(result, width) {
|
|
|
11497
11615
|
width
|
|
11498
11616
|
);
|
|
11499
11617
|
rows.push(rule(theme2, width));
|
|
11500
|
-
for (const
|
|
11618
|
+
for (const outcome2 of result.outcomes) rows.push(...outcomeLines(outcome2, width, result.refresh));
|
|
11501
11619
|
rows.push(rule(theme2, width));
|
|
11502
11620
|
rows.push(...wrap(refreshLine(result.refresh), width));
|
|
11503
11621
|
if (result.unattempted > 0)
|
|
@@ -11533,7 +11651,7 @@ function formatLibraryImportReview(plan, width, options = {}) {
|
|
|
11533
11651
|
...wrap(
|
|
11534
11652
|
theme2.fg(
|
|
11535
11653
|
"info",
|
|
11536
|
-
`projects ${plan.outcomes.length} resource${plan.outcomes.length === 1 ? "" : "s"}${plan.outcomes.length > 0 ? `: ${plan.outcomes.map((
|
|
11654
|
+
`projects ${plan.outcomes.length} resource${plan.outcomes.length === 1 ? "" : "s"}${plan.outcomes.length > 0 ? `: ${plan.outcomes.map((outcome2) => `${outcome2.kind}:${outcome2.name} (${outcome2.status})`).join(", ")}` : ""}`
|
|
11537
11655
|
),
|
|
11538
11656
|
width
|
|
11539
11657
|
)
|
|
@@ -11631,8 +11749,8 @@ function openReviewOverlay(tui, spec) {
|
|
|
11631
11749
|
if (matchesKey(data, "enter")) {
|
|
11632
11750
|
if (!spec.applicable) return;
|
|
11633
11751
|
settled = true;
|
|
11634
|
-
const
|
|
11635
|
-
body.outcome = () =>
|
|
11752
|
+
const outcome2 = spec.commit();
|
|
11753
|
+
body.outcome = () => outcome2(width);
|
|
11636
11754
|
body.reset();
|
|
11637
11755
|
tui.requestRender();
|
|
11638
11756
|
return;
|
|
@@ -11935,15 +12053,15 @@ function openLibraryOverlay(tui, deps) {
|
|
|
11935
12053
|
columns: columns(),
|
|
11936
12054
|
commit: (accepted) => (deps.applyImport ?? applyLibraryImport)(accepted, true),
|
|
11937
12055
|
outcome: (accepted, result) => {
|
|
11938
|
-
const
|
|
11939
|
-
const committed =
|
|
12056
|
+
const outcome2 = libraryImportOutcome(accepted, result);
|
|
12057
|
+
const committed = outcome2.status === "committed";
|
|
11940
12058
|
return {
|
|
11941
12059
|
planId: accepted.reviewFingerprint,
|
|
11942
12060
|
dryRun: false,
|
|
11943
|
-
outcomes: [
|
|
12061
|
+
outcomes: [outcome2],
|
|
11944
12062
|
committed: committed ? 1 : 0,
|
|
11945
|
-
failed:
|
|
11946
|
-
unattempted:
|
|
12063
|
+
failed: outcome2.status === "failed" ? 1 : 0,
|
|
12064
|
+
unattempted: outcome2.status === "unattempted" ? 1 : 0,
|
|
11947
12065
|
refresh: committed ? deps.lifecycle.retryRefresh(cwd) : { status: "not-applicable", reason: "nothing was imported" }
|
|
11948
12066
|
};
|
|
11949
12067
|
},
|
|
@@ -13456,7 +13574,7 @@ function createOverlaySessionLifecycle(deps) {
|
|
|
13456
13574
|
try {
|
|
13457
13575
|
const turns = deps.readStructuredEntries(sessionId);
|
|
13458
13576
|
const leafTurnId = session.tree(sessionId).leafId;
|
|
13459
|
-
const replayOptions = leafTurnId ? { activeLeafTurnId: leafTurnId } : {};
|
|
13577
|
+
const replayOptions = withContinuityReplay(turns, leafTurnId ? { activeLeafTurnId: leafTurnId } : {}, session);
|
|
13460
13578
|
deps.resetTranscript();
|
|
13461
13579
|
rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
|
|
13462
13580
|
const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, replayOptions);
|
|
@@ -13508,8 +13626,9 @@ function createOverlaySessionLifecycle(deps) {
|
|
|
13508
13626
|
if (!sessionId) throw new Error("no current session after turn switch");
|
|
13509
13627
|
const turns = deps.readStructuredEntries(sessionId);
|
|
13510
13628
|
deps.resetTranscript();
|
|
13511
|
-
|
|
13512
|
-
|
|
13629
|
+
const replayOptions = withContinuityReplay(turns, { uptoTurnId: turnId }, session);
|
|
13630
|
+
rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
|
|
13631
|
+
const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, replayOptions);
|
|
13513
13632
|
deps.chat.resetForSession(turnId, replayMessages);
|
|
13514
13633
|
rescopeToBranch(session, turns, turnId);
|
|
13515
13634
|
} catch (error) {
|
|
@@ -13580,12 +13699,10 @@ function createOverlaySessionLifecycle(deps) {
|
|
|
13580
13699
|
function replayFork(forkedSessionId, parentTurnId, session) {
|
|
13581
13700
|
try {
|
|
13582
13701
|
const turns = deps.readStructuredEntries(forkedSessionId);
|
|
13583
|
-
rehydrateChatPanelFromTurns(deps.chatPanel, turns);
|
|
13584
13702
|
const leafTurnId = session.tree(forkedSessionId).leafId ?? parentTurnId;
|
|
13585
|
-
const
|
|
13586
|
-
|
|
13587
|
-
|
|
13588
|
-
);
|
|
13703
|
+
const replayOptions = withContinuityReplay(turns, leafTurnId ? { activeLeafTurnId: leafTurnId } : {}, session);
|
|
13704
|
+
rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
|
|
13705
|
+
const replayMessages = buildModelReplayAgentMessagesFromTurns(turns, replayOptions);
|
|
13589
13706
|
deps.chat.resetForSession(leafTurnId, replayMessages);
|
|
13590
13707
|
rescopeToBranch(session, turns, leafTurnId);
|
|
13591
13708
|
} catch (error) {
|
|
@@ -13808,8 +13925,9 @@ function createOverlaySessionLifecycle(deps) {
|
|
|
13808
13925
|
try {
|
|
13809
13926
|
const turns = deps.readStructuredEntries(toSessionId);
|
|
13810
13927
|
deps.resetTranscript();
|
|
13811
|
-
|
|
13812
|
-
deps.
|
|
13928
|
+
const replayOptions = withContinuityReplay(turns, {}, session);
|
|
13929
|
+
rehydrateChatPanelFromTurns(deps.chatPanel, turns, replayOptions);
|
|
13930
|
+
deps.chat.resetForSession(null, buildModelReplayAgentMessagesFromTurns(turns, replayOptions));
|
|
13813
13931
|
rescopeToBranch(session, turns, null);
|
|
13814
13932
|
} catch (error) {
|
|
13815
13933
|
deps.stderr(`[/handoff] seeding replay failed: ${error instanceof Error ? error.message : String(error)}
|
|
@@ -13969,7 +14087,7 @@ function routeAuthOverlayKey(data, deps) {
|
|
|
13969
14087
|
}
|
|
13970
14088
|
return false;
|
|
13971
14089
|
}
|
|
13972
|
-
function
|
|
14090
|
+
function routeReadOnlyOverlayKey(data, deps) {
|
|
13973
14091
|
if (isEscapeKey(data)) {
|
|
13974
14092
|
deps.closeOverlay();
|
|
13975
14093
|
return true;
|
|
@@ -13999,16 +14117,13 @@ function routeOverlayKey(data, overlayState, deps, matches) {
|
|
|
13999
14117
|
return true;
|
|
14000
14118
|
}
|
|
14001
14119
|
if (overlayState === "auth") return routeAuthOverlayKey(data, deps);
|
|
14002
|
-
if (overlayState === "
|
|
14003
|
-
routeCostOverlayKey(data, deps);
|
|
14004
|
-
return true;
|
|
14005
|
-
}
|
|
14120
|
+
if (overlayState === "usage") return routeReadOnlyOverlayKey(data, deps);
|
|
14006
14121
|
if (overlayState === "context-view") {
|
|
14007
|
-
|
|
14122
|
+
routeReadOnlyOverlayKey(data, deps);
|
|
14008
14123
|
return true;
|
|
14009
14124
|
}
|
|
14010
14125
|
if (overlayState === "side-question") {
|
|
14011
|
-
|
|
14126
|
+
routeReadOnlyOverlayKey(data, deps);
|
|
14012
14127
|
return true;
|
|
14013
14128
|
}
|
|
14014
14129
|
if (overlayState === "handoff-review") return false;
|
|
@@ -14072,7 +14187,7 @@ function createOverlayLifecycle(deps) {
|
|
|
14072
14187
|
openTreeOverlay: openTreeOverlayFactory,
|
|
14073
14188
|
openMessagePickerOverlay: openMessagePickerOverlayFactory,
|
|
14074
14189
|
openCwdFallbackOverlay: openCwdFallbackOverlayFactory,
|
|
14075
|
-
|
|
14190
|
+
openUsageOverlay: openUsageOverlayFactory,
|
|
14076
14191
|
openContextOverlay: openContextOverlayFactory,
|
|
14077
14192
|
openContextResetOverlay: openContextResetOverlayFactory,
|
|
14078
14193
|
openTasksOverlay: openTasksOverlayFactory,
|
|
@@ -14264,6 +14379,8 @@ function createOverlayLifecycle(deps) {
|
|
|
14264
14379
|
tui,
|
|
14265
14380
|
transitions: overlayTransitions,
|
|
14266
14381
|
observability: deps.app.observability,
|
|
14382
|
+
...deps.getQuotaSnapshots ? { getQuotaSnapshots: deps.getQuotaSnapshots } : {},
|
|
14383
|
+
...deps.getDispatchRows ? { getDispatchRows: deps.getDispatchRows } : {},
|
|
14267
14384
|
...deps.app.getSessionId ? { getSessionId: deps.app.getSessionId } : {},
|
|
14268
14385
|
getContextLedger: () => deps.app.chat.contextLedger(),
|
|
14269
14386
|
contextChat: deps.app.chat,
|
|
@@ -14292,7 +14409,7 @@ function createOverlayLifecycle(deps) {
|
|
|
14292
14409
|
startDispatchBoardTicker: () => interactiveTickers.startDispatchBoardTicker(),
|
|
14293
14410
|
closeOverlay,
|
|
14294
14411
|
showOverlayFrame,
|
|
14295
|
-
...
|
|
14412
|
+
...openUsageOverlayFactory ? { openUsageOverlay: openUsageOverlayFactory } : {},
|
|
14296
14413
|
...openContextOverlayFactory ? { openContextOverlay: openContextOverlayFactory } : {},
|
|
14297
14414
|
...openContextResetOverlayFactory ? { openContextResetOverlay: openContextResetOverlayFactory } : {},
|
|
14298
14415
|
...openTasksOverlayFactory ? { openTasksOverlay: openTasksOverlayFactory } : {},
|
|
@@ -14308,7 +14425,7 @@ function createOverlayLifecycle(deps) {
|
|
|
14308
14425
|
const openResumeOverlayState = overlaySessions.openResume;
|
|
14309
14426
|
const openTreeOverlayState = overlaySessions.openTree;
|
|
14310
14427
|
const openMessagePickerOverlayState = overlaySessions.openMessagePicker;
|
|
14311
|
-
const
|
|
14428
|
+
const openUsageOverlayState = overlayGeneralOpeners.openUsage;
|
|
14312
14429
|
const openContextViewOverlayState = overlayGeneralOpeners.openContextView;
|
|
14313
14430
|
const openContextResetOverlayState = overlayGeneralOpeners.openContextReset;
|
|
14314
14431
|
const toggleFooterDashboardState = overlayGeneralOpeners.toggleFooter;
|
|
@@ -14329,7 +14446,7 @@ function createOverlayLifecycle(deps) {
|
|
|
14329
14446
|
isAskUserWaiting: overlayAskUser.isWaiting,
|
|
14330
14447
|
resetAskUserCancellation: overlayAskUser.resetCancellation,
|
|
14331
14448
|
refreshSettingsOverlay: overlayModelSelectors.refreshSettingsOverlay,
|
|
14332
|
-
|
|
14449
|
+
openUsageOverlayState,
|
|
14333
14450
|
openContextViewOverlayState,
|
|
14334
14451
|
openContextResetOverlayState,
|
|
14335
14452
|
toggleFooterDashboardState,
|
|
@@ -15553,10 +15670,10 @@ function createInteractiveEventProjection(deps) {
|
|
|
15553
15670
|
deps.bus.on(BusChannels.ContextPruned, (payload) => {
|
|
15554
15671
|
const event = payload;
|
|
15555
15672
|
if (event && typeof event === "object" && typeof event.tokensBefore === "number" && typeof event.tokensAfter === "number") {
|
|
15556
|
-
const
|
|
15673
|
+
const outcome2 = event.tokensAfter < event.tokensBefore ? "Reclaimed context" : "Context updated";
|
|
15557
15674
|
deps.notify(
|
|
15558
15675
|
"info",
|
|
15559
|
-
`[Compaction] ${
|
|
15676
|
+
`[Compaction] ${outcome2}: ${event.tokensBefore} -> ${event.tokensAfter} tokens (${event.stage})`,
|
|
15560
15677
|
"compaction-notice"
|
|
15561
15678
|
);
|
|
15562
15679
|
}
|
|
@@ -15960,7 +16077,7 @@ function createInteractiveInputRuntime(deps) {
|
|
|
15960
16077
|
},
|
|
15961
16078
|
cancelFocusedOwner: () => {
|
|
15962
16079
|
const state = deps.overlay.getState();
|
|
15963
|
-
if (["permission-confirm", "
|
|
16080
|
+
if (["permission-confirm", "usage", "context-view", "side-question", "dispatch-board", "auth"].includes(state))
|
|
15964
16081
|
deps.overlay.closeOverlay();
|
|
15965
16082
|
else if (focused()?.handleInput) {
|
|
15966
16083
|
focused()?.handleInput?.("\x1B");
|
|
@@ -16078,89 +16195,1041 @@ function createInteractiveInputRuntime(deps) {
|
|
|
16078
16195
|
deps.onShutdownArmedChange?.(armed);
|
|
16079
16196
|
deps.refreshFooter();
|
|
16080
16197
|
},
|
|
16081
|
-
closeOverlay: () => deps.overlay.closeOverlay(),
|
|
16082
|
-
listNotifications: () => deps.notifications.list(),
|
|
16083
|
-
dismissNotification: (id) => deps.notifications.dismiss(id),
|
|
16084
|
-
dismissAllNotifications: () => deps.notifications.dismissAll(),
|
|
16085
|
-
shutdownDisposers: [
|
|
16086
|
-
() => deps.shutdown.stopTickers(),
|
|
16087
|
-
() => leaderKeys.dispose(),
|
|
16088
|
-
() => removeReload?.(),
|
|
16089
|
-
() => deps.shutdown.disposeInteractiveTickers(),
|
|
16090
|
-
() => deps.shutdown.disposeBeforeStatus(),
|
|
16091
|
-
() => deps.shutdown.disposeProjectionPrimary(),
|
|
16092
|
-
() => deps.shutdown.disposeStatus(),
|
|
16093
|
-
() => deps.shutdown.disposeProjectionRemaining(),
|
|
16094
|
-
() => deps.shutdown.disposeOverlay(),
|
|
16095
|
-
() => deps.shutdown.stopAgentProgress(),
|
|
16096
|
-
() => deps.shutdown.disposeChat(),
|
|
16097
|
-
() => deps.shutdown.disposeSubscriptions()
|
|
16098
|
-
],
|
|
16099
|
-
stopUi: deps.stopUi,
|
|
16100
|
-
...deps.beforeStopUi ? { beforeStopUi: deps.beforeStopUi } : {},
|
|
16101
|
-
cancelParkedCalls: deps.cancelParkedCalls,
|
|
16102
|
-
onShutdown: deps.onShutdown,
|
|
16103
|
-
registerTerminalTeardown: deps.registerTerminalTeardown ?? ((teardown) => getTerminationCoordinator().onDrain(teardown)),
|
|
16104
|
-
// stderr for the same reason src/core/termination.ts uses it for a failed
|
|
16105
|
-
// hook: by the time teardown fails there is no UI left to carry a notice.
|
|
16106
|
-
reportShutdownFailure: deps.reportShutdownFailure ?? ((step, error) => {
|
|
16107
|
-
process.stderr.write(
|
|
16108
|
-
`[clio-coder:interactive] ${step} failed: ${error instanceof Error ? error.message : String(error)}
|
|
16109
|
-
`
|
|
16110
|
-
);
|
|
16111
|
-
})
|
|
16198
|
+
closeOverlay: () => deps.overlay.closeOverlay(),
|
|
16199
|
+
listNotifications: () => deps.notifications.list(),
|
|
16200
|
+
dismissNotification: (id) => deps.notifications.dismiss(id),
|
|
16201
|
+
dismissAllNotifications: () => deps.notifications.dismissAll(),
|
|
16202
|
+
shutdownDisposers: [
|
|
16203
|
+
() => deps.shutdown.stopTickers(),
|
|
16204
|
+
() => leaderKeys.dispose(),
|
|
16205
|
+
() => removeReload?.(),
|
|
16206
|
+
() => deps.shutdown.disposeInteractiveTickers(),
|
|
16207
|
+
() => deps.shutdown.disposeBeforeStatus(),
|
|
16208
|
+
() => deps.shutdown.disposeProjectionPrimary(),
|
|
16209
|
+
() => deps.shutdown.disposeStatus(),
|
|
16210
|
+
() => deps.shutdown.disposeProjectionRemaining(),
|
|
16211
|
+
() => deps.shutdown.disposeOverlay(),
|
|
16212
|
+
() => deps.shutdown.stopAgentProgress(),
|
|
16213
|
+
() => deps.shutdown.disposeChat(),
|
|
16214
|
+
() => deps.shutdown.disposeSubscriptions()
|
|
16215
|
+
],
|
|
16216
|
+
stopUi: deps.stopUi,
|
|
16217
|
+
...deps.beforeStopUi ? { beforeStopUi: deps.beforeStopUi } : {},
|
|
16218
|
+
cancelParkedCalls: deps.cancelParkedCalls,
|
|
16219
|
+
onShutdown: deps.onShutdown,
|
|
16220
|
+
registerTerminalTeardown: deps.registerTerminalTeardown ?? ((teardown) => getTerminationCoordinator().onDrain(teardown)),
|
|
16221
|
+
// stderr for the same reason src/core/termination.ts uses it for a failed
|
|
16222
|
+
// hook: by the time teardown fails there is no UI left to carry a notice.
|
|
16223
|
+
reportShutdownFailure: deps.reportShutdownFailure ?? ((step, error) => {
|
|
16224
|
+
process.stderr.write(
|
|
16225
|
+
`[clio-coder:interactive] ${step} failed: ${error instanceof Error ? error.message : String(error)}
|
|
16226
|
+
`
|
|
16227
|
+
);
|
|
16228
|
+
})
|
|
16229
|
+
});
|
|
16230
|
+
deps.registerInputListener((data) => {
|
|
16231
|
+
deps.onInputIngress?.(classifyInputAction(data, deps), data);
|
|
16232
|
+
return controller.handleInput(data);
|
|
16233
|
+
});
|
|
16234
|
+
return controller;
|
|
16235
|
+
}
|
|
16236
|
+
function classifyInputAction(data, deps) {
|
|
16237
|
+
if (data.length === 0 || isKeyRelease(data)) return "no-visual-change";
|
|
16238
|
+
if (deps.keybindings.matches(data, "tui.input.submit")) return "submit";
|
|
16239
|
+
const sgrMousePrefix = `${String.fromCharCode(27)}[<`;
|
|
16240
|
+
if (data.startsWith(`${sgrMousePrefix}64;`) || data.startsWith(`${sgrMousePrefix}65;`) || deps.keybindings.matches(data, "tui.altScreen.pageUp") || deps.keybindings.matches(data, "tui.altScreen.pageDown") || deps.keybindings.matches(data, "tui.editor.pageUp") || deps.keybindings.matches(data, "tui.editor.pageDown")) {
|
|
16241
|
+
return "scroll";
|
|
16242
|
+
}
|
|
16243
|
+
if (deps.overlay.getState() !== "closed") return "overlay";
|
|
16244
|
+
return "editor";
|
|
16245
|
+
}
|
|
16246
|
+
function overlayScopeLabel(state) {
|
|
16247
|
+
const names = {
|
|
16248
|
+
closed: "Composer",
|
|
16249
|
+
"permission-confirm": "Permission",
|
|
16250
|
+
"dispatch-board": "Workers",
|
|
16251
|
+
auth: "Authentication",
|
|
16252
|
+
usage: "Usage",
|
|
16253
|
+
"context-view": "Context",
|
|
16254
|
+
"context-reset": "Context reset",
|
|
16255
|
+
tasks: "Tasks",
|
|
16256
|
+
decisions: "Decisions",
|
|
16257
|
+
memory: "Memory",
|
|
16258
|
+
view: "View",
|
|
16259
|
+
model: "Model",
|
|
16260
|
+
"model-scope": "Model cycle set",
|
|
16261
|
+
settings: "Settings",
|
|
16262
|
+
resume: "Resume",
|
|
16263
|
+
tree: "Session tree",
|
|
16264
|
+
"message-picker": "Messages",
|
|
16265
|
+
"cwd-fallback": "Working directory",
|
|
16266
|
+
"ask-user": "Interview",
|
|
16267
|
+
help: "Help",
|
|
16268
|
+
extensions: "Extensions",
|
|
16269
|
+
interop: "Interop",
|
|
16270
|
+
"skills-hub": "Library",
|
|
16271
|
+
"side-question": "Side question",
|
|
16272
|
+
"handoff-review": "Handoff review",
|
|
16273
|
+
"fleet-run-approval": "Run approval"
|
|
16274
|
+
};
|
|
16275
|
+
return names[state];
|
|
16276
|
+
}
|
|
16277
|
+
|
|
16278
|
+
// src/interactive/interactive-presentation.ts
|
|
16279
|
+
init_esm_shims();
|
|
16280
|
+
import { performance as performance3 } from "node:perf_hooks";
|
|
16281
|
+
|
|
16282
|
+
// src/domains/quota/summary-feed.ts
|
|
16283
|
+
init_esm_shims();
|
|
16284
|
+
|
|
16285
|
+
// src/domains/quota/service.ts
|
|
16286
|
+
init_esm_shims();
|
|
16287
|
+
|
|
16288
|
+
// src/domains/quota/cache.ts
|
|
16289
|
+
init_esm_shims();
|
|
16290
|
+
var DEFAULT_QUOTA_CACHE_TTL_MS = 5 * 6e4;
|
|
16291
|
+
function createQuotaCache(options = {}) {
|
|
16292
|
+
const ttlMs = options.ttlMs ?? DEFAULT_QUOTA_CACHE_TTL_MS;
|
|
16293
|
+
const now = options.now ?? Date.now;
|
|
16294
|
+
const entries = /* @__PURE__ */ new Map();
|
|
16295
|
+
const fresh = (entry) => entry !== void 0 && now() - entry.storedAtMs < ttlMs;
|
|
16296
|
+
return {
|
|
16297
|
+
read(providerId) {
|
|
16298
|
+
const entry = entries.get(providerId);
|
|
16299
|
+
return fresh(entry) && entry !== void 0 ? entry.snapshot : null;
|
|
16300
|
+
},
|
|
16301
|
+
readLastGood(providerId) {
|
|
16302
|
+
const entry = entries.get(providerId);
|
|
16303
|
+
if (entry === void 0) return null;
|
|
16304
|
+
return fresh(entry) ? entry.snapshot : { ...entry.snapshot, stale: true };
|
|
16305
|
+
},
|
|
16306
|
+
write(snapshot) {
|
|
16307
|
+
entries.set(snapshot.providerId, { snapshot, storedAtMs: now() });
|
|
16308
|
+
},
|
|
16309
|
+
clear(providerId) {
|
|
16310
|
+
if (providerId === void 0) entries.clear();
|
|
16311
|
+
else entries.delete(providerId);
|
|
16312
|
+
},
|
|
16313
|
+
async resolve(provider) {
|
|
16314
|
+
const cached = entries.get(provider.id);
|
|
16315
|
+
if (fresh(cached) && cached !== void 0) return cached.snapshot;
|
|
16316
|
+
const snapshot = await provider.fetch();
|
|
16317
|
+
if (snapshot.status === "ok") {
|
|
16318
|
+
entries.set(provider.id, { snapshot, storedAtMs: now() });
|
|
16319
|
+
return snapshot;
|
|
16320
|
+
}
|
|
16321
|
+
if (cached === void 0) return snapshot;
|
|
16322
|
+
return {
|
|
16323
|
+
...cached.snapshot,
|
|
16324
|
+
stale: true,
|
|
16325
|
+
message: snapshot.message ?? cached.snapshot.message ?? null
|
|
16326
|
+
};
|
|
16327
|
+
}
|
|
16328
|
+
};
|
|
16329
|
+
}
|
|
16330
|
+
|
|
16331
|
+
// src/domains/quota/registry.ts
|
|
16332
|
+
init_esm_shims();
|
|
16333
|
+
|
|
16334
|
+
// src/domains/quota/anthropic-max-provider.ts
|
|
16335
|
+
init_esm_shims();
|
|
16336
|
+
|
|
16337
|
+
// src/domains/quota/anthropic-usage.ts
|
|
16338
|
+
init_esm_shims();
|
|
16339
|
+
|
|
16340
|
+
// src/domains/quota/types.ts
|
|
16341
|
+
init_esm_shims();
|
|
16342
|
+
function parseRetryAfterSeconds(value) {
|
|
16343
|
+
if (!value) return null;
|
|
16344
|
+
const seconds = Number.parseFloat(value.trim());
|
|
16345
|
+
if (!Number.isFinite(seconds)) return null;
|
|
16346
|
+
return Math.max(0, seconds);
|
|
16347
|
+
}
|
|
16348
|
+
function formatPlan(value) {
|
|
16349
|
+
if (!value) return null;
|
|
16350
|
+
const words = value.replace(/_/g, " ").trim();
|
|
16351
|
+
if (!words) return null;
|
|
16352
|
+
return words.replace(/\S+/g, (word) => word.charAt(0).toUpperCase() + word.slice(1).toLowerCase());
|
|
16353
|
+
}
|
|
16354
|
+
|
|
16355
|
+
// src/domains/quota/anthropic-usage.ts
|
|
16356
|
+
var ANTHROPIC_USAGE_URL = "https://api.anthropic.com/api/oauth/usage";
|
|
16357
|
+
var ANTHROPIC_OAUTH_BETA = "oauth-2025-04-20";
|
|
16358
|
+
var WINDOW_ORDER = { session: 0, weekly: 1 };
|
|
16359
|
+
function outcome(status, message, extra = {}) {
|
|
16360
|
+
return { status, message, windows: [], credits: null, retryAfterSeconds: null, ...extra };
|
|
16361
|
+
}
|
|
16362
|
+
async function fetchAnthropicUsage(token, dependencies) {
|
|
16363
|
+
const controller = new AbortController();
|
|
16364
|
+
const timer = setTimeout(() => controller.abort(), dependencies.timeoutMs);
|
|
16365
|
+
let response;
|
|
16366
|
+
try {
|
|
16367
|
+
response = await dependencies.fetch(ANTHROPIC_USAGE_URL, {
|
|
16368
|
+
method: "GET",
|
|
16369
|
+
headers: {
|
|
16370
|
+
Authorization: `Bearer ${token}`,
|
|
16371
|
+
"anthropic-beta": ANTHROPIC_OAUTH_BETA
|
|
16372
|
+
},
|
|
16373
|
+
signal: controller.signal
|
|
16374
|
+
});
|
|
16375
|
+
} catch (error) {
|
|
16376
|
+
return outcome("error", describeError2(error, dependencies.timeoutMs));
|
|
16377
|
+
} finally {
|
|
16378
|
+
clearTimeout(timer);
|
|
16379
|
+
}
|
|
16380
|
+
if (response.status === 401 || response.status === 403) {
|
|
16381
|
+
await discardBody(response);
|
|
16382
|
+
return outcome("expired", null);
|
|
16383
|
+
}
|
|
16384
|
+
if (response.status === 429) {
|
|
16385
|
+
await discardBody(response);
|
|
16386
|
+
return outcome("error", "HTTP 429", {
|
|
16387
|
+
retryAfterSeconds: parseRetryAfterSeconds(response.headers.get("Retry-After"))
|
|
16388
|
+
});
|
|
16389
|
+
}
|
|
16390
|
+
if (response.status !== 200) {
|
|
16391
|
+
await discardBody(response);
|
|
16392
|
+
return outcome("error", `HTTP ${response.status}`);
|
|
16393
|
+
}
|
|
16394
|
+
let body;
|
|
16395
|
+
try {
|
|
16396
|
+
body = await response.json();
|
|
16397
|
+
} catch {
|
|
16398
|
+
return outcome("error", "Unexpected usage response");
|
|
16399
|
+
}
|
|
16400
|
+
if (!isRecord(body)) {
|
|
16401
|
+
return outcome("error", "Unexpected usage response");
|
|
16402
|
+
}
|
|
16403
|
+
return outcome("ok", null, { windows: usageWindows(body), credits: usageCredits(body.spend) });
|
|
16404
|
+
}
|
|
16405
|
+
function usageWindows(body) {
|
|
16406
|
+
const fromLimits = windowsFromLimits(body.limits);
|
|
16407
|
+
const windows = fromLimits.length > 0 ? fromLimits : windowsFromFlat(body);
|
|
16408
|
+
return windows.sort((left, right) => {
|
|
16409
|
+
const order = (WINDOW_ORDER[left.key] ?? 2) - (WINDOW_ORDER[right.key] ?? 2);
|
|
16410
|
+
return order !== 0 ? order : left.label.localeCompare(right.label);
|
|
16411
|
+
});
|
|
16412
|
+
}
|
|
16413
|
+
function windowsFromLimits(raw) {
|
|
16414
|
+
if (!Array.isArray(raw)) return [];
|
|
16415
|
+
const windows = [];
|
|
16416
|
+
for (const entry of raw) {
|
|
16417
|
+
if (!isRecord(entry)) continue;
|
|
16418
|
+
const percent = asNumber(entry.percent);
|
|
16419
|
+
if (percent === null) continue;
|
|
16420
|
+
const common = {
|
|
16421
|
+
usedPct: percent,
|
|
16422
|
+
resetsAt: asIsoString(entry.resets_at)
|
|
16423
|
+
};
|
|
16424
|
+
if (typeof entry.severity === "string") common.severity = entry.severity;
|
|
16425
|
+
if (entry.is_active === true) common.active = true;
|
|
16426
|
+
if (entry.kind === "session") {
|
|
16427
|
+
windows.push({ key: "session", label: "5h", short: "5h", ...common });
|
|
16428
|
+
} else if (entry.kind === "weekly_all") {
|
|
16429
|
+
windows.push({ key: "weekly", label: "Weekly", short: "wk", ...common });
|
|
16430
|
+
} else if (entry.kind === "weekly_scoped") {
|
|
16431
|
+
const name = scopeName(entry.scope);
|
|
16432
|
+
if (name === null) continue;
|
|
16433
|
+
windows.push({ key: `weekly_scoped.${slug(name)}`, label: name, scope: name, ...common });
|
|
16434
|
+
}
|
|
16435
|
+
}
|
|
16436
|
+
return windows;
|
|
16437
|
+
}
|
|
16438
|
+
function windowsFromFlat(body) {
|
|
16439
|
+
const windows = [];
|
|
16440
|
+
const fiveHour = bucketWindow(body.five_hour, "session", "5h", "5h");
|
|
16441
|
+
if (fiveHour !== null) windows.push(fiveHour);
|
|
16442
|
+
const sevenDay = bucketWindow(body.seven_day, "weekly", "Weekly", "wk");
|
|
16443
|
+
if (sevenDay !== null) windows.push(sevenDay);
|
|
16444
|
+
return windows;
|
|
16445
|
+
}
|
|
16446
|
+
function bucketWindow(raw, key, label, short) {
|
|
16447
|
+
if (!isRecord(raw)) return null;
|
|
16448
|
+
const usedPct = asNumber(raw.utilization);
|
|
16449
|
+
if (usedPct === null) return null;
|
|
16450
|
+
return { key, label, short, usedPct, resetsAt: asIsoString(raw.resets_at) };
|
|
16451
|
+
}
|
|
16452
|
+
function scopeName(raw) {
|
|
16453
|
+
if (!isRecord(raw)) return null;
|
|
16454
|
+
const model = raw.model;
|
|
16455
|
+
if (!isRecord(model)) return null;
|
|
16456
|
+
const name = typeof model.display_name === "string" ? model.display_name.trim() : "";
|
|
16457
|
+
if (name.length === 0) return null;
|
|
16458
|
+
return slug(name) === "all-models" || slug(name) === "all" ? null : name;
|
|
16459
|
+
}
|
|
16460
|
+
function usageCredits(raw) {
|
|
16461
|
+
if (!isRecord(raw) || raw.enabled !== true) return null;
|
|
16462
|
+
const percent = asNumber(raw.percent);
|
|
16463
|
+
const limit = majorAmount(raw.limit);
|
|
16464
|
+
if (limit === null) {
|
|
16465
|
+
return percent === null ? null : { display: `${percent.toFixed(0)}% used`, usedPct: percent };
|
|
16466
|
+
}
|
|
16467
|
+
const used = majorAmount(raw.used);
|
|
16468
|
+
if (used === null) return null;
|
|
16469
|
+
const currency = isRecord(raw.limit) && typeof raw.limit.currency === "string" ? raw.limit.currency : "USD";
|
|
16470
|
+
const symbol = currency === "USD" ? "$" : "";
|
|
16471
|
+
const usedPct = percent ?? (limit > 0 ? used / limit * 100 : null);
|
|
16472
|
+
return { display: `${symbol}${used.toFixed(2)} / ${symbol}${limit.toFixed(2)}`, usedPct };
|
|
16473
|
+
}
|
|
16474
|
+
function majorAmount(raw) {
|
|
16475
|
+
if (!isRecord(raw)) return null;
|
|
16476
|
+
const minor = asNumber(raw.amount_minor);
|
|
16477
|
+
if (minor === null) return null;
|
|
16478
|
+
const exponent = asNumber(raw.exponent) ?? 0;
|
|
16479
|
+
return minor / 10 ** exponent;
|
|
16480
|
+
}
|
|
16481
|
+
function isRecord(value) {
|
|
16482
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16483
|
+
}
|
|
16484
|
+
function asNumber(value) {
|
|
16485
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
16486
|
+
if (typeof value === "string") {
|
|
16487
|
+
const parsed = Number.parseFloat(value.trim());
|
|
16488
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
16489
|
+
}
|
|
16490
|
+
return null;
|
|
16491
|
+
}
|
|
16492
|
+
function asIsoString(value) {
|
|
16493
|
+
if (typeof value !== "string" || value.trim().length === 0) return null;
|
|
16494
|
+
const parsed = new Date(value);
|
|
16495
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString();
|
|
16496
|
+
}
|
|
16497
|
+
function slug(value) {
|
|
16498
|
+
return value.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
|
|
16499
|
+
}
|
|
16500
|
+
function describeError2(error, timeoutMs) {
|
|
16501
|
+
if (error instanceof Error) {
|
|
16502
|
+
return error.name === "AbortError" ? `timeout after ${timeoutMs}ms` : error.message;
|
|
16503
|
+
}
|
|
16504
|
+
return String(error);
|
|
16505
|
+
}
|
|
16506
|
+
async function discardBody(response) {
|
|
16507
|
+
try {
|
|
16508
|
+
await response.body?.cancel();
|
|
16509
|
+
} catch {
|
|
16510
|
+
return;
|
|
16511
|
+
}
|
|
16512
|
+
}
|
|
16513
|
+
|
|
16514
|
+
// src/domains/quota/anthropic-max-provider.ts
|
|
16515
|
+
var ANTHROPIC_MAX_QUOTA_PROVIDER_ID = "anthropic-max";
|
|
16516
|
+
var AUTH_PROVIDER_ID = "anthropic";
|
|
16517
|
+
var DISPLAY_NAME = "Anthropic Max";
|
|
16518
|
+
var REQUEST_TIMEOUT_MS = 15e3;
|
|
16519
|
+
function parseStoredAnthropicCredential(raw) {
|
|
16520
|
+
if (!isRecord2(raw) || raw.type !== "oauth") return null;
|
|
16521
|
+
const access = raw.access;
|
|
16522
|
+
if (typeof access !== "string" || access.length === 0) return null;
|
|
16523
|
+
const refresh = raw.refresh;
|
|
16524
|
+
return {
|
|
16525
|
+
accessToken: access,
|
|
16526
|
+
expiresAtMs: asNumber2(raw.expires),
|
|
16527
|
+
hasRefreshToken: typeof refresh === "string" && refresh.length > 0
|
|
16528
|
+
};
|
|
16529
|
+
}
|
|
16530
|
+
async function readStoredCredential() {
|
|
16531
|
+
try {
|
|
16532
|
+
return parseStoredAnthropicCredential(openAuthStorage().get(AUTH_PROVIDER_ID));
|
|
16533
|
+
} catch {
|
|
16534
|
+
return null;
|
|
16535
|
+
}
|
|
16536
|
+
}
|
|
16537
|
+
function createAnthropicMaxQuotaProvider(options = {}) {
|
|
16538
|
+
const readCredentials = options.readCredentials ?? readStoredCredential;
|
|
16539
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
16540
|
+
const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS;
|
|
16541
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
16542
|
+
const snapshot = (status, message, extra = {}) => ({
|
|
16543
|
+
providerId: ANTHROPIC_MAX_QUOTA_PROVIDER_ID,
|
|
16544
|
+
displayName: DISPLAY_NAME,
|
|
16545
|
+
status,
|
|
16546
|
+
windows: [],
|
|
16547
|
+
message,
|
|
16548
|
+
fetchedAt: now().toISOString(),
|
|
16549
|
+
...extra
|
|
16550
|
+
});
|
|
16551
|
+
return {
|
|
16552
|
+
id: ANTHROPIC_MAX_QUOTA_PROVIDER_ID,
|
|
16553
|
+
displayName: DISPLAY_NAME,
|
|
16554
|
+
async detect() {
|
|
16555
|
+
return await readCredentials() !== null;
|
|
16556
|
+
},
|
|
16557
|
+
async fetch() {
|
|
16558
|
+
const credentials = await readCredentials();
|
|
16559
|
+
if (credentials === null) {
|
|
16560
|
+
return snapshot("no_credentials", "Clio holds no Anthropic OAuth credential");
|
|
16561
|
+
}
|
|
16562
|
+
if (credentials.expiresAtMs !== null && credentials.expiresAtMs <= now().getTime()) {
|
|
16563
|
+
return snapshot(
|
|
16564
|
+
"expired",
|
|
16565
|
+
credentials.hasRefreshToken ? "Clio's Anthropic token expired; the next turn refreshes it" : "Run clio-coder auth login anthropic again"
|
|
16566
|
+
);
|
|
16567
|
+
}
|
|
16568
|
+
const usage = await fetchAnthropicUsage(credentials.accessToken, { fetch: doFetch, timeoutMs });
|
|
16569
|
+
if (usage.status !== "ok") {
|
|
16570
|
+
return snapshot(usage.status, usage.message ?? "Run clio-coder auth login anthropic again", {
|
|
16571
|
+
retryAfterSeconds: usage.retryAfterSeconds
|
|
16572
|
+
});
|
|
16573
|
+
}
|
|
16574
|
+
return snapshot("ok", null, { windows: usage.windows, credits: usage.credits });
|
|
16575
|
+
}
|
|
16576
|
+
};
|
|
16577
|
+
}
|
|
16578
|
+
function isRecord2(value) {
|
|
16579
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16580
|
+
}
|
|
16581
|
+
function asNumber2(value) {
|
|
16582
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
16583
|
+
if (typeof value === "string") {
|
|
16584
|
+
const parsed = Number.parseFloat(value.trim());
|
|
16585
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
16586
|
+
}
|
|
16587
|
+
return null;
|
|
16588
|
+
}
|
|
16589
|
+
|
|
16590
|
+
// src/domains/quota/antigravity-provider.ts
|
|
16591
|
+
init_esm_shims();
|
|
16592
|
+
import { readFile } from "node:fs/promises";
|
|
16593
|
+
import { homedir as homedir2 } from "node:os";
|
|
16594
|
+
import { join } from "node:path";
|
|
16595
|
+
var ANTIGRAVITY_QUOTA_PROVIDER_ID = "antigravity";
|
|
16596
|
+
var DISPLAY_NAME2 = "Antigravity";
|
|
16597
|
+
var USER_AGENT = "antigravity";
|
|
16598
|
+
var REQUEST_TIMEOUT_MS2 = 2e4;
|
|
16599
|
+
var EXPIRY_SKEW_MS = 6e4;
|
|
16600
|
+
var WINDOW_ORDER2 = { session: 0, weekly: 1 };
|
|
16601
|
+
var MODEL_PREFIXES = ["gemini", "claude", "gpt", "image", "imagen"];
|
|
16602
|
+
var ENDPOINTS = [
|
|
16603
|
+
"https://daily-cloudcode-pa.googleapis.com",
|
|
16604
|
+
"https://daily-cloudcode-pa.sandbox.googleapis.com",
|
|
16605
|
+
"https://cloudcode-pa.googleapis.com"
|
|
16606
|
+
];
|
|
16607
|
+
function defaultCredentialsPath() {
|
|
16608
|
+
return join(homedir2(), ".gemini", "antigravity-cli", "antigravity-oauth-token");
|
|
16609
|
+
}
|
|
16610
|
+
function parseCredentials(raw) {
|
|
16611
|
+
if (!isRecord3(raw)) return null;
|
|
16612
|
+
const token = raw.token;
|
|
16613
|
+
if (!isRecord3(token)) return null;
|
|
16614
|
+
const accessToken = token.access_token;
|
|
16615
|
+
if (typeof accessToken !== "string" || accessToken.length === 0) return null;
|
|
16616
|
+
const refreshToken = token.refresh_token;
|
|
16617
|
+
return {
|
|
16618
|
+
accessToken,
|
|
16619
|
+
refreshToken: typeof refreshToken === "string" && refreshToken.length > 0 ? refreshToken : null,
|
|
16620
|
+
expiryMs: asEpochMs(token.expiry)
|
|
16621
|
+
};
|
|
16622
|
+
}
|
|
16623
|
+
async function readCredentialsFile(path) {
|
|
16624
|
+
let text;
|
|
16625
|
+
try {
|
|
16626
|
+
text = await readFile(path, "utf8");
|
|
16627
|
+
} catch {
|
|
16628
|
+
return null;
|
|
16629
|
+
}
|
|
16630
|
+
try {
|
|
16631
|
+
return parseCredentials(JSON.parse(text));
|
|
16632
|
+
} catch {
|
|
16633
|
+
return null;
|
|
16634
|
+
}
|
|
16635
|
+
}
|
|
16636
|
+
function createAntigravityQuotaProvider(options = {}) {
|
|
16637
|
+
const credentialsPath = options.credentialsPath ?? defaultCredentialsPath();
|
|
16638
|
+
const readCredentials = options.readCredentials ?? (() => readCredentialsFile(credentialsPath));
|
|
16639
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
16640
|
+
const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS2;
|
|
16641
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
16642
|
+
const snapshot = (status, message, extra = {}) => ({
|
|
16643
|
+
providerId: ANTIGRAVITY_QUOTA_PROVIDER_ID,
|
|
16644
|
+
displayName: DISPLAY_NAME2,
|
|
16645
|
+
status,
|
|
16646
|
+
windows: [],
|
|
16647
|
+
message,
|
|
16648
|
+
fetchedAt: now().toISOString(),
|
|
16649
|
+
...extra
|
|
16650
|
+
});
|
|
16651
|
+
const post = async (url, token, body) => {
|
|
16652
|
+
const controller = new AbortController();
|
|
16653
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
16654
|
+
let response;
|
|
16655
|
+
try {
|
|
16656
|
+
response = await doFetch(url, {
|
|
16657
|
+
method: "POST",
|
|
16658
|
+
headers: {
|
|
16659
|
+
Authorization: `Bearer ${token}`,
|
|
16660
|
+
"Content-Type": "application/json",
|
|
16661
|
+
"User-Agent": USER_AGENT
|
|
16662
|
+
},
|
|
16663
|
+
body: JSON.stringify(body),
|
|
16664
|
+
signal: controller.signal
|
|
16665
|
+
});
|
|
16666
|
+
} catch (error) {
|
|
16667
|
+
return { kind: "error", message: describeError3(error, timeoutMs) };
|
|
16668
|
+
} finally {
|
|
16669
|
+
clearTimeout(timer);
|
|
16670
|
+
}
|
|
16671
|
+
if (response.status === 401 || response.status === 403) {
|
|
16672
|
+
await discardBody2(response);
|
|
16673
|
+
return { kind: "auth" };
|
|
16674
|
+
}
|
|
16675
|
+
if (response.status !== 200) {
|
|
16676
|
+
await discardBody2(response);
|
|
16677
|
+
return { kind: "error", message: `HTTP ${response.status}` };
|
|
16678
|
+
}
|
|
16679
|
+
let data;
|
|
16680
|
+
try {
|
|
16681
|
+
data = await response.json();
|
|
16682
|
+
} catch {
|
|
16683
|
+
return { kind: "error", message: "Unexpected usage response" };
|
|
16684
|
+
}
|
|
16685
|
+
return isRecord3(data) ? { kind: "ok", data } : { kind: "error", message: "Unexpected usage response" };
|
|
16686
|
+
};
|
|
16687
|
+
const collect = async (base, token) => {
|
|
16688
|
+
const load = await post(`${base}/v1internal:loadCodeAssist`, token, { metadata: { ideType: "ANTIGRAVITY" } });
|
|
16689
|
+
if (load.kind !== "ok") return load;
|
|
16690
|
+
const project = typeof load.data.cloudaicompanionProject === "string" ? load.data.cloudaicompanionProject : null;
|
|
16691
|
+
const plan = tierPlan(load.data.currentTier);
|
|
16692
|
+
if (project !== null) {
|
|
16693
|
+
const summary = await post(`${base}/v1internal:retrieveUserQuotaSummary`, token, { project });
|
|
16694
|
+
if (summary.kind === "auth") return summary;
|
|
16695
|
+
if (summary.kind === "ok") {
|
|
16696
|
+
const windows = windowsFromSummary(summary.data);
|
|
16697
|
+
if (windows.length > 0) return { kind: "ok", windows, plan };
|
|
16698
|
+
}
|
|
16699
|
+
}
|
|
16700
|
+
const models = await post(`${base}/v1internal:fetchAvailableModels`, token, project === null ? {} : { project });
|
|
16701
|
+
if (models.kind !== "ok") return models;
|
|
16702
|
+
return { kind: "ok", windows: modelWindows(models.data), plan };
|
|
16703
|
+
};
|
|
16704
|
+
return {
|
|
16705
|
+
id: ANTIGRAVITY_QUOTA_PROVIDER_ID,
|
|
16706
|
+
displayName: DISPLAY_NAME2,
|
|
16707
|
+
async detect() {
|
|
16708
|
+
return await readCredentials() !== null;
|
|
16709
|
+
},
|
|
16710
|
+
async fetch() {
|
|
16711
|
+
const credentials = await readCredentials();
|
|
16712
|
+
if (credentials === null) {
|
|
16713
|
+
return snapshot("no_credentials", "No Antigravity credentials found");
|
|
16714
|
+
}
|
|
16715
|
+
if (credentials.expiryMs !== null && credentials.expiryMs <= now().getTime() + EXPIRY_SKEW_MS) {
|
|
16716
|
+
return snapshot("expired", "Antigravity's stored token expired; run the agy command once to refresh it");
|
|
16717
|
+
}
|
|
16718
|
+
let sawAuthFailure = false;
|
|
16719
|
+
let lastError = null;
|
|
16720
|
+
for (const base of ENDPOINTS) {
|
|
16721
|
+
const result = await collect(base, credentials.accessToken);
|
|
16722
|
+
if (result.kind === "auth") {
|
|
16723
|
+
sawAuthFailure = true;
|
|
16724
|
+
continue;
|
|
16725
|
+
}
|
|
16726
|
+
if (result.kind === "error") {
|
|
16727
|
+
lastError = result.message;
|
|
16728
|
+
continue;
|
|
16729
|
+
}
|
|
16730
|
+
if (result.windows.length > 0) {
|
|
16731
|
+
return snapshot("ok", null, { windows: result.windows, plan: result.plan });
|
|
16732
|
+
}
|
|
16733
|
+
}
|
|
16734
|
+
if (sawAuthFailure) return snapshot("expired", "Sign in with Antigravity again");
|
|
16735
|
+
if (lastError !== null) return snapshot("error", lastError);
|
|
16736
|
+
return snapshot("error", "Antigravity returned no quota");
|
|
16737
|
+
}
|
|
16738
|
+
};
|
|
16739
|
+
}
|
|
16740
|
+
function tierPlan(raw) {
|
|
16741
|
+
if (!isRecord3(raw)) return null;
|
|
16742
|
+
const plan = formatPlan(typeof raw.name === "string" ? raw.name : null);
|
|
16743
|
+
if (plan === null) return null;
|
|
16744
|
+
return plan.toLowerCase() === DISPLAY_NAME2.toLowerCase() ? null : plan;
|
|
16745
|
+
}
|
|
16746
|
+
function windowsFromSummary(data) {
|
|
16747
|
+
if (!Array.isArray(data.groups)) return [];
|
|
16748
|
+
const groups = data.groups.filter(isRecord3).sort((a, b) => Number(isGeminiGroup(b)) - Number(isGeminiGroup(a)));
|
|
16749
|
+
return groups.flatMap((group, index) => {
|
|
16750
|
+
const scope = typeof group.displayName === "string" && group.displayName.trim() ? group.displayName.trim() : `Model group ${index + 1}`;
|
|
16751
|
+
return windowsFromGroup(group).map((window) => ({
|
|
16752
|
+
...window,
|
|
16753
|
+
key: index === 0 ? window.key : `group.${index}.${window.key}`,
|
|
16754
|
+
scope
|
|
16755
|
+
}));
|
|
16112
16756
|
});
|
|
16113
|
-
|
|
16114
|
-
|
|
16115
|
-
|
|
16757
|
+
}
|
|
16758
|
+
function windowsFromGroup(group) {
|
|
16759
|
+
if (!Array.isArray(group.buckets)) return [];
|
|
16760
|
+
const windows = [];
|
|
16761
|
+
for (const bucket of group.buckets) {
|
|
16762
|
+
if (!isRecord3(bucket)) continue;
|
|
16763
|
+
const window = typeof bucket.window === "string" ? bucket.window.toLowerCase() : null;
|
|
16764
|
+
const usedPct = usedFromRemaining(bucket.remainingFraction);
|
|
16765
|
+
if (usedPct === null) continue;
|
|
16766
|
+
if (window === "5h") {
|
|
16767
|
+
windows.push({ key: "session", label: "5h", short: "5h", usedPct, resetsAt: asIsoString2(bucket.resetTime) });
|
|
16768
|
+
} else if (window === "weekly") {
|
|
16769
|
+
windows.push({ key: "weekly", label: "Weekly", short: "wk", usedPct, resetsAt: asIsoString2(bucket.resetTime) });
|
|
16770
|
+
}
|
|
16771
|
+
}
|
|
16772
|
+
return windows.sort((left, right) => (WINDOW_ORDER2[left.key] ?? 2) - (WINDOW_ORDER2[right.key] ?? 2));
|
|
16773
|
+
}
|
|
16774
|
+
function isGeminiGroup(group) {
|
|
16775
|
+
if (mentionsGemini(group.displayName) || mentionsGemini(group.description)) return true;
|
|
16776
|
+
if (!Array.isArray(group.buckets)) return false;
|
|
16777
|
+
return group.buckets.some((bucket) => {
|
|
16778
|
+
if (!isRecord3(bucket)) return false;
|
|
16779
|
+
const id = typeof bucket.bucketId === "string" ? bucket.bucketId.toLowerCase() : "";
|
|
16780
|
+
return id.startsWith("gemini-") || mentionsGemini(bucket.displayName);
|
|
16116
16781
|
});
|
|
16117
|
-
return controller;
|
|
16118
16782
|
}
|
|
16119
|
-
function
|
|
16120
|
-
|
|
16121
|
-
|
|
16122
|
-
|
|
16123
|
-
if (
|
|
16124
|
-
|
|
16783
|
+
function mentionsGemini(value) {
|
|
16784
|
+
return typeof value === "string" && value.toLowerCase().includes("gemini");
|
|
16785
|
+
}
|
|
16786
|
+
function modelWindows(data) {
|
|
16787
|
+
if (!isRecord3(data.models)) return [];
|
|
16788
|
+
const windows = [];
|
|
16789
|
+
for (const [name, info] of Object.entries(data.models)) {
|
|
16790
|
+
if (!isRecord3(info) || !isRecord3(info.quotaInfo)) continue;
|
|
16791
|
+
if (!MODEL_PREFIXES.some((prefix) => name.toLowerCase().startsWith(prefix))) continue;
|
|
16792
|
+
const usedPct = usedFromRemaining(info.quotaInfo.remainingFraction);
|
|
16793
|
+
if (usedPct === null) continue;
|
|
16794
|
+
windows.push({
|
|
16795
|
+
key: `model.${name}`,
|
|
16796
|
+
label: "Model quota",
|
|
16797
|
+
short: name,
|
|
16798
|
+
scope: name,
|
|
16799
|
+
usedPct,
|
|
16800
|
+
resetsAt: asIsoString2(info.quotaInfo.resetTime)
|
|
16801
|
+
});
|
|
16125
16802
|
}
|
|
16126
|
-
|
|
16127
|
-
return "editor";
|
|
16803
|
+
return windows;
|
|
16128
16804
|
}
|
|
16129
|
-
function
|
|
16130
|
-
const
|
|
16131
|
-
|
|
16132
|
-
|
|
16133
|
-
|
|
16134
|
-
|
|
16135
|
-
|
|
16136
|
-
|
|
16137
|
-
|
|
16138
|
-
|
|
16139
|
-
|
|
16140
|
-
|
|
16141
|
-
|
|
16142
|
-
|
|
16143
|
-
|
|
16144
|
-
|
|
16145
|
-
|
|
16146
|
-
|
|
16147
|
-
|
|
16148
|
-
|
|
16149
|
-
|
|
16150
|
-
|
|
16151
|
-
|
|
16152
|
-
|
|
16153
|
-
|
|
16154
|
-
|
|
16155
|
-
|
|
16156
|
-
|
|
16805
|
+
function usedFromRemaining(raw) {
|
|
16806
|
+
const remaining = asNumber3(raw);
|
|
16807
|
+
if (remaining === null) return null;
|
|
16808
|
+
return (1 - Math.min(1, Math.max(0, remaining))) * 100;
|
|
16809
|
+
}
|
|
16810
|
+
function isRecord3(value) {
|
|
16811
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16812
|
+
}
|
|
16813
|
+
function asNumber3(value) {
|
|
16814
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
16815
|
+
if (typeof value === "string") {
|
|
16816
|
+
const parsed = Number.parseFloat(value.trim());
|
|
16817
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
16818
|
+
}
|
|
16819
|
+
return null;
|
|
16820
|
+
}
|
|
16821
|
+
function asIsoString2(value) {
|
|
16822
|
+
if (typeof value !== "string" || value.trim().length === 0) return null;
|
|
16823
|
+
const parsed = new Date(value);
|
|
16824
|
+
return Number.isNaN(parsed.getTime()) ? null : parsed.toISOString();
|
|
16825
|
+
}
|
|
16826
|
+
function asEpochMs(value) {
|
|
16827
|
+
if (typeof value !== "string" || value.trim().length === 0) return null;
|
|
16828
|
+
const parsed = Date.parse(value);
|
|
16829
|
+
return Number.isNaN(parsed) ? null : parsed;
|
|
16830
|
+
}
|
|
16831
|
+
function describeError3(error, timeoutMs) {
|
|
16832
|
+
if (error instanceof Error) {
|
|
16833
|
+
return error.name === "AbortError" ? `timeout after ${timeoutMs}ms` : error.message;
|
|
16834
|
+
}
|
|
16835
|
+
return String(error);
|
|
16836
|
+
}
|
|
16837
|
+
async function discardBody2(response) {
|
|
16838
|
+
try {
|
|
16839
|
+
await response.body?.cancel();
|
|
16840
|
+
} catch {
|
|
16841
|
+
return;
|
|
16842
|
+
}
|
|
16843
|
+
}
|
|
16844
|
+
|
|
16845
|
+
// src/domains/quota/claude-code-provider.ts
|
|
16846
|
+
init_esm_shims();
|
|
16847
|
+
import { readFile as readFile2 } from "node:fs/promises";
|
|
16848
|
+
import { homedir as homedir3 } from "node:os";
|
|
16849
|
+
import { join as join2 } from "node:path";
|
|
16850
|
+
var CLAUDE_CODE_QUOTA_PROVIDER_ID = "claude-code";
|
|
16851
|
+
var DISPLAY_NAME3 = "Claude Code";
|
|
16852
|
+
var REQUEST_TIMEOUT_MS3 = 15e3;
|
|
16853
|
+
function defaultClaudeCredentialsPath() {
|
|
16854
|
+
return join2(homedir3(), ".claude", ".credentials.json");
|
|
16855
|
+
}
|
|
16856
|
+
function parseClaudeCredentials(raw) {
|
|
16857
|
+
if (!isRecord4(raw)) return null;
|
|
16858
|
+
const oauth = raw.claudeAiOauth;
|
|
16859
|
+
if (!isRecord4(oauth)) return null;
|
|
16860
|
+
const token = oauth.accessToken;
|
|
16861
|
+
if (typeof token !== "string" || token.length === 0) return null;
|
|
16862
|
+
const subscription = oauth.subscriptionType;
|
|
16863
|
+
const refreshToken = oauth.refreshToken;
|
|
16864
|
+
return {
|
|
16865
|
+
accessToken: token,
|
|
16866
|
+
subscriptionType: typeof subscription === "string" ? subscription : null,
|
|
16867
|
+
expiresAtMs: asNumber4(oauth.expiresAt),
|
|
16868
|
+
refreshTokenExpiresAtMs: asNumber4(oauth.refreshTokenExpiresAt),
|
|
16869
|
+
hasRefreshToken: typeof refreshToken === "string" && refreshToken.length > 0
|
|
16157
16870
|
};
|
|
16158
|
-
|
|
16871
|
+
}
|
|
16872
|
+
function expiryMessage(credentials, nowMs) {
|
|
16873
|
+
const { expiresAtMs, refreshTokenExpiresAtMs, hasRefreshToken } = credentials;
|
|
16874
|
+
if (expiresAtMs === null || expiresAtMs > nowMs) return null;
|
|
16875
|
+
const refreshUsable = hasRefreshToken && (refreshTokenExpiresAtMs === null || refreshTokenExpiresAtMs > nowMs);
|
|
16876
|
+
return refreshUsable ? "Claude Code's stored token expired; run the claude command once to refresh it" : "Sign in with Claude Code again";
|
|
16877
|
+
}
|
|
16878
|
+
async function readCredentialsFile2(path) {
|
|
16879
|
+
let text;
|
|
16880
|
+
try {
|
|
16881
|
+
text = await readFile2(path, "utf8");
|
|
16882
|
+
} catch {
|
|
16883
|
+
return null;
|
|
16884
|
+
}
|
|
16885
|
+
try {
|
|
16886
|
+
return parseClaudeCredentials(JSON.parse(text));
|
|
16887
|
+
} catch {
|
|
16888
|
+
return null;
|
|
16889
|
+
}
|
|
16890
|
+
}
|
|
16891
|
+
function createClaudeCodeQuotaProvider(options = {}) {
|
|
16892
|
+
const credentialsPath = options.credentialsPath ?? defaultClaudeCredentialsPath();
|
|
16893
|
+
const readCredentials = options.readCredentials ?? (() => readCredentialsFile2(credentialsPath));
|
|
16894
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
16895
|
+
const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS3;
|
|
16896
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
16897
|
+
const snapshot = (status, message, extra = {}) => ({
|
|
16898
|
+
providerId: CLAUDE_CODE_QUOTA_PROVIDER_ID,
|
|
16899
|
+
displayName: DISPLAY_NAME3,
|
|
16900
|
+
status,
|
|
16901
|
+
windows: [],
|
|
16902
|
+
message,
|
|
16903
|
+
fetchedAt: now().toISOString(),
|
|
16904
|
+
...extra
|
|
16905
|
+
});
|
|
16906
|
+
return {
|
|
16907
|
+
id: CLAUDE_CODE_QUOTA_PROVIDER_ID,
|
|
16908
|
+
displayName: DISPLAY_NAME3,
|
|
16909
|
+
async detect() {
|
|
16910
|
+
return await readCredentials() !== null;
|
|
16911
|
+
},
|
|
16912
|
+
async fetch() {
|
|
16913
|
+
const credentials = await readCredentials();
|
|
16914
|
+
if (credentials === null) {
|
|
16915
|
+
return snapshot("no_credentials", "No Claude Code credentials found");
|
|
16916
|
+
}
|
|
16917
|
+
const expired = expiryMessage(credentials, now().getTime());
|
|
16918
|
+
if (expired !== null) {
|
|
16919
|
+
return snapshot("expired", expired);
|
|
16920
|
+
}
|
|
16921
|
+
const usage = await fetchAnthropicUsage(credentials.accessToken, { fetch: doFetch, timeoutMs });
|
|
16922
|
+
if (usage.status !== "ok") {
|
|
16923
|
+
return snapshot(usage.status, usage.message ?? "Sign in with Claude Code again", {
|
|
16924
|
+
retryAfterSeconds: usage.retryAfterSeconds
|
|
16925
|
+
});
|
|
16926
|
+
}
|
|
16927
|
+
return snapshot("ok", null, {
|
|
16928
|
+
windows: usage.windows,
|
|
16929
|
+
credits: usage.credits,
|
|
16930
|
+
plan: formatPlan(credentials.subscriptionType)
|
|
16931
|
+
});
|
|
16932
|
+
}
|
|
16933
|
+
};
|
|
16934
|
+
}
|
|
16935
|
+
function isRecord4(value) {
|
|
16936
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
16937
|
+
}
|
|
16938
|
+
function asNumber4(value) {
|
|
16939
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
16940
|
+
if (typeof value === "string") {
|
|
16941
|
+
const parsed = Number.parseFloat(value.trim());
|
|
16942
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
16943
|
+
}
|
|
16944
|
+
return null;
|
|
16159
16945
|
}
|
|
16160
16946
|
|
|
16161
|
-
// src/
|
|
16947
|
+
// src/domains/quota/codex-provider.ts
|
|
16162
16948
|
init_esm_shims();
|
|
16163
|
-
import {
|
|
16949
|
+
import { readFile as readFile3 } from "node:fs/promises";
|
|
16950
|
+
import { homedir as homedir4 } from "node:os";
|
|
16951
|
+
import { join as join3 } from "node:path";
|
|
16952
|
+
var CODEX_QUOTA_PROVIDER_ID = "codex";
|
|
16953
|
+
var CODEX_USAGE_URL = "https://chatgpt.com/backend-api/wham/usage";
|
|
16954
|
+
var DISPLAY_NAME4 = "Codex";
|
|
16955
|
+
var REQUEST_TIMEOUT_MS4 = 15e3;
|
|
16956
|
+
var WINDOW_ORDER3 = { session: 0, weekly: 1 };
|
|
16957
|
+
var WEEKLY_THRESHOLD_SECONDS = 86400;
|
|
16958
|
+
function defaultCodexCredentialsPath() {
|
|
16959
|
+
const codexHome = process.env.CODEX_HOME;
|
|
16960
|
+
return codexHome ? join3(codexHome, "auth.json") : join3(homedir4(), ".codex", "auth.json");
|
|
16961
|
+
}
|
|
16962
|
+
function parseCodexCredentials(raw) {
|
|
16963
|
+
if (!isRecord5(raw)) return null;
|
|
16964
|
+
const tokens = raw.tokens;
|
|
16965
|
+
if (!isRecord5(tokens)) return null;
|
|
16966
|
+
const accessToken = tokens.access_token;
|
|
16967
|
+
if (typeof accessToken !== "string" || accessToken.length === 0) return null;
|
|
16968
|
+
const accountId = tokens.account_id;
|
|
16969
|
+
return {
|
|
16970
|
+
accessToken,
|
|
16971
|
+
accountId: typeof accountId === "string" ? accountId : null
|
|
16972
|
+
};
|
|
16973
|
+
}
|
|
16974
|
+
async function readCredentialsFile3(path) {
|
|
16975
|
+
let text;
|
|
16976
|
+
try {
|
|
16977
|
+
text = await readFile3(path, "utf8");
|
|
16978
|
+
} catch {
|
|
16979
|
+
return null;
|
|
16980
|
+
}
|
|
16981
|
+
try {
|
|
16982
|
+
return parseCodexCredentials(JSON.parse(text));
|
|
16983
|
+
} catch {
|
|
16984
|
+
return null;
|
|
16985
|
+
}
|
|
16986
|
+
}
|
|
16987
|
+
function createCodexQuotaProvider(options = {}) {
|
|
16988
|
+
const credentialsPath = options.credentialsPath ?? defaultCodexCredentialsPath();
|
|
16989
|
+
const readCredentials = options.readCredentials ?? (() => readCredentialsFile3(credentialsPath));
|
|
16990
|
+
const doFetch = options.fetch ?? globalThis.fetch;
|
|
16991
|
+
const timeoutMs = options.timeoutMs ?? REQUEST_TIMEOUT_MS4;
|
|
16992
|
+
const now = options.now ?? (() => /* @__PURE__ */ new Date());
|
|
16993
|
+
const snapshot = (status, message, extra = {}) => ({
|
|
16994
|
+
providerId: CODEX_QUOTA_PROVIDER_ID,
|
|
16995
|
+
displayName: DISPLAY_NAME4,
|
|
16996
|
+
status,
|
|
16997
|
+
windows: [],
|
|
16998
|
+
message,
|
|
16999
|
+
fetchedAt: now().toISOString(),
|
|
17000
|
+
...extra
|
|
17001
|
+
});
|
|
17002
|
+
return {
|
|
17003
|
+
id: CODEX_QUOTA_PROVIDER_ID,
|
|
17004
|
+
displayName: DISPLAY_NAME4,
|
|
17005
|
+
async detect() {
|
|
17006
|
+
return await readCredentials() !== null;
|
|
17007
|
+
},
|
|
17008
|
+
async fetch() {
|
|
17009
|
+
const credentials = await readCredentials();
|
|
17010
|
+
if (credentials === null) {
|
|
17011
|
+
return snapshot("no_credentials", "No Codex credentials found");
|
|
17012
|
+
}
|
|
17013
|
+
const headers = {
|
|
17014
|
+
Authorization: `Bearer ${credentials.accessToken}`,
|
|
17015
|
+
"User-Agent": "codex-cli"
|
|
17016
|
+
};
|
|
17017
|
+
if (credentials.accountId !== null) {
|
|
17018
|
+
headers["ChatGPT-Account-Id"] = credentials.accountId;
|
|
17019
|
+
}
|
|
17020
|
+
const controller = new AbortController();
|
|
17021
|
+
const timer = setTimeout(() => controller.abort(), timeoutMs);
|
|
17022
|
+
let response;
|
|
17023
|
+
try {
|
|
17024
|
+
response = await doFetch(CODEX_USAGE_URL, {
|
|
17025
|
+
method: "GET",
|
|
17026
|
+
headers,
|
|
17027
|
+
signal: controller.signal
|
|
17028
|
+
});
|
|
17029
|
+
} catch (error) {
|
|
17030
|
+
return snapshot("error", describeError4(error, timeoutMs));
|
|
17031
|
+
} finally {
|
|
17032
|
+
clearTimeout(timer);
|
|
17033
|
+
}
|
|
17034
|
+
if (response.status === 401 || response.status === 403) {
|
|
17035
|
+
await discardBody3(response);
|
|
17036
|
+
return snapshot("expired", "Sign in with Codex again");
|
|
17037
|
+
}
|
|
17038
|
+
if (response.status !== 200) {
|
|
17039
|
+
await discardBody3(response);
|
|
17040
|
+
return snapshot("error", `HTTP ${response.status}`);
|
|
17041
|
+
}
|
|
17042
|
+
let body;
|
|
17043
|
+
try {
|
|
17044
|
+
body = await response.json();
|
|
17045
|
+
} catch {
|
|
17046
|
+
return snapshot("error", "Unexpected usage response");
|
|
17047
|
+
}
|
|
17048
|
+
if (!isRecord5(body)) {
|
|
17049
|
+
return snapshot("error", "Unexpected usage response");
|
|
17050
|
+
}
|
|
17051
|
+
const planType = typeof body.plan_type === "string" ? body.plan_type : null;
|
|
17052
|
+
return snapshot("ok", null, {
|
|
17053
|
+
windows: usageWindows2(body.rate_limit),
|
|
17054
|
+
credits: usageCredits2(body.credits),
|
|
17055
|
+
plan: formatPlan(planType)
|
|
17056
|
+
});
|
|
17057
|
+
}
|
|
17058
|
+
};
|
|
17059
|
+
}
|
|
17060
|
+
function usageWindows2(raw) {
|
|
17061
|
+
if (!isRecord5(raw)) return [];
|
|
17062
|
+
const windows = [];
|
|
17063
|
+
const primary = buildWindow(raw.primary_window, "session");
|
|
17064
|
+
if (primary !== null) windows.push(primary);
|
|
17065
|
+
const secondary = buildWindow(raw.secondary_window, "weekly");
|
|
17066
|
+
if (secondary !== null) windows.push(secondary);
|
|
17067
|
+
return windows.sort((left, right) => {
|
|
17068
|
+
const order = (WINDOW_ORDER3[left.key] ?? 2) - (WINDOW_ORDER3[right.key] ?? 2);
|
|
17069
|
+
return order !== 0 ? order : left.label.localeCompare(right.label);
|
|
17070
|
+
});
|
|
17071
|
+
}
|
|
17072
|
+
function buildWindow(raw, defaultKey) {
|
|
17073
|
+
if (!isRecord5(raw)) return null;
|
|
17074
|
+
const usedPct = asNumber5(raw.used_percent);
|
|
17075
|
+
if (usedPct === null) return null;
|
|
17076
|
+
const key = windowKey(raw.limit_window_seconds, defaultKey);
|
|
17077
|
+
const label = key === "weekly" ? "Weekly" : "5h";
|
|
17078
|
+
const short = key === "weekly" ? "wk" : "5h";
|
|
17079
|
+
return { key, label, short, usedPct, resetsAt: epochSecondsToIso(raw.reset_at) };
|
|
17080
|
+
}
|
|
17081
|
+
function windowKey(limitWindowSeconds, defaultKey) {
|
|
17082
|
+
const seconds = asNumber5(limitWindowSeconds);
|
|
17083
|
+
if (seconds === null) return defaultKey;
|
|
17084
|
+
return seconds >= WEEKLY_THRESHOLD_SECONDS ? "weekly" : "session";
|
|
17085
|
+
}
|
|
17086
|
+
function usageCredits2(raw) {
|
|
17087
|
+
if (!isRecord5(raw)) return null;
|
|
17088
|
+
if (raw.unlimited === true) return { display: "Unlimited", usedPct: null };
|
|
17089
|
+
if (raw.has_credits === true && typeof raw.balance === "string" && raw.balance.length > 0) {
|
|
17090
|
+
return { display: raw.balance, usedPct: null };
|
|
17091
|
+
}
|
|
17092
|
+
return null;
|
|
17093
|
+
}
|
|
17094
|
+
function isRecord5(value) {
|
|
17095
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17096
|
+
}
|
|
17097
|
+
function asNumber5(value) {
|
|
17098
|
+
if (typeof value === "number") return Number.isFinite(value) ? value : null;
|
|
17099
|
+
if (typeof value === "string") {
|
|
17100
|
+
const parsed = Number.parseFloat(value.trim());
|
|
17101
|
+
return Number.isFinite(parsed) ? parsed : null;
|
|
17102
|
+
}
|
|
17103
|
+
return null;
|
|
17104
|
+
}
|
|
17105
|
+
function epochSecondsToIso(value) {
|
|
17106
|
+
const seconds = asNumber5(value);
|
|
17107
|
+
if (seconds === null) return null;
|
|
17108
|
+
const date = new Date(seconds * 1e3);
|
|
17109
|
+
return Number.isNaN(date.getTime()) ? null : date.toISOString();
|
|
17110
|
+
}
|
|
17111
|
+
function describeError4(error, timeoutMs) {
|
|
17112
|
+
if (error instanceof Error) {
|
|
17113
|
+
return error.name === "AbortError" ? `timeout after ${timeoutMs}ms` : error.message;
|
|
17114
|
+
}
|
|
17115
|
+
return String(error);
|
|
17116
|
+
}
|
|
17117
|
+
async function discardBody3(response) {
|
|
17118
|
+
try {
|
|
17119
|
+
await response.body?.cancel();
|
|
17120
|
+
} catch {
|
|
17121
|
+
return;
|
|
17122
|
+
}
|
|
17123
|
+
}
|
|
17124
|
+
|
|
17125
|
+
// src/domains/quota/registry.ts
|
|
17126
|
+
function buildQuotaProviders() {
|
|
17127
|
+
return [
|
|
17128
|
+
createAnthropicMaxQuotaProvider(),
|
|
17129
|
+
createClaudeCodeQuotaProvider(),
|
|
17130
|
+
createCodexQuotaProvider(),
|
|
17131
|
+
createAntigravityQuotaProvider()
|
|
17132
|
+
// The copilot adapter attaches here once its credential shape is confirmed.
|
|
17133
|
+
];
|
|
17134
|
+
}
|
|
17135
|
+
|
|
17136
|
+
// src/domains/quota/service.ts
|
|
17137
|
+
function createQuotaService(options = {}) {
|
|
17138
|
+
const providers = options.providers ?? buildQuotaProviders();
|
|
17139
|
+
const cache = options.cache ?? createQuotaCache({ ttlMs: options.ttlMs ?? DEFAULT_QUOTA_CACHE_TTL_MS });
|
|
17140
|
+
const includeLocal = options.includeLocal ?? true;
|
|
17141
|
+
const withLocal = (snapshots) => {
|
|
17142
|
+
if (!includeLocal) return snapshots;
|
|
17143
|
+
const local = options.localRuntimeLabel ? localQuotaSnapshot({ runtimeLabel: options.localRuntimeLabel }) : localQuotaSnapshot();
|
|
17144
|
+
return [...snapshots, local];
|
|
17145
|
+
};
|
|
17146
|
+
return {
|
|
17147
|
+
peek() {
|
|
17148
|
+
const cached = [];
|
|
17149
|
+
for (const provider of providers) {
|
|
17150
|
+
const snapshot = cache.readLastGood(provider.id);
|
|
17151
|
+
if (snapshot !== null) cached.push(snapshot);
|
|
17152
|
+
}
|
|
17153
|
+
return withLocal(cached);
|
|
17154
|
+
},
|
|
17155
|
+
async read() {
|
|
17156
|
+
const settled = await Promise.all(
|
|
17157
|
+
providers.map(async (provider) => {
|
|
17158
|
+
try {
|
|
17159
|
+
return await cache.resolve(provider);
|
|
17160
|
+
} catch (error) {
|
|
17161
|
+
return {
|
|
17162
|
+
providerId: provider.id,
|
|
17163
|
+
displayName: provider.displayName,
|
|
17164
|
+
status: "error",
|
|
17165
|
+
windows: [],
|
|
17166
|
+
message: error instanceof Error ? error.message : String(error),
|
|
17167
|
+
fetchedAt: null
|
|
17168
|
+
};
|
|
17169
|
+
}
|
|
17170
|
+
})
|
|
17171
|
+
);
|
|
17172
|
+
return withLocal(settled.filter((snapshot) => snapshot.status !== "no_credentials"));
|
|
17173
|
+
},
|
|
17174
|
+
async detected() {
|
|
17175
|
+
const flags = await Promise.all(
|
|
17176
|
+
providers.map(async (provider) => {
|
|
17177
|
+
try {
|
|
17178
|
+
return await provider.detect();
|
|
17179
|
+
} catch {
|
|
17180
|
+
return false;
|
|
17181
|
+
}
|
|
17182
|
+
})
|
|
17183
|
+
);
|
|
17184
|
+
return providers.filter((_, index) => flags[index] === true);
|
|
17185
|
+
}
|
|
17186
|
+
};
|
|
17187
|
+
}
|
|
17188
|
+
|
|
17189
|
+
// src/domains/quota/summary-feed.ts
|
|
17190
|
+
var QUOTA_SUMMARY_TTL_MS = 5 * 6e4;
|
|
17191
|
+
function createQuotaSummaryFeed(options = {}) {
|
|
17192
|
+
const service = options.service ?? createQuotaService();
|
|
17193
|
+
const ttlMs = options.ttlMs ?? QUOTA_SUMMARY_TTL_MS;
|
|
17194
|
+
const now = options.now ?? Date.now;
|
|
17195
|
+
let line = null;
|
|
17196
|
+
let snapshots = [];
|
|
17197
|
+
let readAt = null;
|
|
17198
|
+
let inFlight = false;
|
|
17199
|
+
let disposed = false;
|
|
17200
|
+
const refresh = () => {
|
|
17201
|
+
if (inFlight || disposed) return;
|
|
17202
|
+
inFlight = true;
|
|
17203
|
+
void Promise.resolve().then(() => disposed ? snapshots : service.read()).then((nextSnapshots) => {
|
|
17204
|
+
if (disposed) return;
|
|
17205
|
+
const next = quotaSummaryLine(nextSnapshots);
|
|
17206
|
+
const changed = JSON.stringify(nextSnapshots) !== JSON.stringify(snapshots);
|
|
17207
|
+
snapshots = nextSnapshots;
|
|
17208
|
+
readAt = now();
|
|
17209
|
+
if (changed) {
|
|
17210
|
+
line = next;
|
|
17211
|
+
options.onUpdate?.();
|
|
17212
|
+
}
|
|
17213
|
+
}).catch(() => {
|
|
17214
|
+
readAt = now();
|
|
17215
|
+
}).finally(() => {
|
|
17216
|
+
inFlight = false;
|
|
17217
|
+
});
|
|
17218
|
+
};
|
|
17219
|
+
return {
|
|
17220
|
+
peek() {
|
|
17221
|
+
if (!disposed && (readAt === null || now() - readAt >= ttlMs)) refresh();
|
|
17222
|
+
return line;
|
|
17223
|
+
},
|
|
17224
|
+
peekSnapshots() {
|
|
17225
|
+
if (!disposed && (readAt === null || now() - readAt >= ttlMs)) refresh();
|
|
17226
|
+
return snapshots;
|
|
17227
|
+
},
|
|
17228
|
+
dispose() {
|
|
17229
|
+
disposed = true;
|
|
17230
|
+
}
|
|
17231
|
+
};
|
|
17232
|
+
}
|
|
16164
17233
|
|
|
16165
17234
|
// src/interactive/chat-panel.ts
|
|
16166
17235
|
init_esm_shims();
|
|
@@ -16515,8 +17584,8 @@ function isMermaid(token) {
|
|
|
16515
17584
|
}
|
|
16516
17585
|
function codeSpan(line) {
|
|
16517
17586
|
const content = line || "\xA0";
|
|
16518
|
-
const
|
|
16519
|
-
const fence = "`".repeat(
|
|
17587
|
+
const longestBacktickRun2 = Math.max(0, ...Array.from(content.matchAll(/`+/g), (match) => match[0].length));
|
|
17588
|
+
const fence = "`".repeat(longestBacktickRun2 + 1);
|
|
16520
17589
|
const padding = content.startsWith("`") || content.endsWith("`") ? " " : "";
|
|
16521
17590
|
return `${fence}${padding}${content}${padding}${fence}`;
|
|
16522
17591
|
}
|
|
@@ -18041,8 +19110,8 @@ function footerKeyHint(now, narrow = false) {
|
|
|
18041
19110
|
})
|
|
18042
19111
|
];
|
|
18043
19112
|
const count = narrow ? 1 : 2;
|
|
18044
|
-
|
|
18045
|
-
|
|
19113
|
+
if (!entries.length) return null;
|
|
19114
|
+
const page = Math.floor(now / 12e3) % Math.ceil(entries.length / count);
|
|
18046
19115
|
const start = page * count;
|
|
18047
19116
|
return entries.slice(start, start + count).join(" \xB7 ");
|
|
18048
19117
|
}
|
|
@@ -18051,7 +19120,7 @@ function footerKeyHint(now, narrow = false) {
|
|
|
18051
19120
|
var DASHBOARD_PAGES = ["Activity", "Context", "Status"];
|
|
18052
19121
|
var ACTIVE_AGENT_STATUSES = /* @__PURE__ */ new Set(["running", "enqueued", "cancelling", "retrying", "stale"]);
|
|
18053
19122
|
var clean = (value) => sanitizeCallTargetText(redactSecretString(value));
|
|
18054
|
-
function agentCard(row2, width, compact = false) {
|
|
19123
|
+
function agentCard(row2, width, compact = false, quota = []) {
|
|
18055
19124
|
const theme2 = clioTheme();
|
|
18056
19125
|
const presentation = dispatchStatusPresentation(row2.status, { compact: false });
|
|
18057
19126
|
const name = clean(row2.agentId).replace(
|
|
@@ -18066,6 +19135,9 @@ function agentCard(row2, width, compact = false) {
|
|
|
18066
19135
|
);
|
|
18067
19136
|
const field = (label, value) => wrapTextWithAnsi(`${theme2.fg("dim", `${label} `)}${clean(value)}`, width);
|
|
18068
19137
|
lines.push(...previewRows(field("Route", `${row2.targetId}/${row2.wireModelId}`), 2, width));
|
|
19138
|
+
const weekly = routeWeeklyQuota(row2, quota);
|
|
19139
|
+
if (weekly)
|
|
19140
|
+
lines.push(...previewRows(field("Account", `Shared ${weekly.account} \xB7 ${weekly.label}`), compact ? 1 : 2, width));
|
|
18069
19141
|
if (row2.taskSummary)
|
|
18070
19142
|
lines.push(...compact ? previewRows(field("Task", row2.taskSummary), 2, width) : field("Task", row2.taskSummary));
|
|
18071
19143
|
const activity = renderDispatchActivity(row2, width);
|
|
@@ -18136,8 +19208,8 @@ function activityPage(state, width, budget) {
|
|
|
18136
19208
|
if (first && second) {
|
|
18137
19209
|
cards.push(
|
|
18138
19210
|
...zipColumns(
|
|
18139
|
-
agentCard(first, col, true),
|
|
18140
|
-
agentCard(second, width - col - 5, true),
|
|
19211
|
+
agentCard(first, col, true, state.quota),
|
|
19212
|
+
agentCard(second, width - col - 5, true, state.quota),
|
|
18141
19213
|
col,
|
|
18142
19214
|
width - col - 5,
|
|
18143
19215
|
` ${theme2.fg("frame", "\u2502")} `
|
|
@@ -18148,7 +19220,7 @@ function activityPage(state, width, budget) {
|
|
|
18148
19220
|
}
|
|
18149
19221
|
} else
|
|
18150
19222
|
for (const row2 of active) {
|
|
18151
|
-
const card = agentCard(row2, width, active.length > 1 || cardBudget < 18);
|
|
19223
|
+
const card = agentCard(row2, width, active.length > 1 || cardBudget < 18, state.quota);
|
|
18152
19224
|
if (cards.length + card.length + 2 > cardBudget && shown > 0) break;
|
|
18153
19225
|
cards.push(...card, "");
|
|
18154
19226
|
shown++;
|
|
@@ -18198,16 +19270,17 @@ function contextPage(state, width) {
|
|
|
18198
19270
|
...wrapTextWithAnsi(
|
|
18199
19271
|
theme2.style(
|
|
18200
19272
|
"accent",
|
|
18201
|
-
`${formatFooterTokens(ledger.usedTokens)} / ${ledger.contextWindow > 0 ? formatFooterTokens(ledger.contextWindow) : "unknown window"} tokens${ledger.percent === null ? "" : ` \xB7 ${ledger.percent.toFixed(1)}% occupied`}`,
|
|
19273
|
+
state.context.budget ? `${contextUsageText(state.context)} tokens` : `${formatFooterTokens(ledger.usedTokens)} / ${ledger.contextWindow > 0 ? formatFooterTokens(ledger.contextWindow) : "unknown window"} tokens${ledger.percent === null ? "" : ` \xB7 ${ledger.percent.toFixed(1)}% occupied`}`,
|
|
18202
19274
|
{ bold: true }
|
|
18203
19275
|
),
|
|
18204
19276
|
width
|
|
18205
19277
|
),
|
|
18206
19278
|
...wrapTextWithAnsi(
|
|
18207
|
-
|
|
19279
|
+
`${state.context.budget ? "Capture diagnostics: " : ""}Free ${ledger.contextWindow > 0 ? formatFooterTokens(ledger.freeTokens) : "unknown"} \xB7 reserved ${formatFooterTokens(ledger.reserveTokens)} \xB7 ${ledger.toolCount} tool definitions \xB7 compaction ${ledger.compactionAuto ? `auto${ledger.compactionThreshold === null ? "" : ` @${Math.round(ledger.compactionThreshold * 100)}%`}` : "manual"}`,
|
|
18208
19280
|
width
|
|
18209
19281
|
)
|
|
18210
19282
|
];
|
|
19283
|
+
out.push(theme2.fg("dim", "Context occupancy is per request; subscription limits are account-wide \xB7 /usage"));
|
|
18211
19284
|
const gridWidth = Math.max(12, Math.min(64, width >= 76 ? Math.floor(width * 0.38) : width));
|
|
18212
19285
|
const gridHeight = width >= 76 ? 8 : 3;
|
|
18213
19286
|
const grid = renderContextMeterGrid(ledger, gridWidth, gridHeight, theme2);
|
|
@@ -18218,7 +19291,13 @@ function contextPage(state, width) {
|
|
|
18218
19291
|
legendWidth
|
|
18219
19292
|
)
|
|
18220
19293
|
);
|
|
18221
|
-
out.push(
|
|
19294
|
+
out.push(
|
|
19295
|
+
"",
|
|
19296
|
+
rule(theme2, width, {
|
|
19297
|
+
left: state.context.budget ? "CAPTURE DIAGNOSTICS" : "CONTEXT COMPOSITION",
|
|
19298
|
+
leftToken: "accent"
|
|
19299
|
+
})
|
|
19300
|
+
);
|
|
18222
19301
|
out.push(...width >= 76 ? zipColumns(grid, legend, gridWidth, legendWidth, " ") : [...grid, "", ...legend]);
|
|
18223
19302
|
out.push(
|
|
18224
19303
|
...wrapTextWithAnsi(
|
|
@@ -18278,11 +19357,20 @@ function renderCompactDashboard(state, width) {
|
|
|
18278
19357
|
const activity = `${theme2.fg("accent", phase)}${workers ? theme2.fg("agent", ` \xB7 ${workers} active`) : ""}`;
|
|
18279
19358
|
const identity = clean(state.session.target ?? "No model selected");
|
|
18280
19359
|
const thinking = theme2.fg("reason", `think ${clean(state.session.thinking ?? "off")}`);
|
|
18281
|
-
const usage =
|
|
18282
|
-
const context = `${ledger ?
|
|
19360
|
+
const usage = contextUsageText(state.context);
|
|
19361
|
+
const context = `${ledger || state.context.budget ? contextOccupancyBar(state.context, w >= 100 ? 14 : 8, theme2) : ""} ${usage}`;
|
|
18283
19362
|
const rightWidth = Math.min(Math.floor(w * 0.48), visibleWidth(context));
|
|
18284
|
-
const
|
|
18285
|
-
const
|
|
19363
|
+
const weekly = state.quotaRoute ? routeWeeklyQuota(state.quotaRoute, state.quota ?? []) : null;
|
|
19364
|
+
const leftRoom = Math.max(1, w - rightWidth - 3);
|
|
19365
|
+
const activityLabel = fit(activity, Math.min(visibleWidth(activity), Math.max(5, Math.floor(leftRoom / 3))));
|
|
19366
|
+
const badge = weekly && leftRoom - visibleWidth(activityLabel) - visibleWidth(weekly.label) >= 16 ? theme2.fg(
|
|
19367
|
+
weekly.severity === "critical" ? "error" : weekly.severity === "normal" ? "muted" : "warning",
|
|
19368
|
+
weekly.label
|
|
19369
|
+
) : "";
|
|
19370
|
+
const baseRoom = leftRoom - visibleWidth(activityLabel) - (badge ? visibleWidth(badge) + 3 : 0) - 5;
|
|
19371
|
+
const showThinking = baseRoom - visibleWidth(thinking) - 3 >= 12;
|
|
19372
|
+
const identityRoom = Math.max(1, baseRoom - (showThinking ? visibleWidth(thinking) + 3 : 0));
|
|
19373
|
+
const left = `${activityLabel} \xB7 ${theme2.fg("muted", fitIdentityLabel(identity, identityRoom))}${badge ? ` \xB7 ${badge}` : ""}${showThinking ? ` \xB7 ${thinking}` : ""}`;
|
|
18286
19374
|
const pair = (l, r, rw) => `${fit(l, w - rw - 3)} ${fit(r, rw)}`;
|
|
18287
19375
|
const notice = [...state.notices].filter((n) => n.expiresAt === null || n.expiresAt > state.now).sort((a, b) => b.addedAt - a.addedAt)[0];
|
|
18288
19376
|
const key = getKeybindings().getKeys("clio-coder.status.toggle").join("/") || "Dashboard";
|
|
@@ -18290,18 +19378,28 @@ function renderCompactDashboard(state, width) {
|
|
|
18290
19378
|
const foot = urgent ? theme2.fg("warning", urgent) : notice ? theme2.fg(
|
|
18291
19379
|
notice.level === "error" ? "error" : notice.level === "warning" ? "warning" : "muted",
|
|
18292
19380
|
`\u2022 ${clean(notice.text)}`
|
|
18293
|
-
) : state.demoHint ? `${theme2.fg("accent", "Tip")} ${theme2.fg("muted", clean(state.demoHint))}` : theme2.fg(
|
|
19381
|
+
) : state.demoHint ? `${theme2.fg("accent", "Tip")} ${theme2.fg("muted", clean(state.demoHint))}` : theme2.fg("dim", footerKeyHint(state.now, w < 120) ?? `${key} Dashboard`);
|
|
19382
|
+
const hintWidth = Math.min(Math.floor(w * 0.48), visibleWidth(foot));
|
|
19383
|
+
const workspaceWidth = Math.max(1, w - hintWidth - 3);
|
|
19384
|
+
const git = `${clean(state.workspace.branch ?? "no Git branch")}${state.workspace.dirty ? " *" : ""}`;
|
|
19385
|
+
const gitWidth = Math.min(visibleWidth(git), Math.max(4, Math.floor(workspaceWidth * 0.45)));
|
|
19386
|
+
const cwdWidth = Math.max(1, workspaceWidth - gitWidth - 3);
|
|
19387
|
+
const workspace = theme2.fg(
|
|
18294
19388
|
"dim",
|
|
18295
|
-
|
|
19389
|
+
`${fitIdentityLabel(clean(state.workspace.cwd), cwdWidth)} \xB7 ${fitIdentityLabel(git, gitWidth)}`
|
|
18296
19390
|
);
|
|
18297
|
-
|
|
18298
|
-
return [
|
|
18299
|
-
fit(pair(left, context, rightWidth)),
|
|
18300
|
-
fit(pair(foot, hint, Math.min(Math.floor(w * 0.4), visibleWidth(hint))))
|
|
18301
|
-
];
|
|
19391
|
+
return [fit(pair(left, context, rightWidth)), fit(pair(workspace, foot, hintWidth))];
|
|
18302
19392
|
}
|
|
18303
19393
|
function statusPage(state, width) {
|
|
18304
19394
|
const theme2 = clioTheme();
|
|
19395
|
+
const quotaRows = [
|
|
19396
|
+
theme2.style(
|
|
19397
|
+
"accent",
|
|
19398
|
+
`SESSION \xB7 ${formatFooterTokens(state.sessionTokens?.totalTokens ?? 0)} recorded tokens \xB7 ${formatCostAggregate(state.sessionCost) ?? "cost not yet priced"}`,
|
|
19399
|
+
{ bold: true }
|
|
19400
|
+
),
|
|
19401
|
+
...renderQuotaAccounts(state.quota ?? [], width, { compact: true, now: state.now })
|
|
19402
|
+
];
|
|
18305
19403
|
const active = state.dispatchRows.filter((row2) => ACTIVE_AGENT_STATUSES.has(row2.status));
|
|
18306
19404
|
const completed = state.dispatchRows.filter((row2) => row2.status === "completed").length;
|
|
18307
19405
|
const failed = state.dispatchRows.filter((row2) => ["failed", "dead", "aborted"].includes(row2.status)).length;
|
|
@@ -18331,7 +19429,6 @@ function statusPage(state, width) {
|
|
|
18331
19429
|
["Target", state.session.target ?? "not selected"],
|
|
18332
19430
|
["Tracked cost", formatCostAggregate(state.sessionCost) ?? "not yet priced"],
|
|
18333
19431
|
["Clio ceiling", state.costCeilingUsd === void 0 ? "unknown" : `$${state.costCeilingUsd} \xB7 tracked pricing only`],
|
|
18334
|
-
["Provider quota", "not reported by provider"],
|
|
18335
19432
|
["MCP connected", names(state.connections?.mcp)],
|
|
18336
19433
|
["Plugins active", names(state.connections?.plugins)],
|
|
18337
19434
|
[
|
|
@@ -18385,6 +19482,7 @@ function statusPage(state, width) {
|
|
|
18385
19482
|
];
|
|
18386
19483
|
if (width < 76)
|
|
18387
19484
|
return [
|
|
19485
|
+
...quotaRows,
|
|
18388
19486
|
...section("COST & CONNECTIONS", left, width),
|
|
18389
19487
|
...section("LOCAL MACHINE", right, width),
|
|
18390
19488
|
theme2.fg("accent", "CONTEXT ENGINE"),
|
|
@@ -18395,6 +19493,7 @@ function statusPage(state, width) {
|
|
|
18395
19493
|
];
|
|
18396
19494
|
const col = Math.floor((width - 5) / 2);
|
|
18397
19495
|
return [
|
|
19496
|
+
...quotaRows,
|
|
18398
19497
|
...zipColumns(
|
|
18399
19498
|
section("COST & CONNECTIONS", left, col),
|
|
18400
19499
|
section("LOCAL MACHINE", right, width - col - 5),
|
|
@@ -18428,7 +19527,7 @@ function renderDashboardPage(state, page, width, terminalRows, cycleKey) {
|
|
|
18428
19527
|
const hint = truncateToWidth(
|
|
18429
19528
|
theme2.fg(
|
|
18430
19529
|
"muted",
|
|
18431
|
-
`${cycleKey || "Dashboard"} \u2192 ${next} \xB7 ${page === "Status" ? "/
|
|
19530
|
+
`${cycleKey || "Dashboard"} \u2192 ${next} \xB7 ${page === "Status" ? "/usage \xB7 /mcp \xB7 /library" : "composer stays active"}`
|
|
18432
19531
|
),
|
|
18433
19532
|
safeWidth,
|
|
18434
19533
|
"\u2026",
|
|
@@ -18441,7 +19540,7 @@ function renderDashboardPage(state, page, width, terminalRows, cycleKey) {
|
|
|
18441
19540
|
else content = statusPage(state, safeWidth);
|
|
18442
19541
|
content = content.flatMap((line) => visibleWidth(line) > safeWidth ? wrapTextWithAnsi(line, safeWidth) : [line]);
|
|
18443
19542
|
if (content.length > available) {
|
|
18444
|
-
const detail = page === "Activity" ? `${getKeybindings().getKeys("clio-coder.dispatchBoard.toggle").join("/") || "Fleet Runs"} \xB7 /view` : page === "Context" ? "/context" : "/
|
|
19543
|
+
const detail = page === "Activity" ? `${getKeybindings().getKeys("clio-coder.dispatchBoard.toggle").join("/") || "Fleet Runs"} \xB7 /view` : page === "Context" ? "/context" : "/usage \xB7 /context";
|
|
18445
19544
|
content = [
|
|
18446
19545
|
...content.slice(0, available - 1),
|
|
18447
19546
|
truncateToWidth(theme2.fg("dim", `More detail: ${detail}`), safeWidth, "\u2026", true)
|
|
@@ -18453,7 +19552,7 @@ function renderDashboardPage(state, page, width, terminalRows, cycleKey) {
|
|
|
18453
19552
|
|
|
18454
19553
|
// src/interactive/footer/system-metrics.ts
|
|
18455
19554
|
init_esm_shims();
|
|
18456
|
-
import { readdir, readFile } from "node:fs/promises";
|
|
19555
|
+
import { readdir, readFile as readFile4 } from "node:fs/promises";
|
|
18457
19556
|
import { cpus, freemem, platform, release, totalmem } from "node:os";
|
|
18458
19557
|
function counterRate(current, previous, elapsedMs) {
|
|
18459
19558
|
return elapsedMs > 0 && current >= previous && Number.isFinite(current) && Number.isFinite(previous) ? (current - previous) * 1e3 / elapsedMs : null;
|
|
@@ -18492,7 +19591,7 @@ function busiest(current, previous, elapsed) {
|
|
|
18492
19591
|
});
|
|
18493
19592
|
return rates.sort((a, b) => b.first + b.second - a.first - a.second)[0] ?? null;
|
|
18494
19593
|
}
|
|
18495
|
-
var read = (path) =>
|
|
19594
|
+
var read = (path) => readFile4(path, "utf8").catch(() => null);
|
|
18496
19595
|
var numeric = async (path) => {
|
|
18497
19596
|
const raw = await read(path);
|
|
18498
19597
|
if (raw === null || raw.trim() === "") return null;
|
|
@@ -18795,6 +19894,13 @@ function buildFooterDashboard(deps) {
|
|
|
18795
19894
|
const toolProfile = settings?.integrations.externalAgents?.defaults?.toolGovernance ?? "clio-coder-policy";
|
|
18796
19895
|
return {
|
|
18797
19896
|
resources: machine.snapshot(),
|
|
19897
|
+
quota: deps.getQuotaSnapshots?.() ?? [],
|
|
19898
|
+
...current?.runtime && wireModelId ? {
|
|
19899
|
+
quotaRoute: {
|
|
19900
|
+
runtimeId: current.runtime.id,
|
|
19901
|
+
wireModelId
|
|
19902
|
+
}
|
|
19903
|
+
} : {},
|
|
18798
19904
|
...deps.getConnections ? { connections: deps.getConnections() } : {},
|
|
18799
19905
|
...settings ? { costCeilingUsd: settings.safety.limits.sessionCostUsd } : {},
|
|
18800
19906
|
workspace: workspaceFacts(deps, branchSlot),
|
|
@@ -18824,6 +19930,13 @@ function buildFooterDashboard(deps) {
|
|
|
18824
19930
|
} : null
|
|
18825
19931
|
},
|
|
18826
19932
|
context: {
|
|
19933
|
+
...contextUsage?.revision ? {
|
|
19934
|
+
budget: {
|
|
19935
|
+
revision: contextUsage.revision,
|
|
19936
|
+
historical: contextUsage.historical ?? true,
|
|
19937
|
+
inputSource: contextUsage.inputSource ?? "unknown"
|
|
19938
|
+
}
|
|
19939
|
+
} : {},
|
|
18827
19940
|
label: null,
|
|
18828
19941
|
used: contextUsage?.tokens ?? null,
|
|
18829
19942
|
contextWindow: contextUsage?.contextWindow ?? null,
|
|
@@ -19005,8 +20118,8 @@ init_esm_shims();
|
|
|
19005
20118
|
init_esm_shims();
|
|
19006
20119
|
import { execFile as execFile2 } from "node:child_process";
|
|
19007
20120
|
import { open, readdir as readdir2, stat } from "node:fs/promises";
|
|
19008
|
-
import { homedir as
|
|
19009
|
-
import { basename as basename2, dirname, join, relative as relative4, resolve as resolve3, sep } from "node:path";
|
|
20121
|
+
import { homedir as homedir5 } from "node:os";
|
|
20122
|
+
import { basename as basename2, dirname, join as join4, relative as relative4, resolve as resolve3, sep } from "node:path";
|
|
19010
20123
|
var MAX_COMPLETION_ROWS = 40;
|
|
19011
20124
|
var PREVIEW_BYTES = 2048;
|
|
19012
20125
|
var PREVIEW_CHARS = 120;
|
|
@@ -19054,7 +20167,7 @@ function buildWorkspaceSnapshot(basePath, visibleFiles, trackedFiles) {
|
|
|
19054
20167
|
const tracked = trackedFiles.has(path);
|
|
19055
20168
|
files.push({
|
|
19056
20169
|
path,
|
|
19057
|
-
absolutePath:
|
|
20170
|
+
absolutePath: join4(basePath, path),
|
|
19058
20171
|
isDirectory: false,
|
|
19059
20172
|
tracked,
|
|
19060
20173
|
descendantFiles: 0,
|
|
@@ -19072,7 +20185,7 @@ function buildWorkspaceSnapshot(basePath, visibleFiles, trackedFiles) {
|
|
|
19072
20185
|
const directories = [...directoryFacts].map(
|
|
19073
20186
|
([path, facts]) => ({
|
|
19074
20187
|
path,
|
|
19075
|
-
absolutePath:
|
|
20188
|
+
absolutePath: join4(basePath, path),
|
|
19076
20189
|
isDirectory: true,
|
|
19077
20190
|
tracked: facts.tracked,
|
|
19078
20191
|
descendantFiles: facts.descendantFiles,
|
|
@@ -19129,7 +20242,7 @@ function explicitPathQuery(query) {
|
|
|
19129
20242
|
return query.startsWith("../") || query.startsWith("~/") || query.startsWith("/");
|
|
19130
20243
|
}
|
|
19131
20244
|
function resolveDisplayBase(basePath, displayBase) {
|
|
19132
|
-
if (displayBase.startsWith("~/")) return resolve3(
|
|
20245
|
+
if (displayBase.startsWith("~/")) return resolve3(homedir5(), displayBase.slice(2));
|
|
19133
20246
|
if (displayBase.startsWith("/")) return resolve3(displayBase);
|
|
19134
20247
|
return resolve3(basePath, displayBase);
|
|
19135
20248
|
}
|
|
@@ -19147,7 +20260,7 @@ async function explicitCandidates(basePath, query, trackedFiles) {
|
|
|
19147
20260
|
const candidates = [];
|
|
19148
20261
|
for (const entry of await readdir2(directory, { withFileTypes: true })) {
|
|
19149
20262
|
if (entry.name === ".git" || /[\r\n\0]/u.test(entry.name)) continue;
|
|
19150
|
-
const absolutePath =
|
|
20263
|
+
const absolutePath = join4(directory, entry.name);
|
|
19151
20264
|
let isDirectory = entry.isDirectory();
|
|
19152
20265
|
let isFile = entry.isFile();
|
|
19153
20266
|
if (!isDirectory && !isFile && entry.isSymbolicLink()) {
|
|
@@ -19799,6 +20912,12 @@ function createInteractivePresentation(deps) {
|
|
|
19799
20912
|
const key = keybindings.getKeys("tui.input.submit")[0];
|
|
19800
20913
|
return key === void 0 || key.length === 0 ? null : formatKeyLabel(key, "");
|
|
19801
20914
|
};
|
|
20915
|
+
const quotaSummary = createQuotaSummaryFeed({
|
|
20916
|
+
onUpdate: () => {
|
|
20917
|
+
footer?.refresh();
|
|
20918
|
+
requestRender();
|
|
20919
|
+
}
|
|
20920
|
+
});
|
|
19802
20921
|
const banner = factories.createBanner({
|
|
19803
20922
|
providers: deps.providers,
|
|
19804
20923
|
...deps.agents ? { getAgentCount: () => deps.agents?.listSpecs().filter(isUserVisibleAgent).length ?? 0 } : {},
|
|
@@ -19813,6 +20932,9 @@ function createInteractivePresentation(deps) {
|
|
|
19813
20932
|
return key ? formatKeyLabel(key, "") : null;
|
|
19814
20933
|
},
|
|
19815
20934
|
onFactsRefreshed: requestRender,
|
|
20935
|
+
// Subscription usage is read lazily off the render path and cached, so the
|
|
20936
|
+
// banner reads a string and never awaits a provider.
|
|
20937
|
+
getQuotaSummary: () => quotaSummary.peek(),
|
|
19816
20938
|
...deps.getSettings ? { getSettings: deps.getSettings } : {}
|
|
19817
20939
|
});
|
|
19818
20940
|
if (deps.startsResumed === true) banner.collapseToSessionHeader();
|
|
@@ -19945,6 +21067,7 @@ function createInteractivePresentation(deps) {
|
|
|
19945
21067
|
getSessionTokens: () => observabilitySnapshot.session.tokens,
|
|
19946
21068
|
getTokenThroughput: () => liveThroughput === null ? observabilitySnapshot.session.latestThroughput : currentLiveThroughput(),
|
|
19947
21069
|
getSessionCost: () => observabilitySnapshot.session.cost,
|
|
21070
|
+
getQuotaSnapshots: () => quotaSummary.peekSnapshots(),
|
|
19948
21071
|
getContextUsage: () => deps.chat.contextUsage(),
|
|
19949
21072
|
getContextLedger: () => deps.chat.contextLedger(),
|
|
19950
21073
|
getDispatchRows: () => dispatchBoardStore.rows(),
|
|
@@ -20145,6 +21268,7 @@ function createInteractivePresentation(deps) {
|
|
|
20145
21268
|
const disposeBeforeStatus = () => {
|
|
20146
21269
|
if (beforeStatusDisposed) return;
|
|
20147
21270
|
beforeStatusDisposed = true;
|
|
21271
|
+
quotaSummary.dispose();
|
|
20148
21272
|
banner.dispose();
|
|
20149
21273
|
footer.dispose();
|
|
20150
21274
|
unsubscribeObservability();
|
|
@@ -20186,6 +21310,7 @@ function createInteractivePresentation(deps) {
|
|
|
20186
21310
|
},
|
|
20187
21311
|
changeOutputStyle: (mutation) => chatRenderer.mutate(() => preserveTranscriptScroll(transcriptView, deps.terminal.columns, mutation), "output-style"),
|
|
20188
21312
|
getObservabilitySnapshot: () => observabilitySnapshot,
|
|
21313
|
+
getQuotaSnapshots: () => quotaSummary.peekSnapshots(),
|
|
20189
21314
|
recordChatEvent,
|
|
20190
21315
|
recordToolStart: (toolCallId, toolName) => {
|
|
20191
21316
|
footerActiveTools.add(toolCallId);
|
|
@@ -20223,7 +21348,7 @@ function createInteractivePresentation(deps) {
|
|
|
20223
21348
|
// src/interactive/interactive-slash-runtime.ts
|
|
20224
21349
|
init_esm_shims();
|
|
20225
21350
|
import { mkdirSync, writeFileSync } from "node:fs";
|
|
20226
|
-
import { join as
|
|
21351
|
+
import { join as join5, resolve as resolve4 } from "node:path";
|
|
20227
21352
|
|
|
20228
21353
|
// src/interactive/context-recall-command.ts
|
|
20229
21354
|
init_esm_shims();
|
|
@@ -20560,6 +21685,13 @@ function renderDoctorReport(findings, width) {
|
|
|
20560
21685
|
|
|
20561
21686
|
// src/interactive/interactive-slash-runtime.ts
|
|
20562
21687
|
var EXPORT_RENDER_WIDTH = 100;
|
|
21688
|
+
function longestBacktickRun(lines) {
|
|
21689
|
+
let longest = 0;
|
|
21690
|
+
for (const line of lines) {
|
|
21691
|
+
for (const run of line.match(/`+/gu) ?? []) longest = Math.max(longest, run.length);
|
|
21692
|
+
}
|
|
21693
|
+
return longest;
|
|
21694
|
+
}
|
|
20563
21695
|
function resolveThinkingCapability(providers, settings) {
|
|
20564
21696
|
const resolved = resolveModelRuntimeCapabilitiesForProviders(
|
|
20565
21697
|
providers,
|
|
@@ -20754,7 +21886,7 @@ function createInteractiveSlashRuntime(deps) {
|
|
|
20754
21886
|
deps.requestRender();
|
|
20755
21887
|
},
|
|
20756
21888
|
runDoctor: async ({ deep }) => {
|
|
20757
|
-
const { collectDoctorFindings, doctorNotice } = await import("./doctor-
|
|
21889
|
+
const { collectDoctorFindings, doctorNotice } = await import("./doctor-53AVQXAO.js");
|
|
20758
21890
|
const autonomy = deps.getSettings?.().safety.autonomy;
|
|
20759
21891
|
const findings = await collectDoctorFindings({
|
|
20760
21892
|
workspaceRoot: cwd(),
|
|
@@ -20792,7 +21924,7 @@ function createInteractiveSlashRuntime(deps) {
|
|
|
20792
21924
|
};
|
|
20793
21925
|
return options.dryRun ? deps.share.planImport(resolve4(archivePath), importOptions) : deps.share.importArchive(resolve4(archivePath), importOptions);
|
|
20794
21926
|
},
|
|
20795
|
-
|
|
21927
|
+
openUsage: deps.openUsage,
|
|
20796
21928
|
openSideQuestion: deps.openSideQuestion,
|
|
20797
21929
|
// `/oracle` is refused, never queued, while a turn streams: the digest it
|
|
20798
21930
|
// packs describes the record as it stands.
|
|
@@ -20898,6 +22030,15 @@ function createInteractiveSlashRuntime(deps) {
|
|
|
20898
22030
|
deps.setEditorText(text);
|
|
20899
22031
|
deps.requestRender();
|
|
20900
22032
|
},
|
|
22033
|
+
runHandoffRecovery: (handoffId, action) => {
|
|
22034
|
+
if (!deps.onRecoverHandoff) {
|
|
22035
|
+
appendCommandNotice("error", "[/context recover] native handoff recovery is unavailable");
|
|
22036
|
+
return;
|
|
22037
|
+
}
|
|
22038
|
+
void deps.onRecoverHandoff(handoffId, action).catch(
|
|
22039
|
+
(error) => appendCommandNotice("error", `[/context recover] ${error instanceof Error ? error.message : String(error)}`)
|
|
22040
|
+
);
|
|
22041
|
+
},
|
|
20901
22042
|
runCompact: (instructions) => {
|
|
20902
22043
|
runCompactWithNotice(deps.onCompact, appendCommandNotice, instructions);
|
|
20903
22044
|
},
|
|
@@ -20911,23 +22052,29 @@ function createInteractiveSlashRuntime(deps) {
|
|
|
20911
22052
|
const turns = deps.readStructuredEntries(sessionId);
|
|
20912
22053
|
const exportPanel = createChatPanel({ unboundedToolBodies: true, getOutputStyle: () => "detailed" });
|
|
20913
22054
|
const leafTurnId = deps.session?.tree(sessionId).leafId ?? null;
|
|
20914
|
-
rehydrateChatPanelFromTurns(
|
|
20915
|
-
|
|
20916
|
-
|
|
20917
|
-
|
|
22055
|
+
rehydrateChatPanelFromTurns(
|
|
22056
|
+
exportPanel,
|
|
22057
|
+
turns,
|
|
22058
|
+
withContinuityReplay(
|
|
22059
|
+
turns,
|
|
22060
|
+
{ unboundedToolBodies: true, ...leafTurnId ? { activeLeafTurnId: leafTurnId } : {} },
|
|
22061
|
+
deps.session
|
|
22062
|
+
)
|
|
22063
|
+
);
|
|
20918
22064
|
const ansiLines = exportPanel.render(EXPORT_RENDER_WIDTH);
|
|
20919
22065
|
const exportedAt = deps.now?.() ?? /* @__PURE__ */ new Date();
|
|
20920
22066
|
const date = dateLocal(exportedAt);
|
|
20921
22067
|
const requestedPath = pathArg?.trim() ?? "";
|
|
20922
22068
|
const markdown = requestedPath.toLowerCase().endsWith(".md");
|
|
20923
22069
|
const target = resolve4(
|
|
20924
|
-
requestedPath.length > 0 ? requestedPath :
|
|
22070
|
+
requestedPath.length > 0 ? requestedPath : join5(".clio-coder", "exports", `${sessionId}-${date}.html`)
|
|
20925
22071
|
);
|
|
20926
22072
|
mkdirSync(resolve4(target, ".."), { recursive: true });
|
|
20927
22073
|
if (markdown) {
|
|
20928
22074
|
const lines = ansiLines.map(stripTerminalSequences);
|
|
20929
|
-
const
|
|
20930
|
-
|
|
22075
|
+
const fence = "`".repeat(Math.max(3, longestBacktickRun(lines) + 1));
|
|
22076
|
+
const header = [`# Clio session ${sessionId}`, "", `Exported ${exportedAt.toISOString()}`, "", `${fence}text`];
|
|
22077
|
+
writeFileSync(target, `${[...header, ...lines, fence, ""].join("\n")}`, "utf8");
|
|
20931
22078
|
} else {
|
|
20932
22079
|
writeFileSync(target, renderSessionHtml({ sessionId, exportedAt: exportedAt.toISOString(), ansiLines }), "utf8");
|
|
20933
22080
|
}
|
|
@@ -20970,7 +22117,7 @@ function createInteractiveSlashRuntime(deps) {
|
|
|
20970
22117
|
runContextRecall: (ref) => {
|
|
20971
22118
|
const session = deps.session;
|
|
20972
22119
|
if (!session) return;
|
|
20973
|
-
const
|
|
22120
|
+
const outcome2 = runOperatorRecall(ref, {
|
|
20974
22121
|
hasSession: () => session.current() !== null,
|
|
20975
22122
|
readEntries: () => {
|
|
20976
22123
|
const sessionId = deps.chat.getSessionId();
|
|
@@ -20984,12 +22131,12 @@ function createInteractiveSlashRuntime(deps) {
|
|
|
20984
22131
|
onRecalled: (payload) => deps.bus.emit(BusChannels.ContextRecalled, payload),
|
|
20985
22132
|
...deps.now ? { now: () => (deps.now?.() ?? /* @__PURE__ */ new Date()).getTime() } : {}
|
|
20986
22133
|
});
|
|
20987
|
-
if (!
|
|
20988
|
-
appendCommandNotice("error",
|
|
22134
|
+
if (!outcome2.ok) {
|
|
22135
|
+
appendCommandNotice("error", outcome2.message);
|
|
20989
22136
|
return;
|
|
20990
22137
|
}
|
|
20991
|
-
appendCommandNotice("success",
|
|
20992
|
-
deps.io.stdout(`${
|
|
22138
|
+
appendCommandNotice("success", outcome2.headline);
|
|
22139
|
+
deps.io.stdout(`${outcome2.body}
|
|
20993
22140
|
`);
|
|
20994
22141
|
deps.requestRender();
|
|
20995
22142
|
}
|
|
@@ -21188,7 +22335,11 @@ function createInteractiveTickers(deps) {
|
|
|
21188
22335
|
taskIslandHidden = hidden;
|
|
21189
22336
|
if (rows.length > 0)
|
|
21190
22337
|
taskIsland.setText(
|
|
21191
|
-
formatTaskIslandLines(
|
|
22338
|
+
formatTaskIslandLines(
|
|
22339
|
+
rows,
|
|
22340
|
+
Math.max(1, Math.min(4, Math.floor((taskIslandHeight - 8) / 10))),
|
|
22341
|
+
deps.getQuotaSnapshots?.() ?? []
|
|
22342
|
+
).join("\n")
|
|
21192
22343
|
);
|
|
21193
22344
|
else if (board) taskIsland.setText(formatTaskBoardIslandLines(board).join("\n"));
|
|
21194
22345
|
taskIsland.invalidate();
|
|
@@ -21297,7 +22448,8 @@ function createSessionTranscript(deps) {
|
|
|
21297
22448
|
deps.chat.resetForSession(
|
|
21298
22449
|
leafTurnId,
|
|
21299
22450
|
buildModelReplayAgentMessagesFromTurns(turns, {
|
|
21300
|
-
...leafTurnId ? { activeLeafTurnId: leafTurnId } : {}
|
|
22451
|
+
...leafTurnId ? { activeLeafTurnId: leafTurnId } : {},
|
|
22452
|
+
continuity: continuityContextFromSession(deps.session)
|
|
21301
22453
|
})
|
|
21302
22454
|
);
|
|
21303
22455
|
deps.refreshStatus();
|
|
@@ -21810,6 +22962,7 @@ async function createInteractiveApplication(deps) {
|
|
|
21810
22962
|
...deps.onSelectModel ? { onSelectModel: deps.onSelectModel } : {},
|
|
21811
22963
|
...deps.onSetThinkingLevel ? { onSetThinkingLevel: deps.onSetThinkingLevel } : {},
|
|
21812
22964
|
...deps.onCompact ? { onCompact: deps.onCompact } : {},
|
|
22965
|
+
...deps.onRecoverHandoff ? { onRecoverHandoff: deps.onRecoverHandoff } : {},
|
|
21813
22966
|
...deps.onInit ? { onInit: deps.onInit } : {},
|
|
21814
22967
|
...deps.onContextClear ? { onContextClear: deps.onContextClear } : {},
|
|
21815
22968
|
...deps.onContextRefresh ? { onContextRefresh: deps.onContextRefresh } : {},
|
|
@@ -21823,7 +22976,7 @@ async function createInteractiveApplication(deps) {
|
|
|
21823
22976
|
expandSubmit: (text) => expandInteractiveSubmitAsync(text, deps.resources),
|
|
21824
22977
|
openAskUser: (questions, options) => openAskUserOverlayState(questions, options),
|
|
21825
22978
|
openSkillsHub: (request) => openSkillsHubState(request),
|
|
21826
|
-
|
|
22979
|
+
openUsage: () => openUsageOverlayState(),
|
|
21827
22980
|
openSideQuestion: (question) => openSideQuestionOverlayState(question),
|
|
21828
22981
|
startHandoff: (goal) => startHandoffState(goal),
|
|
21829
22982
|
startFleetRun: (name, vars) => startFleetRunState(name, vars),
|
|
@@ -21879,6 +23032,7 @@ async function createInteractiveApplication(deps) {
|
|
|
21879
23032
|
getTerminationCoordinator().onDrain(() => editorSubmit.shutdownEditorBash(), { timeoutMs: EDITOR_BASH_SHUTDOWN_MS });
|
|
21880
23033
|
editor.onSubmit = editorSubmit.submitEditorText;
|
|
21881
23034
|
const interactiveTickers = createInteractiveTickers({
|
|
23035
|
+
getQuotaSnapshots: presentation.getQuotaSnapshots,
|
|
21882
23036
|
tui,
|
|
21883
23037
|
dispatchBoardStore,
|
|
21884
23038
|
contextActivityStore,
|
|
@@ -21897,6 +23051,8 @@ async function createInteractiveApplication(deps) {
|
|
|
21897
23051
|
resetTranscript();
|
|
21898
23052
|
};
|
|
21899
23053
|
overlayLifecycle = createOverlayLifecycle({
|
|
23054
|
+
getQuotaSnapshots: presentation.getQuotaSnapshots,
|
|
23055
|
+
getDispatchRows: () => dispatchBoardStore.rows(),
|
|
21900
23056
|
app: deps,
|
|
21901
23057
|
tui,
|
|
21902
23058
|
footer,
|
|
@@ -21932,7 +23088,7 @@ async function createInteractiveApplication(deps) {
|
|
|
21932
23088
|
const {
|
|
21933
23089
|
closeOverlay,
|
|
21934
23090
|
openAskUserOverlayState,
|
|
21935
|
-
|
|
23091
|
+
openUsageOverlayState,
|
|
21936
23092
|
openSideQuestionOverlayState,
|
|
21937
23093
|
startHandoffState,
|
|
21938
23094
|
startFleetRunState,
|
|
@@ -21999,11 +23155,11 @@ async function createInteractiveApplication(deps) {
|
|
|
21999
23155
|
);
|
|
22000
23156
|
};
|
|
22001
23157
|
const backgroundActiveDispatch = () => {
|
|
22002
|
-
const
|
|
23158
|
+
const outcome2 = deps.onBackgroundDispatch?.() ?? {
|
|
22003
23159
|
ok: false,
|
|
22004
23160
|
message: "background: dispatch backgrounding is unavailable in this session"
|
|
22005
23161
|
};
|
|
22006
|
-
notify(
|
|
23162
|
+
notify(outcome2.ok ? "success" : "info", outcome2.message, "dispatch:background");
|
|
22007
23163
|
};
|
|
22008
23164
|
const mux = deps.mux;
|
|
22009
23165
|
const muxBridge = mux && mux.mode !== "none" && deps.createMuxBridge ? deps.createMuxBridge({
|
|
@@ -22285,7 +23441,7 @@ async function createInteractiveApplication(deps) {
|
|
|
22285
23441
|
});
|
|
22286
23442
|
const settings = deps.getSettings?.();
|
|
22287
23443
|
if (settings)
|
|
22288
|
-
void import("./startup-background-
|
|
23444
|
+
void import("./startup-background-JR2KDK6R.js").then(
|
|
22289
23445
|
({ prepareWorkerTargets }) => prepareWorkerTargets({
|
|
22290
23446
|
settings,
|
|
22291
23447
|
providers: deps.providers,
|
|
@@ -22378,4 +23534,4 @@ export {
|
|
|
22378
23534
|
routeOverlayKey,
|
|
22379
23535
|
startInteractive
|
|
22380
23536
|
};
|
|
22381
|
-
//# sourceMappingURL=interactive-
|
|
23537
|
+
//# sourceMappingURL=interactive-JRCBENLZ.js.map
|