@ashlr/hub 3.10.0 → 3.10.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +101 -0
- package/dist/authority-surface.json +43 -23
- package/dist/build-identity.json +2 -2
- package/dist/core/daemon/capacity-publisher.d.ts +19 -0
- package/dist/core/daemon/capacity-publisher.js +49 -2
- package/dist/core/daemon/capacity-publisher.js.map +1 -1
- package/dist/core/daemon/overnight-status.d.ts +13 -0
- package/dist/core/daemon/overnight-status.js +93 -8
- package/dist/core/daemon/overnight-status.js.map +1 -1
- package/dist/core/fleet/dispatch-router.js +26 -9
- package/dist/core/fleet/dispatch-router.js.map +1 -1
- package/dist/core/fleet/fleet-runtime-journal.js +12 -5
- package/dist/core/fleet/fleet-runtime-journal.js.map +1 -1
- package/dist/core/fleet/fleet-types.d.ts +13 -0
- package/dist/core/routing/budget-store.js +11 -5
- package/dist/core/routing/budget-store.js.map +1 -1
- package/dist/core/routing/capacity-history-api.d.ts +30 -0
- package/dist/core/routing/capacity-history-api.js +147 -0
- package/dist/core/routing/capacity-history-api.js.map +1 -0
- package/dist/core/routing/capacity-history-types.d.ts +63 -0
- package/dist/core/routing/capacity-history-types.js +18 -0
- package/dist/core/routing/capacity-history-types.js.map +1 -0
- package/dist/core/routing/capacity-history.d.ts +130 -0
- package/dist/core/routing/capacity-history.js +654 -0
- package/dist/core/routing/capacity-history.js.map +1 -0
- package/dist/core/routing/headroom.d.ts +5 -1
- package/dist/core/routing/headroom.js +82 -41
- package/dist/core/routing/headroom.js.map +1 -1
- package/dist/core/routing/router.d.ts +8 -1
- package/dist/core/routing/router.js +49 -16
- package/dist/core/routing/router.js.map +1 -1
- package/dist/core/routing/seat-reasons.d.ts +35 -0
- package/dist/core/routing/seat-reasons.js +48 -0
- package/dist/core/routing/seat-reasons.js.map +1 -0
- package/dist/core/routing/types.d.ts +37 -0
- package/dist/core/routing/types.js.map +1 -1
- package/dist/core/verse/fleet-history-types.d.ts +12 -4
- package/dist/core/verse/fleet-history-types.js +4 -2
- package/dist/core/verse/fleet-history-types.js.map +1 -1
- package/dist/core/verse/fleet-live-api.d.ts +14 -1
- package/dist/core/verse/fleet-live-api.js +31 -11
- package/dist/core/verse/fleet-live-api.js.map +1 -1
- package/dist/core/verse/preferences.d.ts +3 -1
- package/dist/core/verse/preferences.js +5 -2
- package/dist/core/verse/preferences.js.map +1 -1
- package/dist/core/verse/types.d.ts +5 -1
- package/dist/core/verse/types.js.map +1 -1
- package/dist/core/verse/verse-api.js +2 -1
- package/dist/core/verse/verse-api.js.map +1 -1
- package/dist/core/web/public/next/assets/{ActionMenu-DhbNne-M.js → ActionMenu-BBB7VYjz.js} +2 -2
- package/dist/core/web/public/next/assets/{ActionMenu-DhbNne-M.js.map → ActionMenu-BBB7VYjz.js.map} +1 -1
- package/dist/core/web/public/next/assets/Advanced-Bywv_iYR.css +1 -0
- package/dist/core/web/public/next/assets/Advanced-xVYFAeA8.js +2 -0
- package/dist/core/web/public/next/assets/Advanced-xVYFAeA8.js.map +1 -0
- package/dist/core/web/public/next/assets/{App-DyBg1v_q.js → App-CbDCLAxn.js} +5 -5
- package/dist/core/web/public/next/assets/{App-DyBg1v_q.js.map → App-CbDCLAxn.js.map} +1 -1
- package/dist/core/web/public/next/assets/AppsSection-B5HWJi9I.js +2 -0
- package/dist/core/web/public/next/assets/AppsSection-B5HWJi9I.js.map +1 -0
- package/dist/core/web/public/next/assets/AreaTrend-BgnK0wAy.js +2 -0
- package/dist/core/web/public/next/assets/AreaTrend-BgnK0wAy.js.map +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-BF5UCsMv.js +2 -0
- package/dist/core/web/public/next/assets/{AutonomySection-CoMngwNB.js.map → AutonomySection-BF5UCsMv.js.map} +1 -1
- package/dist/core/web/public/next/assets/BranchBar-BZNQ50YE.css +1 -0
- package/dist/core/web/public/next/assets/BranchBar-nfSb59Kv.js +2 -0
- package/dist/core/web/public/next/assets/BranchBar-nfSb59Kv.js.map +1 -0
- package/dist/core/web/public/next/assets/BudgetControl-BESM12dO.js +2 -0
- package/dist/core/web/public/next/assets/BudgetControl-BESM12dO.js.map +1 -0
- package/dist/core/web/public/next/assets/BurnDown-D1AfskPT.js +2 -0
- package/dist/core/web/public/next/assets/BurnDown-D1AfskPT.js.map +1 -0
- package/dist/core/web/public/next/assets/{Button-0-nNbv1h.js → Button-Cr_qkQEc.js} +2 -2
- package/dist/core/web/public/next/assets/{Button-0-nNbv1h.js.map → Button-Cr_qkQEc.js.map} +1 -1
- package/dist/core/web/public/next/assets/CapacityStrip-Cc28CyWk.css +1 -0
- package/dist/core/web/public/next/assets/CapacityStrip-DqqYnLek.js +2 -0
- package/dist/core/web/public/next/assets/CapacityStrip-DqqYnLek.js.map +1 -0
- package/dist/core/web/public/next/assets/ChatSection-DoqjyVoj.js +3 -0
- package/dist/core/web/public/next/assets/{ChatSection-B9cdRKUh.js.map → ChatSection-DoqjyVoj.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CommandPalette-GpeCSrPy.js → CommandPalette-lLV-OR63.js} +2 -2
- package/dist/core/web/public/next/assets/{CommandPalette-GpeCSrPy.js.map → CommandPalette-lLV-OR63.js.map} +1 -1
- package/dist/core/web/public/next/assets/CommandSection-fiZ4DJpM.js +2 -0
- package/dist/core/web/public/next/assets/CommandSection-fiZ4DJpM.js.map +1 -0
- package/dist/core/web/public/next/assets/Composer-ByzxOJK6.css +1 -0
- package/dist/core/web/public/next/assets/Composer.module-C8U73KdQ.js +2 -0
- package/dist/core/web/public/next/assets/{Composer.module-DJMdrqNt.js.map → Composer.module-C8U73KdQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/DiffPane-BAvvbBsf.css +1 -0
- package/dist/core/web/public/next/assets/DiffPane-BVxhK-cy.js +2 -0
- package/dist/core/web/public/next/assets/DiffPane-BVxhK-cy.js.map +1 -0
- package/dist/core/web/public/next/assets/{DiffViewer-tOGWk0CA.js → DiffViewer-yCdw9J-Y.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffViewer-tOGWk0CA.js.map → DiffViewer-yCdw9J-Y.js.map} +1 -1
- package/dist/core/web/public/next/assets/DockHost-B4RaYOET.css +1 -0
- package/dist/core/web/public/next/assets/DockHost-BZReKwos.js +2 -0
- package/dist/core/web/public/next/assets/DockHost-BZReKwos.js.map +1 -0
- package/dist/core/web/public/next/assets/{EmptyState-DdJ4CxtO.js → EmptyState-D1GDxVZy.js} +2 -2
- package/dist/core/web/public/next/assets/{EmptyState-DdJ4CxtO.js.map → EmptyState-D1GDxVZy.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Epistemic-BLjM5y_y.js → Epistemic-DRp4dBfB.js} +2 -2
- package/dist/core/web/public/next/assets/{Epistemic-BLjM5y_y.js.map → Epistemic-DRp4dBfB.js.map} +1 -1
- package/dist/core/web/public/next/assets/FleetSection-CFiWeOEs.css +1 -0
- package/dist/core/web/public/next/assets/FleetSection-rPLy_NPo.js +3 -0
- package/dist/core/web/public/next/assets/FleetSection-rPLy_NPo.js.map +1 -0
- package/dist/core/web/public/next/assets/Funnel-zvDj3He4.js +2 -0
- package/dist/core/web/public/next/assets/Funnel-zvDj3He4.js.map +1 -0
- package/dist/core/web/public/next/assets/GearTray-CkviqjYr.js +2 -0
- package/dist/core/web/public/next/assets/GearTray-CkviqjYr.js.map +1 -0
- package/dist/core/web/public/next/assets/GrowthSection-Bg5sW0jI.js +2 -0
- package/dist/core/web/public/next/assets/GrowthSection-Bg5sW0jI.js.map +1 -0
- package/dist/core/web/public/next/assets/HandoffDialog-DcPj1ri9.js +2 -0
- package/dist/core/web/public/next/assets/HandoffDialog-DcPj1ri9.js.map +1 -0
- package/dist/core/web/public/next/assets/{Input-CTu0CycC.js → Input-Ci7TD96x.js} +2 -2
- package/dist/core/web/public/next/assets/{Input-CTu0CycC.js.map → Input-Ci7TD96x.js.map} +1 -1
- package/dist/core/web/public/next/assets/{LeaderCard-BuSDeATv.js → LeaderCard-BSFTlMRF.js} +2 -2
- package/dist/core/web/public/next/assets/{LeaderCard-BuSDeATv.js.map → LeaderCard-BSFTlMRF.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MatrixHeatmap-9dKgJ_pT.css → MatrixHeatmap-Bmnvo1l1.css} +1 -1
- package/dist/core/web/public/next/assets/MatrixHeatmap-DojKZe9L.js +2 -0
- package/dist/core/web/public/next/assets/MatrixHeatmap-DojKZe9L.js.map +1 -0
- package/dist/core/web/public/next/assets/McpSection-CvcYu1X_.js +2 -0
- package/dist/core/web/public/next/assets/{McpSection-1UncWBpW.js.map → McpSection-CvcYu1X_.js.map} +1 -1
- package/dist/core/web/public/next/assets/MessageMarkdown-BrLCrb73.js +3 -0
- package/dist/core/web/public/next/assets/{MessageMarkdown-C4pl9LI5.js.map → MessageMarkdown-BrLCrb73.js.map} +1 -1
- package/dist/core/web/public/next/assets/MessageMarkdown-Cgh5f1-Q.css +1 -0
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-CZsF77ZM.js → MessageMarkdownRenderer-CjmdBw2p.js} +2 -2
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-CZsF77ZM.js.map → MessageMarkdownRenderer-CjmdBw2p.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Meter-C18ciKz4.js → Meter-DTHbmhQg.js} +2 -2
- package/dist/core/web/public/next/assets/{Meter-C18ciKz4.js.map → Meter-DTHbmhQg.js.map} +1 -1
- package/dist/core/web/public/next/assets/MindSection-DcO9fmYe.js +2 -0
- package/dist/core/web/public/next/assets/MindSection-DcO9fmYe.js.map +1 -0
- package/dist/core/web/public/next/assets/MutationTokenDialog-Cqn2uPV6.js +2 -0
- package/dist/core/web/public/next/assets/MutationTokenDialog-Cqn2uPV6.js.map +1 -0
- package/dist/core/web/public/next/assets/NeedsYouDrawer-BpvidnM2.css +1 -0
- package/dist/core/web/public/next/assets/NeedsYouDrawer-hiTINupk.js +2 -0
- package/dist/core/web/public/next/assets/NeedsYouDrawer-hiTINupk.js.map +1 -0
- package/dist/core/web/public/next/assets/NeedsYouList-B4Z37Phx.js +2 -0
- package/dist/core/web/public/next/assets/NeedsYouList-B4Z37Phx.js.map +1 -0
- package/dist/core/web/public/next/assets/NeedsYouList-CruOt4JT.css +1 -0
- package/dist/core/web/public/next/assets/NewChatDialog-utSckh7C.js +3 -0
- package/dist/core/web/public/next/assets/{NewChatDialog-B_BsS9pr.js.map → NewChatDialog-utSckh7C.js.map} +1 -1
- package/dist/core/web/public/next/assets/OnboardingFlow-7N3YSUHN.js +2 -0
- package/dist/core/web/public/next/assets/{OnboardingFlow-CtCPpgoX.js.map → OnboardingFlow-7N3YSUHN.js.map} +1 -1
- package/dist/core/web/public/next/assets/PreviewPane-CqzkaAjG.js +2 -0
- package/dist/core/web/public/next/assets/PreviewPane-CqzkaAjG.js.map +1 -0
- package/dist/core/web/public/next/assets/PreviewPane-DoMsJSG3.css +1 -0
- package/dist/core/web/public/next/assets/RailStatus-sZhApA8k.js +2 -0
- package/dist/core/web/public/next/assets/RailStatus-sZhApA8k.js.map +1 -0
- package/dist/core/web/public/next/assets/{RefreshIndicator-CnhEovMZ.js → RefreshIndicator-C1uQIegT.js} +2 -2
- package/dist/core/web/public/next/assets/{RefreshIndicator-CnhEovMZ.js.map → RefreshIndicator-C1uQIegT.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-28gLwmwV.js → ResourcePoolConsoleApp-DXjjV6Sh.js} +4 -4
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-28gLwmwV.js.map → ResourcePoolConsoleApp-DXjjV6Sh.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-AyUPCIb3.js → RouteErrorBoundary-D1LZxQjN.js} +2 -2
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-AyUPCIb3.js.map → RouteErrorBoundary-D1LZxQjN.js.map} +1 -1
- package/dist/core/web/public/next/assets/SeatSelector-CT92PqM_.js +3 -0
- package/dist/core/web/public/next/assets/{SeatSelector-DaUO-zoK.js.map → SeatSelector-CT92PqM_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Segmented-B_8c_83S.js → Segmented-BMvq-FfD.js} +2 -2
- package/dist/core/web/public/next/assets/{Segmented-B_8c_83S.js.map → Segmented-BMvq-FfD.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Select-Bl5g5Dt_.js → Select-DkdeoSQn.js} +2 -2
- package/dist/core/web/public/next/assets/{Select-Bl5g5Dt_.js.map → Select-DkdeoSQn.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionInsightChip-w0I21q0c.js → SessionInsightChip-CwlakUYU.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionInsightChip-w0I21q0c.js.map → SessionInsightChip-CwlakUYU.js.map} +1 -1
- package/dist/core/web/public/next/assets/SessionSearch-DFByh2NZ.js +2 -0
- package/dist/core/web/public/next/assets/{SessionSearch-B5aQ0BCM.js.map → SessionSearch-DFByh2NZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/SettingsSection-DgSaHFK4.js +2 -0
- package/dist/core/web/public/next/assets/SettingsSection-DgSaHFK4.js.map +1 -0
- package/dist/core/web/public/next/assets/{Sheet-CVjk-cLI.js → Sheet-C7APkGPt.js} +2 -2
- package/dist/core/web/public/next/assets/{Sheet-CVjk-cLI.js.map → Sheet-C7APkGPt.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-BiBjnBcc.js → ShortcutsOverlay-ZPyXUS_I.js} +2 -2
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-BiBjnBcc.js.map → ShortcutsOverlay-ZPyXUS_I.js.map} +1 -1
- package/dist/core/web/public/next/assets/Sidebar-BRc1vGDF.css +1 -0
- package/dist/core/web/public/next/assets/Sidebar-Chsgazmk.js +3 -0
- package/dist/core/web/public/next/assets/Sidebar-Chsgazmk.js.map +1 -0
- package/dist/core/web/public/next/assets/{Slider-BS9MU5ZV.js → Slider-B0kjW7cd.js} +2 -2
- package/dist/core/web/public/next/assets/{Slider-BS9MU5ZV.js.map → Slider-B0kjW7cd.js.map} +1 -1
- package/dist/core/web/public/next/assets/{StatusBadge-DAf-ArKE.js → StatusBadge-wv4e6f8b.js} +2 -2
- package/dist/core/web/public/next/assets/{StatusBadge-DAf-ArKE.js.map → StatusBadge-wv4e6f8b.js.map} +1 -1
- package/dist/core/web/public/next/assets/StepBand-Db8WPw8J.js +2 -0
- package/dist/core/web/public/next/assets/StepBand-Db8WPw8J.js.map +1 -0
- package/dist/core/web/public/next/assets/{Surface-CiYOdNKQ.js → Surface-BkDrQ4t3.js} +2 -2
- package/dist/core/web/public/next/assets/{Surface-CiYOdNKQ.js.map → Surface-BkDrQ4t3.js.map} +1 -1
- package/dist/core/web/public/next/assets/Swimlane-Dcve56cP.js +2 -0
- package/dist/core/web/public/next/assets/Swimlane-Dcve56cP.js.map +1 -0
- package/dist/core/web/public/next/assets/{Switch-BzRXtNPt.js → Switch-DamlpSMY.js} +2 -2
- package/dist/core/web/public/next/assets/{Switch-BzRXtNPt.js.map → Switch-DamlpSMY.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Tag-DEEbDz7T.js → Tag-Cs4tudBN.js} +2 -2
- package/dist/core/web/public/next/assets/{Tag-DEEbDz7T.js.map → Tag-Cs4tudBN.js.map} +1 -1
- package/dist/core/web/public/next/assets/TerminalPane-BDkKFych.js +7 -0
- package/dist/core/web/public/next/assets/TerminalPane-BDkKFych.js.map +1 -0
- package/dist/core/web/public/next/assets/TerminalPane-BwfMbnJz.css +1 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-BE72VyBL.js +2 -0
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-DKqAf-eD.js.map → UniverseConsoleApp-BE72VyBL.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseView-D6081LQL.js → UniverseView-BbmYY2P4.js} +2 -2
- package/dist/core/web/public/next/assets/{UniverseView-D6081LQL.js.map → UniverseView-BbmYY2P4.js.map} +1 -1
- package/dist/core/web/public/next/assets/UsageSection-DsB-Jqyl.css +1 -0
- package/dist/core/web/public/next/assets/UsageSection-DsC5WmLk.js +2 -0
- package/dist/core/web/public/next/assets/UsageSection-DsC5WmLk.js.map +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CXJWDiEM.css +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-Dq_hREXs.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-Dq_hREXs.js.map +1 -0
- package/dist/core/web/public/next/assets/Workspace-BYW9dm90.css +1 -0
- package/dist/core/web/public/next/assets/Workspace-CKvVEPFq.js +10 -0
- package/dist/core/web/public/next/assets/Workspace-CKvVEPFq.js.map +1 -0
- package/dist/core/web/public/next/assets/actions-BnjZy8a-.js +2 -0
- package/dist/core/web/public/next/assets/actions-BnjZy8a-.js.map +1 -0
- package/dist/core/web/public/next/assets/actions-Ddfg2iLl.css +1 -0
- package/dist/core/web/public/next/assets/{budget-queries-Dacv1VYP.js → budget-queries-Cp6vO7FH.js} +2 -2
- package/dist/core/web/public/next/assets/{budget-queries-Dacv1VYP.js.map → budget-queries-Cp6vO7FH.js.map} +1 -1
- package/dist/core/web/public/next/assets/calendar-day-BxBYHfX1.js +2 -0
- package/dist/core/web/public/next/assets/calendar-day-BxBYHfX1.js.map +1 -0
- package/dist/core/web/public/next/assets/capacity-strip-model-9-Yb211u.js +2 -0
- package/dist/core/web/public/next/assets/capacity-strip-model-9-Yb211u.js.map +1 -0
- package/dist/core/web/public/next/assets/charts-BmbKhjqw.js +2 -0
- package/dist/core/web/public/next/assets/charts-BmbKhjqw.js.map +1 -0
- package/dist/core/web/public/next/assets/colors-BZ3a9wFf.js +2 -0
- package/dist/core/web/public/next/assets/colors-BZ3a9wFf.js.map +1 -0
- package/dist/core/web/public/next/assets/{command-bus-CpYuam1F.js → command-bus-DHJJLWh8.js} +2 -2
- package/dist/core/web/public/next/assets/{command-bus-CpYuam1F.js.map → command-bus-DHJJLWh8.js.map} +1 -1
- package/dist/core/web/public/next/assets/context-model-BGznyHNQ.js +2 -0
- package/dist/core/web/public/next/assets/context-model-BGznyHNQ.js.map +1 -0
- package/dist/core/web/public/next/assets/context-model-DeJ28uSZ.js +2 -0
- package/dist/core/web/public/next/assets/context-model-DeJ28uSZ.js.map +1 -0
- package/dist/core/web/public/next/assets/context-queries-_mEgy4eg.js +2 -0
- package/dist/core/web/public/next/assets/context-queries-_mEgy4eg.js.map +1 -0
- package/dist/core/web/public/next/assets/context.module-BijAfoJw.js +2 -0
- package/dist/core/web/public/next/assets/context.module-BijAfoJw.js.map +1 -0
- package/dist/core/web/public/next/assets/{control-queries-BGjarMm9.js → control-queries-C4TG8blN.js} +2 -2
- package/dist/core/web/public/next/assets/{control-queries-BGjarMm9.js.map → control-queries-C4TG8blN.js.map} +1 -1
- package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js +2 -0
- package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js.map +1 -0
- package/dist/core/web/public/next/assets/dock-icons-BB7Fi6hT.js +2 -0
- package/dist/core/web/public/next/assets/dock-icons-BB7Fi6hT.js.map +1 -0
- package/dist/core/web/public/next/assets/dock-panes-mnIwSpRp.js +2 -0
- package/dist/core/web/public/next/assets/{dock-panes-BNTLvX7G.js.map → dock-panes-mnIwSpRp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{dock-store-_E5h6TEq.js → dock-store-CdHQRP8s.js} +2 -2
- package/dist/core/web/public/next/assets/{dock-store-_E5h6TEq.js.map → dock-store-CdHQRP8s.js.map} +1 -1
- package/dist/core/web/public/next/assets/fleet-model-B4FKC7fH.js +2 -0
- package/dist/core/web/public/next/assets/fleet-model-B4FKC7fH.js.map +1 -0
- package/dist/core/web/public/next/assets/format-DKrNjdwD.js +2 -0
- package/dist/core/web/public/next/assets/format-DKrNjdwD.js.map +1 -0
- package/dist/core/web/public/next/assets/format-lW58rL2y.js +2 -0
- package/dist/core/web/public/next/assets/format-lW58rL2y.js.map +1 -0
- package/dist/core/web/public/next/assets/{git-model-5v5xGobf.js → git-model-DaGw1SzS.js} +2 -2
- package/dist/core/web/public/next/assets/{git-model-5v5xGobf.js.map → git-model-DaGw1SzS.js.map} +1 -1
- package/dist/core/web/public/next/assets/global-DG1fmn4y.js +2 -0
- package/dist/core/web/public/next/assets/global-DG1fmn4y.js.map +1 -0
- package/dist/core/web/public/next/assets/{guarded-action-vOPc8v75.js → guarded-action--lguLXfz.js} +2 -2
- package/dist/core/web/public/next/assets/{guarded-action-vOPc8v75.js.map → guarded-action--lguLXfz.js.map} +1 -1
- package/dist/core/web/public/next/assets/{icons-DWb24OA6.js → icons-YPgbel-I.js} +2 -2
- package/dist/core/web/public/next/assets/{icons-DWb24OA6.js.map → icons-YPgbel-I.js.map} +1 -1
- package/dist/core/web/public/next/assets/{index-afDA8cwW.js → index-Dk8R-3a7.js} +3 -3
- package/dist/core/web/public/next/assets/{index-afDA8cwW.js.map → index-Dk8R-3a7.js.map} +1 -1
- package/dist/core/web/public/next/assets/live-model-44wEU6I8.js +2 -0
- package/dist/core/web/public/next/assets/live-model-44wEU6I8.js.map +1 -0
- package/dist/core/web/public/next/assets/mind-B9PzLcl0.css +1 -0
- package/dist/core/web/public/next/assets/mind.module-BOABBdi_.js +2 -0
- package/dist/core/web/public/next/assets/mind.module-BOABBdi_.js.map +1 -0
- package/dist/core/web/public/next/assets/mutations-DjXM3IDg.js +2 -0
- package/dist/core/web/public/next/assets/{mutations-C6E10SPX.js.map → mutations-DjXM3IDg.js.map} +1 -1
- package/dist/core/web/public/next/assets/{overnight-queries-CCGfiS-g.js → overnight-queries-Be_eossf.js} +2 -2
- package/dist/core/web/public/next/assets/{overnight-queries-CCGfiS-g.js.map → overnight-queries-Be_eossf.js.map} +1 -1
- package/dist/core/web/public/next/assets/pane-chrome-8JmEhHVD.css +1 -0
- package/dist/core/web/public/next/assets/pane-chrome.module-D7o-fVd0.js +2 -0
- package/dist/core/web/public/next/assets/pane-chrome.module-D7o-fVd0.js.map +1 -0
- package/dist/core/web/public/next/assets/primitives-Dl3SEQvh.js +1 -0
- package/dist/core/web/public/next/assets/{queries-BuYIEHst.js → queries-CYEVCq5r.js} +2 -2
- package/dist/core/web/public/next/assets/{queries-BuYIEHst.js.map → queries-CYEVCq5r.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reasoning-pref-BVzGczV7.js → reasoning-pref-a_ZP6GzU.js} +2 -2
- package/dist/core/web/public/next/assets/{reasoning-pref-BVzGczV7.js.map → reasoning-pref-a_ZP6GzU.js.map} +1 -1
- package/dist/core/web/public/next/assets/seat-subscription-CRigL-GE.js +2 -0
- package/dist/core/web/public/next/assets/seat-subscription-CRigL-GE.js.map +1 -0
- package/dist/core/web/public/next/assets/{section-visibility-CSrsTcwK.js → section-visibility-u7q-Q9AA.js} +2 -2
- package/dist/core/web/public/next/assets/{section-visibility-CSrsTcwK.js.map → section-visibility-u7q-Q9AA.js.map} +1 -1
- package/dist/core/web/public/next/assets/{sidebar-model-C8fyqSQY.js → sidebar-model-i4WRuQ6j.js} +2 -2
- package/dist/core/web/public/next/assets/{sidebar-model-C8fyqSQY.js.map → sidebar-model-i4WRuQ6j.js.map} +1 -1
- package/dist/core/web/public/next/assets/slots-CV9ZuLQU.js +3 -0
- package/dist/core/web/public/next/assets/{slots-W8gkmdfE.js.map → slots-CV9ZuLQU.js.map} +1 -1
- package/dist/core/web/public/next/assets/surface-data-DLvmUX9z.js +2 -0
- package/dist/core/web/public/next/assets/surface-data-DLvmUX9z.js.map +1 -0
- package/dist/core/web/public/next/assets/surface-prefetch-Ct2JwXvL.js +2 -0
- package/dist/core/web/public/next/assets/surface-prefetch-Ct2JwXvL.js.map +1 -0
- package/dist/core/web/public/next/assets/tasks-model-DWs5u9RO.js +2 -0
- package/dist/core/web/public/next/assets/{tasks-model-CnYQzgxk.js.map → tasks-model-DWs5u9RO.js.map} +1 -1
- package/dist/core/web/public/next/assets/{terminal-icons-CxUYaWX9.js → terminal-icons-Ct9cZsEK.js} +2 -2
- package/dist/core/web/public/next/assets/{terminal-icons-CxUYaWX9.js.map → terminal-icons-Ct9cZsEK.js.map} +1 -1
- package/dist/core/web/public/next/assets/{tool-semantics-CTRuLF5j.js → tool-semantics-GX8ScuSH.js} +2 -2
- package/dist/core/web/public/next/assets/{tool-semantics-CTRuLF5j.js.map → tool-semantics-GX8ScuSH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{turn-files-BvB5LLNw.js → turn-files-BPHQzYuH.js} +2 -2
- package/dist/core/web/public/next/assets/{turn-files-BvB5LLNw.js.map → turn-files-BPHQzYuH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{usage-queries-CQOpeE1H.js → usage-queries-CI_y9oWZ.js} +2 -2
- package/dist/core/web/public/next/assets/{usage-queries-CQOpeE1H.js.map → usage-queries-CI_y9oWZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/use-guarded-action-DVCtLzSo.js +2 -0
- package/dist/core/web/public/next/assets/use-guarded-action-DVCtLzSo.js.map +1 -0
- package/dist/core/web/public/next/assets/{use-ticker-hryPXnyp.js → use-ticker-C3LQ2IYs.js} +2 -2
- package/dist/core/web/public/next/assets/{use-ticker-hryPXnyp.js.map → use-ticker-C3LQ2IYs.js.map} +1 -1
- package/dist/core/web/public/next/assets/use-token-gate-B5gOFkeH.js +2 -0
- package/dist/core/web/public/next/assets/use-token-gate-B5gOFkeH.js.map +1 -0
- package/dist/core/web/public/next/assets/{useActivity-Cg_9-7nt.js → useActivity-C3R1Sudh.js} +2 -2
- package/dist/core/web/public/next/assets/{useActivity-Cg_9-7nt.js.map → useActivity-C3R1Sudh.js.map} +1 -1
- package/dist/core/web/public/next/assets/useChartWidth-0APW0BR3.js +2 -0
- package/dist/core/web/public/next/assets/useChartWidth-0APW0BR3.js.map +1 -0
- package/dist/core/web/public/next/assets/useChartWidth-BAtVgn2n.css +1 -0
- package/dist/core/web/public/next/assets/{useSeatsRefresh-4Ov9eT1F.js → useSeatsRefresh-BN8bso-n.js} +2 -2
- package/dist/core/web/public/next/assets/{useSeatsRefresh-4Ov9eT1F.js.map → useSeatsRefresh-BN8bso-n.js.map} +1 -1
- package/dist/core/web/public/next/assets/verse-model-yHPwjf-7.js +2 -0
- package/dist/core/web/public/next/assets/verse-model-yHPwjf-7.js.map +1 -0
- package/dist/core/web/public/next/assets/{verse-queries-BjQoOTwv.js → verse-queries-2PxoBISm.js} +2 -2
- package/dist/core/web/public/next/assets/{verse-queries-BjQoOTwv.js.map → verse-queries-2PxoBISm.js.map} +1 -1
- package/dist/core/web/public/next/assets/verse-store-DHTuZpYa.js +3 -0
- package/dist/core/web/public/next/assets/verse-store-DHTuZpYa.js.map +1 -0
- package/dist/core/web/public/next/assets/verse-ui-store-Dy4HuDBV.js +3 -0
- package/dist/core/web/public/next/assets/{verse-ui-store-KTTKfv-T.js.map → verse-ui-store-Dy4HuDBV.js.map} +1 -1
- package/dist/core/web/public/next/assets/{viewport-ZB86jdES.js → viewport-DDoJ_xVq.js} +2 -2
- package/dist/core/web/public/next/assets/{viewport-ZB86jdES.js.map → viewport-DDoJ_xVq.js.map} +1 -1
- package/dist/core/web/public/next/assets/warmup-BsL2LdR-.js +3 -0
- package/dist/core/web/public/next/assets/warmup-BsL2LdR-.js.map +1 -0
- package/dist/core/web/public/next/assets/{workspace-model-4hq_Mv3N.js → workspace-model-Dd3LmIym.js} +2 -2
- package/dist/core/web/public/next/assets/{workspace-model-4hq_Mv3N.js.map → workspace-model-Dd3LmIym.js.map} +1 -1
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/package.json +1 -1
- package/dist/core/web/public/next/assets/Advanced-CHjxJt2z.css +0 -1
- package/dist/core/web/public/next/assets/Advanced-DM0DYibH.js +0 -2
- package/dist/core/web/public/next/assets/Advanced-DM0DYibH.js.map +0 -1
- package/dist/core/web/public/next/assets/AppsSection-CXxbfPJQ.js +0 -2
- package/dist/core/web/public/next/assets/AppsSection-CXxbfPJQ.js.map +0 -1
- package/dist/core/web/public/next/assets/AreaTrend-gUVXkfhf.js +0 -2
- package/dist/core/web/public/next/assets/AreaTrend-gUVXkfhf.js.map +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-CoMngwNB.js +0 -2
- package/dist/core/web/public/next/assets/BranchBar-C-NovaXr.js +0 -2
- package/dist/core/web/public/next/assets/BranchBar-C-NovaXr.js.map +0 -1
- package/dist/core/web/public/next/assets/BranchBar-C9BpPVLr.css +0 -1
- package/dist/core/web/public/next/assets/BudgetControl-P5lMxHvQ.js +0 -2
- package/dist/core/web/public/next/assets/BudgetControl-P5lMxHvQ.js.map +0 -1
- package/dist/core/web/public/next/assets/BurnDown-4P1LDoCL.js +0 -2
- package/dist/core/web/public/next/assets/BurnDown-4P1LDoCL.js.map +0 -1
- package/dist/core/web/public/next/assets/CapacityStrip-D6Yyg4a1.js +0 -2
- package/dist/core/web/public/next/assets/CapacityStrip-D6Yyg4a1.js.map +0 -1
- package/dist/core/web/public/next/assets/CapacityStrip-wgFP9MUA.css +0 -1
- package/dist/core/web/public/next/assets/ChatSection-B9cdRKUh.js +0 -3
- package/dist/core/web/public/next/assets/CommandSection-BC0uXim_.js +0 -2
- package/dist/core/web/public/next/assets/CommandSection-BC0uXim_.js.map +0 -1
- package/dist/core/web/public/next/assets/Composer-CkcwbQhG.css +0 -1
- package/dist/core/web/public/next/assets/Composer.module-DJMdrqNt.js +0 -2
- package/dist/core/web/public/next/assets/DiffPane-5uLKa0au.js +0 -2
- package/dist/core/web/public/next/assets/DiffPane-5uLKa0au.js.map +0 -1
- package/dist/core/web/public/next/assets/DiffPane-Csboxnn0.css +0 -1
- package/dist/core/web/public/next/assets/DockHost-BGnTgdIb.css +0 -1
- package/dist/core/web/public/next/assets/DockHost-CBV_6Ehi.js +0 -2
- package/dist/core/web/public/next/assets/DockHost-CBV_6Ehi.js.map +0 -1
- package/dist/core/web/public/next/assets/FleetSection-DuJcQCGg.js +0 -3
- package/dist/core/web/public/next/assets/FleetSection-DuJcQCGg.js.map +0 -1
- package/dist/core/web/public/next/assets/FleetSection-w9AjqfTR.css +0 -1
- package/dist/core/web/public/next/assets/Funnel-qX3Hlbce.js +0 -2
- package/dist/core/web/public/next/assets/Funnel-qX3Hlbce.js.map +0 -1
- package/dist/core/web/public/next/assets/GearTray-kVGP1coG.js +0 -2
- package/dist/core/web/public/next/assets/GearTray-kVGP1coG.js.map +0 -1
- package/dist/core/web/public/next/assets/GrowthSection-CYxJ9MH5.js +0 -2
- package/dist/core/web/public/next/assets/GrowthSection-CYxJ9MH5.js.map +0 -1
- package/dist/core/web/public/next/assets/HandoffDialog-DHZo3Ev0.js +0 -2
- package/dist/core/web/public/next/assets/HandoffDialog-DHZo3Ev0.js.map +0 -1
- package/dist/core/web/public/next/assets/MatrixHeatmap-B_JWCjZx.js +0 -2
- package/dist/core/web/public/next/assets/MatrixHeatmap-B_JWCjZx.js.map +0 -1
- package/dist/core/web/public/next/assets/McpSection-1UncWBpW.js +0 -2
- package/dist/core/web/public/next/assets/MessageMarkdown-C4pl9LI5.js +0 -3
- package/dist/core/web/public/next/assets/MessageMarkdown-Czcl3L_Q.css +0 -1
- package/dist/core/web/public/next/assets/MindSection-C3fCw_fD.js +0 -2
- package/dist/core/web/public/next/assets/MindSection-C3fCw_fD.js.map +0 -1
- package/dist/core/web/public/next/assets/MutationTokenDialog-Dn0tzCrh.js +0 -2
- package/dist/core/web/public/next/assets/MutationTokenDialog-Dn0tzCrh.js.map +0 -1
- package/dist/core/web/public/next/assets/NeedsYouDrawer-CuNYJCJ0.js +0 -2
- package/dist/core/web/public/next/assets/NeedsYouDrawer-CuNYJCJ0.js.map +0 -1
- package/dist/core/web/public/next/assets/NeedsYouDrawer-SkhvvdLb.css +0 -1
- package/dist/core/web/public/next/assets/NewChatDialog-B_BsS9pr.js +0 -3
- package/dist/core/web/public/next/assets/OnboardingFlow-CtCPpgoX.js +0 -2
- package/dist/core/web/public/next/assets/PreviewPane-Cx6RRwzM.js +0 -2
- package/dist/core/web/public/next/assets/PreviewPane-Cx6RRwzM.js.map +0 -1
- package/dist/core/web/public/next/assets/PreviewPane-WQJFjSXe.css +0 -1
- package/dist/core/web/public/next/assets/RailStatus-BWs6xevj.js +0 -2
- package/dist/core/web/public/next/assets/RailStatus-BWs6xevj.js.map +0 -1
- package/dist/core/web/public/next/assets/SeatSelector-DaUO-zoK.js +0 -3
- package/dist/core/web/public/next/assets/SessionSearch-B5aQ0BCM.js +0 -2
- package/dist/core/web/public/next/assets/SettingsSection-CuESA30a.js +0 -2
- package/dist/core/web/public/next/assets/SettingsSection-CuESA30a.js.map +0 -1
- package/dist/core/web/public/next/assets/Sidebar-DfD8MNZt.css +0 -1
- package/dist/core/web/public/next/assets/Sidebar-q11dtYZf.js +0 -3
- package/dist/core/web/public/next/assets/Sidebar-q11dtYZf.js.map +0 -1
- package/dist/core/web/public/next/assets/StepBand-B1W7rU70.js +0 -2
- package/dist/core/web/public/next/assets/StepBand-B1W7rU70.js.map +0 -1
- package/dist/core/web/public/next/assets/Swimlane-BR40WVcj.js +0 -2
- package/dist/core/web/public/next/assets/Swimlane-BR40WVcj.js.map +0 -1
- package/dist/core/web/public/next/assets/TerminalPane-CPKUTD9K.js +0 -7
- package/dist/core/web/public/next/assets/TerminalPane-CPKUTD9K.js.map +0 -1
- package/dist/core/web/public/next/assets/TerminalPane-CmE2QL-Q.css +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-DKqAf-eD.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-B6fR3cru.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-B6fR3cru.js.map +0 -1
- package/dist/core/web/public/next/assets/UsageSection-DwgNOYvi.css +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-C0V221WL.css +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-bjARLPwN.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-bjARLPwN.js.map +0 -1
- package/dist/core/web/public/next/assets/Workspace-DQXMVDf7.css +0 -1
- package/dist/core/web/public/next/assets/Workspace-DtJb5tiM.js +0 -10
- package/dist/core/web/public/next/assets/Workspace-DtJb5tiM.js.map +0 -1
- package/dist/core/web/public/next/assets/actions-Bszsdpms.js +0 -2
- package/dist/core/web/public/next/assets/actions-Bszsdpms.js.map +0 -1
- package/dist/core/web/public/next/assets/actions-Dug8YIf0.css +0 -1
- package/dist/core/web/public/next/assets/capacity-strip-model-BR539Ci8.js +0 -2
- package/dist/core/web/public/next/assets/capacity-strip-model-BR539Ci8.js.map +0 -1
- package/dist/core/web/public/next/assets/charts-D4NaLaXA.js +0 -2
- package/dist/core/web/public/next/assets/charts-D4NaLaXA.js.map +0 -1
- package/dist/core/web/public/next/assets/colors-B-vHsX1S.js +0 -2
- package/dist/core/web/public/next/assets/colors-B-vHsX1S.js.map +0 -1
- package/dist/core/web/public/next/assets/context-model-Bto3LZn2.js +0 -2
- package/dist/core/web/public/next/assets/context-model-Bto3LZn2.js.map +0 -1
- package/dist/core/web/public/next/assets/context-queries-DVdSLrYy.js +0 -2
- package/dist/core/web/public/next/assets/context-queries-DVdSLrYy.js.map +0 -1
- package/dist/core/web/public/next/assets/context.module-B_k02HNU.js +0 -2
- package/dist/core/web/public/next/assets/context.module-B_k02HNU.js.map +0 -1
- package/dist/core/web/public/next/assets/dock-icons-oG8d7mNZ.js +0 -2
- package/dist/core/web/public/next/assets/dock-icons-oG8d7mNZ.js.map +0 -1
- package/dist/core/web/public/next/assets/dock-panes-BNTLvX7G.js +0 -2
- package/dist/core/web/public/next/assets/fleet-model-ClBbQ0Uj.js +0 -2
- package/dist/core/web/public/next/assets/fleet-model-ClBbQ0Uj.js.map +0 -1
- package/dist/core/web/public/next/assets/format-BNYWGJat.js +0 -2
- package/dist/core/web/public/next/assets/format-BNYWGJat.js.map +0 -1
- package/dist/core/web/public/next/assets/global-DVgMguLr.js +0 -2
- package/dist/core/web/public/next/assets/global-DVgMguLr.js.map +0 -1
- package/dist/core/web/public/next/assets/live-model-Dm6ITHvX.js +0 -2
- package/dist/core/web/public/next/assets/live-model-Dm6ITHvX.js.map +0 -1
- package/dist/core/web/public/next/assets/mind-B-lYfSUJ.css +0 -1
- package/dist/core/web/public/next/assets/mind.module-BzhAlg3e.js +0 -2
- package/dist/core/web/public/next/assets/mind.module-BzhAlg3e.js.map +0 -1
- package/dist/core/web/public/next/assets/mutations-C6E10SPX.js +0 -2
- package/dist/core/web/public/next/assets/primitives-DQvYikjm.js +0 -1
- package/dist/core/web/public/next/assets/seat-subscription-CrWOV4Qc.js +0 -2
- package/dist/core/web/public/next/assets/seat-subscription-CrWOV4Qc.js.map +0 -1
- package/dist/core/web/public/next/assets/slots-W8gkmdfE.js +0 -3
- package/dist/core/web/public/next/assets/surface-data-ZtCegYMQ.js +0 -2
- package/dist/core/web/public/next/assets/surface-data-ZtCegYMQ.js.map +0 -1
- package/dist/core/web/public/next/assets/tasks-model-CnYQzgxk.js +0 -2
- package/dist/core/web/public/next/assets/types-Dypu22dp.js +0 -3
- package/dist/core/web/public/next/assets/types-Dypu22dp.js.map +0 -1
- package/dist/core/web/public/next/assets/use-guarded-action-CO_aAsed.js +0 -2
- package/dist/core/web/public/next/assets/use-guarded-action-CO_aAsed.js.map +0 -1
- package/dist/core/web/public/next/assets/use-token-gate-DYA2-ALC.js +0 -2
- package/dist/core/web/public/next/assets/use-token-gate-DYA2-ALC.js.map +0 -1
- package/dist/core/web/public/next/assets/useChartWidth-B8E5mJgM.css +0 -1
- package/dist/core/web/public/next/assets/useChartWidth-MEXvDxDL.js +0 -2
- package/dist/core/web/public/next/assets/useChartWidth-MEXvDxDL.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-model-E98kXngO.js +0 -2
- package/dist/core/web/public/next/assets/verse-model-E98kXngO.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-store-BgKx_YGs.js +0 -2
- package/dist/core/web/public/next/assets/verse-store-BgKx_YGs.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-ui-store-KTTKfv-T.js +0 -3
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as e,n as t,s as n}from"./index-afDA8cwW.js";import{n as r,t as i}from"./MutationTokenDialog-Dn0tzCrh.js";import{t as a}from"./Button-0-nNbv1h.js";import{t as o}from"./use-guarded-action-CO_aAsed.js";var s=n(e(),1),c={lead:`_lead_i2poc_8`,bar:`_bar_i2poc_14`,barSpacer:`_barSpacer_i2poc_22`,barSecondary:`_barSecondary_i2poc_26`,switchWrap:`_switchWrap_i2poc_32`,barLabel:`_barLabel_i2poc_38`,pillLabel:`_pillLabel_i2poc_39`,switchOption:`_switchOption_i2poc_48`,touchMark:`_touchMark_i2poc_54`,pill:`_pill_i2poc_39`,chip:`_chip_i2poc_59`,linkButton:`_linkButton_i2poc_88`,moreLink:`_moreLink_i2poc_89`,dot:`_dot_i2poc_103`,verdict:`_verdict_i2poc_126`,verdictPart:`_verdictPart_i2poc_135`,verdictSep:`_verdictSep_i2poc_149`,since:`_since_i2poc_153`,sinceLead:`_sinceLead_i2poc_162`,sinceEmpty:`_sinceEmpty_i2poc_166`,sinceChip:`_sinceChip_i2poc_170`,actionNote:`_actionNote_i2poc_196`,actionError:`_actionError_i2poc_197`,kbd:`_kbd_i2poc_251`,muted:`_muted_i2poc_260`,mono:`_mono_i2poc_267`,num:`_num_i2poc_272`,confirmBody:`_confirmBody_i2poc_277`,confirmActions:`_confirmActions_i2poc_283`,needsList:`_needsList_i2poc_291`,needsRow:`_needsRow_i2poc_299`,sevDot:`_sevDot_i2poc_313`,needsText:`_needsText_i2poc_327`,needsTitle:`_needsTitle_i2poc_334`,needsDetail:`_needsDetail_i2poc_341`,needsMeta:`_needsMeta_i2poc_348`,needsActions:`_needsActions_i2poc_355`,allClear:`_allClear_i2poc_363`,allClearTitle:`_allClearTitle_i2poc_370`,allClearBody:`_allClearBody_i2poc_378`,memo:`_memo_i2poc_384`,memoRow:`_memoRow_i2poc_391`,memoText:`_memoText_i2poc_402`,delta:`_delta_i2poc_408`,dryRun:`_dryRun_i2poc_421`,actionList:`_actionList_i2poc_433`,actionRow:`_actionRow_i2poc_442`,actionSummary:`_actionSummary_i2poc_451`,classBadge:`_classBadge_i2poc_456`,actionText:`_actionText_i2poc_479`,actionWhy:`_actionWhy_i2poc_492`,actionState:`_actionState_i2poc_499`,statusWord:`_statusWord_i2poc_505`,vetoChip:`_vetoChip_i2poc_520`,ring:`_ring_i2poc_524`,ringTrack:`_ringTrack_i2poc_534`,ringFill:`_ringFill_i2poc_540`,ringText:`_ringText_i2poc_547`,kpis:`_kpis_i2poc_552`,burnGrid:`_burnGrid_i2poc_567`,burnStrip:`_burnStrip_i2poc_579`,burnItem:`_burnItem_i2poc_590`,freeSeat:`_freeSeat_i2poc_598`,freeHead:`_freeHead_i2poc_608`,freeTitle:`_freeTitle_i2poc_614`,freeValue:`_freeValue_i2poc_621`,freeBody:`_freeBody_i2poc_628`,scope:`_scope_i2poc_635`,scopeBlock:`_scopeBlock_i2poc_641`,scopeLead:`_scopeLead_i2poc_647`,scopeMeta:`_scopeMeta_i2poc_654`,scopeTable:`_scopeTable_i2poc_661`,scopeList:`_scopeList_i2poc_681`,ladder:`_ladder_i2poc_689`,ladderId:`_ladderId_i2poc_708`,sheetFooter:`_sheetFooter_i2poc_713`,sheetFootnote:`_sheetFootnote_i2poc_719`,sheetButtons:`_sheetButtons_i2poc_726`},l=t();function u({spec:e,onConfirm:t,onCancel:n}){let i=(0,s.useId)(),o=(0,s.useRef)(null),u=(0,s.useRef)(null);return(0,l.jsxs)(r,{open:e!==null,onClose:n,titleId:i,title:e?.title??``,initialFocusRef:e?.destructive?o:u,children:[(0,l.jsx)(`div`,{className:c.confirmBody,children:e?.body}),(0,l.jsxs)(`div`,{className:c.confirmActions,children:[(0,l.jsx)(a,{ref:o,variant:`ghost`,onClick:n,children:`Cancel`}),(0,l.jsx)(a,{ref:u,variant:e?.destructive?`danger`:`primary`,onClick:t,children:e?.confirmLabel??`Confirm`})]})]})}function d(){let e=o(),[t,n]=(0,s.useState)(null),{request:r}=e,a=(0,s.useCallback)((e,t,i={})=>{let a=()=>r(e,t,i.onDone);i.confirm?n({spec:i.confirm,run:a}):a()},[r]),c=(0,l.jsxs)(l.Fragment,{children:[(0,l.jsx)(u,{spec:t?.spec??null,onCancel:()=>n(null),onConfirm:()=>{let e=t;n(null),e?.run()}}),(0,l.jsx)(i,{open:e.tokenOpen,onClose:e.closeToken,reason:e.tokenReason,tokenHelp:`the mutation token ashlr verse printed`})]});return{act:a,busy:e.busy,error:e.error,clearError:e.clearError,readOnly:e.readOnly,dialogs:c}}function f({actions:e}){return e.readOnly?(0,l.jsx)(`p`,{className:c.actionNote,role:`status`,children:`Read-only session: this server was started without dispatch, so switching, stopping and vetoing are unavailable. Everything shown is live.`}):e.error?(0,l.jsxs)(`p`,{className:c.actionError,role:`alert`,children:[e.error,(0,l.jsx)(`button`,{type:`button`,className:c.linkButton,onClick:e.clearError,children:`Dismiss`})]}):null}export{d as n,c as r,f as t};
|
|
2
|
-
//# sourceMappingURL=actions-Bszsdpms.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"actions-Bszsdpms.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/command/command.module.css","../../../../../../src/web-ui/routes/verse/command/actions.tsx"],"sourcesContent":["/*\n * routes/verse/command/command.module.css — Command's cards and top bar\n * (unit C7). Tokens only: style-scan-310 bans raw hex colours and px font\n * sizes in this folder, and every colour here follows the theme.\n */\n\n/* ---- lead: top bar, verdict, since ------------------------------------ */\n.lead {\n display: flex;\n flex-direction: column;\n gap: var(--space-3);\n}\n\n.bar {\n display: flex;\n align-items: center;\n flex-wrap: wrap;\n gap: var(--space-2) var(--space-3);\n min-height: var(--control-h);\n}\n\n.barSpacer {\n flex: 1;\n}\n\n.barSecondary {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-2);\n}\n\n.switchWrap {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.barLabel,\n.pillLabel {\n font-family: var(--font-display);\n font-size: var(--text-2xs-size);\n line-height: var(--text-2xs-line);\n letter-spacing: var(--tracking-label);\n text-transform: uppercase;\n color: var(--text-tertiary);\n}\n\n.switchOption {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n}\n\n.touchMark {\n color: var(--text-tertiary);\n}\n\n.pill,\n.chip {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n min-height: var(--control-h-sm);\n padding: 0 var(--space-3);\n border: 1px solid var(--border-default);\n border-radius: var(--radius-full);\n background: var(--bg-surface);\n color: var(--text-primary);\n font-family: var(--font-ui);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n white-space: nowrap;\n}\n\nbutton.pill,\nbutton.chip {\n cursor: pointer;\n transition: background-color var(--duration-fast) var(--ease-standard);\n}\n\nbutton.pill:hover,\nbutton.chip:hover {\n background: var(--bg-hover);\n}\n\n.pill:focus-visible,\n.chip:focus-visible,\n.linkButton:focus-visible,\n.moreLink:focus-visible {\n outline: 2px solid var(--border-focus);\n outline-offset: 2px;\n}\n\n.chip[data-tone='warning'] {\n border-color: var(--status-warning-solid);\n}\n\n.chip[data-tone='danger'] {\n border-color: var(--status-danger-solid);\n color: var(--status-danger-fg);\n}\n\n.dot {\n width: 8px;\n height: 8px;\n border-radius: var(--radius-full);\n flex: none;\n background: var(--status-neutral-solid);\n}\n\n.dot[data-tone='success'] {\n background: var(--status-success-solid);\n}\n.dot[data-tone='warning'] {\n background: var(--status-warning-solid);\n}\n.dot[data-tone='danger'] {\n background: var(--status-danger-solid);\n}\n.dot[data-tone='unknown'] {\n background: var(--chart-unknown-hatch);\n border: 1px solid var(--status-unknown-solid);\n}\n\n/* Verdict: 17/24, weight 500 (SPEC-310C §6). */\n.verdict {\n margin: 0;\n font-size: var(--text-lg-size);\n line-height: var(--text-lg-line);\n font-weight: var(--font-weight-medium);\n color: var(--text-primary);\n font-variant-numeric: tabular-nums;\n}\n\n.verdictPart[data-tone='danger'] {\n color: var(--status-danger-fg);\n}\n.verdictPart[data-tone='warning'] {\n color: var(--status-warning-fg);\n}\n.verdictPart[data-tone='success'] {\n color: var(--status-success-fg);\n}\n.verdictPart[data-tone='unknown'] {\n color: var(--status-unknown-fg);\n font-style: italic;\n}\n\n.verdictSep {\n color: var(--text-tertiary);\n}\n\n.since {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n}\n\n.sinceLead {\n color: var(--text-tertiary);\n}\n\n.sinceEmpty {\n color: var(--text-tertiary);\n}\n\n.sinceChip {\n display: inline-flex;\n align-items: center;\n padding: 1px var(--space-2);\n border-radius: var(--radius-full);\n background: var(--status-neutral-bg);\n color: var(--status-neutral-fg);\n font-variant-numeric: tabular-nums;\n}\n.sinceChip[data-tone='success'] {\n background: var(--status-success-bg);\n color: var(--status-success-fg);\n}\n.sinceChip[data-tone='danger'] {\n background: var(--status-danger-bg);\n color: var(--status-danger-fg);\n}\n.sinceChip[data-tone='warning'] {\n background: var(--status-warning-bg);\n color: var(--status-warning-fg);\n}\n.sinceChip[data-tone='info'] {\n background: var(--status-info-bg);\n color: var(--status-info-fg);\n}\n\n.actionNote,\n.actionError {\n margin: 0;\n padding: var(--space-2) var(--space-3);\n border-radius: var(--radius-md);\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n}\n\n.actionNote {\n background: var(--bg-hover);\n color: var(--text-secondary);\n}\n\n.actionError {\n display: flex;\n align-items: baseline;\n gap: var(--space-3);\n background: var(--status-danger-bg);\n color: var(--status-danger-fg);\n}\n\n/* ---- shared small controls ------------------------------------------- */\n.linkButton,\n.moreLink {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n padding: 0;\n border: 0;\n background: none;\n color: var(--text-link);\n font: inherit;\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n text-decoration: none;\n cursor: pointer;\n white-space: nowrap;\n}\n\n.linkButton:hover,\n.moreLink:hover {\n text-decoration: underline;\n}\n\n.moreLink {\n align-self: flex-start;\n}\n\n.moreLink:disabled {\n color: var(--text-disabled);\n cursor: default;\n text-decoration: none;\n}\n\n.kbd {\n padding: 0 var(--space-1);\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-xs);\n color: var(--text-tertiary);\n font-family: var(--font-mono);\n font-size: var(--text-2xs-size);\n}\n\n.muted {\n margin: 0;\n color: var(--text-tertiary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n}\n\n.mono {\n font-family: var(--font-mono);\n font-size: var(--text-xs-size);\n}\n\n.num {\n text-align: right;\n font-variant-numeric: tabular-nums;\n}\n\n.confirmBody {\n color: var(--text-secondary);\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line-relaxed);\n}\n\n.confirmActions {\n display: flex;\n justify-content: flex-end;\n gap: var(--space-2);\n margin-top: var(--space-5);\n}\n\n/* ---- Needs you ------------------------------------------------------- */\n.needsList {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.needsRow {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto;\n align-items: start;\n gap: var(--space-2) var(--space-3);\n padding: var(--space-2) 0;\n border-top: 1px solid var(--border-subtle);\n}\n\n.needsRow:first-child {\n border-top: 0;\n padding-top: 0;\n}\n\n.sevDot {\n width: 8px;\n height: 8px;\n margin-top: 6px;\n border-radius: var(--radius-full);\n background: var(--status-info-solid);\n}\n.sevDot[data-severity='warn'] {\n background: var(--status-warning-solid);\n}\n.sevDot[data-severity='high'] {\n background: var(--status-danger-solid);\n}\n\n.needsText {\n display: flex;\n flex-direction: column;\n gap: 2px;\n min-width: 0;\n}\n\n.needsTitle {\n color: var(--text-primary);\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n overflow-wrap: anywhere;\n}\n\n.needsDetail {\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n overflow-wrap: anywhere;\n}\n\n.needsMeta {\n color: var(--text-tertiary);\n font-family: var(--font-mono);\n font-size: var(--text-2xs-size);\n line-height: var(--text-2xs-line);\n}\n\n.needsActions {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n align-items: center;\n gap: var(--space-2);\n}\n\n.allClear {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n padding: var(--space-4) 0;\n}\n\n.allClearTitle {\n font-family: var(--font-display);\n font-size: var(--text-md-size);\n line-height: var(--text-md-line);\n font-weight: var(--font-weight-semibold);\n color: var(--text-primary);\n}\n\n.allClearBody {\n color: var(--text-secondary);\n font-size: var(--text-sm-size);\n}\n\n/* ---- Leader ---------------------------------------------------------- */\n.memo {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n margin: 0;\n}\n\n.memoRow {\n display: grid;\n grid-template-columns: 96px minmax(0, 1fr);\n gap: var(--space-3);\n align-items: baseline;\n}\n\n.memoRow dd {\n margin: 0;\n}\n\n.memoText {\n color: var(--text-primary);\n font-size: var(--text-base-size);\n line-height: var(--text-base-line);\n}\n\n.delta {\n display: inline-block;\n margin-left: var(--space-2);\n padding: 0 var(--space-2);\n border-radius: var(--radius-full);\n background: var(--status-info-bg);\n color: var(--status-info-fg);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line-relaxed);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n.dryRun {\n font-family: var(--font-display); /* micro-labels follow the Display-font setting */\n padding: 0 var(--space-2);\n border: 1px dashed var(--border-strong);\n border-radius: var(--radius-full);\n color: var(--text-secondary);\n font-size: var(--text-2xs-size);\n line-height: var(--text-xs-line);\n text-transform: uppercase;\n letter-spacing: var(--tracking-label);\n}\n\n.actionList {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n border-top: 1px solid var(--border-subtle);\n}\n\n.actionRow {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr) auto;\n gap: var(--space-3);\n align-items: center;\n padding: var(--space-2) 0;\n border-bottom: 1px solid var(--border-subtle);\n}\n\n.actionRow[data-status='vetoed'] .actionSummary {\n text-decoration: line-through;\n color: var(--text-tertiary);\n}\n\n.classBadge {\n display: inline-flex;\n align-items: center;\n justify-content: center;\n width: 20px;\n height: 20px;\n border: 1px solid var(--border-default);\n border-radius: var(--radius-sm);\n color: var(--text-secondary);\n font-family: var(--font-display);\n font-size: var(--text-2xs-size);\n font-weight: var(--font-weight-semibold);\n}\n\n.classBadge[data-class='B'] {\n border-color: var(--status-warning-solid);\n color: var(--status-warning-fg);\n}\n\n.classBadge[data-class='C'] {\n border-style: dashed;\n}\n\n.actionText {\n display: flex;\n flex-direction: column;\n min-width: 0;\n}\n\n.actionSummary {\n color: var(--text-primary);\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n overflow-wrap: anywhere;\n}\n\n.actionWhy {\n color: var(--text-tertiary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n overflow-wrap: anywhere;\n}\n\n.actionState {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.statusWord {\n color: var(--text-tertiary);\n font-size: var(--text-xs-size);\n white-space: nowrap;\n}\n\n.statusWord[data-status='escalated'] {\n color: var(--status-warning-fg);\n}\n\n.statusWord[data-status='failed'],\n.statusWord[data-status='refused'] {\n color: var(--status-danger-fg);\n}\n\n.vetoChip {\n border: 1px solid var(--border-default);\n}\n\n.ring {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n color: var(--status-warning-fg);\n font-size: var(--text-xs-size);\n font-variant-numeric: tabular-nums;\n white-space: nowrap;\n}\n\n.ringTrack {\n fill: none;\n stroke: var(--border-subtle);\n stroke-width: 2.5;\n}\n\n.ringFill {\n fill: none;\n stroke: var(--status-warning-solid);\n stroke-width: 2.5;\n stroke-linecap: round;\n}\n\n.ringText {\n min-width: 4ch;\n}\n\n/* ---- KPIs and burn-downs --------------------------------------------- */\n.kpis {\n display: grid;\n grid-template-columns: repeat(5, minmax(0, 1fr));\n gap: var(--surface-gap);\n align-items: start;\n}\n\n[data-viewport='medium'] .kpis {\n grid-template-columns: repeat(3, minmax(0, 1fr));\n}\n\n[data-viewport='compact'] .kpis {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n\n.burnGrid {\n display: grid;\n grid-template-columns: repeat(4, minmax(0, 1fr));\n gap: var(--surface-gap);\n align-items: start;\n}\n\n[data-viewport='medium'] .burnGrid {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n}\n\n/* 375: one card at a time, snapping — the next card peeks in at the edge. */\n.burnStrip {\n display: grid;\n grid-auto-flow: column;\n grid-auto-columns: 86%;\n gap: var(--space-3);\n overflow-x: auto;\n overscroll-behavior-x: contain;\n scroll-snap-type: x mandatory;\n padding-bottom: var(--space-1);\n}\n\n.burnStrip > .burnItem {\n scroll-snap-align: start;\n}\n\n.burnItem {\n min-width: 0;\n}\n\n.freeSeat {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n padding: var(--card-pad);\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-lg);\n background: var(--bg-surface);\n}\n\n.freeHead {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.freeTitle {\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n font-weight: var(--font-weight-semibold);\n color: var(--text-primary);\n}\n\n.freeValue {\n font-size: var(--text-2xl-size);\n line-height: var(--text-2xl-line);\n font-weight: var(--font-weight-semibold);\n color: var(--text-secondary);\n}\n\n.freeBody {\n color: var(--text-tertiary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line-relaxed);\n}\n\n/* ---- Touch ID sheet -------------------------------------------------- */\n.scope {\n display: flex;\n flex-direction: column;\n gap: var(--space-5);\n}\n\n.scopeBlock {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n}\n\n.scopeLead {\n margin: 0;\n color: var(--text-primary);\n font-size: var(--text-base-size);\n line-height: var(--text-base-line);\n}\n\n.scopeMeta {\n margin: 0;\n color: var(--text-tertiary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line-relaxed);\n}\n\n.scopeTable {\n width: 100%;\n border-collapse: collapse;\n font-size: var(--text-xs-size);\n}\n\n.scopeTable th {\n padding: var(--space-1) var(--space-2) var(--space-1) 0;\n border-bottom: 1px solid var(--border-subtle);\n color: var(--text-tertiary);\n font-weight: var(--font-weight-medium);\n text-align: left;\n}\n\n.scopeTable td {\n padding: var(--space-1) var(--space-2) var(--space-1) 0;\n border-bottom: 1px solid var(--border-subtle);\n color: var(--text-primary);\n}\n\n.scopeList {\n margin: 0;\n padding-left: var(--space-4);\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line-relaxed);\n}\n\n.ladder {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n margin: 0;\n padding: 0;\n list-style: none;\n counter-reset: rung;\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line-relaxed);\n color: var(--text-secondary);\n}\n\n.ladder li {\n display: grid;\n grid-template-columns: 56px minmax(0, 1fr);\n gap: var(--space-2);\n}\n\n.ladderId {\n font-family: var(--font-mono);\n color: var(--text-primary);\n}\n\n.sheetFooter {\n display: flex;\n flex-direction: column;\n gap: var(--space-3);\n}\n\n.sheetFootnote {\n margin: 0;\n color: var(--text-tertiary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line-relaxed);\n}\n\n.sheetButtons {\n display: flex;\n justify-content: flex-end;\n gap: var(--space-2);\n}\n\n@media (prefers-reduced-motion: reduce) {\n button.pill,\n button.chip {\n transition: none;\n }\n}\n","/**\n * routes/verse/command/actions.tsx — how every write on the four surfaces\n * reaches the server (unit C7).\n *\n * Order is fixed and the same for a click, a key and the palette\n * (SPEC-310C §1 \"Guarded actions ask for confirmation, then the mutation\n * token\"):\n *\n * 1. a confirmation dialog, when the action asks for one (Stop, Veto,\n * Resume, every Needs-you approve / reject / veto);\n * 2. the mutation token, when none is held (useGuardedAction);\n * 3. the request, one at a time, with the server's own refusal sentence\n * shown on failure and read-only sessions explained, never errored.\n *\n * LOWERING needs no confirmation (SPEC-310B I1: \"lowering authority is\n * instant\") — callers simply omit `confirm` for the switch-down path.\n */\nimport { useCallback, useId, useRef, useState, type ReactNode } from 'react';\nimport { MutationTokenDialog } from '../../../components/auth/MutationTokenDialog.js';\nimport { Dialog } from '../../../components/primitives/Dialog.js';\nimport { Button } from '../../../components/primitives/Button.js';\nimport { useGuardedAction } from '../autonomy/use-guarded-action.js';\nimport styles from './command.module.css';\n\nexport interface ConfirmSpec {\n title: string;\n body: ReactNode;\n confirmLabel: string;\n destructive?: boolean;\n}\n\nexport function ConfirmDialog({ spec, onConfirm, onCancel }: { spec: ConfirmSpec | null; onConfirm: () => void; onCancel: () => void }) {\n const titleId = useId();\n const cancelRef = useRef<HTMLButtonElement>(null);\n const confirmRef = useRef<HTMLButtonElement>(null);\n return (\n <Dialog\n open={spec !== null}\n onClose={onCancel}\n titleId={titleId}\n title={spec?.title ?? ''}\n // A destructive confirm starts on Cancel, so a stray Enter never stops the fleet.\n initialFocusRef={spec?.destructive ? cancelRef : confirmRef}\n >\n <div className={styles.confirmBody}>{spec?.body}</div>\n <div className={styles.confirmActions}>\n <Button ref={cancelRef} variant=\"ghost\" onClick={onCancel}>\n Cancel\n </Button>\n <Button ref={confirmRef} variant={spec?.destructive ? 'danger' : 'primary'} onClick={onConfirm}>\n {spec?.confirmLabel ?? 'Confirm'}\n </Button>\n </div>\n </Dialog>\n );\n}\n\nexport interface SurfaceActions {\n /** Confirm (when asked), then token (when needed), then run `fn`. */\n act: <T>(fn: () => Promise<T>, reason: string, options?: { confirm?: ConfirmSpec; onDone?: (result: T) => void }) => void;\n busy: boolean;\n error: string | null;\n clearError: () => void;\n readOnly: boolean;\n /** Render once per surface. */\n dialogs: ReactNode;\n}\n\nexport function useSurfaceActions(): SurfaceActions {\n const guard = useGuardedAction();\n const [pending, setPending] = useState<{ spec: ConfirmSpec; run: () => void } | null>(null);\n const { request } = guard;\n\n const act = useCallback(\n <T,>(fn: () => Promise<T>, reason: string, options: { confirm?: ConfirmSpec; onDone?: (result: T) => void } = {}) => {\n const run = () => request(fn, reason, options.onDone);\n if (options.confirm) setPending({ spec: options.confirm, run });\n else run();\n },\n [request],\n );\n\n const dialogs = (\n <>\n <ConfirmDialog\n spec={pending?.spec ?? null}\n onCancel={() => setPending(null)}\n onConfirm={() => {\n const next = pending;\n setPending(null);\n next?.run();\n }}\n />\n <MutationTokenDialog open={guard.tokenOpen} onClose={guard.closeToken} reason={guard.tokenReason} tokenHelp=\"the mutation token ashlr verse printed\" />\n </>\n );\n\n return { act, busy: guard.busy, error: guard.error, clearError: guard.clearError, readOnly: guard.readOnly, dialogs };\n}\n\n/** The error / read-only line a surface shows under its top bar. */\nexport function ActionStatus({ actions }: { actions: Pick<SurfaceActions, 'error' | 'clearError' | 'readOnly'> }) {\n if (actions.readOnly) {\n return (\n <p className={styles.actionNote} role=\"status\">\n Read-only session: this server was started without dispatch, so switching, stopping and vetoing are unavailable. Everything shown is live.\n </p>\n );\n }\n if (!actions.error) return null;\n return (\n <p className={styles.actionError} role=\"alert\">\n {actions.error}\n <button type=\"button\" className={styles.linkButton} onClick={actions.clearError}>\n Dismiss\n </button>\n </p>\n );\n}\n"],"mappings":"8oFC+BA,SAAgB,EAAc,CAAE,OAAM,YAAW,YAAuF,CACtI,IAAM,GAAA,EAAU,EAAA,MAAA,CAAM,EAChB,GAAA,EAAY,EAAA,OAAA,CAA0B,IAAI,EAC1C,GAAA,EAAa,EAAA,OAAA,CAA0B,IAAI,EACjD,OACE,EAAA,EAAA,KAAA,CAAC,EAAD,CACE,KAAM,IAAS,KACf,QAAS,EACA,UACT,MAAO,GAAM,OAAS,GAEtB,gBAAiB,GAAM,YAAc,EAAY,EANnD,SAAA,EAQE,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,YAAc,SAAA,GAAM,IAAU,CAAA,GACrD,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAO,eAAvB,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,IAAK,EAAW,QAAQ,QAAQ,QAAS,EAAU,SAAA,QAEnD,CAAA,GACR,EAAA,EAAA,IAAA,CAAC,EAAD,CAAQ,IAAK,EAAY,QAAS,GAAM,YAAc,SAAW,UAAW,QAAS,EAClF,SAAA,GAAM,cAAgB,SACjB,CAAA,CACL,CACC,CAAA,CAAA,GAEZ,CAaA,SAAgB,GAAoC,CAClD,IAAM,EAAQ,EAAiB,EACzB,CAAC,EAAS,IAAA,EAAc,EAAA,SAAA,CAAwD,IAAI,EACpF,CAAE,WAAY,EAEd,GAAA,EAAM,EAAA,YAAA,EACL,EAAsB,EAAgB,EAAmE,CAAC,IAAM,CACnH,IAAM,MAAY,EAAQ,EAAI,EAAQ,EAAQ,MAAM,EAChD,EAAQ,QAAS,EAAW,CAAE,KAAM,EAAQ,QAAS,KAAI,CAAC,EACzD,EAAI,CACX,EACA,CAAC,CAAO,CACV,EAEM,GACJ,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,KAAM,GAAS,MAAQ,KACvB,aAAgB,EAAW,IAAI,EAC/B,cAAiB,CACf,IAAM,EAAO,EACb,EAAW,IAAI,EACf,GAAM,IAAI,CACZ,CACD,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,EAAD,CAAqB,KAAM,EAAM,UAAW,QAAS,EAAM,WAAY,OAAQ,EAAM,YAAa,UAAU,wCAA0C,CAAA,CACtJ,CAAA,CAAA,EAGJ,MAAO,CAAE,MAAK,KAAM,EAAM,KAAM,MAAO,EAAM,MAAO,WAAY,EAAM,WAAY,SAAU,EAAM,SAAU,SAAQ,CACtH,CAGA,SAAgB,EAAa,CAAE,WAAmF,CAShH,OARI,EAAQ,UAER,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,WAAY,KAAK,SAAS,SAAA,4IAE5C,CAAA,EAGF,EAAQ,OAEX,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,UAAW,EAAO,YAAa,KAAK,QAAvC,SAAA,CACG,EAAQ,OACT,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,KAAK,SAAS,UAAW,EAAO,WAAY,QAAS,EAAQ,WAAY,SAAA,SAEzE,CAAA,CACP,IAPsB,IAS7B"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
._lead_i2poc_8{gap:var(--space-3);flex-direction:column;display:flex}._bar_i2poc_14{align-items:center;gap:var(--space-2) var(--space-3);min-height:var(--control-h);flex-wrap:wrap;display:flex}._barSpacer_i2poc_22{flex:1}._barSecondary_i2poc_26{gap:var(--space-2);flex-wrap:wrap;display:flex}._switchWrap_i2poc_32{align-items:center;gap:var(--space-2);display:inline-flex}._barLabel_i2poc_38,._pillLabel_i2poc_39{font-family:var(--font-display);font-size:var(--text-2xs-size);line-height:var(--text-2xs-line);letter-spacing:var(--tracking-label);text-transform:uppercase;color:var(--text-tertiary)}._switchOption_i2poc_48{align-items:center;gap:var(--space-1);display:inline-flex}._touchMark_i2poc_54{color:var(--text-tertiary)}._pill_i2poc_39,._chip_i2poc_59{align-items:center;gap:var(--space-2);min-height:var(--control-h-sm);padding:0 var(--space-3);border:1px solid var(--border-default);border-radius:var(--radius-full);background:var(--bg-surface);color:var(--text-primary);font-family:var(--font-ui);font-size:var(--text-xs-size);line-height:var(--text-xs-line);white-space:nowrap;display:inline-flex}button._pill_i2poc_39,button._chip_i2poc_59{cursor:pointer;transition:background-color var(--duration-fast) var(--ease-standard)}button._pill_i2poc_39:hover,button._chip_i2poc_59:hover{background:var(--bg-hover)}._pill_i2poc_39:focus-visible,._chip_i2poc_59:focus-visible,._linkButton_i2poc_88:focus-visible,._moreLink_i2poc_89:focus-visible{outline:2px solid var(--border-focus);outline-offset:2px}._chip_i2poc_59[data-tone=warning]{border-color:var(--status-warning-solid)}._chip_i2poc_59[data-tone=danger]{border-color:var(--status-danger-solid);color:var(--status-danger-fg)}._dot_i2poc_103{border-radius:var(--radius-full);background:var(--status-neutral-solid);flex:none;width:8px;height:8px}._dot_i2poc_103[data-tone=success]{background:var(--status-success-solid)}._dot_i2poc_103[data-tone=warning]{background:var(--status-warning-solid)}._dot_i2poc_103[data-tone=danger]{background:var(--status-danger-solid)}._dot_i2poc_103[data-tone=unknown]{background:var(--chart-unknown-hatch);border:1px solid var(--status-unknown-solid)}._verdict_i2poc_126{font-size:var(--text-lg-size);line-height:var(--text-lg-line);font-weight:var(--font-weight-medium);color:var(--text-primary);font-variant-numeric:tabular-nums;margin:0}._verdictPart_i2poc_135[data-tone=danger]{color:var(--status-danger-fg)}._verdictPart_i2poc_135[data-tone=warning]{color:var(--status-warning-fg)}._verdictPart_i2poc_135[data-tone=success]{color:var(--status-success-fg)}._verdictPart_i2poc_135[data-tone=unknown]{color:var(--status-unknown-fg);font-style:italic}._verdictSep_i2poc_149{color:var(--text-tertiary)}._since_i2poc_153{align-items:center;gap:var(--space-2);font-size:var(--text-xs-size);line-height:var(--text-xs-line);flex-wrap:wrap;display:flex}._sinceLead_i2poc_162,._sinceEmpty_i2poc_166{color:var(--text-tertiary)}._sinceChip_i2poc_170{padding:1px var(--space-2);border-radius:var(--radius-full);background:var(--status-neutral-bg);color:var(--status-neutral-fg);font-variant-numeric:tabular-nums;align-items:center;display:inline-flex}._sinceChip_i2poc_170[data-tone=success]{background:var(--status-success-bg);color:var(--status-success-fg)}._sinceChip_i2poc_170[data-tone=danger]{background:var(--status-danger-bg);color:var(--status-danger-fg)}._sinceChip_i2poc_170[data-tone=warning]{background:var(--status-warning-bg);color:var(--status-warning-fg)}._sinceChip_i2poc_170[data-tone=info]{background:var(--status-info-bg);color:var(--status-info-fg)}._actionNote_i2poc_196,._actionError_i2poc_197{padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);font-size:var(--text-sm-size);line-height:var(--text-sm-line);margin:0}._actionNote_i2poc_196{background:var(--bg-hover);color:var(--text-secondary)}._actionError_i2poc_197{align-items:baseline;gap:var(--space-3);background:var(--status-danger-bg);color:var(--status-danger-fg);display:flex}._linkButton_i2poc_88,._moreLink_i2poc_89{align-items:center;gap:var(--space-1);color:var(--text-link);font:inherit;font-size:var(--text-xs-size);line-height:var(--text-xs-line);cursor:pointer;white-space:nowrap;background:0 0;border:0;padding:0;text-decoration:none;display:inline-flex}._linkButton_i2poc_88:hover,._moreLink_i2poc_89:hover{text-decoration:underline}._moreLink_i2poc_89{align-self:flex-start}._moreLink_i2poc_89:disabled{color:var(--text-disabled);cursor:default;text-decoration:none}._kbd_i2poc_251{padding:0 var(--space-1);border:1px solid var(--border-subtle);border-radius:var(--radius-xs);color:var(--text-tertiary);font-family:var(--font-mono);font-size:var(--text-2xs-size)}._muted_i2poc_260{color:var(--text-tertiary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);margin:0}._mono_i2poc_267{font-family:var(--font-mono);font-size:var(--text-xs-size)}._num_i2poc_272{text-align:right;font-variant-numeric:tabular-nums}._confirmBody_i2poc_277{color:var(--text-secondary);font-size:var(--text-sm-size);line-height:var(--text-sm-line-relaxed)}._confirmActions_i2poc_283{justify-content:flex-end;gap:var(--space-2);margin-top:var(--space-5);display:flex}._needsList_i2poc_291{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}._needsRow_i2poc_299{align-items:start;gap:var(--space-2) var(--space-3);padding:var(--space-2) 0;border-top:1px solid var(--border-subtle);grid-template-columns:auto minmax(0,1fr) auto;display:grid}._needsRow_i2poc_299:first-child{border-top:0;padding-top:0}._sevDot_i2poc_313{border-radius:var(--radius-full);background:var(--status-info-solid);width:8px;height:8px;margin-top:6px}._sevDot_i2poc_313[data-severity=warn]{background:var(--status-warning-solid)}._sevDot_i2poc_313[data-severity=high]{background:var(--status-danger-solid)}._needsText_i2poc_327{flex-direction:column;gap:2px;min-width:0;display:flex}._needsTitle_i2poc_334{color:var(--text-primary);font-size:var(--text-sm-size);line-height:var(--text-sm-line);overflow-wrap:anywhere}._needsDetail_i2poc_341{color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);overflow-wrap:anywhere}._needsMeta_i2poc_348{color:var(--text-tertiary);font-family:var(--font-mono);font-size:var(--text-2xs-size);line-height:var(--text-2xs-line)}._needsActions_i2poc_355{justify-content:flex-end;align-items:center;gap:var(--space-2);flex-wrap:wrap;display:flex}._allClear_i2poc_363{gap:var(--space-1);padding:var(--space-4) 0;flex-direction:column;display:flex}._allClearTitle_i2poc_370{font-family:var(--font-display);font-size:var(--text-md-size);line-height:var(--text-md-line);font-weight:var(--font-weight-semibold);color:var(--text-primary)}._allClearBody_i2poc_378{color:var(--text-secondary);font-size:var(--text-sm-size)}._memo_i2poc_384{gap:var(--space-2);flex-direction:column;margin:0;display:flex}._memoRow_i2poc_391{gap:var(--space-3);grid-template-columns:96px minmax(0,1fr);align-items:baseline;display:grid}._memoRow_i2poc_391 dd{margin:0}._memoText_i2poc_402{color:var(--text-primary);font-size:var(--text-base-size);line-height:var(--text-base-line)}._delta_i2poc_408{margin-left:var(--space-2);padding:0 var(--space-2);border-radius:var(--radius-full);background:var(--status-info-bg);color:var(--status-info-fg);font-size:var(--text-xs-size);line-height:var(--text-xs-line-relaxed);font-variant-numeric:tabular-nums;white-space:nowrap;display:inline-block}._dryRun_i2poc_421{font-family:var(--font-display);padding:0 var(--space-2);border:1px dashed var(--border-strong);border-radius:var(--radius-full);color:var(--text-secondary);font-size:var(--text-2xs-size);line-height:var(--text-xs-line);text-transform:uppercase;letter-spacing:var(--tracking-label)}._actionList_i2poc_433{border-top:1px solid var(--border-subtle);flex-direction:column;margin:0;padding:0;list-style:none;display:flex}._actionRow_i2poc_442{gap:var(--space-3);padding:var(--space-2) 0;border-bottom:1px solid var(--border-subtle);grid-template-columns:auto minmax(0,1fr) auto;align-items:center;display:grid}._actionRow_i2poc_442[data-status=vetoed] ._actionSummary_i2poc_451{color:var(--text-tertiary);text-decoration:line-through}._classBadge_i2poc_456{border:1px solid var(--border-default);border-radius:var(--radius-sm);width:20px;height:20px;color:var(--text-secondary);font-family:var(--font-display);font-size:var(--text-2xs-size);font-weight:var(--font-weight-semibold);justify-content:center;align-items:center;display:inline-flex}._classBadge_i2poc_456[data-class=B]{border-color:var(--status-warning-solid);color:var(--status-warning-fg)}._classBadge_i2poc_456[data-class=C]{border-style:dashed}._actionText_i2poc_479{flex-direction:column;min-width:0;display:flex}._actionSummary_i2poc_451{color:var(--text-primary);font-size:var(--text-sm-size);line-height:var(--text-sm-line);overflow-wrap:anywhere}._actionWhy_i2poc_492{color:var(--text-tertiary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);overflow-wrap:anywhere}._actionState_i2poc_499{align-items:center;gap:var(--space-2);display:inline-flex}._statusWord_i2poc_505{color:var(--text-tertiary);font-size:var(--text-xs-size);white-space:nowrap}._statusWord_i2poc_505[data-status=escalated]{color:var(--status-warning-fg)}._statusWord_i2poc_505[data-status=failed],._statusWord_i2poc_505[data-status=refused]{color:var(--status-danger-fg)}._vetoChip_i2poc_520{border:1px solid var(--border-default)}._ring_i2poc_524{align-items:center;gap:var(--space-1);color:var(--status-warning-fg);font-size:var(--text-xs-size);font-variant-numeric:tabular-nums;white-space:nowrap;display:inline-flex}._ringTrack_i2poc_534{fill:none;stroke:var(--border-subtle);stroke-width:2.5px}._ringFill_i2poc_540{fill:none;stroke:var(--status-warning-solid);stroke-width:2.5px;stroke-linecap:round}._ringText_i2poc_547{min-width:4ch}._kpis_i2poc_552{gap:var(--surface-gap);grid-template-columns:repeat(5,minmax(0,1fr));align-items:start;display:grid}[data-viewport=medium] ._kpis_i2poc_552{grid-template-columns:repeat(3,minmax(0,1fr))}[data-viewport=compact] ._kpis_i2poc_552{grid-template-columns:repeat(2,minmax(0,1fr))}._burnGrid_i2poc_567{gap:var(--surface-gap);grid-template-columns:repeat(4,minmax(0,1fr));align-items:start;display:grid}[data-viewport=medium] ._burnGrid_i2poc_567{grid-template-columns:repeat(2,minmax(0,1fr))}._burnStrip_i2poc_579{gap:var(--space-3);overscroll-behavior-x:contain;scroll-snap-type:x mandatory;padding-bottom:var(--space-1);grid-auto-columns:86%;grid-auto-flow:column;display:grid;overflow-x:auto}._burnStrip_i2poc_579>._burnItem_i2poc_590{scroll-snap-align:start}._burnItem_i2poc_590{min-width:0}._freeSeat_i2poc_598{gap:var(--space-2);padding:var(--card-pad);border:1px solid var(--border-subtle);border-radius:var(--radius-lg);background:var(--bg-surface);flex-direction:column;display:flex}._freeHead_i2poc_608{align-items:center;gap:var(--space-2);display:inline-flex}._freeTitle_i2poc_614{font-size:var(--text-sm-size);line-height:var(--text-sm-line);font-weight:var(--font-weight-semibold);color:var(--text-primary)}._freeValue_i2poc_621{font-size:var(--text-2xl-size);line-height:var(--text-2xl-line);font-weight:var(--font-weight-semibold);color:var(--text-secondary)}._freeBody_i2poc_628{color:var(--text-tertiary);font-size:var(--text-xs-size);line-height:var(--text-xs-line-relaxed)}._scope_i2poc_635{gap:var(--space-5);flex-direction:column;display:flex}._scopeBlock_i2poc_641{gap:var(--space-2);flex-direction:column;display:flex}._scopeLead_i2poc_647{color:var(--text-primary);font-size:var(--text-base-size);line-height:var(--text-base-line);margin:0}._scopeMeta_i2poc_654{color:var(--text-tertiary);font-size:var(--text-xs-size);line-height:var(--text-xs-line-relaxed);margin:0}._scopeTable_i2poc_661{border-collapse:collapse;width:100%;font-size:var(--text-xs-size)}._scopeTable_i2poc_661 th{padding:var(--space-1) var(--space-2) var(--space-1) 0;border-bottom:1px solid var(--border-subtle);color:var(--text-tertiary);font-weight:var(--font-weight-medium);text-align:left}._scopeTable_i2poc_661 td{padding:var(--space-1) var(--space-2) var(--space-1) 0;border-bottom:1px solid var(--border-subtle);color:var(--text-primary)}._scopeList_i2poc_681{padding-left:var(--space-4);color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line-relaxed);margin:0}._ladder_i2poc_689{gap:var(--space-2);counter-reset:rung;font-size:var(--text-xs-size);line-height:var(--text-xs-line-relaxed);color:var(--text-secondary);flex-direction:column;margin:0;padding:0;list-style:none;display:flex}._ladder_i2poc_689 li{gap:var(--space-2);grid-template-columns:56px minmax(0,1fr);display:grid}._ladderId_i2poc_708{font-family:var(--font-mono);color:var(--text-primary)}._sheetFooter_i2poc_713{gap:var(--space-3);flex-direction:column;display:flex}._sheetFootnote_i2poc_719{color:var(--text-tertiary);font-size:var(--text-xs-size);line-height:var(--text-xs-line-relaxed);margin:0}._sheetButtons_i2poc_726{justify-content:flex-end;gap:var(--space-2);display:flex}@media (prefers-reduced-motion:reduce){button._pill_i2poc_39,button._chip_i2poc_59{transition:none}}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./workbench-types-DzN-5trg.js";import{r as t}from"./verse-model-E98kXngO.js";import{t as n}from"./seat-subscription-CrWOV4Qc.js";function r(e,t){if(!e)return null;for(let n of e)if(n.seatId===t)return n;return null}function i(e,t=Date.now()){if(typeof e!=`string`||e.length===0)return null;let n=Date.parse(e);if(!Number.isFinite(n))return null;let r=new Date(n),i=r.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`});return new Date(t).toDateString()===r.toDateString()?`today ${i}`:n>t&&n-t<5184e5?`${r.toLocaleDateString([],{weekday:`short`})} ${i}`:`${r.toLocaleDateString([],{month:`short`,day:`numeric`})}, ${i}`}function a(e){return(e.capacity?.binding??null)?.resetDescription??null}function o(e,t,n=Date.now()){let r=null,o=null;if(t!==null)(t.connection===`signed-out`||t.connection===`exhausted`)&&(r=t.connection,o=t.resetAt);else if(e.engine!==`local`){let t=e.capacity?.usability;(t===`signed-out`||t===`exhausted`)&&(r=t,o=t===`exhausted`?e.capacity?.binding?.resetsAt??null:null)}if(r===null)return null;if(r===`signed-out`)return{connection:r,resetAt:null,reason:`${e.label} is signed out — reconnect it to use this seat.`};let s=i(o,n),c=s===null?a(e):null,l=s===null?c===null?``:` — ${c}`:` — resets ${s}`;return{connection:r,resetAt:o,reason:`${e.label} is out of usage${l}.`}}function s(e){return e.models.some(e=>!e.unavailableReason)}function c(e){return e.engine===`local`?2:e.capacity?.usability===`ready`?0:1}function l(e){let t=e.capacity?.binding?.usedPercent;return typeof t==`number`&&Number.isFinite(t)?t:101}function u(e,t,n){return!(!s(e)||e.health.state===`unavailable`||o(e,t,n)!==null||e.engine===`local`&&t!==null&&t.connection===`unknown`&&t.reasons.length>0)}function d(e,t,n,i=Date.now()){let a=t.find(t=>t.id===e)??null,o=t.map((e,t)=>({seat:e,index:t})).filter(({seat:t})=>t.id!==e&&u(t,r(n,t.id),i));return o.sort((e,t)=>{let n=c(e.seat)-c(t.seat);if(n!==0)return n;if(a!==null){let n=e.seat.engine===a.engine?0:1,r=t.seat.engine===a.engine?0:1;if(n!==r)return n-r}let r=l(e.seat)-l(t.seat);return r===0?e.index-t.index:r}),o.slice(0,5).map(({seat:e})=>e.id)}Object.freeze({"all-in":Object.freeze({claude:Object.freeze({enabled:!0,reservePercent:0}),codex:Object.freeze({enabled:!1,reservePercent:0}),grok:Object.freeze({enabled:!0,reservePercent:0}),local:Object.freeze({enabled:!0,reservePercent:0})}),balanced:Object.freeze({claude:Object.freeze({enabled:!0,reservePercent:40,maxSessionWindowPercent:70}),codex:Object.freeze({enabled:!1,reservePercent:40,maxSessionWindowPercent:70}),grok:Object.freeze({enabled:!0,reservePercent:0}),local:Object.freeze({enabled:!0,reservePercent:0})}),reserve:Object.freeze({claude:Object.freeze({enabled:!0,reservePercent:85,maxSessionWindowPercent:50}),codex:Object.freeze({enabled:!1,reservePercent:85,maxSessionWindowPercent:50}),grok:Object.freeze({enabled:!0,reservePercent:85}),local:Object.freeze({enabled:!0,reservePercent:0})})});var f=Object.freeze({"all-in":`Autonomy may use all available usage on every enabled seat.`,balanced:`Autonomy stops at each seat’s reserve, so you keep headroom for your own sessions.`,reserve:`Autonomy runs on free local models, plus only a small slice of paid seats.`}),p={eligible:`Eligible`,held:`Held back`,off:`Off`,unknown:`No reading`},m=[{value:`reserve`,label:`Reserve`,description:f.reserve},{value:`balanced`,label:`Balanced`,description:f.balanced},{value:`all-in`,label:`All-in`,description:f[`all-in`]}];function h(e,t){if(!t)return!1;let n=e=>m.findIndex(t=>t.value===e);return n(e)>n(t)}function g(e){return Math.round(e)}function _(e,t,n){return t.enabled?n?.eligibleForAutonomy?`eligible`:!e&&(n===null||n.sessionUsedPercent===null&&n.weeklyUsedPercent===null)?`unknown`:`held`:`off`}function v(e,t,n,r){if(t||r===null)return[];let i=[],a=100-n.reservePercent,o=r.weeklyUsedPercent!==null||e===`claude`||e===`grok`;if(o){let t=r.weeklyUsedPercent;i.push({kind:`weekly`,label:e===`grok`?`Billing period`:`Weekly`,usedPercent:t,ceilingPercent:a,binding:r.bindingWindow===`weekly`,description:t===null?`Weekly window: no reading.`:`Weekly window ${g(t)}% used; autonomy stops at ${g(a)}%, ${g(n.reservePercent)}% kept for you.`})}if(r.sessionUsedPercent!==null||e===`claude`){let e=r.sessionUsedPercent,t=n.maxSessionWindowPercent??100,s=o?t:Math.min(t,a);i.push({kind:`session`,label:`5-hour`,usedPercent:e,ceilingPercent:s,binding:r.bindingWindow===`session`,description:e===null?`5-hour window: no reading.`:`5-hour window ${g(e)}% used; ${s>=100?`no autonomy ceiling`:`autonomy stops at ${g(s)}%`}.`})}return i}function y(e){let t=new Map(e.headroom.map(e=>[e.seatId,e]));return e.seatInfo.map(n=>{let r=e.effective[n.seatId]??{seatId:n.seatId,enabled:!1,reservePercent:100},i=t.get(n.seatId)??null,a=i?.reasons??[];return{seatId:n.seatId,label:n.label,engine:n.engine,free:n.free,policy:r,headroom:i,status:_(n.free,r,i),why:a[0]??(n.free?`Local model — free.`:`No reading yet.`),more:a.slice(1),bars:v(n.engine,n.free,r,i),hasSessionCeiling:!n.free&&(n.engine===`claude`||n.engine===`codex`)}})}function b(e){let t=e.filter(e=>e.status===`eligible`).length,n=e.length;if(n===0)return{eligible:t,total:n,sentence:`No seats are known yet.`};let r=e.filter(e=>e.status===`eligible`&&!e.free).length,i=t-r,a=[];return r>0&&a.push(`${r} paid`),i>0&&a.push(`${i} local`),{eligible:t,total:n,sentence:t===0?`No seat can take autonomous work right now.`:`${t} of ${n} seats can take autonomous work (${a.join(`, `)}).`}}function x(e,t){let n=Date.parse(e);if(!Number.isFinite(n))return`unknown`;let r=Math.max(0,Math.round((t-n)/6e4));return r<1?`just now`:r<120?`${r} min ago`:`${Math.round(r/60)} h ago`}function S(e,t=0,n=100){return Number.isFinite(e)?Math.max(t,Math.min(n,Math.round(e))):t}var C={connected:`connected`,expiring:`sign-in expiring`,"signed-out":`signed out`,exhausted:`out of usage`,"binary-skew":`older CLI pinned`,unknown:`not checked`},w={connected:`success`,expiring:`warning`,"signed-out":`danger`,exhausted:`danger`,"binary-skew":`warning`,unknown:`neutral`},T={"signed-out":0,exhausted:1,expiring:2,"binary-skew":3,unknown:4,connected:5};function E(e){return e.connection===`connected`?!1:e.connection!==`unknown`||e.reasons.length>0&&!e.reasons[0].includes(`has not reached this seat`)}function D(e,t=[],n=Date.now()){let r=new Map(t.map(e=>[e.id,e.label]));return e.filter(E).map(e=>{let t=i(e.resetAt,n);return{report:e,label:r.get(e.seatId)??e.seatId,word:C[e.connection],tone:w[e.connection],detail:e.reasons[0]??null,reset:t===null?null:`resets ${t}`}}).sort((e,t)=>T[e.report.connection]-T[t.report.connection])}function O(e){return e.map(e=>/^[A-Za-z0-9_@%+=:,./-]+$/.test(e)||e.startsWith(`~/`)&&/^[A-Za-z0-9_@%+=:,./~-]+$/.test(e)?e:e.startsWith(`~/`)?`~/'${e.slice(2).replaceAll(`'`,`'\\''`)}'`:`'${e.replaceAll(`'`,`'\\''`)}'`).join(` `)}function k(e){if(e.length===0)return`All seats are connected.`;let t=e.filter(e=>e.tone===`danger`).length;return t>0?t===1?`${e.find(e=>e.tone===`danger`).label} can't run turns right now.`:`${t} seats can't run turns right now.`:e.length===1?`${e[0].label} needs attention.`:`${e.length} seats need attention.`}var A={ready:`success`,tight:`warning`,blocked:`danger`,unread:`neutral`};function j(e){return A[e]}function M(e,t){return{id:e.id,label:e.label,usedPercent:e.usedPercent,limitReached:e.limitReached,resetText:e.resetText,binding:t}}function N(e){return e?{connection:e.connection,word:C[e.connection],tone:w[e.connection],reasons:[...e.reasons],fixKind:e.fix.kind,fixCommand:e.fix.command&&e.fix.command.length>0?[...e.fix.command]:null}:null}function P(e){if(!e||e.free)return null;let{policy:t}=e,n=Math.max(0,Math.min(100,Math.round(t.reservePercent))),r=t.enabled?n===0?`No reserve — autonomy may use all of it`:`Reserved for you ${n}%`:`Autonomy off — all yours`;return{percent:t.enabled?n:null,label:r,autonomy:e.status,autonomyWord:p[e.status],why:e.why}}function F(r,i,a){let o=n(r),s=[];o.binding&&s.push(M(o.binding,!0));for(let e of o.others){if(s.length>=3)break;s.push(M(e,!1))}let c=N(i.get(r.id)),l=c!==null&&(c.connection===`signed-out`||c.connection===`exhausted`);return{seatId:r.id,label:r.label,engine:r.engine,monogram:e[r.engine],kind:o.kind,plan:o.plan,cls:l?`blocked`:o.cls,word:l?t.blocked:o.word,summary:l?c.reasons[0]??c.word:o.summary,connection:c,windows:s,credits:o.credits,reserve:P(a.get(r.id)),notes:[...o.notes],localCount:1}}function I(t,r){let i=t.map(e=>n(e)),a=i.filter(e=>e.cls===`ready`).length,o=i.filter(e=>e.cls===`blocked`).length,s=a>0?`ready`:o===i.length?`blocked`:`unread`,c=t.map(e=>r.get(e.id)).find(e=>e!==void 0),l=t.length;return{seatId:`local`,label:`Local models`,engine:`local`,monogram:e.local,kind:`local`,plan:null,cls:s,word:i.find(e=>e.cls===s)?.word??`no reading`,summary:s===`ready`?`${l} ${l===1?`model`:`models`} on this machine · free`:s===`blocked`?i[0]?.summary??`local runtime unavailable`:`readiness not reported`,connection:N(c),windows:[],credits:null,reserve:null,notes:[],localCount:l}}function L(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}var R=e=>typeof e==`number`&&Number.isFinite(e)?e:null;function z(e){if(!L(e)||typeof e.seatId!=`string`)return null;let t=e.bindingWindow;return{seatId:e.seatId,sessionUsedPercent:R(e.sessionUsedPercent),weeklyUsedPercent:R(e.weeklyUsedPercent),bindingWindow:t===`session`||t===`weekly`?t:null,autonomyHeadroomPercent:R(e.autonomyHeadroomPercent),resetAt:typeof e.resetAt==`string`?e.resetAt:null,eligibleForAutonomy:e.eligibleForAutonomy===!0,reasons:Array.isArray(e.reasons)?e.reasons.filter(e=>typeof e==`string`):[]}}function B(e,t){if(!L(t)||typeof t.enabled!=`boolean`)return null;let n=t.reservePercent;if(typeof n!=`number`||!Number.isFinite(n))return null;let r={seatId:e,enabled:t.enabled,reservePercent:n},i=t.maxSessionWindowPercent;return typeof i==`number`&&Number.isFinite(i)&&(r.maxSessionWindowPercent=i),r}function V(e){if(!L(e)||!Array.isArray(e.seatInfo))return new Map;let t=L(e.effective)?e.effective:{},n={},r=[];for(let i of e.seatInfo){if(!L(i)||typeof i.seatId!=`string`)continue;let e=i.seatId,a=i.engine;if(a===`claude`||a===`codex`||a===`grok`||a===`local`){if(Object.prototype.hasOwnProperty.call(t,e)){let r=B(e,t[e]);if(r===null)continue;n[e]=r}r.push({seatId:e,label:typeof i.label==`string`?i.label:e,engine:a,free:i.free===!0})}}let i=Array.isArray(e.headroom)?e.headroom.map(z).filter(e=>e!==null):[],a={...e,seatInfo:r,effective:n,headroom:i};try{return new Map(y(a).map(e=>[e.seatId,e]))}catch{return new Map}}function H(e){let t=new Map;if(!Array.isArray(e))return t;for(let n of e){if(!L(n)||typeof n.seatId!=`string`)continue;let e=n.connection;if(typeof e!=`string`||!Object.prototype.hasOwnProperty.call(C,e))continue;let r=L(n.fix)?n.fix:{},i=r.kind,a=Array.isArray(r.command)&&r.command.every(e=>typeof e==`string`)?r.command:void 0;t.set(n.seatId,{...n,reasons:Array.isArray(n.reasons)?n.reasons.filter(e=>typeof e==`string`):[],fix:{kind:i===`reauth`||i===`repin`||i===`wait`?i:`none`,...a?{command:a}:{}}})}return t}function U(e,t={}){let n=H(t.health),r=V(t.budget),i=Array.isArray(e)?e.filter(e=>L(e)&&typeof e.id==`string`):[],a=t.local??`collapse`,o=i;if(t.seatIds){let e=new Map(i.map(e=>[e.id,e]));o=t.seatIds.map(t=>e.get(t)).filter(e=>e!==void 0)}let s=[],c=[],l=-1;for(let e of o){if(e.engine===`local`){if(a===`hide`)continue;if(a===`collapse`){l===-1&&(l=s.length),c.push(e);continue}}s.push(F(e,n,r))}if(c.length>0){let e=c.length===1?F(c[0],n,r):I(c,n);s.splice(l,0,e)}return s}function W(e){let t=e.filter(e=>e.kind===`subscription`),n=e.filter(e=>e.kind===`local`),r=t.filter(e=>e.cls===`ready`||e.cls===`tight`).length,i=t.filter(e=>e.cls===`unread`).length,a=[];return t.length===0?a.push(`No accounts connected`):a.push(`${r} of ${t.length} ${t.length===1?`account`:`accounts`} usable`),i>0&&a.push(`${i} not read yet`),n.some(e=>e.cls===`ready`)?a.push(`local models ready`):n.length>0&&a.push(`local models not ready`),a.join(` · `)}function G(e){let t=null;for(let n of e){if(n.kind!==`subscription`)continue;let e=n.windows.find(e=>e.binding)??null,r;if(n.cls===`blocked`||e?.limitReached)r=300;else if(e?.usedPercent!=null)r=(n.cls===`tight`?100:0)+e.usedPercent;else continue;(t===null||r>t.score)&&(t={row:n,score:r})}return t?.row??null}function K(e,t,n={}){return U(e,{...n,seatIds:[t],local:`each`})[0]??null}function q(e,t,n){let r=`${e.label} ${t.label}`,i=t.resetText===null?``:`, ${t.resetText}`;if(t.limitReached)return`${r}: limit reached${i}`;if(t.usedPercent===null)return`${r}: no reading${i}`;let a=n!==null&&n>0?`; ${n}% kept for you`:``;return`${r}: ${Math.round(t.usedPercent)}% used${a}${i}`}export{d as _,V as a,k as c,m as d,p as f,x as g,h,j as i,D as l,S as m,W as n,G as o,b as p,K as r,q as s,U as t,O as u,o as v};
|
|
2
|
-
//# sourceMappingURL=capacity-strip-model-BR539Ci8.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"capacity-strip-model-BR539Ci8.js","names":[],"sources":["../../../../../../src/core/verse/seat-readiness.ts","../../../../../../src/core/routing/policy.ts","../../../../../../src/web-ui/routes/verse/budget/budget-model.ts","../../../../../../src/web-ui/routes/verse/health/health-model.ts","../../../../../../src/web-ui/routes/verse/usage/capacity-strip-model.ts"],"sourcesContent":["/**\n * core/verse/seat-readiness.ts — \"can this seat run a turn right now, and if\n * not, where else can the operator go?\" (V3.10, unit A2).\n *\n * PURE and BROWSER-SAFE on purpose: the engine's admission gate\n * (`getSeatReadiness` in core/verse/seats.ts) and the Composer's block\n * (web-ui/routes/verse/health/ComposerSeatBlock.tsx) must give the SAME\n * answer, with the SAME ranked alternatives, or the UI would offer a seat the\n * server then refuses. One implementation, imported by both. Type-only\n * imports and `Intl` only — no node: modules.\n *\n * ── WHAT BLOCKS A SEAT ─────────────────────────────────────────────────────\n * Only POSITIVE evidence that a turn would fail at the provider:\n * - `signed-out` — the CLI said so (status command or the live collector).\n * - `exhausted` — every window that carried a reading is spent and no\n * Codex credit balance remains (`seatUsability` in seats.ts;\n * a spent per-model window beside a healthy account-wide\n * one is `tight`, not exhausted).\n * `unknown`, `expiring` and `binary-skew` are WARNINGS, never refusals: an\n * admission gate that refused on \"we could not read it\" would lock Mason out\n * of his own seats every time a probe hiccuped (docs/VERSE-TELEMETRY-V2.md —\n * no signal is not a verdict).\n *\n * ── HOW ALTERNATIVES ARE RANKED ────────────────────────────────────────────\n * (research r2/accounts.md, recommendation 4): other subscription seats with\n * measured headroom first, then subscription seats whose headroom is tight or\n * unread, then local models (free, always last because they are the weakest).\n * Inside a tier the SAME ENGINE leads (a Codex user blocked on one account most\n * likely wants the other Codex account), then the lower binding-window\n * percentage, then discovery order. A seat with no runnable model, a local\n * seat whose runtime is not answering, or a seat that is itself blocked is\n * never offered.\n */\nimport type { SeatConnection, SeatHealthReport, SeatReadiness } from './health-types.js';\nimport type { VerseSeat } from './types.js';\n\n/** The only connections that refuse a turn. Everything else is a warning. */\nexport const SEAT_BLOCKING_CONNECTIONS: ReadonlySet<SeatConnection> = new Set<SeatConnection>(['signed-out', 'exhausted']);\n\n/** At most this many alternatives are offered — a list, not a directory. */\nexport const SEAT_MAX_ALTERNATIVES = 5;\n\nexport interface SeatBlock {\n connection: 'signed-out' | 'exhausted';\n /** One plain sentence naming the seat and the fact (\"Personal Codex is out of usage — resets Fri 2:25 PM.\"). */\n reason: string;\n /** Machine-readable reset instant, when the provider gave one. */\n resetAt: string | null;\n}\n\nfunction reportFor(reports: readonly SeatHealthReport[] | null | undefined, seatId: string): SeatHealthReport | null {\n if (!reports) return null;\n for (const report of reports) if (report.seatId === seatId) return report;\n return null;\n}\n\n/**\n * A reset instant as a short local phrase (\"Fri 2:25 PM\", \"Sep 30, 2:25 PM\"),\n * or null when `iso` is not a valid instant. Only a MACHINE-READABLE instant\n * is ever formatted — Claude's prose reset never reaches this function.\n */\nexport function describeResetAt(iso: string | null | undefined, now: number = Date.now()): string | null {\n if (typeof iso !== 'string' || iso.length === 0) return null;\n const at = Date.parse(iso);\n if (!Number.isFinite(at)) return null;\n const date = new Date(at);\n const time = date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });\n if (new Date(now).toDateString() === date.toDateString()) return `today ${time}`;\n // Within the coming week the weekday is the clearest name for a day.\n if (at > now && at - now < 6 * 24 * 60 * 60 * 1000) {\n return `${date.toLocaleDateString([], { weekday: 'short' })} ${time}`;\n }\n return `${date.toLocaleDateString([], { month: 'short', day: 'numeric' })}, ${time}`;\n}\n\n/** The provider's own reset wording for the seat's binding window (Claude publishes prose only). */\nfunction bindingResetDescription(seat: VerseSeat): string | null {\n const binding = seat.capacity?.binding ?? null;\n return binding?.resetDescription ?? null;\n}\n\n/**\n * Why `seat` cannot take a turn, or null when nothing positively blocks it.\n *\n * The health report (sweep + live telemetry) wins when present; without one\n * the seat's own `capacity.usability` — which is on every native seat the\n * server serves — is the fallback, so the seat picker can mark a blocked seat\n * before the health endpoint has ever been read.\n */\nexport function seatBlock(\n seat: VerseSeat,\n report: SeatHealthReport | null,\n now: number = Date.now(),\n): SeatBlock | null {\n let connection: SeatBlock['connection'] | null = null;\n let resetAt: string | null = null;\n if (report !== null) {\n if (report.connection === 'signed-out' || report.connection === 'exhausted') {\n connection = report.connection;\n resetAt = report.resetAt;\n }\n } else if (seat.engine !== 'local') {\n const usability = seat.capacity?.usability;\n if (usability === 'signed-out' || usability === 'exhausted') {\n connection = usability;\n resetAt = usability === 'exhausted' ? seat.capacity?.binding?.resetsAt ?? null : null;\n }\n }\n if (connection === null) return null;\n if (connection === 'signed-out') {\n return { connection, resetAt: null, reason: `${seat.label} is signed out — reconnect it to use this seat.` };\n }\n const when = describeResetAt(resetAt, now);\n const prose = when === null ? bindingResetDescription(seat) : null;\n const tail = when !== null ? ` — resets ${when}` : prose !== null ? ` — ${prose}` : '';\n return { connection, resetAt, reason: `${seat.label} is out of usage${tail}.` };\n}\n\nfunction hasRunnableModel(seat: VerseSeat): boolean {\n return seat.models.some((model) => !model.unavailableReason);\n}\n\n/** 0 = subscription seat with measured headroom, 1 = tight/unread subscription seat, 2 = local. */\nfunction tier(seat: VerseSeat): number {\n if (seat.engine === 'local') return 2;\n return seat.capacity?.usability === 'ready' ? 0 : 1;\n}\n\nfunction bindingPercent(seat: VerseSeat): number {\n const used = seat.capacity?.binding?.usedPercent;\n // Unread sorts after every reading: no signal is not \"0% used\".\n return typeof used === 'number' && Number.isFinite(used) ? used : 101;\n}\n\n/** Can `seat` be offered as somewhere else to go? */\nfunction offerable(seat: VerseSeat, report: SeatHealthReport | null, now: number): boolean {\n if (!hasRunnableModel(seat)) return false;\n if (seat.health.state === 'unavailable') return false;\n if (seatBlock(seat, report, now) !== null) return false;\n // A local seat is only worth offering while its runtime answers. `unknown`\n // with reasons is the sweep saying Ollama did not respond.\n if (seat.engine === 'local' && report !== null && report.connection === 'unknown' && report.reasons.length > 0) {\n return false;\n }\n return true;\n}\n\n/** Ranked ids of seats that could take the turn instead of `seatId` (see the file header). */\nexport function rankSeatAlternatives(\n seatId: string,\n seats: readonly VerseSeat[],\n reports: readonly SeatHealthReport[] | null | undefined,\n now: number = Date.now(),\n): string[] {\n const blocked = seats.find((seat) => seat.id === seatId) ?? null;\n const candidates = seats\n .map((seat, index) => ({ seat, index }))\n .filter(({ seat }) => seat.id !== seatId && offerable(seat, reportFor(reports, seat.id), now));\n candidates.sort((a, b) => {\n const byTier = tier(a.seat) - tier(b.seat);\n if (byTier !== 0) return byTier;\n if (blocked !== null) {\n const sameA = a.seat.engine === blocked.engine ? 0 : 1;\n const sameB = b.seat.engine === blocked.engine ? 0 : 1;\n if (sameA !== sameB) return sameA - sameB;\n }\n const byUse = bindingPercent(a.seat) - bindingPercent(b.seat);\n if (byUse !== 0) return byUse;\n return a.index - b.index;\n });\n return candidates.slice(0, SEAT_MAX_ALTERNATIVES).map(({ seat }) => seat.id);\n}\n\n/**\n * The admission answer for one seat. A seat that is not in `seats` at all is\n * reported READY with no reason: the readiness layer has no evidence about\n * it, and \"seat not found\" is the engine's own error to raise.\n */\nexport function seatReadiness(\n seatId: string,\n seats: readonly VerseSeat[],\n reports: readonly SeatHealthReport[] | null | undefined,\n now: number = Date.now(),\n): SeatReadiness {\n const seat = seats.find((candidate) => candidate.id === seatId) ?? null;\n if (seat === null) return { seatId, ready: true, reason: null, alternatives: [] };\n const block = seatBlock(seat, reportFor(reports, seatId), now);\n if (block === null) return { seatId, ready: true, reason: null, alternatives: [] };\n return { seatId, ready: false, reason: block.reason, alternatives: rankSeatAlternatives(seatId, seats, reports, now) };\n}\n","/**\n * Budget policy — mode defaults, effective per-seat policy, and strict update\n * parsing (V3.10 unit A9).\n *\n * THE MODEL (what a stored policy means)\n *\n * `policy.mode` picks a column of MODE_DEFAULTS below. `policy.seats` holds\n * the per-seat policies IN FORCE for that mode, but only for seats the\n * operator has touched; every other seat gets the mode's default for its\n * engine. So what the Budget panel shows is exactly what the router uses —\n * there is no hidden transform layered on top of a slider.\n *\n * Switching mode (`applyModeSwitch`) re-bases every stored seat on the new\n * mode's defaults and keeps only the two choices that are not \"how much\" but\n * \"whether at all\": `enabled` and a hard `dailyUsdCap`. A reserve tuned for\n * `balanced` would be meaningless in `all-in` (which by definition keeps\n * nothing back), so it is not carried across.\n *\n * DEFAULTS (Mason's decisions, recorded 2026-09-24 — binding):\n * balanced (default) — Claude keeps 40% of its weekly window for Mason and\n * is never touched while its 5-hour window is above 70%\n * (protects his live session). Grok 0% reserve. Local\n * unlimited. Codex OFF (no usage) until switched on.\n * all-in — autonomy may use all available usage (no reserve, no\n * session ceiling). Codex stays OFF by default.\n * reserve — free local models plus only a small paid cap: every\n * paid seat keeps 85% of its binding window back and a\n * 5-hour ceiling of 50%, and the router ranks local\n * first (router.ts).\n *\n * BROWSER-SAFE and PURE: no node: imports, no I/O. The Budget UI imports the\n * defaults from here so the \"reset to default\" hint can never drift from the\n * server.\n */\nimport {\n BUDGET_MODES,\n type BudgetMode,\n type BudgetPolicy,\n type BudgetResponse,\n type BudgetUpdateRequest,\n type SeatBudgetPolicy,\n} from './types.js';\n\n/** The engines a seat can belong to (mirrors `VerseEngine`, kept local so this file has no verse import). */\nexport type BudgetEngine = 'claude' | 'codex' | 'grok' | 'local';\n\nexport const BUDGET_ENGINES: readonly BudgetEngine[] = ['claude', 'codex', 'grok', 'local'];\n\n/** Same spelling rule the seat catalog and preferences use for seat ids. */\nexport const BUDGET_SEAT_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._:@/+-]{0,199}$/;\n\n/** Registry bound — a blast radius for a runaway client, not a UI limit. */\nexport const BUDGET_MAX_SEATS = 64;\n\n/** Upper bound on a daily USD cap; anything larger is a typo, not a budget. */\nexport const BUDGET_MAX_DAILY_USD = 10_000;\n\nexport const DEFAULT_BUDGET_MODE: BudgetMode = 'balanced';\n\n/** Who a seat is, for the Budget panel (headroom rows carry only the id). */\nexport interface BudgetSeatInfo {\n seatId: string;\n label: string;\n engine: BudgetEngine;\n /** True for local seats: $0, no provider window. */\n free: boolean;\n}\n\n/**\n * The body `GET/POST /api/verse/budget` actually serves: the frozen\n * `BudgetResponse` plus two ADDITIVE fields the panel needs to render a seat\n * it has never stored a policy for. `seats` stays the stored policy (only the\n * seats the operator touched); `effective` is what the router applies to\n * every seat it currently knows.\n */\nexport interface BudgetView extends BudgetResponse {\n seatInfo: BudgetSeatInfo[];\n effective: Record<string, SeatBudgetPolicy>;\n /** How old a reading may be before autonomy stops spending against it. */\n readingMaxAgeMs: number;\n /** When the seat readings behind `headroom` were sampled. */\n sampledAt: string;\n}\n\n/** Per-engine default in one mode; `seatId` is filled in by `defaultSeatPolicy`. */\ntype EngineDefault = Omit<SeatBudgetPolicy, 'seatId'>;\n\n/**\n * Mode × engine defaults. Frozen so a caller can never mutate the table the\n * whole process reads.\n *\n * Codex is `enabled: false` in every mode on purpose: on 2026-09-24 both Codex\n * accounts were at 100% with resets days away, and Mason turned Codex OFF for\n * autonomy \"until usage returns\". That is a standing choice, not a function of\n * the mode, so a mode switch must not silently turn it back on.\n */\nexport const MODE_DEFAULTS: Readonly<Record<BudgetMode, Readonly<Record<BudgetEngine, Readonly<EngineDefault>>>>> =\n Object.freeze({\n 'all-in': Object.freeze({\n claude: Object.freeze({ enabled: true, reservePercent: 0 }),\n codex: Object.freeze({ enabled: false, reservePercent: 0 }),\n grok: Object.freeze({ enabled: true, reservePercent: 0 }),\n local: Object.freeze({ enabled: true, reservePercent: 0 }),\n }),\n balanced: Object.freeze({\n claude: Object.freeze({ enabled: true, reservePercent: 40, maxSessionWindowPercent: 70 }),\n codex: Object.freeze({ enabled: false, reservePercent: 40, maxSessionWindowPercent: 70 }),\n grok: Object.freeze({ enabled: true, reservePercent: 0 }),\n local: Object.freeze({ enabled: true, reservePercent: 0 }),\n }),\n reserve: Object.freeze({\n claude: Object.freeze({ enabled: true, reservePercent: 85, maxSessionWindowPercent: 50 }),\n codex: Object.freeze({ enabled: false, reservePercent: 85, maxSessionWindowPercent: 50 }),\n grok: Object.freeze({ enabled: true, reservePercent: 85 }),\n local: Object.freeze({ enabled: true, reservePercent: 0 }),\n }),\n });\n\n/** Plain-language one-liners for the mode control (UI + API `why` text share them). */\nexport const MODE_DESCRIPTIONS: Readonly<Record<BudgetMode, string>> = Object.freeze({\n 'all-in': 'Autonomy may use all available usage on every enabled seat.',\n balanced: 'Autonomy stops at each seat’s reserve, so you keep headroom for your own sessions.',\n reserve: 'Autonomy runs on free local models, plus only a small slice of paid seats.',\n});\n\nexport function isBudgetMode(value: unknown): value is BudgetMode {\n return typeof value === 'string' && (BUDGET_MODES as readonly string[]).includes(value);\n}\n\n/**\n * Which engine a seat id belongs to, when the caller has no seat record.\n *\n * Seat ids are account ids from connections.json (`claude`, `codex-personal`,\n * `grok`) or `local:<tag>` for Ollama. An id that names no known engine is\n * treated as `claude`-class — the most protected default — rather than as\n * free local capacity: guessing \"free\" for an unknown seat would be the\n * fail-open this module exists to close.\n */\nexport function engineOfSeatId(seatId: string): BudgetEngine {\n const id = seatId.toLowerCase();\n if (id === 'local' || id.startsWith('local:')) return 'local';\n if (id.startsWith('codex')) return 'codex';\n if (id.startsWith('grok')) return 'grok';\n return 'claude';\n}\n\nexport function defaultSeatPolicy(mode: BudgetMode, seatId: string, engine: BudgetEngine = engineOfSeatId(seatId)): SeatBudgetPolicy {\n const base = MODE_DEFAULTS[mode][engine];\n const out: SeatBudgetPolicy = { seatId, enabled: base.enabled, reservePercent: base.reservePercent };\n if (base.maxSessionWindowPercent !== undefined) out.maxSessionWindowPercent = base.maxSessionWindowPercent;\n if (base.dailyUsdCap !== undefined) out.dailyUsdCap = base.dailyUsdCap;\n return out;\n}\n\n/** The policy the router applies to one seat: the stored one, or the mode default. */\nexport function effectiveSeatPolicy(policy: BudgetPolicy, seatId: string, engine?: BudgetEngine): SeatBudgetPolicy {\n const stored = policy.seats[seatId];\n if (stored) return { ...stored, seatId };\n return defaultSeatPolicy(policy.mode, seatId, engine ?? engineOfSeatId(seatId));\n}\n\n/** The policy a fresh install starts with: balanced, no per-seat deviations. */\nexport function defaultBudgetPolicy(): BudgetPolicy {\n // Epoch, not \"now\": nothing was ever decided here, and a timestamp that\n // moves on every read would claim a change that never happened.\n return { mode: DEFAULT_BUDGET_MODE, seats: {}, updatedAt: new Date(0).toISOString() };\n}\n\n// ---------------------------------------------------------------------------\n// Validation (shared by the store's lenient load and the API's strict update)\n// ---------------------------------------------------------------------------\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction isPercent(value: unknown, low = 0): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= low && value <= 100;\n}\n\nfunction isUsd(value: unknown): value is number {\n return typeof value === 'number' && Number.isFinite(value) && value >= 0 && value <= BUDGET_MAX_DAILY_USD;\n}\n\n/** Whole percents only: a 40.000001% reserve is noise, and integers diff cleanly. */\nfunction wholePercent(value: number): number {\n return Math.round(value);\n}\n\n/** Cents are the finest a USD cap means anything at. */\nfunction cents(value: number): number {\n return Math.round(value * 100) / 100;\n}\n\n/**\n * Salvage one stored seat entry, or null when it is unusable. Lenient on\n * purpose (the file is ours but may be hand-edited): an invalid optional field\n * is dropped, an invalid required field drops the entry — which then falls\n * back to the mode default, the conservative outcome.\n */\nexport function sanitizeSeatPolicy(seatId: string, raw: unknown): SeatBudgetPolicy | null {\n if (!BUDGET_SEAT_ID_RE.test(seatId) || !isObject(raw)) return null;\n if (typeof raw['enabled'] !== 'boolean' || !isPercent(raw['reservePercent'])) return null;\n const out: SeatBudgetPolicy = {\n seatId,\n enabled: raw['enabled'],\n reservePercent: wholePercent(raw['reservePercent']),\n };\n if (isPercent(raw['maxSessionWindowPercent'], 1)) {\n out.maxSessionWindowPercent = wholePercent(raw['maxSessionWindowPercent']);\n }\n if (isUsd(raw['dailyUsdCap'])) out.dailyUsdCap = cents(raw['dailyUsdCap']);\n return out;\n}\n\n/** Field-by-field salvage of a whole stored policy. Never throws. */\nexport function sanitizeBudgetPolicy(raw: unknown): BudgetPolicy {\n const out = defaultBudgetPolicy();\n if (!isObject(raw)) return out;\n if (isBudgetMode(raw['mode'])) out.mode = raw['mode'];\n const updatedAt = raw['updatedAt'];\n if (typeof updatedAt === 'string' && Number.isFinite(Date.parse(updatedAt))) {\n out.updatedAt = new Date(Date.parse(updatedAt)).toISOString();\n }\n const seats = raw['seats'];\n if (isObject(seats)) {\n let kept = 0;\n for (const seatId of Object.keys(seats).sort()) {\n if (kept >= BUDGET_MAX_SEATS) break;\n const entry = sanitizeSeatPolicy(seatId, seats[seatId]);\n if (!entry) continue;\n out.seats[seatId] = entry;\n kept += 1;\n }\n }\n return out;\n}\n\n/** The error the budget module throws for a bad request (duck-typed by `code`, like VerseServiceError). */\nexport class BudgetPolicyError extends Error {\n readonly code: 'VERSE_INVALID' | 'VERSE_TOO_LARGE';\n readonly status: 400 | 413;\n\n constructor(code: 'VERSE_INVALID' | 'VERSE_TOO_LARGE', message: string) {\n super(message);\n this.name = 'BudgetPolicyError';\n this.code = code;\n this.status = code === 'VERSE_TOO_LARGE' ? 413 : 400;\n }\n}\n\n/**\n * A validated per-seat patch. `null` on an optional field means \"clear it\"\n * (JSON has no `undefined`): `maxSessionWindowPercent: null` removes the\n * session ceiling, `dailyUsdCap: null` removes the cap.\n */\nexport interface SeatPolicyPatch {\n enabled?: boolean;\n reservePercent?: number;\n maxSessionWindowPercent?: number | null;\n dailyUsdCap?: number | null;\n}\n\nexport type ParsedBudgetUpdate =\n | { kind: 'mode'; mode: BudgetMode }\n | { kind: 'seat'; seatId: string; patch: SeatPolicyPatch };\n\nconst SEAT_PATCH_KEYS: ReadonlySet<string> = new Set([\n 'enabled',\n 'reservePercent',\n 'maxSessionWindowPercent',\n 'dailyUsdCap',\n]);\n\nfunction sameKeys(value: Record<string, unknown>, keys: readonly string[]): boolean {\n const own = Object.keys(value);\n return own.length === keys.length && keys.every((key) => Object.prototype.hasOwnProperty.call(value, key));\n}\n\n/**\n * Validate a POST body against EXACTLY one `BudgetUpdateRequest` form, so a\n * body can never change more than the operator clicked. Unknown keys are\n * refused (a misspelt `reservepercent` silently dropped would \"succeed\" and\n * change nothing).\n */\nexport function parseBudgetUpdate(value: unknown): ParsedBudgetUpdate {\n if (!isObject(value)) throw new BudgetPolicyError('VERSE_INVALID', 'budget update must be a JSON object');\n\n if (sameKeys(value, ['mode'])) {\n if (!isBudgetMode(value['mode'])) {\n throw new BudgetPolicyError('VERSE_INVALID', `mode must be one of: ${BUDGET_MODES.join(', ')}`);\n }\n return { kind: 'mode', mode: value['mode'] };\n }\n\n if (sameKeys(value, ['seatId', 'policy'])) {\n const seatId = value['seatId'];\n if (typeof seatId !== 'string' || !BUDGET_SEAT_ID_RE.test(seatId)) {\n throw new BudgetPolicyError('VERSE_INVALID', 'seatId must be a seat id');\n }\n const policy = value['policy'];\n if (!isObject(policy)) throw new BudgetPolicyError('VERSE_INVALID', 'policy must be an object');\n const keys = Object.keys(policy);\n if (keys.length === 0) throw new BudgetPolicyError('VERSE_INVALID', 'policy must change at least one field');\n for (const key of keys) {\n if (!SEAT_PATCH_KEYS.has(key)) throw new BudgetPolicyError('VERSE_INVALID', `unknown policy key: ${key}`);\n }\n const patch: SeatPolicyPatch = {};\n if ('enabled' in policy) {\n if (typeof policy['enabled'] !== 'boolean') throw new BudgetPolicyError('VERSE_INVALID', 'enabled must be a boolean');\n patch.enabled = policy['enabled'];\n }\n if ('reservePercent' in policy) {\n if (!isPercent(policy['reservePercent'])) {\n throw new BudgetPolicyError('VERSE_INVALID', 'reservePercent must be a number from 0 to 100');\n }\n patch.reservePercent = wholePercent(policy['reservePercent']);\n }\n if ('maxSessionWindowPercent' in policy) {\n const v = policy['maxSessionWindowPercent'];\n if (v !== null && !isPercent(v, 1)) {\n throw new BudgetPolicyError('VERSE_INVALID', 'maxSessionWindowPercent must be a number from 1 to 100, or null');\n }\n patch.maxSessionWindowPercent = v === null ? null : wholePercent(v);\n }\n if ('dailyUsdCap' in policy) {\n const v = policy['dailyUsdCap'];\n if (v !== null && !isUsd(v)) {\n throw new BudgetPolicyError('VERSE_INVALID', `dailyUsdCap must be a number from 0 to ${BUDGET_MAX_DAILY_USD}, or null`);\n }\n patch.dailyUsdCap = v === null ? null : cents(v);\n }\n return { kind: 'seat', seatId, patch };\n }\n\n throw new BudgetPolicyError('VERSE_INVALID', 'budget update must be exactly one of {mode} or {seatId, policy}');\n}\n\n/**\n * Re-base every stored seat on `mode`'s defaults, keeping `enabled` and a hard\n * `dailyUsdCap` (see the file header for why reserves are not carried).\n */\nexport function applyModeSwitch(\n policy: BudgetPolicy,\n mode: BudgetMode,\n nowIso: string,\n engineOf?: (seatId: string) => BudgetEngine | undefined,\n): BudgetPolicy {\n const seats: Record<string, SeatBudgetPolicy> = {};\n for (const seatId of Object.keys(policy.seats).sort()) {\n const stored = policy.seats[seatId]!;\n const next = defaultSeatPolicy(mode, seatId, engineOf?.(seatId) ?? engineOfSeatId(seatId));\n next.enabled = stored.enabled;\n if (stored.dailyUsdCap !== undefined) next.dailyUsdCap = stored.dailyUsdCap;\n seats[seatId] = next;\n }\n return { mode, seats, updatedAt: nowIso };\n}\n\n/** Apply one validated per-seat patch on top of the seat's effective policy. */\nexport function applySeatPatch(\n policy: BudgetPolicy,\n seatId: string,\n patch: SeatPolicyPatch,\n nowIso: string,\n engine?: BudgetEngine,\n): BudgetPolicy {\n if (!(seatId in policy.seats) && Object.keys(policy.seats).length >= BUDGET_MAX_SEATS) {\n throw new BudgetPolicyError('VERSE_TOO_LARGE', `at most ${BUDGET_MAX_SEATS} seats can carry a budget policy`);\n }\n const next = effectiveSeatPolicy(policy, seatId, engine);\n if (patch.enabled !== undefined) next.enabled = patch.enabled;\n if (patch.reservePercent !== undefined) next.reservePercent = patch.reservePercent;\n if (patch.maxSessionWindowPercent !== undefined) {\n if (patch.maxSessionWindowPercent === null) delete next.maxSessionWindowPercent;\n else next.maxSessionWindowPercent = patch.maxSessionWindowPercent;\n }\n if (patch.dailyUsdCap !== undefined) {\n if (patch.dailyUsdCap === null) delete next.dailyUsdCap;\n else next.dailyUsdCap = patch.dailyUsdCap;\n }\n const seats: Record<string, SeatBudgetPolicy> = { ...policy.seats, [seatId]: next };\n const sorted: Record<string, SeatBudgetPolicy> = {};\n for (const id of Object.keys(seats).sort()) sorted[id] = seats[id]!;\n return { mode: policy.mode, seats: sorted, updatedAt: nowIso };\n}\n\n/** Apply exactly one update form. Pure — the caller persists. */\nexport function applyBudgetUpdate(\n policy: BudgetPolicy,\n update: BudgetUpdateRequest | ParsedBudgetUpdate,\n nowIso: string,\n engineOf?: (seatId: string) => BudgetEngine | undefined,\n): BudgetPolicy {\n const parsed: ParsedBudgetUpdate = 'kind' in update ? update : parseBudgetUpdate(update);\n if (parsed.kind === 'mode') return applyModeSwitch(policy, parsed.mode, nowIso, engineOf);\n return applySeatPatch(policy, parsed.seatId, parsed.patch, nowIso, engineOf?.(parsed.seatId));\n}\n","/**\n * routes/verse/budget/budget-model.ts — pure view-model for the Budget panel.\n *\n * Turns a `BudgetView` (GET /api/verse/budget) into one row per seat: who it\n * is, the policy in force, a one-line verdict, and the geometry of its\n * headroom bars. No React, no fetch — so every honesty rule is unit-tested\n * here rather than asserted through the DOM.\n *\n * HONESTY RULES (docs/VERSE-TELEMETRY-V2.md):\n * - Unknown is not zero. A window with no reading renders as `unknown`\n * (dashed track + words), never an empty bar (\"plenty left\") or a full one\n * (\"exhausted\").\n * - The verdict is always a WORD (Eligible / Held back / Off / No reading);\n * colour only reinforces it.\n * - The \"why\" line is the server's own sentence, verbatim.\n */\nimport {\n MODE_DESCRIPTIONS,\n type BudgetEngine,\n type BudgetView,\n} from '../../../../core/routing/policy.js';\nimport type { BudgetMode, SeatBudgetPolicy, SeatHeadroom } from '../../../../core/routing/types.js';\n\nexport type BudgetSeatStatus = 'eligible' | 'held' | 'off' | 'unknown';\n\nexport const STATUS_WORDS: Readonly<Record<BudgetSeatStatus, string>> = {\n eligible: 'Eligible',\n held: 'Held back',\n off: 'Off',\n unknown: 'No reading',\n};\n\n/** One horizontal headroom bar (a usage window against its autonomy ceiling). */\nexport interface BudgetBar {\n kind: 'weekly' | 'session';\n label: string;\n /** 0–100, or null when this window has no reading. */\n usedPercent: number | null;\n /** Where autonomy stops (0–100). 100 = no ceiling. */\n ceilingPercent: number;\n /** Plain-language summary for screen readers and the table view. */\n description: string;\n /** True when this bar is the one binding autonomy right now. */\n binding: boolean;\n}\n\nexport interface BudgetSeatRow {\n seatId: string;\n label: string;\n engine: BudgetEngine;\n free: boolean;\n policy: SeatBudgetPolicy;\n headroom: SeatHeadroom | null;\n status: BudgetSeatStatus;\n /** First server reason, verbatim. */\n why: string;\n /** Remaining server reasons, verbatim. */\n more: string[];\n bars: BudgetBar[];\n /** Whether the 5-hour ceiling control applies (subscription seats with a short window). */\n hasSessionCeiling: boolean;\n}\n\nexport const BUDGET_MODE_OPTIONS: ReadonlyArray<{ value: BudgetMode; label: string; description: string }> = [\n { value: 'reserve', label: 'Reserve', description: MODE_DESCRIPTIONS.reserve },\n { value: 'balanced', label: 'Balanced', description: MODE_DESCRIPTIONS.balanced },\n { value: 'all-in', label: 'All-in', description: MODE_DESCRIPTIONS['all-in'] },\n];\n\n/**\n * Whether `mode` is above a grant's ceiling. Rank is the order of\n * BUDGET_MODE_OPTIONS (reserve < balanced < all-in) — the same order as\n * core/authority BUDGET_MODE_RANK, restated here so the budget panel does not\n * import the authority module into the web bundle. No ceiling (null) = no\n * mode is above it.\n */\nexport function modeAboveCeiling(mode: BudgetMode, ceiling: BudgetMode | null | undefined): boolean {\n if (!ceiling) return false;\n const rank = (m: BudgetMode) => BUDGET_MODE_OPTIONS.findIndex((o) => o.value === m);\n return rank(mode) > rank(ceiling);\n}\n\nfunction round(n: number): number {\n return Math.round(n);\n}\n\nfunction statusOf(free: boolean, policy: SeatBudgetPolicy, headroom: SeatHeadroom | null): BudgetSeatStatus {\n if (!policy.enabled) return 'off';\n if (headroom?.eligibleForAutonomy) return 'eligible';\n if (!free && (headroom === null || (headroom.sessionUsedPercent === null && headroom.weeklyUsedPercent === null))) {\n return 'unknown';\n }\n return 'held';\n}\n\nfunction barsFor(engine: BudgetEngine, free: boolean, policy: SeatBudgetPolicy, h: SeatHeadroom | null): BudgetBar[] {\n if (free || h === null) return [];\n const bars: BudgetBar[] = [];\n const reserveCeiling = 100 - policy.reservePercent;\n const hasWeekly = h.weeklyUsedPercent !== null || engine === 'claude' || engine === 'grok';\n if (hasWeekly) {\n const used = h.weeklyUsedPercent;\n bars.push({\n kind: 'weekly',\n label: engine === 'grok' ? 'Billing period' : 'Weekly',\n usedPercent: used,\n ceilingPercent: reserveCeiling,\n binding: h.bindingWindow === 'weekly',\n description: used === null\n ? 'Weekly window: no reading.'\n : `Weekly window ${round(used)}% used; autonomy stops at ${round(reserveCeiling)}%, ${round(policy.reservePercent)}% kept for you.`,\n });\n }\n if (h.sessionUsedPercent !== null || engine === 'claude') {\n const used = h.sessionUsedPercent;\n const sessionCeiling = policy.maxSessionWindowPercent ?? 100;\n const ceiling = hasWeekly ? sessionCeiling : Math.min(sessionCeiling, reserveCeiling);\n bars.push({\n kind: 'session',\n label: '5-hour',\n usedPercent: used,\n ceilingPercent: ceiling,\n binding: h.bindingWindow === 'session',\n description: used === null\n ? '5-hour window: no reading.'\n : `5-hour window ${round(used)}% used; ${ceiling >= 100 ? 'no autonomy ceiling' : `autonomy stops at ${round(ceiling)}%`}.`,\n });\n }\n return bars;\n}\n\n/** Rows in the server's seat order (which lists the operator's preferred local tags first). */\nexport function buildBudgetRows(view: BudgetView): BudgetSeatRow[] {\n const headroomById = new Map(view.headroom.map((h) => [h.seatId, h]));\n return view.seatInfo.map((info) => {\n const policy = view.effective[info.seatId] ?? { seatId: info.seatId, enabled: false, reservePercent: 100 };\n const headroom = headroomById.get(info.seatId) ?? null;\n const reasons = headroom?.reasons ?? [];\n return {\n seatId: info.seatId,\n label: info.label,\n engine: info.engine,\n free: info.free,\n policy,\n headroom,\n status: statusOf(info.free, policy, headroom),\n why: reasons[0] ?? (info.free ? 'Local model — free.' : 'No reading yet.'),\n more: reasons.slice(1),\n bars: barsFor(info.engine, info.free, policy, headroom),\n hasSessionCeiling: !info.free && (info.engine === 'claude' || info.engine === 'codex'),\n };\n });\n}\n\n/** Headline counts for the panel summary (\"3 of 7 seats can take autonomous work\"). */\nexport function budgetSummary(rows: readonly BudgetSeatRow[]): { eligible: number; total: number; sentence: string } {\n const eligible = rows.filter((r) => r.status === 'eligible').length;\n const total = rows.length;\n if (total === 0) return { eligible, total, sentence: 'No seats are known yet.' };\n const paid = rows.filter((r) => r.status === 'eligible' && !r.free).length;\n const free = eligible - paid;\n const parts: string[] = [];\n if (paid > 0) parts.push(`${paid} paid`);\n if (free > 0) parts.push(`${free} local`);\n return {\n eligible,\n total,\n sentence: eligible === 0\n ? 'No seat can take autonomous work right now.'\n : `${eligible} of ${total} seats can take autonomous work (${parts.join(', ')}).`,\n };\n}\n\n/** Human age of the readings, e.g. \"just now\", \"4 min ago\". */\nexport function readingAge(sampledAt: string, nowMs: number): string {\n const t = Date.parse(sampledAt);\n if (!Number.isFinite(t)) return 'unknown';\n const minutes = Math.max(0, Math.round((nowMs - t) / 60_000));\n if (minutes < 1) return 'just now';\n if (minutes < 120) return `${minutes} min ago`;\n return `${Math.round(minutes / 60)} h ago`;\n}\n\n/** Clamp a slider value to the range the API accepts. */\nexport function clampPercent(value: number, low = 0, high = 100): number {\n if (!Number.isFinite(value)) return low;\n return Math.max(low, Math.min(high, Math.round(value)));\n}\n","/**\n * routes/verse/health/health-model.ts — how a seat health report reads on\n * screen (V3.10, unit A2). Pure: no React, no I/O.\n *\n * Every surface that shows seat health (the banner, the Composer block, the\n * seat picker) takes its words from here so one seat is never described two\n * ways. State is never carried by colour alone: every tone comes with a word.\n */\nimport type { SeatConnection, SeatHealthReport } from '../../../../core/verse/health-types.js';\nimport { describeResetAt } from '../../../../core/verse/seat-readiness.js';\nimport type { VerseSeat } from '../../../data/api-types.js';\n\nexport type HealthTone = 'danger' | 'warning' | 'neutral' | 'success';\n\nexport const CONNECTION_WORD: Record<SeatConnection, string> = {\n connected: 'connected',\n expiring: 'sign-in expiring',\n 'signed-out': 'signed out',\n exhausted: 'out of usage',\n 'binary-skew': 'older CLI pinned',\n unknown: 'not checked',\n};\n\nexport const CONNECTION_TONE: Record<SeatConnection, HealthTone> = {\n connected: 'success',\n expiring: 'warning',\n 'signed-out': 'danger',\n exhausted: 'danger',\n 'binary-skew': 'warning',\n unknown: 'neutral',\n};\n\n/** Most urgent first: what blocks work, then what will, then what could be better. */\nconst SEVERITY: Record<SeatConnection, number> = {\n 'signed-out': 0,\n exhausted: 1,\n expiring: 2,\n 'binary-skew': 3,\n unknown: 4,\n connected: 5,\n};\n\nexport interface SeatHealthIssue {\n report: SeatHealthReport;\n /** The seat's human label (falls back to the id when the seat is not in the roster). */\n label: string;\n word: string;\n tone: HealthTone;\n /** The first, most specific reason, or null. */\n detail: string | null;\n /** \"resets Fri 2:25 PM\" when the provider gave an instant. */\n reset: string | null;\n}\n\n/**\n * Is this report worth interrupting the operator for? Every non-connected\n * state is, EXCEPT an `unknown` with nothing to say (a sweep that has not run\n * yet is not a fault, and saying \"not checked\" about every seat at boot would\n * teach the operator to ignore the banner).\n */\nexport function needsAttention(report: SeatHealthReport): boolean {\n if (report.connection === 'connected') return false;\n if (report.connection === 'unknown') {\n return report.reasons.length > 0 && !report.reasons[0]!.includes('has not reached this seat');\n }\n return true;\n}\n\nexport function seatHealthIssues(\n reports: readonly SeatHealthReport[],\n seats: readonly VerseSeat[] = [],\n now: number = Date.now(),\n): SeatHealthIssue[] {\n const labels = new Map(seats.map((seat) => [seat.id, seat.label]));\n return reports\n .filter(needsAttention)\n .map((report) => {\n const when = describeResetAt(report.resetAt, now);\n return {\n report,\n label: labels.get(report.seatId) ?? report.seatId,\n word: CONNECTION_WORD[report.connection],\n tone: CONNECTION_TONE[report.connection],\n detail: report.reasons[0] ?? null,\n reset: when === null ? null : `resets ${when}`,\n };\n })\n .sort((a, b) => SEVERITY[a.report.connection] - SEVERITY[b.report.connection]);\n}\n\n/**\n * An argv rendered for copy-paste into a POSIX shell. Plain words stay bare;\n * anything else is single-quoted. A leading `~/` stays OUTSIDE the quotes so\n * the shell still expands it.\n */\nexport function shellCommandText(argv: readonly string[]): string {\n return argv.map((arg) => {\n if (/^[A-Za-z0-9_@%+=:,./-]+$/.test(arg)) return arg;\n if (arg.startsWith('~/') && /^[A-Za-z0-9_@%+=:,./~-]+$/.test(arg)) return arg;\n if (arg.startsWith('~/')) return `~/'${arg.slice(2).replaceAll(\"'\", \"'\\\\''\")}'`;\n return `'${arg.replaceAll(\"'\", \"'\\\\''\")}'`;\n }).join(' ');\n}\n\n/** One line summarising the whole roster for a collapsed banner. */\nexport function issuesHeadline(issues: readonly SeatHealthIssue[]): string {\n if (issues.length === 0) return 'All seats are connected.';\n const blocked = issues.filter((issue) => issue.tone === 'danger').length;\n if (blocked > 0) {\n return blocked === 1 ? `${issues.find((i) => i.tone === 'danger')!.label} can't run turns right now.`\n : `${blocked} seats can't run turns right now.`;\n }\n return issues.length === 1 ? `${issues[0]!.label} needs attention.` : `${issues.length} seats need attention.`;\n}\n","/**\n * routes/verse/usage/capacity-strip-model.ts — ONE projection of \"how much of\n * each seat is left, what is it tied to, and how much is kept for me\", for\n * every surface that shows seat capacity (SPEC-310C §4: Apps & Accounts,\n * Usage, Resources, NewChatDialog, onboarding; the rail foot's capacity ring\n * and the composer's seat chip read `scarcestSeat` / `capacityRowFor`).\n *\n * Three sources, each already cached app-wide, each read HERE and nowhere\n * else so a seat is never described two ways:\n * - the seat itself (`VerseSeat`, from bootstrap / the /seats poll) — plan,\n * windows, resets, credits, through `seat-subscription.ts`, which owns the\n * honesty rules (binding window leads, no reading ≠ zero, the sentinel 100\n * is a flag, prose resets stay prose);\n * - A2's health report — connected / expiring / signed out / older CLI, and\n * the command that fixes it;\n * - A9's budget view — the reserve kept for Mason and whether autonomy may\n * use the seat right now, through `budget-model.ts`'s own rows.\n * Any of the last two may be missing; the row then says less, never more.\n *\n * Pure: no React, no I/O.\n */\nimport type { BudgetView } from '../../../../core/routing/policy.js';\nimport type { SeatBudgetPolicy, SeatHeadroom } from '../../../../core/routing/types.js';\nimport type { SeatConnection, SeatFixKind, SeatHealthReport } from '../../../../core/verse/health-types.js';\nimport { ENGINE_MONOGRAM } from '../../../../core/verse/workbench-types.js';\nimport type { VerseEngine, VerseSeat } from '../../../data/api-types.js';\nimport { buildBudgetRows, STATUS_WORDS, type BudgetSeatStatus } from '../budget/budget-model.js';\nimport { CONNECTION_TONE, CONNECTION_WORD, type HealthTone } from '../health/health-model.js';\nimport { seatSubscription, type SeatCapacityClass, type SeatWindowView } from '../seat-subscription.js';\nimport { SEAT_CAPACITY_WORD } from '../verse-model.js';\n\nexport type { SeatCapacityClass };\n\ntype BudgetRow = ReturnType<typeof buildBudgetRows>[number];\n\n/** Rows show at most this many windows: the binding one and the next two. */\nexport const CAPACITY_MAX_WINDOWS = 3;\n\nexport interface CapacityWindowRow {\n id: string;\n /** \"5-hour window\", \"weekly window\", \"weekly fable window\". */\n label: string;\n /** 0–100, or null = no reading (never a substituted zero). */\n usedPercent: number | null;\n /** The provider flagged the limit; no percentage exists. */\n limitReached: boolean;\n /** Provider prose verbatim, or a formatted instant; null when neither. */\n resetText: string | null;\n /** True for the window that constrains work right now. */\n binding: boolean;\n}\n\nexport interface CapacityConnection {\n connection: SeatConnection;\n word: string;\n tone: HealthTone;\n /** Plain, already-scrubbed reasons; empty when connected. */\n reasons: string[];\n fixKind: SeatFixKind;\n /** argv; null when nothing fixes it from a terminal. */\n fixCommand: string[] | null;\n}\n\nexport interface CapacityReserve {\n /** Share of the binding window kept for Mason; null when autonomy is off for this seat. */\n percent: number | null;\n /** \"Reserved for you 40%\", \"Autonomy off — all yours\", \"No reserve\". */\n label: string;\n autonomy: BudgetSeatStatus;\n /** \"Eligible\", \"Held back\", \"Off\", \"No reading\". */\n autonomyWord: string;\n /** The router's own first reason, verbatim. */\n why: string;\n}\n\nexport interface CapacityRow {\n /** A seat id, or `local` for the collapsed local row. */\n seatId: string;\n label: string;\n engine: VerseEngine;\n monogram: string;\n kind: 'subscription' | 'local';\n plan: string | null;\n cls: SeatCapacityClass;\n /** usable / tight / blocked / no reading. */\n word: string;\n /** One phrase: \"62% of 5-hour window used\", \"signed out — reconnect this account\". */\n summary: string;\n connection: CapacityConnection | null;\n windows: CapacityWindowRow[];\n credits: string | null;\n reserve: CapacityReserve | null;\n notes: string[];\n /** For the collapsed local row: how many local seats it stands for. */\n localCount: number;\n}\n\nexport interface CapacityInputs {\n health?: readonly SeatHealthReport[] | null;\n budget?: BudgetView | null;\n /**\n * Local seats: `collapse` (default) folds every Ollama tag into one row —\n * they share one machine and one readiness, and twelve identical rows are\n * noise; `each` lists them; `hide` drops them.\n */\n local?: 'collapse' | 'each' | 'hide';\n /** Only these seats, in this order (the new-chat dialog passes the chosen one). */\n seatIds?: readonly string[];\n}\n\nconst TONE_OF_CLASS: Record<SeatCapacityClass, HealthTone> = {\n ready: 'success',\n tight: 'warning',\n blocked: 'danger',\n unread: 'neutral',\n};\n\n/** How a capacity class reads as a tone (a word always rides with it). */\nexport function capacityTone(cls: SeatCapacityClass): HealthTone {\n return TONE_OF_CLASS[cls];\n}\n\nfunction windowRow(w: SeatWindowView, binding: boolean): CapacityWindowRow {\n return { id: w.id, label: w.label, usedPercent: w.usedPercent, limitReached: w.limitReached, resetText: w.resetText, binding };\n}\n\nfunction connectionOf(report: SeatHealthReport | undefined): CapacityConnection | null {\n if (!report) return null;\n return {\n connection: report.connection,\n word: CONNECTION_WORD[report.connection],\n tone: CONNECTION_TONE[report.connection],\n reasons: [...report.reasons],\n fixKind: report.fix.kind,\n fixCommand: report.fix.command && report.fix.command.length > 0 ? [...report.fix.command] : null,\n };\n}\n\nfunction reserveOf(budgetRow: BudgetRow | undefined): CapacityReserve | null {\n if (!budgetRow || budgetRow.free) return null;\n const { policy } = budgetRow;\n const pct = Math.max(0, Math.min(100, Math.round(policy.reservePercent)));\n const label = !policy.enabled\n ? 'Autonomy off — all yours'\n : pct === 0\n ? 'No reserve — autonomy may use all of it'\n : `Reserved for you ${pct}%`;\n return {\n percent: policy.enabled ? pct : null,\n label,\n autonomy: budgetRow.status,\n autonomyWord: STATUS_WORDS[budgetRow.status],\n why: budgetRow.why,\n };\n}\n\nfunction seatRow(\n seat: VerseSeat,\n health: ReadonlyMap<string, SeatHealthReport>,\n budget: ReadonlyMap<string, BudgetRow>,\n): CapacityRow {\n const view = seatSubscription(seat);\n const windows: CapacityWindowRow[] = [];\n if (view.binding) windows.push(windowRow(view.binding, true));\n for (const w of view.others) {\n if (windows.length >= CAPACITY_MAX_WINDOWS) break;\n windows.push(windowRow(w, false));\n }\n const connection = connectionOf(health.get(seat.id));\n // A seat A2 found signed out or out of usage cannot run a turn, whatever\n // its last window reading says (the engine's readiness gate refuses it —\n // seat-readiness.ts SEAT_BLOCKING_CONNECTIONS). Counting it \"usable\"\n // would promise a chat the engine will refuse.\n const blockedByHealth = connection !== null && (connection.connection === 'signed-out' || connection.connection === 'exhausted');\n return {\n seatId: seat.id,\n label: seat.label,\n engine: seat.engine,\n monogram: ENGINE_MONOGRAM[seat.engine],\n kind: view.kind,\n plan: view.plan,\n cls: blockedByHealth ? 'blocked' : view.cls,\n word: blockedByHealth ? SEAT_CAPACITY_WORD.blocked : view.word,\n summary: blockedByHealth ? (connection.reasons[0] ?? connection.word) : view.summary,\n connection,\n windows,\n credits: view.credits,\n reserve: reserveOf(budget.get(seat.id)),\n notes: [...view.notes],\n localCount: 1,\n };\n}\n\nfunction collapsedLocal(seats: readonly VerseSeat[], health: ReadonlyMap<string, SeatHealthReport>): CapacityRow {\n const rows = seats.map((s) => seatSubscription(s));\n const ready = rows.filter((r) => r.cls === 'ready').length;\n const blocked = rows.filter((r) => r.cls === 'blocked').length;\n const cls: SeatCapacityClass = ready > 0 ? 'ready' : blocked === rows.length ? 'blocked' : 'unread';\n // One runtime behind every tag: the first report that says anything speaks for it.\n const report = seats.map((s) => health.get(s.id)).find((r) => r !== undefined);\n const count = seats.length;\n return {\n seatId: 'local',\n label: 'Local models',\n engine: 'local',\n monogram: ENGINE_MONOGRAM.local,\n kind: 'local',\n plan: null,\n cls,\n word: rows.find((r) => r.cls === cls)?.word ?? 'no reading',\n summary: cls === 'ready'\n ? `${count} ${count === 1 ? 'model' : 'models'} on this machine · free`\n : cls === 'blocked'\n ? (rows[0]?.summary ?? 'local runtime unavailable')\n : 'readiness not reported',\n connection: connectionOf(report),\n windows: [],\n credits: null,\n reserve: null,\n notes: [],\n localCount: count,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Tolerant readers\n// ---------------------------------------------------------------------------\n//\n// WHY THESE EXIST. The strip is mounted on five surfaces (Apps, Usage,\n// onboarding, NewChatDialog, the rail ring via scarcestSeat) and renders\n// synchronously from three cached server reads. The types say what a healthy\n// server sends, but the cache holds whatever arrived: a `{}` from a budget\n// route that has not landed on an older sidecar, a half-written health file,\n// a future field shape. One `undefined.map` inside `useMemo` takes the whole\n// surface down with it (INT6 found exactly that with `/api/verse/budget` →\n// `{}`). So each optional source is checked HERE, at the one boundary every\n// view shares, and the rule is the module's own: a source that cannot be\n// read makes the row say LESS, never crash and never invent. A bad entry is\n// dropped on its own; the rest of the source still speaks.\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nconst nullablePercent = (v: unknown): number | null => (typeof v === 'number' && Number.isFinite(v) ? v : null);\n\nfunction readHeadroom(value: unknown): SeatHeadroom | null {\n if (!isRecord(value) || typeof value['seatId'] !== 'string') return null;\n const binding = value['bindingWindow'];\n return {\n seatId: value['seatId'],\n sessionUsedPercent: nullablePercent(value['sessionUsedPercent']),\n weeklyUsedPercent: nullablePercent(value['weeklyUsedPercent']),\n bindingWindow: binding === 'session' || binding === 'weekly' ? binding : null,\n autonomyHeadroomPercent: nullablePercent(value['autonomyHeadroomPercent']),\n resetAt: typeof value['resetAt'] === 'string' ? value['resetAt'] : null,\n // Only an explicit `true` makes a seat eligible — a garbled flag is \"not known to be eligible\".\n eligibleForAutonomy: value['eligibleForAutonomy'] === true,\n reasons: Array.isArray(value['reasons']) ? value['reasons'].filter((r): r is string => typeof r === 'string') : [],\n };\n}\n\nfunction readPolicy(seatId: string, value: unknown): SeatBudgetPolicy | null {\n if (!isRecord(value) || typeof value['enabled'] !== 'boolean') return null;\n const reserve = value['reservePercent'];\n if (typeof reserve !== 'number' || !Number.isFinite(reserve)) return null;\n const out: SeatBudgetPolicy = { seatId, enabled: value['enabled'], reservePercent: reserve };\n const session = value['maxSessionWindowPercent'];\n if (typeof session === 'number' && Number.isFinite(session)) out.maxSessionWindowPercent = session;\n return out;\n}\n\n/**\n * The budget view → rows keyed by seat, or an empty map when the view cannot\n * be read. A seat whose policy entry is present but malformed is DROPPED\n * rather than handed to budget-model's \"no policy → off\" default: that default\n * is right for a seat the server genuinely has no policy for, but for a\n * garbled entry it would print \"Autonomy off — all yours\", a claim nobody\n * made.\n */\nexport function readBudgetRows(view: unknown): Map<string, BudgetRow> {\n if (!isRecord(view) || !Array.isArray(view['seatInfo'])) return new Map();\n const effectiveIn = isRecord(view['effective']) ? view['effective'] : {};\n const effective: Record<string, SeatBudgetPolicy> = {};\n const seatInfo: BudgetView['seatInfo'] = [];\n for (const info of view['seatInfo']) {\n if (!isRecord(info) || typeof info['seatId'] !== 'string') continue;\n const seatId = info['seatId'];\n const engine = info['engine'];\n if (engine !== 'claude' && engine !== 'codex' && engine !== 'grok' && engine !== 'local') continue;\n if (Object.prototype.hasOwnProperty.call(effectiveIn, seatId)) {\n const policy = readPolicy(seatId, effectiveIn[seatId]);\n if (policy === null) continue;\n effective[seatId] = policy;\n }\n seatInfo.push({\n seatId,\n label: typeof info['label'] === 'string' ? info['label'] : seatId,\n engine,\n free: info['free'] === true,\n });\n }\n const headroom = Array.isArray(view['headroom'])\n ? view['headroom'].map(readHeadroom).filter((h): h is SeatHeadroom => h !== null)\n : [];\n const safe = { ...(view as unknown as BudgetView), seatInfo, effective, headroom };\n try {\n return new Map(buildBudgetRows(safe).map((r) => [r.seatId, r]));\n } catch {\n // Belt and braces: budget-model is pure and the input is now well-typed,\n // but a reserve line is never worth a blank strip.\n return new Map();\n }\n}\n\n/** Health reports keyed by seat, keeping only reports that can be described honestly. */\nexport function readHealthReports(reports: unknown): Map<string, SeatHealthReport> {\n const out = new Map<string, SeatHealthReport>();\n if (!Array.isArray(reports)) return out;\n for (const r of reports) {\n if (!isRecord(r) || typeof r['seatId'] !== 'string') continue;\n const connection = r['connection'];\n // An unknown connection word has no tone or wording — describing it\n // would mean guessing; the row falls back to its window reading.\n if (typeof connection !== 'string' || !Object.prototype.hasOwnProperty.call(CONNECTION_WORD, connection)) continue;\n const fix = isRecord(r['fix']) ? r['fix'] : {};\n const kind = fix['kind'];\n const command = Array.isArray(fix['command']) && fix['command'].every((a) => typeof a === 'string')\n ? (fix['command'] as string[])\n : undefined;\n out.set(r['seatId'], {\n ...(r as unknown as SeatHealthReport),\n reasons: Array.isArray(r['reasons']) ? r['reasons'].filter((x): x is string => typeof x === 'string') : [],\n fix: {\n kind: kind === 'reauth' || kind === 'repin' || kind === 'wait' ? kind : 'none',\n ...(command ? { command } : {}),\n },\n });\n }\n return out;\n}\n\n/** Seats → rows, in the roster's own order (the server lists the operator's preferred seats first). */\nexport function buildCapacityRows(seats: readonly VerseSeat[], inputs: CapacityInputs = {}): CapacityRow[] {\n const health = readHealthReports(inputs.health);\n const budget = readBudgetRows(inputs.budget);\n // The roster comes from bootstrap; a malformed one reads as \"no seats yet\",\n // the strip's honest empty state, rather than a crash.\n const roster = Array.isArray(seats)\n ? seats.filter((s): s is VerseSeat => isRecord(s) && typeof (s as { id?: unknown }).id === 'string')\n : [];\n const localMode = inputs.local ?? 'collapse';\n let chosen: readonly VerseSeat[] = roster;\n if (inputs.seatIds) {\n const byId = new Map(roster.map((s) => [s.id, s]));\n chosen = inputs.seatIds.map((id) => byId.get(id)).filter((s): s is VerseSeat => s !== undefined);\n }\n const out: CapacityRow[] = [];\n const locals: VerseSeat[] = [];\n let localIndex = -1;\n for (const seat of chosen) {\n if (seat.engine === 'local') {\n if (localMode === 'hide') continue;\n if (localMode === 'collapse') {\n if (localIndex === -1) localIndex = out.length;\n locals.push(seat);\n continue;\n }\n }\n out.push(seatRow(seat, health, budget));\n }\n if (locals.length > 0) {\n // A single local seat keeps its own name; several fold into one row.\n const row = locals.length === 1 ? seatRow(locals[0]!, health, budget) : collapsedLocal(locals, health);\n out.splice(localIndex, 0, row);\n }\n return out;\n}\n\n/**\n * The strip's one sentence: how many paid seats are usable, and what local\n * adds. Counts only what was READ — an unread seat is named as unread, never\n * folded into \"blocked\".\n */\nexport function capacityHeadline(rows: readonly CapacityRow[]): string {\n const paid = rows.filter((r) => r.kind === 'subscription');\n const local = rows.filter((r) => r.kind === 'local');\n const usable = paid.filter((r) => r.cls === 'ready' || r.cls === 'tight').length;\n const unread = paid.filter((r) => r.cls === 'unread').length;\n const parts: string[] = [];\n if (paid.length === 0) parts.push('No accounts connected');\n else parts.push(`${usable} of ${paid.length} ${paid.length === 1 ? 'account' : 'accounts'} usable`);\n if (unread > 0) parts.push(`${unread} not read yet`);\n if (local.some((r) => r.cls === 'ready')) parts.push('local models ready');\n else if (local.length > 0) parts.push('local models not ready');\n return parts.join(' · ');\n}\n\n/**\n * The seat closest to running out — the rail foot's capacity ring (C1).\n * Blocked beats tight beats a measured percent; unread seats never win,\n * because an empty ring would claim headroom nobody measured.\n */\nexport function scarcestSeat(rows: readonly CapacityRow[]): CapacityRow | null {\n let best: { row: CapacityRow; score: number } | null = null;\n for (const row of rows) {\n if (row.kind !== 'subscription') continue;\n const binding = row.windows.find((w) => w.binding) ?? null;\n let score: number;\n if (row.cls === 'blocked' || binding?.limitReached) score = 300;\n else if (binding?.usedPercent != null) score = (row.cls === 'tight' ? 100 : 0) + binding.usedPercent;\n else continue;\n if (best === null || score > best.score) best = { row, score };\n }\n return best?.row ?? null;\n}\n\n/** One seat's row (the composer's seat chip, C3), or null when the seat is not in the roster. */\nexport function capacityRowFor(seats: readonly VerseSeat[], seatId: string, inputs: Omit<CapacityInputs, 'seatIds' | 'local'> = {}): CapacityRow | null {\n return buildCapacityRows(seats, { ...inputs, seatIds: [seatId], local: 'each' })[0] ?? null;\n}\n\n/** The accessible sentence for one window bar. */\nexport function windowSentence(row: Pick<CapacityRow, 'label'>, w: CapacityWindowRow, reservePercent: number | null): string {\n const head = `${row.label} ${w.label}`;\n const reset = w.resetText === null ? '' : `, ${w.resetText}`;\n if (w.limitReached) return `${head}: limit reached${reset}`;\n if (w.usedPercent === null) return `${head}: no reading${reset}`;\n const kept = reservePercent !== null && reservePercent > 0 ? `; ${reservePercent}% kept for you` : '';\n return `${head}: ${Math.round(w.usedPercent)}% used${kept}${reset}`;\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{a as e,n as t,s as n}from"./index-afDA8cwW.js";import"./useChartWidth-MEXvDxDL.js";import{a as r,c as i,g as a,t as o}from"./colors-B-vHsX1S.js";import"./Swimlane-BR40WVcj.js";import"./BurnDown-4P1LDoCL.js";import"./AreaTrend-gUVXkfhf.js";import"./Funnel-qX3Hlbce.js";import"./StepBand-B1W7rU70.js";import"./MatrixHeatmap-B_JWCjZx.js";var s={figure:`_figure_1si9v_1`,caption:`_caption_1si9v_12`,title:`_title_1si9v_20`,description:`_description_1si9v_26`,plot:`_plot_1si9v_31`,tableDisclosure:`_tableDisclosure_1si9v_36`,tableBody:`_tableBody_1si9v_61`,caveat:`_caveat_1si9v_65`,empty:`_empty_1si9v_75`},c=t();function l({title:e,description:t,caveat:n,children:r,table:i,empty:a,emptyMessage:o=`No data for this window.`}){return(0,c.jsxs)(`figure`,{className:s.figure,children:[(0,c.jsxs)(`figcaption`,{className:s.caption,children:[(0,c.jsx)(`span`,{className:s.title,children:e}),t?(0,c.jsx)(`span`,{className:s.description,children:t}):null]}),n?(0,c.jsx)(`p`,{className:s.caveat,role:`note`,children:n}):null,a?(0,c.jsx)(`p`,{className:s.empty,children:o}):(0,c.jsx)(`div`,{className:s.plot,children:r}),i?(0,c.jsxs)(`details`,{className:s.tableDisclosure,children:[(0,c.jsx)(`summary`,{children:`View as table`}),(0,c.jsx)(`div`,{className:s.tableBody,children:i})]}):null]})}var u={legend:`_legend_4pgvn_1`,item:`_item_4pgvn_10`,swatch:`_swatch_4pgvn_18`,swatchLine:`_swatchLine_4pgvn_25`};function d({items:e}){return e.length<2?null:(0,c.jsx)(`ul`,{className:u.legend,children:e.map(e=>(0,c.jsxs)(`li`,{className:u.item,children:[(0,c.jsx)(`span`,{className:e.kind===`line`?u.swatchLine:u.swatch,style:{background:e.color},"aria-hidden":`true`}),e.label]},e.label))})}var f=n(e(),1),p={svg:`_svg_djmd1_1`,gridline:`_gridline_djmd1_7`,axis:`_axis_djmd1_12`,axisLabel:`_axisLabel_djmd1_17`,line:`_line_djmd1_23`,area:`_area_djmd1_30`,marker:`_marker_djmd1_35`,endLabel:`_endLabel_djmd1_40`,crosshairLine:`_crosshairLine_djmd1_46`,overlay:`_overlay_djmd1_52`,wrap:`_wrap_djmd1_57`,tooltip:`_tooltip_djmd1_61`,tooltipDate:`_tooltipDate_djmd1_77`,tooltipRow:`_tooltipRow_djmd1_82`,tooltipKey:`_tooltipKey_djmd1_88`,tooltipValue:`_tooltipValue_djmd1_94`,tooltipGap:`_tooltipGap_djmd1_99`},m=640,h=44,g=12,_=12,v=24,y=4,b=6.4,x=4,S=150;function C(e){let t=[],n=[];for(let r of e){if(r.y===null){n.length&&t.push(n),n=[];continue}n.push({x:r.x,y:r.y})}return n.length&&t.push(n),t}function w(e,t,n){if(t<=e)return[e];let r=(t-e)/n;return Array.from({length:n+1},(t,n)=>e+r*n)}function T({series:e,height:t=200,area:n=!1,formatX:i=e=>String(e),formatY:s=e=>String(e),ariaLabel:l}){let u=(0,f.useRef)(null),[T,E]=(0,f.useState)(null),[D,O]=(0,f.useState)(null),k=e.flatMap(e=>e.points.map(e=>e.x)),A=e.flatMap(e=>e.points.map(e=>e.y)).filter(e=>e!==null);if(k.length===0)return(0,c.jsx)(`p`,{children:`No data.`});let j=Math.min(...k),M=Math.max(...k),N=Math.min(0,...A),P=Math.max(1e-4,...A),F=M-j||1,I=P-N||1,L=e.length>=1&&e.length<=4,R=L?Math.max(...e.map(e=>e.label.length))*b:0,z=L&&R<=S,B=g+(z?x+R:0),V=e.length>=2,H=596-B,U=t-_-v,W=e=>h+(e-j)/F*H,G=e=>_+U-(e-N)/I*U,K=w(N,P,y),q=Array.from(new Set(k)).sort((e,t)=>e-t);function J(e){let t=u.current;if(!t)return null;let n=t.getBoundingClientRect(),r=(e-n.left)/n.width*m,i=j+(r-h)/H*F,a=q[0],o=1/0;for(let e of q){let t=Math.abs(e-i);t<o&&(o=t,a=e)}return a}function Y(e){let t=J(e.clientX);if(t===null)return;E(t);let n=u.current;if(n){let e=n.getBoundingClientRect(),r=W(t)/m*e.width;O({left:r,top:0})}}let X=T===null?null:e.map(e=>({series:e,point:e.points.find(e=>e.x===T)??null}));return(0,c.jsxs)(`div`,{className:p.wrap,children:[(0,c.jsxs)(`svg`,{ref:u,className:p.svg,viewBox:`0 0 ${m} ${t}`,role:`img`,"aria-label":l,onPointerMove:Y,onPointerLeave:()=>E(null),children:[K.map((e,t)=>(0,c.jsxs)(`g`,{children:[(0,c.jsx)(`line`,{x1:h,x2:m-B,y1:G(e),y2:G(e),className:p.gridline,stroke:r}),(0,c.jsx)(`text`,{x:38,y:G(e),dy:`0.32em`,textAnchor:`end`,className:p.axisLabel,children:s(e)})]},t)),(0,c.jsx)(`line`,{x1:h,x2:m-B,y1:t-v,y2:t-v,className:p.axis,stroke:o}),q.length>1?[q[0],q[q.length-1]].map((e,n)=>(0,c.jsx)(`text`,{x:W(e),y:t-6,textAnchor:n===0?`start`:`end`,className:p.axisLabel,children:i(e)},n)):null,e.map((t,r)=>{let i=a(r),o=C(t.points);return(0,c.jsxs)(`g`,{children:[n&&e.length===1?o.map((e,t)=>{let n=e.map((e,t)=>`${t===0?`M`:`L`}${W(e.x)},${G(e.y)}`).join(` `)+` L${W(e[e.length-1].x)},${G(N)} L${W(e[0].x)},${G(N)} Z`;return(0,c.jsx)(`path`,{d:n,fill:i,className:p.area},t)}):null,o.map((e,t)=>(0,c.jsx)(`path`,{d:e.map((e,t)=>`${t===0?`M`:`L`}${W(e.x)},${G(e.y)}`).join(` `),stroke:i,className:p.line},t)),z&&o.length?(()=>{let e=o[o.length-1],n=e[e.length-1];return(0,c.jsx)(`text`,{x:W(n.x)+x,y:G(n.y),dy:`0.32em`,className:p.endLabel,fill:i,children:t.label})})():null]},t.id)}),T===null?null:(0,c.jsx)(`line`,{x1:W(T),x2:W(T),y1:_,y2:t-v,className:p.crosshairLine}),T===null?null:e.map((e,t)=>{let n=e.points.find(e=>e.x===T);return!n||n.y===null?null:(0,c.jsx)(`circle`,{cx:W(n.x),cy:G(n.y),r:4,fill:a(t),className:p.marker},e.id)}),(0,c.jsx)(`rect`,{x:h,y:_,width:H,height:U,className:p.overlay,onFocus:()=>E(q[q.length-1]??null)})]}),X&&D?(0,c.jsxs)(`div`,{className:p.tooltip,style:{left:D.left,top:D.top},children:[(0,c.jsx)(`div`,{className:p.tooltipDate,children:i(T)}),X.map(({series:e,point:t},n)=>(0,c.jsxs)(`div`,{className:p.tooltipRow,children:[(0,c.jsx)(`span`,{className:p.tooltipKey,style:{background:a(n)},"aria-hidden":`true`}),t&&t.y!==null?(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(`span`,{className:p.tooltipValue,children:s(t.y)}),V?(0,c.jsx)(`span`,{children:e.label}):null]}):(0,c.jsxs)(`span`,{className:p.tooltipGap,children:[`no data`,V?` — ${e.label}`:``]})]},e.id))]}):null,V?(0,c.jsx)(d,{items:e.map((e,t)=>({label:e.label,color:a(t),kind:`line`}))}):null]})}var E={svg:`_svg_o4jfa_1`,bar:`_bar_o4jfa_6`,baseline:`_baseline_o4jfa_15`,gridline:`_gridline_o4jfa_20`,axisLabel:`_axisLabel_o4jfa_25`,valueLabel:`_valueLabel_o4jfa_31`,categoryLabel:`_categoryLabel_o4jfa_38`,hitArea:`_hitArea_o4jfa_44`,tooltip:`_tooltip_o4jfa_49`,tooltipValue:`_tooltipValue_o4jfa_63`,tooltipLabel:`_tooltipLabel_o4jfa_68`,wrap:`_wrap_o4jfa_73`},D=24,O=10;function k({data:e,height:t=160,orientation:n=`vertical`,color:a=i,formatValue:s=e=>String(e),ariaLabel:l}){let u=(0,f.useId)(),[d,p]=(0,f.useState)(null),m=e.map(e=>e.value).filter(e=>e!==null),h=Math.max(0,...m,1e-4),g=Math.min(0,...m),_=h-g||1;if(n===`horizontal`){let n=Math.min(D,Math.max(14,Math.floor((t-O)/e.length)-O)),i=e.length*(n+O)+O;return(0,c.jsxs)(`div`,{className:E.wrap,children:[(0,c.jsxs)(`svg`,{className:E.svg,width:588,height:i,viewBox:`0 0 588 ${i}`,role:`img`,"aria-label":l,children:[(0,c.jsx)(`line`,{x1:120,y1:0,x2:120,y2:i,className:E.baseline,stroke:o}),e.map((e,t)=>{let i=O+t*(n+O),o=e.value===null?0:(e.value-g)/_*420;return(0,c.jsxs)(`g`,{children:[(0,c.jsx)(`text`,{x:112,y:i+n/2,dy:`0.32em`,textAnchor:`end`,className:E.categoryLabel,children:e.label.length>22?`${e.label.slice(0,21)}…`:e.label}),e.value===null?(0,c.jsx)(`line`,{x1:124,y1:i+n/2,x2:134,y2:i+n/2,stroke:r,strokeWidth:2,strokeDasharray:`2 2`}):(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(`rect`,{x:120,y:i,width:Math.max(2,o),height:n,rx:4,fill:a,className:E.bar}),(0,c.jsx)(`text`,{x:120+Math.max(2,o)+6,y:i+n/2,dy:`0.32em`,className:E.valueLabel,children:s(e.value)})]}),(0,c.jsx)(`rect`,{className:E.hitArea,x:0,y:i-O/2,width:588,height:n+O,tabIndex:0,role:`img`,"aria-label":`${e.label}: ${e.value===null?`no data`:s(e.value)}`,onPointerEnter:()=>p(t),onPointerLeave:()=>p(e=>e===t?null:e),onFocus:()=>p(t),onBlur:()=>p(e=>e===t?null:e)})]},e.label+t)})]}),d===null?null:(0,c.jsxs)(`div`,{className:E.tooltip,style:{left:128,top:O+d*(n+O)-4},children:[(0,c.jsx)(`span`,{className:E.tooltipValue,children:e[d].value===null?`no data`:s(e[d].value)}),(0,c.jsx)(`span`,{className:E.tooltipLabel,children:e[d].label})]})]})}let v=e.length?Math.max(D,0):D,y=Math.min(D,v),b=t,x=b+20+30,S=e.length*(y+O)+O,C=20+b-(0-g)/_*b;return(0,c.jsxs)(`div`,{className:E.wrap,children:[(0,c.jsxs)(`svg`,{className:E.svg,width:S,height:x,viewBox:`0 0 ${S} ${x}`,role:`img`,"aria-label":l,children:[(0,c.jsx)(`line`,{x1:0,y1:C,x2:S,y2:C,className:E.baseline,stroke:o}),e.map((e,t)=>{let n=O+t*(y+O),i=e.value===null?0:Math.abs(e.value-g)/_*b,o=e.value!==null&&e.value>=0?C-i:C;return(0,c.jsxs)(`g`,{children:[e.value===null?(0,c.jsx)(`line`,{x1:n+y/2-5,y1:C,x2:n+y/2+5,y2:C,stroke:r,strokeWidth:2,strokeDasharray:`2 2`}):(0,c.jsxs)(c.Fragment,{children:[(0,c.jsx)(`rect`,{x:n,y:o,width:y,height:Math.max(2,i),rx:4,fill:a,className:E.bar}),(0,c.jsx)(`text`,{x:n+y/2,y:o-4,textAnchor:`middle`,className:E.valueLabel,children:s(e.value)})]}),(0,c.jsx)(`text`,{x:n+y/2,y:x-8,textAnchor:`middle`,className:E.axisLabel,children:e.label.length>10?`${e.label.slice(0,9)}…`:e.label}),(0,c.jsx)(`rect`,{className:E.hitArea,x:n-O/2,y:0,width:y+O,height:x,tabIndex:0,role:`img`,"aria-label":`${e.label}: ${e.value===null?`no data`:s(e.value)}`,onPointerEnter:()=>p(t),onPointerLeave:()=>p(e=>e===t?null:e),onFocus:()=>p(t),onBlur:()=>p(e=>e===t?null:e)})]},e.label+t)})]}),d===null?null:(0,c.jsxs)(`div`,{className:E.tooltip,style:{left:O+d*(y+O),top:0},id:`${u}-tooltip`,children:[(0,c.jsx)(`span`,{className:E.tooltipValue,children:e[d].value===null?`no data`:s(e[d].value)}),(0,c.jsx)(`span`,{className:E.tooltipLabel,children:e[d].label})]})]})}export{l as i,T as n,d as r,k as t};
|
|
2
|
-
//# sourceMappingURL=charts-D4NaLaXA.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"charts-D4NaLaXA.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/ChartContainer.module.css","../../../../../../src/web-ui/components/charts/ChartContainer.tsx","../../../../../../src/web-ui/components/charts/Legend.module.css","../../../../../../src/web-ui/components/charts/Legend.tsx","../../../../../../src/web-ui/components/charts/LineChart.module.css","../../../../../../src/web-ui/components/charts/LineChart.tsx","../../../../../../src/web-ui/components/charts/BarChart.module.css","../../../../../../src/web-ui/components/charts/BarChart.tsx"],"sourcesContent":[".figure {\n margin: 0;\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-lg);\n background: var(--bg-surface);\n padding: var(--space-4);\n /* Fixed heights must include the axis-label band — this container instead\n grows with its content so a chart's x-axis labels never get clipped or\n forced into a nested scroll (dataviz anti-patterns). */\n}\n\n.caption {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-3);\n margin-bottom: var(--space-3);\n}\n\n.title {\n font-size: var(--text-sm-size);\n font-weight: var(--font-weight-semibold);\n color: var(--text-primary);\n}\n\n.description {\n font-size: var(--text-xs-size);\n color: var(--text-tertiary);\n}\n\n.plot {\n width: 100%;\n overflow-x: auto;\n}\n\n.tableDisclosure {\n margin-top: var(--space-3);\n border-top: 1px solid var(--border-subtle);\n padding-top: var(--space-2);\n}\n\n.tableDisclosure > summary {\n cursor: pointer;\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n list-style: none;\n}\n\n.tableDisclosure > summary::-webkit-details-marker {\n display: none;\n}\n\n.tableDisclosure > summary::before {\n content: '▸ ';\n}\n\n.tableDisclosure[open] > summary::before {\n content: '▾ ';\n}\n\n.tableBody {\n margin-top: var(--space-2);\n}\n\n.caveat {\n margin: 0 0 var(--space-3);\n padding: var(--space-2) var(--space-3);\n border-radius: var(--radius-md);\n background: var(--status-unknown-bg);\n color: var(--status-unknown-fg);\n font-size: var(--text-xs-size);\n line-height: var(--text-sm-line);\n}\n\n.empty {\n color: var(--text-tertiary);\n font-size: var(--text-sm-size);\n padding: var(--space-6) 0;\n text-align: center;\n}\n","/**\n * components/charts/ChartContainer.tsx — the figure every chart mounts\n * inside: title/description, the plot itself, an optional caveat banner\n * (epistemic-honesty-adjacent: for a chart built on data with a known,\n * disclosed limitation — see ProductionView's judge-verdict caveat), an\n * optional table-view twin (the WCAG-clean accessibility equivalent every\n * chart should ship per the dataviz skill), and an empty state that never\n * lies about missing data.\n */\nimport type { ReactNode } from 'react';\nimport './chart-tokens.css';\nimport styles from './ChartContainer.module.css';\n\nexport interface ChartContainerProps {\n title: string;\n description?: string;\n /** A short, honest note about a known limitation of the data behind this\n * chart (e.g. \"counts may include X, not yet separable\"). Never omit a\n * caveat to make a chart look cleaner than the data actually is. */\n caveat?: string;\n /** The chart itself (SVG + legend). */\n children: ReactNode;\n /** The accessibility twin — same data as a real HTML table. Omit only\n * when the chart already IS a table. */\n table?: ReactNode;\n /** When true, renders the empty state instead of `children`. */\n empty?: boolean;\n emptyMessage?: string;\n}\n\nexport function ChartContainer({\n title,\n description,\n caveat,\n children,\n table,\n empty,\n emptyMessage = 'No data for this window.',\n}: ChartContainerProps) {\n return (\n <figure className={styles.figure}>\n <figcaption className={styles.caption}>\n <span className={styles.title}>{title}</span>\n {description ? <span className={styles.description}>{description}</span> : null}\n </figcaption>\n {caveat ? (\n <p className={styles.caveat} role=\"note\">\n {caveat}\n </p>\n ) : null}\n {empty ? (\n <p className={styles.empty}>{emptyMessage}</p>\n ) : (\n <div className={styles.plot}>{children}</div>\n )}\n {table ? (\n <details className={styles.tableDisclosure}>\n <summary>View as table</summary>\n <div className={styles.tableBody}>{table}</div>\n </details>\n ) : null}\n </figure>\n );\n}\n",".legend {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-1) var(--space-4);\n margin: var(--space-2) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.item {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n}\n\n.swatch {\n width: 10px;\n height: 10px;\n border-radius: var(--radius-full);\n flex: none;\n}\n\n.swatchLine {\n width: 14px;\n height: 2px;\n border-radius: var(--radius-full);\n flex: none;\n}\n","/**\n * components/charts/Legend.tsx — the dependable identity channel. A legend\n * is always present for two or more series (never rely on color-matching\n * alone); a single series needs no legend box because the chart's own title\n * already names it (see marks-and-anatomy.md \"Labels & legend\").\n */\nimport styles from './Legend.module.css';\n\nexport interface LegendItem {\n label: string;\n color: string;\n /** 'line' for line charts (a short stroke key), 'swatch' for bar/area. */\n kind?: 'line' | 'swatch';\n}\n\nexport function Legend({ items }: { items: LegendItem[] }) {\n if (items.length < 2) return null;\n return (\n <ul className={styles.legend}>\n {items.map((it) => (\n <li key={it.label} className={styles.item}>\n <span\n className={it.kind === 'line' ? styles.swatchLine : styles.swatch}\n style={{ background: it.color }}\n aria-hidden=\"true\"\n />\n {it.label}\n </li>\n ))}\n </ul>\n );\n}\n",".svg {\n display: block;\n width: 100%;\n height: auto;\n}\n\n.gridline {\n stroke: var(--chart-grid);\n stroke-width: 1;\n}\n\n.axis {\n stroke: var(--chart-axis);\n stroke-width: 1;\n}\n\n.axisLabel {\n font-size: var(--text-xs-size);\n fill: var(--text-tertiary);\n font-family: var(--font-ui);\n}\n\n.line {\n fill: none;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.area {\n opacity: 0.1;\n stroke: none;\n}\n\n.marker {\n stroke: var(--chart-surface);\n stroke-width: 2;\n}\n\n.endLabel {\n font-size: var(--text-xs-size);\n font-family: var(--font-ui);\n font-weight: var(--font-weight-medium);\n}\n\n.crosshairLine {\n stroke: var(--chart-axis);\n stroke-width: 1;\n pointer-events: none;\n}\n\n.overlay {\n fill: transparent;\n cursor: crosshair;\n}\n\n.wrap {\n position: relative;\n}\n\n.tooltip {\n position: absolute;\n pointer-events: none;\n background: var(--chart-tooltip-bg);\n border: 1px solid var(--chart-tooltip-border);\n border-radius: var(--radius-sm);\n box-shadow: var(--shadow-md);\n padding: var(--space-2);\n font-size: var(--text-xs-size);\n color: var(--text-primary);\n white-space: nowrap;\n z-index: var(--z-dropdown);\n transform: translate(-50%, -100%);\n margin-top: -10px;\n}\n\n.tooltipDate {\n color: var(--text-tertiary);\n margin-bottom: var(--space-1);\n}\n\n.tooltipRow {\n display: flex;\n align-items: center;\n gap: var(--space-1);\n}\n\n.tooltipKey {\n width: 12px;\n height: 2px;\n flex: none;\n}\n\n.tooltipValue {\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n}\n\n.tooltipGap {\n color: var(--text-tertiary);\n font-style: italic;\n}\n","/**\n * components/charts/LineChart.tsx — trend over time. A gap (`null` y) is\n * split into a separate path segment so it renders as a visible break in\n * the line, never as a straight line through a missing value and never as\n * a silent zero. Single series gets an optional soft area fill; two-plus\n * series always render a legend (never color-matching alone).\n */\nimport { useRef, useState } from 'react';\nimport type { Series } from './types.js';\nimport { seriesColor, CHART_GRID, CHART_AXIS } from './colors.js';\nimport { Legend } from './Legend.js';\nimport './chart-tokens.css';\nimport styles from './LineChart.module.css';\n\nconst VBOX_W = 640;\nconst PAD_L = 44;\nconst PAD_R = 12;\nconst PAD_T = 12;\nconst PAD_B = 24;\nconst TICKS_Y = 4;\n/* Direct end-of-line labels need a gutter of their own. They are drawn in USER\n units — the viewBox scales the font along with the geometry, so a reserve\n measured in user units holds at every rendered width — and `--text-xs-size`\n resolves to 12 user units here, where the UI sans averages a shade over 6\n units per character at medium weight. 6.4 rounds that up so the reserve errs\n wide rather than clipping. Without the reserve the label was drawn at\n `VBOX_W - PAD_R + 4` with only PAD_R (12u) of room and the svg's own\n `overflow: hidden` cropped it to its first glyph — \"Estimated spend\"\n rendered as a lone \"E\". */\nconst END_LABEL_CH = 6.4;\nconst END_LABEL_GAP = 4;\n/* Past this the gutter would cost more plot than the label is worth, so the\n label is dropped rather than shrinking the chart around it. Nothing is lost:\n Legend.tsx deliberately renders nothing below two series because the panel\n heading already names a lone series, and two-plus series always have the\n legend regardless. */\nconst END_LABEL_MAX = 150;\n\ninterface Run {\n x: number;\n y: number;\n}\n\nfunction splitRuns(points: Series['points']): Run[][] {\n const runs: Run[][] = [];\n let current: Run[] = [];\n for (const p of points) {\n if (p.y === null) {\n if (current.length) runs.push(current);\n current = [];\n continue;\n }\n current.push({ x: p.x, y: p.y });\n }\n if (current.length) runs.push(current);\n return runs;\n}\n\nfunction niceTicks(min: number, max: number, count: number): number[] {\n if (max <= min) return [min];\n const step = (max - min) / count;\n return Array.from({ length: count + 1 }, (_, i) => min + step * i);\n}\n\nexport function LineChart({\n series,\n height = 200,\n area = false,\n formatX = (x: number) => String(x),\n formatY = (y: number) => String(y),\n ariaLabel,\n}: {\n series: Series[];\n height?: number;\n area?: boolean;\n formatX?: (x: number) => string;\n formatY?: (y: number) => string;\n ariaLabel: string;\n}) {\n const svgRef = useRef<SVGSVGElement>(null);\n const [hoverX, setHoverX] = useState<number | null>(null);\n const [tooltipPos, setTooltipPos] = useState<{ left: number; top: number } | null>(null);\n\n const allX = series.flatMap((s) => s.points.map((p) => p.x));\n const knownY = series.flatMap((s) => s.points.map((p) => p.y)).filter((y): y is number => y !== null);\n if (allX.length === 0) {\n return <p>No data.</p>;\n }\n const xMin = Math.min(...allX);\n const xMax = Math.max(...allX);\n const yMin = Math.min(0, ...knownY);\n const yMax = Math.max(0.0001, ...knownY);\n const xRange = xMax - xMin || 1;\n const yRange = yMax - yMin || 1;\n\n /* Decided before the scales, because the reserved gutter is what plotW is\n measured against — and the gridlines and x-axis stop at the same edge. */\n const wantEndLabels = series.length >= 1 && series.length <= 4;\n const endLabelW = wantEndLabels\n ? Math.max(...series.map((s) => s.label.length)) * END_LABEL_CH\n : 0;\n const showEndLabels = wantEndLabels && endLabelW <= END_LABEL_MAX;\n const padR = PAD_R + (showEndLabels ? END_LABEL_GAP + endLabelW : 0);\n const showLegend = series.length >= 2;\n\n const plotW = VBOX_W - PAD_L - padR;\n const plotH = height - PAD_T - PAD_B;\n const xScale = (x: number) => PAD_L + ((x - xMin) / xRange) * plotW;\n const yScale = (y: number) => PAD_T + plotH - ((y - yMin) / yRange) * plotH;\n\n const yTicks = niceTicks(yMin, yMax, TICKS_Y);\n\n // Nearest-x lookup across a reference axis (the union of all distinct x\n // values, since series may not share every point).\n const xAxis = Array.from(new Set(allX)).sort((a, b) => a - b);\n\n function nearestX(clientX: number): number | null {\n const svg = svgRef.current;\n if (!svg) return null;\n const rect = svg.getBoundingClientRect();\n const svgX = ((clientX - rect.left) / rect.width) * VBOX_W;\n const dataX = xMin + ((svgX - PAD_L) / plotW) * xRange;\n let nearest = xAxis[0];\n let best = Infinity;\n for (const x of xAxis) {\n const d = Math.abs(x - dataX);\n if (d < best) {\n best = d;\n nearest = x;\n }\n }\n return nearest;\n }\n\n function handleMove(e: React.PointerEvent<SVGSVGElement>) {\n const x = nearestX(e.clientX);\n if (x === null) return;\n setHoverX(x);\n const svg = svgRef.current;\n if (svg) {\n const rect = svg.getBoundingClientRect();\n const px = (xScale(x) / VBOX_W) * rect.width;\n setTooltipPos({ left: px, top: 0 });\n }\n }\n\n const hoverPoints =\n hoverX !== null\n ? series.map((s) => ({\n series: s,\n point: s.points.find((p) => p.x === hoverX) ?? null,\n }))\n : null;\n\n return (\n <div className={styles.wrap}>\n <svg\n ref={svgRef}\n className={styles.svg}\n viewBox={`0 0 ${VBOX_W} ${height}`}\n role=\"img\"\n aria-label={ariaLabel}\n onPointerMove={handleMove}\n onPointerLeave={() => setHoverX(null)}\n >\n {yTicks.map((t, i) => (\n <g key={i}>\n <line\n x1={PAD_L}\n x2={VBOX_W - padR}\n y1={yScale(t)}\n y2={yScale(t)}\n className={styles.gridline}\n stroke={CHART_GRID}\n />\n <text x={PAD_L - 6} y={yScale(t)} dy=\"0.32em\" textAnchor=\"end\" className={styles.axisLabel}>\n {formatY(t)}\n </text>\n </g>\n ))}\n <line\n x1={PAD_L}\n x2={VBOX_W - padR}\n y1={height - PAD_B}\n y2={height - PAD_B}\n className={styles.axis}\n stroke={CHART_AXIS}\n />\n {xAxis.length > 1\n ? [xAxis[0], xAxis[xAxis.length - 1]].map((x, i) => (\n <text\n key={i}\n x={xScale(x)}\n y={height - 6}\n textAnchor={i === 0 ? 'start' : 'end'}\n className={styles.axisLabel}\n >\n {formatX(x)}\n </text>\n ))\n : null}\n\n {series.map((s, si) => {\n const color = seriesColor(si);\n const runs = splitRuns(s.points);\n return (\n <g key={s.id}>\n {area && series.length === 1\n ? runs.map((run, ri) => {\n const d =\n run.map((p, j) => `${j === 0 ? 'M' : 'L'}${xScale(p.x)},${yScale(p.y)}`).join(' ') +\n ` L${xScale(run[run.length - 1].x)},${yScale(yMin)} L${xScale(run[0].x)},${yScale(yMin)} Z`;\n return <path key={ri} d={d} fill={color} className={styles.area} />;\n })\n : null}\n {runs.map((run, ri) => (\n <path\n key={ri}\n d={run.map((p, j) => `${j === 0 ? 'M' : 'L'}${xScale(p.x)},${yScale(p.y)}`).join(' ')}\n stroke={color}\n className={styles.line}\n />\n ))}\n {showEndLabels && runs.length ? (\n (() => {\n const lastRun = runs[runs.length - 1];\n const last = lastRun[lastRun.length - 1];\n return (\n <text\n x={xScale(last.x) + END_LABEL_GAP}\n y={yScale(last.y)}\n dy=\"0.32em\"\n className={styles.endLabel}\n fill={color}\n >\n {s.label}\n </text>\n );\n })()\n ) : null}\n </g>\n );\n })}\n\n {hoverX !== null ? (\n <line\n x1={xScale(hoverX)}\n x2={xScale(hoverX)}\n y1={PAD_T}\n y2={height - PAD_B}\n className={styles.crosshairLine}\n />\n ) : null}\n {hoverX !== null\n ? series.map((s, si) => {\n const p = s.points.find((pt) => pt.x === hoverX);\n if (!p || p.y === null) return null;\n return (\n <circle\n key={s.id}\n cx={xScale(p.x)}\n cy={yScale(p.y)}\n r={4}\n fill={seriesColor(si)}\n className={styles.marker}\n />\n );\n })\n : null}\n\n <rect\n x={PAD_L}\n y={PAD_T}\n width={plotW}\n height={plotH}\n className={styles.overlay}\n onFocus={() => setHoverX(xAxis[xAxis.length - 1] ?? null)}\n />\n </svg>\n {hoverPoints && tooltipPos ? (\n <div className={styles.tooltip} style={{ left: tooltipPos.left, top: tooltipPos.top }}>\n <div className={styles.tooltipDate}>{formatX(hoverX as number)}</div>\n {hoverPoints.map(({ series: s, point }, i) => (\n <div className={styles.tooltipRow} key={s.id}>\n <span className={styles.tooltipKey} style={{ background: seriesColor(i) }} aria-hidden=\"true\" />\n {point && point.y !== null ? (\n <>\n <span className={styles.tooltipValue}>{formatY(point.y)}</span>\n {showLegend ? <span>{s.label}</span> : null}\n </>\n ) : (\n <span className={styles.tooltipGap}>no data{showLegend ? ` — ${s.label}` : ''}</span>\n )}\n </div>\n ))}\n </div>\n ) : null}\n {showLegend ? (\n <Legend items={series.map((s, i) => ({ label: s.label, color: seriesColor(i), kind: 'line' }))} />\n ) : null}\n </div>\n );\n}\n",".svg {\n display: block;\n overflow: visible;\n}\n\n.bar {\n transition: opacity var(--duration-fast) var(--ease-standard);\n}\n\n.bar:hover,\n.bar:focus-visible {\n opacity: 0.82;\n}\n\n.baseline {\n stroke: var(--chart-axis);\n stroke-width: 1;\n}\n\n.gridline {\n stroke: var(--chart-grid);\n stroke-width: 1;\n}\n\n.axisLabel {\n font-size: 10px;\n fill: var(--text-tertiary);\n font-family: var(--font-ui);\n}\n\n.valueLabel {\n font-size: 10px;\n fill: var(--text-secondary);\n font-family: var(--font-ui);\n font-variant-numeric: tabular-nums;\n}\n\n.categoryLabel {\n font-size: 10px;\n fill: var(--text-secondary);\n font-family: var(--font-ui);\n}\n\n.hitArea {\n fill: transparent;\n cursor: pointer;\n}\n\n.tooltip {\n position: absolute;\n pointer-events: none;\n background: var(--chart-tooltip-bg);\n border: 1px solid var(--chart-tooltip-border);\n border-radius: var(--radius-sm);\n box-shadow: var(--shadow-md);\n padding: var(--space-1) var(--space-2);\n font-size: var(--text-xs-size);\n color: var(--text-primary);\n white-space: nowrap;\n z-index: var(--z-dropdown);\n}\n\n.tooltipValue {\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n}\n\n.tooltipLabel {\n color: var(--text-tertiary);\n margin-left: var(--space-1);\n}\n\n.wrap {\n position: relative;\n}\n","/**\n * components/charts/BarChart.tsx — categorical magnitude comparison.\n * Single hue by default (nominal categories never get a value-ramp — see\n * dataviz anti-patterns \"a value-ramp on nominal categories\"). Vertical for\n * a handful of short-named categories, horizontal for many or long-named\n * ones (dataviz choosing-a-form.md). Null values render as an explicit\n * \"no data\" dash, never a silent zero-height bar indistinguishable from a\n * real zero.\n */\nimport { useId, useState } from 'react';\nimport type { CategoricalDatum } from './types.js';\nimport { CHART_SEQUENTIAL, CHART_AXIS, CHART_GRID } from './colors.js';\nimport './chart-tokens.css';\nimport styles from './BarChart.module.css';\n\nconst BAR_MAX = 24;\nconst GAP = 10;\n\nexport function BarChart({\n data,\n height = 160,\n orientation = 'vertical',\n color = CHART_SEQUENTIAL,\n formatValue = (v: number) => String(v),\n ariaLabel,\n}: {\n data: CategoricalDatum[];\n height?: number;\n orientation?: 'vertical' | 'horizontal';\n color?: string;\n formatValue?: (v: number) => string;\n ariaLabel: string;\n}) {\n const uid = useId();\n const [hover, setHover] = useState<number | null>(null);\n\n const known = data.map((d) => d.value).filter((v): v is number => v !== null);\n const maxVal = Math.max(0, ...known, 0.0001);\n const minVal = Math.min(0, ...known);\n const range = maxVal - minVal || 1;\n\n if (orientation === 'horizontal') {\n const LABEL_W = 120;\n const PAD_R = 48;\n const rowH = Math.min(BAR_MAX, Math.max(14, Math.floor((height - GAP) / data.length) - GAP));\n const plotW = 420;\n const svgH = data.length * (rowH + GAP) + GAP;\n const svgW = LABEL_W + plotW + PAD_R;\n\n return (\n <div className={styles.wrap}>\n <svg\n className={styles.svg}\n width={svgW}\n height={svgH}\n viewBox={`0 0 ${svgW} ${svgH}`}\n role=\"img\"\n aria-label={ariaLabel}\n >\n <line x1={LABEL_W} y1={0} x2={LABEL_W} y2={svgH} className={styles.baseline} stroke={CHART_AXIS} />\n {data.map((d, i) => {\n const y = GAP + i * (rowH + GAP);\n const barW = d.value !== null ? ((d.value - minVal) / range) * plotW : 0;\n return (\n <g key={d.label + i}>\n <text\n x={LABEL_W - 8}\n y={y + rowH / 2}\n dy=\"0.32em\"\n textAnchor=\"end\"\n className={styles.categoryLabel}\n >\n {d.label.length > 22 ? `${d.label.slice(0, 21)}…` : d.label}\n </text>\n {d.value === null ? (\n <line\n x1={LABEL_W + 4}\n y1={y + rowH / 2}\n x2={LABEL_W + 14}\n y2={y + rowH / 2}\n stroke={CHART_GRID}\n strokeWidth={2}\n strokeDasharray=\"2 2\"\n />\n ) : (\n <>\n <rect\n x={LABEL_W}\n y={y}\n width={Math.max(2, barW)}\n height={rowH}\n rx={4}\n fill={color}\n className={styles.bar}\n />\n <text\n x={LABEL_W + Math.max(2, barW) + 6}\n y={y + rowH / 2}\n dy=\"0.32em\"\n className={styles.valueLabel}\n >\n {formatValue(d.value)}\n </text>\n </>\n )}\n <rect\n className={styles.hitArea}\n x={0}\n y={y - GAP / 2}\n width={svgW}\n height={rowH + GAP}\n tabIndex={0}\n role=\"img\"\n aria-label={`${d.label}: ${d.value === null ? 'no data' : formatValue(d.value)}`}\n onPointerEnter={() => setHover(i)}\n onPointerLeave={() => setHover((h) => (h === i ? null : h))}\n onFocus={() => setHover(i)}\n onBlur={() => setHover((h) => (h === i ? null : h))}\n />\n </g>\n );\n })}\n </svg>\n {hover !== null ? (\n <div\n className={styles.tooltip}\n style={{ left: LABEL_W + 8, top: GAP + hover * (rowH + GAP) - 4 }}\n >\n <span className={styles.tooltipValue}>\n {data[hover].value === null ? 'no data' : formatValue(data[hover].value as number)}\n </span>\n <span className={styles.tooltipLabel}>{data[hover].label}</span>\n </div>\n ) : null}\n </div>\n );\n }\n\n // Vertical orientation.\n const barSlot = data.length ? Math.max(BAR_MAX, 0) : BAR_MAX;\n const barW = Math.min(BAR_MAX, barSlot);\n const PAD_T = 20;\n const PAD_B = 30;\n const plotH = height;\n const svgH = plotH + PAD_T + PAD_B;\n const svgW = data.length * (barW + GAP) + GAP;\n const zeroY = PAD_T + plotH - ((0 - minVal) / range) * plotH;\n\n return (\n <div className={styles.wrap}>\n <svg\n className={styles.svg}\n width={svgW}\n height={svgH}\n viewBox={`0 0 ${svgW} ${svgH}`}\n role=\"img\"\n aria-label={ariaLabel}\n >\n <line x1={0} y1={zeroY} x2={svgW} y2={zeroY} className={styles.baseline} stroke={CHART_AXIS} />\n {data.map((d, i) => {\n const x = GAP + i * (barW + GAP);\n const barH = d.value !== null ? (Math.abs(d.value - minVal) / range) * plotH : 0;\n const top = d.value !== null && d.value >= 0 ? zeroY - barH : zeroY;\n return (\n <g key={d.label + i}>\n {d.value === null ? (\n <line\n x1={x + barW / 2 - 5}\n y1={zeroY}\n x2={x + barW / 2 + 5}\n y2={zeroY}\n stroke={CHART_GRID}\n strokeWidth={2}\n strokeDasharray=\"2 2\"\n />\n ) : (\n <>\n <rect\n x={x}\n y={top}\n width={barW}\n height={Math.max(2, barH)}\n rx={4}\n fill={color}\n className={styles.bar}\n />\n <text x={x + barW / 2} y={top - 4} textAnchor=\"middle\" className={styles.valueLabel}>\n {formatValue(d.value)}\n </text>\n </>\n )}\n <text\n x={x + barW / 2}\n y={svgH - 8}\n textAnchor=\"middle\"\n className={styles.axisLabel}\n >\n {d.label.length > 10 ? `${d.label.slice(0, 9)}…` : d.label}\n </text>\n <rect\n className={styles.hitArea}\n x={x - GAP / 2}\n y={0}\n width={barW + GAP}\n height={svgH}\n tabIndex={0}\n role=\"img\"\n aria-label={`${d.label}: ${d.value === null ? 'no data' : formatValue(d.value)}`}\n onPointerEnter={() => setHover(i)}\n onPointerLeave={() => setHover((h) => (h === i ? null : h))}\n onFocus={() => setHover(i)}\n onBlur={() => setHover((h) => (h === i ? null : h))}\n />\n </g>\n );\n })}\n </svg>\n {hover !== null ? (\n <div\n className={styles.tooltip}\n style={{ left: GAP + hover * (barW + GAP), top: 0 }}\n id={`${uid}-tooltip`}\n >\n <span className={styles.tooltipValue}>\n {data[hover].value === null ? 'no data' : formatValue(data[hover].value as number)}\n </span>\n <span className={styles.tooltipLabel}>{data[hover].label}</span>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
var e=`var(--chart-neutral)`;function t(t){return!Number.isInteger(t)||t<0||t>=6?e:`var(--chart-series-${t+1})`}var n=`var(--chart-sequential)`,r=`var(--chart-sequential-soft)`;function i(e){return`var(--chart-seq-${Number.isFinite(e)?Math.max(1,Math.min(7,Math.round(e))):1})`}function a(e){return i(1+Math.max(0,Math.min(1,e))*6)}var o=`var(--chart-diverging-pos)`,s=`var(--chart-diverging-neg)`,c=`var(--chart-diverging-mid)`,l=`var(--chart-grid)`,u=`var(--chart-axis)`;function d(e){return`var(--status-${e}-solid)`}function f(e){return`var(--chart-heat-${Math.max(0,Math.min(4,Math.round(e)))})`}var p=`var(--chart-track)`,m=Object.freeze({size:6,angle:45,strokeWidth:1.5,stroke:`var(--chart-unknown)`});function h(e){return`chart-hatch-${e.replace(/[^A-Za-z0-9_-]/g,``)}`}var g=`var(--chart-queued-outline)`;function _(e){return`var(--engine-${e})`}export{d as _,l as a,n as c,m as d,_ as f,t as g,a as h,o as i,r as l,f as m,c as n,e as o,h as p,s as r,g as s,u as t,p as u};
|
|
2
|
-
//# sourceMappingURL=colors-B-vHsX1S.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"colors-B-vHsX1S.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/colors.ts"],"sourcesContent":["/**\n * components/charts/colors.ts — the one place a chart asks for a colour\n * (owner: unit C0, with chart-tokens.css; the chart components are C7's).\n * Every value is a `var(--chart-*)` / `var(--engine-*)` / `var(--status-*)`\n * reference, never a literal hex, so theming is automatic and light and dark\n * can never drift apart. The roles — quantity, categorical, unknown, queued,\n * engine, status — are explained in chart-tokens.css's header.\n */\n\n/**\n * Identity slots in the categorical rotation. SIX (V3.10): the palette is\n * derived to stay clear of every engine, status and quantity hue, and no\n * seventh family clears that bar — see design/tokens.css.\n */\nexport const SERIES_SLOT_COUNT = 6;\n\n/** The \"Other\"/overflow bucket colour — never part of the identity rotation. */\nexport const CHART_NEUTRAL = 'var(--chart-neutral)';\n\n/**\n * Fixed-order categorical colour for series `slot` (0-based). Colour follows\n * the entity, never its row number: assign each series its slot once (e.g.\n * by a stable sort) and keep it even when others are filtered out — never\n * re-pack slots to \"fill the gap\" (dataviz anti-pattern: recolor-on-filter).\n *\n * Past the sixth slot this answers the NEUTRAL \"Other\" colour instead of\n * cycling: a repeated colour would tell the reader two series are one. A\n * chart with more than six series should fold its tail into \"Other\" and say\n * so in the legend and the table.\n */\nexport function seriesColor(slot: number): string {\n if (!Number.isInteger(slot) || slot < 0 || slot >= SERIES_SLOT_COUNT) return CHART_NEUTRAL;\n return `var(--chart-series-${slot + 1})`;\n}\n\n/** Default single hue for magnitude (sequential) and for one nominal series. */\nexport const CHART_SEQUENTIAL = 'var(--chart-sequential)';\nexport const CHART_SEQUENTIAL_SOFT = 'var(--chart-sequential-soft)';\n\n/** Steps in the quantity ramp (`--chart-seq-1..7`, azure 214°). */\nexport const SEQ_STEP_COUNT = 7;\n\n/** Quantity ramp step 1..7 (1 = least). Out-of-range steps clamp. */\nexport function seqColor(step: number): string {\n const n = Number.isFinite(step) ? Math.max(1, Math.min(SEQ_STEP_COUNT, Math.round(step))) : 1;\n return `var(--chart-seq-${n})`;\n}\n\n/**\n * A magnitude in [0, 1] → its quantity step. For a known value only: an\n * unknown (null / NaN) is the hatch below, never the lightest step — a pale\n * azure cell would claim \"a little\", which is a measurement nobody made.\n */\nexport function quantityColor(fraction: number): string {\n const f = Math.max(0, Math.min(1, fraction));\n return seqColor(1 + f * (SEQ_STEP_COUNT - 1));\n}\n\nexport const CHART_DIVERGING_POS = 'var(--chart-diverging-pos)';\nexport const CHART_DIVERGING_NEG = 'var(--chart-diverging-neg)';\nexport const CHART_DIVERGING_MID = 'var(--chart-diverging-mid)';\n\nexport const CHART_GRID = 'var(--chart-grid)';\nexport const CHART_AXIS = 'var(--chart-axis)';\n\n/** Status tones (the StatusBadge vocabulary). Status colours carry STATE, never\n * identity, and always travel with a text label (legend, tooltip, table). */\nexport type ChartTone = 'neutral' | 'info' | 'running' | 'success' | 'warning' | 'danger' | 'unknown';\n\nexport function toneColor(tone: ChartTone): string {\n return `var(--status-${tone}-solid)`;\n}\n\n/** Sequential heat steps 0..4 (0 = a true zero, not \"no data\"). */\nexport function heatColor(step: number): string {\n const n = Math.max(0, Math.min(4, Math.round(step)));\n return `var(--chart-heat-${n})`;\n}\n\n/** Unfilled meter/gauge track: the lightest step of the quantity ramp, not a gray. */\nexport const CHART_TRACK = 'var(--chart-track)';\n\n// ---------------------------------------------------------------------------\n// Unknown, queued / parked\n// ---------------------------------------------------------------------------\n\n/** The unknown gray — for the hatch stroke and the outline around it. */\nexport const CHART_UNKNOWN = 'var(--chart-unknown)';\n\n/** A CSS background that draws the 45° unknown hatch (HTML bars, tiles, cells). */\nexport const CHART_UNKNOWN_HATCH = 'var(--chart-unknown-hatch)';\n\n/**\n * The SVG version of the same hatch, as data: render it once per chart as\n *\n * <pattern id={id} width={size} height={size} patternUnits=\"userSpaceOnUse\"\n * patternTransform={`rotate(${angle})`}>\n * <line x1={0} y1={0} x2={0} y2={size} stroke={stroke} strokeWidth={strokeWidth} />\n * </pattern>\n *\n * with `id` from `hatchPatternId(useId())` — ids are document-global, so a\n * shared literal id would let one chart's unmount blank another's hatch —\n * and fill unknown marks with `url(#id)` plus a CHART_UNKNOWN outline.\n */\nexport const UNKNOWN_HATCH = Object.freeze({\n size: 6,\n angle: 45,\n strokeWidth: 1.5,\n stroke: CHART_UNKNOWN,\n});\n\n/** A document-safe pattern id from React's `useId()` (which contains `:`). */\nexport function hatchPatternId(reactId: string): string {\n return `chart-hatch-${reactId.replace(/[^A-Za-z0-9_-]/g, '')}`;\n}\n\n/** Queued / parked work: an outline in this colour, no fill. */\nexport const CHART_QUEUED_OUTLINE = 'var(--chart-queued-outline)';\n\n// ---------------------------------------------------------------------------\n// Engines (identity only)\n// ---------------------------------------------------------------------------\n\nexport type ChartEngine = 'claude' | 'codex' | 'grok' | 'local';\n\n/**\n * An engine's identity colour. ONLY for charts that show nothing but engines\n * (runs by engine, usage bars) and the 2px tick beside a lane label — pass it\n * explicitly per series; a chart never picks engine colours by index. When\n * status colour is on screen, show engines by position and monogram instead.\n */\nexport function engineColor(engine: ChartEngine): string {\n return `var(--engine-${engine})`;\n}\n"],"mappings":"AAiBA,IAAa,EAAgB,uBAa7B,SAAgB,EAAY,EAAsB,CAEhD,MADI,CAAC,OAAO,UAAU,CAAI,GAAK,EAAO,GAAK,GAAA,EAAkC,EACtE,sBAAsB,EAAO,EAAE,EACxC,CAGA,IAAa,EAAmB,0BACnB,EAAwB,+BAMrC,SAAgB,EAAS,EAAsB,CAE7C,MAAO,mBADG,OAAO,SAAS,CAAI,EAAI,KAAK,IAAI,EAAG,KAAK,IAAA,EAAoB,KAAK,MAAM,CAAI,CAAC,CAAC,EAAI,EAChE,EAC9B,CAOA,SAAgB,EAAc,EAA0B,CAEtD,OAAO,EAAS,EADN,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,CAAQ,CACtB,EAAK,CAAmB,CAC9C,CAEA,IAAa,EAAsB,6BACtB,EAAsB,6BACtB,EAAsB,6BAEtB,EAAa,oBACb,EAAa,oBAM1B,SAAgB,EAAU,EAAyB,CACjD,MAAO,gBAAgB,EAAK,QAC9B,CAGA,SAAgB,EAAU,EAAsB,CAE9C,MAAO,oBADG,KAAK,IAAI,EAAG,KAAK,IAAI,EAAG,KAAK,MAAM,CAAI,CAAC,CACvB,EAAE,EAC/B,CAGA,IAAa,EAAc,qBAwBd,EAAgB,OAAO,OAAO,CACzC,KAAM,EACN,MAAO,GACP,YAAa,IACb,OAAQ,sBACV,CAAC,EAGD,SAAgB,EAAe,EAAyB,CACtD,MAAO,eAAe,EAAQ,QAAQ,kBAAmB,EAAE,GAC7D,CAGA,IAAa,EAAuB,8BAcpC,SAAgB,EAAY,EAA6B,CACvD,MAAO,gBAAgB,EAAO,EAChC"}
|
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
import{$ as e,G as t,W as n,Z as r,nt as i}from"./global-DVgMguLr.js";import{r as a}from"./verse-store-BgKx_YGs.js";import{b as o,f as s,i as c,t as l,v as u}from"./verse-model-E98kXngO.js";function d(e,t){return e?s([e],{seatId:e.id,model:t}):null}function f(e,t){return t!==`standard`&&n(e,t)!==null?t:`standard`}function p(e,t){return n(e,f(e,t))}function m(e,t){let n=u(e);if(n!==null)return n;let r=t.unavailableReason;return typeof r==`string`&&r.trim().length>0?r.trim():null}var h={standard:`Standard`,expansive:`Expansive`},g={claude:`Claude Code`,codex:`Codex CLI`,grok:`Grok CLI`,local:`Claude Code`};function _(e){let t=typeof e.cliVersion==`string`?e.cliVersion.trim():``;return t.length>0?`${g[e.engine]} ${t}`:null}function v(e){return(e.notes??[]).filter(e=>typeof e==`string`&&e.trim().length>0)}function y(e){return e===`fallback`}function b(e,t=`standard`){let r=f(e,t),i=n(e,r);return i?`${`${a(i.contextWindow)} ctx${y(e.windowSource)?` (est.)`:``}`}${i.autoCompactAt===null?``:` · compacts ≈${a(i.autoCompactAt)}`}${r===`expansive`?` (expansive)`:``}`:`window unknown`}function x(t){let r=n(t,`standard`),i=e(t)?n(t,`expansive`):null,o=[];if(!r)o.push(`Context window unknown for this model.`);else{let e=r.autoCompactAt===null?``:`; compacts at about ${a(r.autoCompactAt)}${i?` in Standard`:``}`;o.push(`${a(r.contextWindow)}-token window${e}.`)}return i&&o.push(`Expansive runs to about ${a(i.autoCompactAt??i.contextWindow)} before compacting.`),t.windowSource&&o.push(`Window ${c[t.windowSource]}.`),o.join(` `)}function S(e){return e===`codex`?l:null}function C(e){let t=n(e,`standard`),r=n(e,`expansive`),i=t?t.autoCompactAt??t.contextWindow:null,o=r?r.autoCompactAt??r.contextWindow:null;return i===null||o===null||i<=0?null:`A turn at ${a(o)} re-sends ${(o/i).toFixed(1)}× the tokens of one at ${a(i)}.`}function w(e,t,r){let i=n(t,`standard`),o=n(t,`expansive`),s=i?i.autoCompactAt??i.contextWindow:null,c=o?o.autoCompactAt??o.contextWindow:null;if(r===`standard`||c===null)return s===null?`The CLI compacts at its own default point for this model.`:e===`claude`?`Compacts at about ${a(s)}. Every turn re-sends the whole context, so holding it under this point keeps each turn cheaper and recall sharper.`:`Compacts at about ${a(s)} — the CLI's own default budget for this model.`;let l=C(t),u=S(e);return`Runs to about ${a(c)} before compacting — for tightly coupled, cross-cutting work that needs everything in view at once. Each turn re-sends everything held, so a long expansive chat uses noticeably more of your plan per turn.${l?` ${l}`:``}${u?` ${u}`:``}`}function T(e,t){return n(t,`standard`)?e===`grok`||e===`local`?`One budget: this CLI compacts at its own fixed point, and Verse cannot raise it per chat.`:`One budget: this model has no larger window to expand into.`:`This model’s window is unknown, so Verse cannot offer a larger budget for it.`}var E={fits:`code fits`,tight:`code fits, tight`,expansive:`code needs expansive`,split:`code too big — split`},D={fits:`Fits`,tight:`Tight fit`,expansive:`Needs expansive`,split:`Split the work`};function O(e){return e.roots.some(e=>e.truncated)}function k(e,t,a,o){if(typeof e!=`number`||!Number.isFinite(e)||e<0)return null;let s=i(o);if(f(t,a)===`expansive`&&t){let i=n(t,`expansive`);return r(e,{...t,contextWindow:i.contextWindow,autoCompactAt:i.autoCompactAt,expansive:null},s)}return r(e,t,s)}function A(t){let r=`${t.floor?`at least `:``}~${a(t.tokens)} tokens of tracked code`,i=f(t.option,t.mode)===`expansive`,o=n(t.option,`standard`),s=n(t.option,`expansive`),c=o?a(o.autoCompactAt??o.contextWindow):null,l=s?a(s.autoCompactAt??s.contextWindow):null,u=i?l:c,d=i?`Expansive budget`:`budget`;switch(t.verdict){case`fits`:return`All ${r} fits well inside this model's ${d}${u?` (compacts ≈${u})`:``}, with room left for the conversation.`;case`tight`:{let n=!i&&l!==null&&e(t.option)?` Expansive (≈${l}) would hold it with room to spare.`:``;return`${M(r)} fits under the ≈${u??`?`} compaction point${i?` of the Expansive budget`:``}, with little room for the conversation — expect it to compact if the agent reads widely.${n}`}case`expansive`:return`${M(r)} is more than the Standard budget (≈${c??`?`}) holds; only Expansive (≈${l??`?`}) takes it all. Switch to Expansive, or narrow the folders to the part you are changing.`;case`split`:return`${M(r)} is more than any single context on this model holds${l?`, even Expansive (≈${l})`:``}. Split the work: fan it out across several chats, each scoped to one folder or subsystem, or narrow this chat to the part you are changing.`}}function j(e){let t=e?` for ${g[e]}`:``;return`Estimated from the size of tracked text files (bytes ÷ 4), plus an estimated ~${a(i(e))} of fixed prompt${t} that every chat starts with. An agent rarely reads everything, so this is a ceiling, not a forecast.`}function M(e){return e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1)}function N(t,n){let r=o(n,t);return{tokens:Math.floor(r.contextTokens),exact:r.exact,window:r.contextWindow,autoCompactAt:r.autoCompactAt,source:r.source,mode:r.mode,hasModes:e(r.option)}}function P(e){return e.cacheReadTokens<=0&&e.cacheCreationTokens<=0?null:t(e)}function F(e){return e===null||!Number.isFinite(e)?`—`:`${Math.round(e*100)}%`}function I(e){let t=new Map,n=0,r=null,i=(e,n,r)=>{if(!Number.isFinite(n)||n<0)return;let i=t.get(e)??{exact:null,bound:null};r?i.exact=Math.max(i.exact??0,n):i.bound=Math.max(i.bound??0,n),t.set(e,i)};for(let t of e)switch(t.type){case`usage`:r=t.usage,i(t.turnId,t.usage.contextTokens,t.usage.contextTokensExact!==!1);break;case`context`:t.turnId!==null&&i(t.turnId,t.contextTokens,t.exact);break;case`compaction`:n+=1}let a=0,o=null,s=!0,c=0;for(let e of t.values()){let t=e.exact??e.bound;t!==null&&(e.exact===null&&(s=!1),c+=1,a+=t,o=o===null?t:Math.max(o,t))}return{turns:c,average:c===0?null:Math.round(a/c),peak:o,exact:s,compactions:n,lastTurnCacheHit:r===null?null:P(r)}}function L(e,t,n,r){if(e.status===`running`||r===null)return null;let a=Date.parse(r);if(!Number.isFinite(a))return null;let o=n-a;return o<36e5||t<i(e.engine)?null:{idleMs:o,tokens:t,local:e.engine===`local`}}function R(e,t){return e.window!==null&&t.window!==null?e.tokens/e.window>t.tokens/t.window:e.window!==null||t.window===null&&e.tokens>t.tokens}function z(e,t){let n=new Map;for(let t of e){let e=n.get(t.seatId)??[];e.push(t),n.set(t.seatId,e)}let r=[];for(let[e,i]of n){let n=t.find(t=>t.id===e)??null,a=0,o=0,s=0,c=0,l=0,u=0,d=0,f=null;for(let e of i){a+=e.usage.inputTokens,o+=e.usage.cacheReadTokens,s+=e.usage.cacheCreationTokens,c+=e.usage.outputTokens,l+=e.turnCount,u+=e.compactionCount??0;let n=N(e,t);if(n.mode===`expansive`&&(d+=1),n.tokens<=0)continue;let r={sessionId:e.id,title:e.title,tokens:n.tokens,window:n.window,exact:n.exact};(f===null||R(r,f))&&(f=r)}r.push({seatId:e,label:n?.label??e,engine:n?.engine??i[0].engine,retired:n===null,sessions:i.length,turns:l,promptTokens:a+o+s,outputTokens:c,cacheHitRatio:P({inputTokens:a,cacheReadTokens:o,cacheCreationTokens:s}),compactions:u,expansiveSessions:d,fullest:f})}return r.sort((e,t)=>t.promptTokens-e.promptTokens||e.label.localeCompare(t.label))}export{d as C,z as S,I as T,T as _,p as a,_ as b,A as c,F as d,L as f,m as g,k as h,w as i,O as l,x as m,D as n,S as o,b as p,E as r,C as s,h as t,j as u,P as v,N as w,v as x,f as y};
|
|
2
|
-
//# sourceMappingURL=context-model-Bto3LZn2.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"context-model-Bto3LZn2.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/usage/context-model.ts"],"sourcesContent":["/**\n * routes/verse/usage/context-model.ts — the ONE projection of context facts\n * for every surface that shows a seat: the seat picker's rows, the new-chat\n * dialog's context block, the resources panel's \"This chat\" efficiency block,\n * and the Usage section's per-seat efficiency table.\n *\n * WHY ONE MODULE. Before V3.9 every surface read `seat.contextWindow` (the\n * DEFAULT model's window) or the session's creation-time window, and three of\n * them rendered \"200k\" for a 1M Claude model. The arithmetic now lives in\n * core/verse/context-math.ts, shared with the server; this module is only the\n * wording and the aggregation, so the picker, the dialog and the panel cannot\n * describe one model's budget three different ways.\n *\n * HONESTY RULES this module enforces (docs/VERSE-CONTEXT.md):\n *\n * 1. UNKNOWN IS NOT A NUMBER. A model whose budget is unknown reads \"window\n * unknown\", never a default dressed as a fact. A Verse fallback window is\n * marked \"est.\", and its source says so in words.\n * 2. AN UPPER BOUND IS NOT A MEASUREMENT. Codex's turn total sums every model\n * call; until its rollout is read, occupancy is \"≤ N\", and any statistic\n * built on such a reading carries the same flag.\n * 3. NO CACHE REPORTED IS NOT A 0% HIT RATE. A provider that reported no\n * cache activity at all (Ollama; codex on its very first call) gets \"none\n * reported\", not a 0% that reads \"caching is broken\".\n * 4. NOTHING HERE SPENDS. Every figure is derived from what the server\n * already returned (seats, sessions, the open chat's event log).\n *\n * Pure: no React, no I/O.\n */\nimport {\n CACHE_IDLE_TTL_MS,\n budgetFor,\n cacheHitRatio,\n fitVerdict,\n hasExpansiveMode,\n sessionOverheadTokens,\n} from '../../../../core/verse/context-math.js';\nimport type {\n VerseContextBudget,\n VerseContextFit,\n VerseContextMode,\n VerseEngine,\n VerseEvent,\n VerseFitVerdict,\n VerseModelOption,\n VerseSeat,\n VerseSession,\n VerseUsage,\n VerseWindowSource,\n} from '../../../../core/verse/types.js';\nimport { CODEX_EXPANSIVE_METERING_NOTE, WINDOW_SOURCE_TEXT, modelOptionFor, seatUnavailableReason, sessionContextBudget } from '../verse-model.js';\nimport { formatTokens } from '../verse-store.js';\n\n// ---------------------------------------------------------------------------\n// Models and modes\n// ---------------------------------------------------------------------------\n\n/**\n * A seat's option for a model id, matching through the alias table (a chat\n * remembered on `claude-opus-5.5` is the catalog's `claude-opus-5-5`). The\n * lookup itself is verse-model's `modelOptionFor`, the one the context meter\n * uses, so the picker and the meter can never resolve one id two ways.\n */\nexport function seatModelOption(seat: VerseSeat | null | undefined, modelId: string): VerseModelOption | null {\n return seat ? modelOptionFor([seat], { seatId: seat.id, model: modelId }) : null;\n}\n\n/** `mode` when this model has a budget for it, else `standard` — never a mode the CLI cannot be told. */\nexport function resolveContextMode(option: VerseModelOption | null | undefined, mode: VerseContextMode): VerseContextMode {\n return mode !== 'standard' && budgetFor(option, mode) !== null ? mode : 'standard';\n}\n\n/** The budget a model runs with in a mode (resolved), or null when even its standard window is unknown. */\nexport function effectiveBudget(option: VerseModelOption | null | undefined, mode: VerseContextMode): VerseContextBudget | null {\n return budgetFor(option, resolveContextMode(option, mode));\n}\n\n/** Why this model cannot be chosen on this seat, or null when it can. The seat's own outage wins. */\nexport function modelUnavailableReason(seat: VerseSeat, option: VerseModelOption): string | null {\n const seatReason = seatUnavailableReason(seat);\n if (seatReason !== null) return seatReason;\n const reason = option.unavailableReason;\n return typeof reason === 'string' && reason.trim().length > 0 ? reason.trim() : null;\n}\n\nexport const CONTEXT_MODE_LABEL: Record<VerseContextMode, string> = {\n standard: 'Standard',\n expansive: 'Expansive',\n};\n\n/** How each seat's CLI is named when its pinned version is shown. */\nexport const ENGINE_CLI_NAME: Record<VerseEngine, string> = {\n claude: 'Claude Code',\n codex: 'Codex CLI',\n grok: 'Grok CLI',\n local: 'Claude Code',\n};\n\n/** \"Claude Code 2.1.257\" — the binary this seat is pinned to; null when unknown (local seats, old servers). */\nexport function seatCliLine(seat: VerseSeat): string | null {\n const version = typeof seat.cliVersion === 'string' ? seat.cliVersion.trim() : '';\n return version.length > 0 ? `${ENGINE_CLI_NAME[seat.engine]} ${version}` : null;\n}\n\n/** The seat's own plain-language context facts (binary skew, catalog not yet fetched, …). */\nexport function seatContextNotes(seat: VerseSeat): string[] {\n return (seat.notes ?? []).filter((n): n is string => typeof n === 'string' && n.trim().length > 0);\n}\n\n// ---------------------------------------------------------------------------\n// Window provenance\n// ---------------------------------------------------------------------------\n\n// Window provenance wording is verse-model's `WINDOW_SOURCE_TEXT` — the\n// meter's tooltip, the picker and the resources panel all read that one table.\n\nexport function isEstimatedWindow(source: VerseWindowSource | null | undefined): boolean {\n return source === 'fallback';\n}\n\n// ---------------------------------------------------------------------------\n// Picker and dialog wording\n// ---------------------------------------------------------------------------\n\n/**\n * The compact per-model phrase a picker row carries: \"1M ctx · compacts ≈367k\".\n * Uses the budget for `mode` when the model has one, and names the mode only\n * when it is not the default, so an ordinary row stays short.\n */\nexport function modelContextPhrase(option: VerseModelOption, mode: VerseContextMode = 'standard'): string {\n const resolved = resolveContextMode(option, mode);\n const budget = budgetFor(option, resolved);\n if (!budget) return 'window unknown';\n const window = `${formatTokens(budget.contextWindow)} ctx${isEstimatedWindow(option.windowSource) ? ' (est.)' : ''}`;\n const compacts = budget.autoCompactAt === null ? '' : ` · compacts ≈${formatTokens(budget.autoCompactAt)}`;\n return `${window}${compacts}${resolved === 'expansive' ? ' (expansive)' : ''}`;\n}\n\n/**\n * The full sentence for a tooltip or the dialog: the window, where each mode\n * compacts, and how the window is known.\n */\nexport function modelContextSentence(option: VerseModelOption): string {\n const standard = budgetFor(option, 'standard');\n const expansive = hasExpansiveMode(option) ? budgetFor(option, 'expansive') : null;\n const parts: string[] = [];\n if (!standard) {\n parts.push('Context window unknown for this model.');\n } else {\n const where = standard.autoCompactAt === null\n ? ''\n : `; compacts at about ${formatTokens(standard.autoCompactAt)}${expansive ? ' in Standard' : ''}`;\n parts.push(`${formatTokens(standard.contextWindow)}-token window${where}.`);\n }\n if (expansive) {\n parts.push(`Expansive runs to about ${formatTokens(expansive.autoCompactAt ?? expansive.contextWindow)} before compacting.`);\n }\n if (option.windowSource) parts.push(`Window ${WINDOW_SOURCE_TEXT[option.windowSource]}.`);\n return parts.join(' ');\n}\n\n/**\n * The metering caveat an Expansive cost sentence must carry for this engine,\n * or null when there is none. The wording is verse-model's\n * CODEX_EXPANSIVE_METERING_NOTE — ONE sentence for the new-chat dialog, the\n * handoff dialog, the in-chat mode menu and the \"Expansive could help\" chip.\n * The ratio those surfaces quote (≈3.2× for a 785k vs 245k codex turn) counts\n * re-sent TOKENS only; GPT-5.6-class requests above 272k reportedly also\n * count about 2× against plan limits (docs/VERSE-CONTEXT.md §2.3, a single\n * secondary source), so the note is worded as reported, never as a measured\n * multiplier. Standard never crosses 272k; Expansive does by design.\n */\nexport function expansiveMeteringNote(engine: VerseEngine | null | undefined): string | null {\n return engine === 'codex' ? CODEX_EXPANSIVE_METERING_NOTE : null;\n}\n\n/**\n * \"A turn at 967k re-sends 2.6× the tokens of one at 367k.\" — the only ratio\n * any Expansive cost sentence quotes, and it is arithmetic on the model's own\n * budgets. Null when either compaction point is unknown. It comes BEFORE the\n * codex metering note, whose \"twice that\" refers to it.\n */\nexport function expansiveRatioSentence(option: VerseModelOption | null | undefined): string | null {\n const standard = budgetFor(option, 'standard');\n const expansive = budgetFor(option, 'expansive');\n const stdCap = standard ? standard.autoCompactAt ?? standard.contextWindow : null;\n const expCap = expansive ? expansive.autoCompactAt ?? expansive.contextWindow : null;\n if (stdCap === null || expCap === null || stdCap <= 0) return null;\n return `A turn at ${formatTokens(expCap)} re-sends ${(expCap / stdCap).toFixed(1)}× the tokens of one at ${formatTokens(stdCap)}.`;\n}\n\n/**\n * What each mode costs, in plain words, for the mode selector. Numbers come\n * from the model's own budgets; the only ratio quoted is arithmetic (every\n * turn re-sends everything held, so a turn at X re-sends X/Y of one at Y) —\n * a token ratio, not a usage multiplier, which is why codex also carries the\n * shared metering caveat.\n */\nexport function contextModeDescription(engine: VerseEngine, option: VerseModelOption, mode: VerseContextMode): string {\n const standard = budgetFor(option, 'standard');\n const expansive = budgetFor(option, 'expansive');\n const stdCap = standard ? standard.autoCompactAt ?? standard.contextWindow : null;\n const expCap = expansive ? expansive.autoCompactAt ?? expansive.contextWindow : null;\n if (mode === 'standard' || expCap === null) {\n if (stdCap === null) return 'The CLI compacts at its own default point for this model.';\n return engine === 'claude'\n ? `Compacts at about ${formatTokens(stdCap)}. Every turn re-sends the whole context, so holding it under this point keeps each turn cheaper and recall sharper.`\n : `Compacts at about ${formatTokens(stdCap)} — the CLI's own default budget for this model.`;\n }\n const ratio = expansiveRatioSentence(option);\n const metering = expansiveMeteringNote(engine);\n return `Runs to about ${formatTokens(expCap)} before compacting — for tightly coupled, cross-cutting work that needs everything in view at once. Each turn re-sends everything held, so a long expansive chat uses noticeably more of your plan per turn.${ratio ? ` ${ratio}` : ''}${metering ? ` ${metering}` : ''}`;\n}\n\n/** Why a model offers no mode choice, for the one line where the selector would be. */\nexport function noModeReason(engine: VerseEngine, option: VerseModelOption): string {\n if (!budgetFor(option, 'standard')) return 'This model’s window is unknown, so Verse cannot offer a larger budget for it.';\n if (engine === 'grok' || engine === 'local') return 'One budget: this CLI compacts at its own fixed point, and Verse cannot raise it per chat.';\n return 'One budget: this model has no larger window to expand into.';\n}\n\n// ---------------------------------------------------------------------------\n// Context fit\n// ---------------------------------------------------------------------------\n\n/** Short form for a picker row, where it sits beside the capacity words. */\nexport const FIT_SHORT: Record<VerseFitVerdict, string> = {\n fits: 'code fits',\n tight: 'code fits, tight',\n expansive: 'code needs expansive',\n split: 'code too big — split',\n};\n\n/** Badge text for the chosen model. */\nexport const FIT_LABEL: Record<VerseFitVerdict, string> = {\n fits: 'Fits',\n tight: 'Tight fit',\n expansive: 'Needs expansive',\n split: 'Split the work',\n};\n\n/** A fit reading that is a FLOOR (a root hit its file or time cap). */\nexport function fitIsFloor(fit: VerseContextFit): boolean {\n return fit.roots.some((r) => r.truncated);\n}\n\n/**\n * The verdict for a model IN THE MODE THE CHAT WOULD RUN IN, or null when its\n * budget is unknown (never guessed).\n *\n * `engine` is the seat's engine: the fixed prompt added to the code is that\n * CLI's estimate (context-math `sessionOverheadTokens` — ≈15k local, ≈25k\n * claude), not one flat figure. With a flat 30k a 64k local seat (compacts\n * ≈32.5k) called anything over ~2.5k tokens of code \"too big — split\". Null\n * falls back to the largest estimate.\n *\n * In Standard this is context-math's `fitVerdict` as is — including\n * \"expansive\", the suggestion that only the bigger budget holds the code. In\n * Expansive the bigger budget IS the budget, so the same thresholds are\n * applied to it: the code fits, fits tightly, or no single context on this\n * model holds it. Without this, a chat already set to Expansive would still be\n * told its code \"fits tightly under ≈367k\" — true of a budget it is not using.\n */\nexport function modelFit(\n tokens: number | null | undefined,\n option: VerseModelOption | null | undefined,\n mode: VerseContextMode,\n engine: VerseEngine | null,\n): VerseFitVerdict | null {\n if (typeof tokens !== 'number' || !Number.isFinite(tokens) || tokens < 0) return null;\n const overhead = sessionOverheadTokens(engine);\n if (resolveContextMode(option, mode) === 'expansive' && option) {\n const expansive = budgetFor(option, 'expansive')!;\n return fitVerdict(tokens, { ...option, contextWindow: expansive.contextWindow, autoCompactAt: expansive.autoCompactAt, expansive: null }, overhead);\n }\n return fitVerdict(tokens, option, overhead);\n}\n\n/**\n * The sentence under the fit badge, for the verdict `modelFit` gave in the\n * chat's mode. In Standard a tight fit also names the Expansive budget when\n * one exists, and \"needs expansive\" says what to do — suggestions only;\n * nothing here switches the mode.\n */\nexport function fitExplanation(input: {\n verdict: VerseFitVerdict;\n tokens: number;\n option: VerseModelOption;\n mode: VerseContextMode;\n floor?: boolean;\n}): string {\n const amount = `${input.floor ? 'at least ' : ''}~${formatTokens(input.tokens)} tokens of tracked code`;\n const inExpansive = resolveContextMode(input.option, input.mode) === 'expansive';\n const standard = budgetFor(input.option, 'standard');\n const expansive = budgetFor(input.option, 'expansive');\n const stdCap = standard ? formatTokens(standard.autoCompactAt ?? standard.contextWindow) : null;\n const expCap = expansive ? formatTokens(expansive.autoCompactAt ?? expansive.contextWindow) : null;\n const cap = inExpansive ? expCap : stdCap;\n const budget = inExpansive ? 'Expansive budget' : 'budget';\n switch (input.verdict) {\n case 'fits':\n return `All ${amount} fits well inside this model's ${budget}${cap ? ` (compacts ≈${cap})` : ''}, with room left for the conversation.`;\n case 'tight': {\n const roomier = !inExpansive && expCap !== null && hasExpansiveMode(input.option)\n ? ` Expansive (≈${expCap}) would hold it with room to spare.`\n : '';\n return `${capitalize(amount)} fits under the ≈${cap ?? '?'} compaction point${inExpansive ? ' of the Expansive budget' : ''}, with little room for the conversation — expect it to compact if the agent reads widely.${roomier}`;\n }\n case 'expansive':\n return `${capitalize(amount)} is more than the Standard budget (≈${stdCap ?? '?'}) holds; only Expansive (≈${expCap ?? '?'}) takes it all. Switch to Expansive, or narrow the folders to the part you are changing.`;\n case 'split':\n return `${capitalize(amount)} is more than any single context on this model holds${expCap ? `, even Expansive (≈${expCap})` : ''}. Split the work: fan it out across several chats, each scoped to one folder or subsystem, or narrow this chat to the part you are changing.`;\n }\n}\n\n/**\n * How the working-set figure is made — shown once, beside the badge. Names the\n * fixed-prompt figure the verdict added, and calls it an estimate: no CLI\n * reports its base prompt before a turn has run.\n */\nexport function fitMethodNote(engine: VerseEngine | null): string {\n const cli = engine ? ` for ${ENGINE_CLI_NAME[engine]}` : '';\n return `Estimated from the size of tracked text files (bytes ÷ 4), plus an estimated ~${formatTokens(sessionOverheadTokens(engine))} of fixed prompt${cli} that every chat starts with. An agent rarely reads everything, so this is a ceiling, not a forecast.`;\n}\n\nfunction capitalize(text: string): string {\n return text.length === 0 ? text : text.charAt(0).toUpperCase() + text.slice(1);\n}\n\n// ---------------------------------------------------------------------------\n// One session's context\n// ---------------------------------------------------------------------------\n\nexport interface SessionContextView {\n tokens: number;\n /** False when `tokens` is an upper bound (codex before its rollout is read). */\n exact: boolean;\n window: number | null;\n autoCompactAt: number | null;\n /** How the window is known; null when nothing says (no window, or a stored one without provenance). */\n source: VerseWindowSource | null;\n mode: VerseContextMode;\n /** The session's model has a real expansive budget on its seat. */\n hasModes: boolean;\n}\n\n/**\n * The window a session is measured against, by the precedence every surface\n * shares — runtime → the seat's CURRENT catalog budget for the model and mode\n * → what the record stored → the seat default. The precedence itself lives in\n * verse-model's `sessionContextBudget` (the context meter reads it too); this\n * only adds whether the model offers a second mode, for the panels here.\n */\nexport function sessionContext(session: VerseSession, seats: readonly VerseSeat[]): SessionContextView {\n const budget = sessionContextBudget(seats, session);\n return {\n tokens: Math.floor(budget.contextTokens),\n exact: budget.exact,\n window: budget.contextWindow,\n autoCompactAt: budget.autoCompactAt,\n source: budget.source,\n mode: budget.mode,\n hasModes: hasExpansiveMode(budget.option),\n };\n}\n\n/**\n * Cache-hit ratio, except when the provider reported no cache activity at all\n * — then null (\"none reported\"), because 0% would claim caching failed when\n * the truth is that nothing was said about it.\n */\nexport function reportedCacheHitRatio(usage: Pick<VerseUsage, 'inputTokens' | 'cacheReadTokens' | 'cacheCreationTokens'>): number | null {\n if (usage.cacheReadTokens <= 0 && usage.cacheCreationTokens <= 0) return null;\n return cacheHitRatio(usage);\n}\n\nexport function formatRatio(ratio: number | null): string {\n if (ratio === null || !Number.isFinite(ratio)) return '—';\n return `${Math.round(ratio * 100)}%`;\n}\n\nexport interface TurnContextStats {\n /** Turns with at least one context reading. */\n turns: number;\n /** Mean of each turn's context (its largest trustworthy reading); null with no turns. */\n average: number | null;\n /** Largest per-turn context seen. */\n peak: number | null;\n /** False when any counted turn had only an upper-bound reading. */\n exact: boolean;\n /** Compactions recorded in the log. */\n compactions: number;\n /** Cache-hit ratio of the most recent turn (see `reportedCacheHitRatio`). */\n lastTurnCacheHit: number | null;\n}\n\n/**\n * Context per turn from the open chat's event log.\n *\n * A turn's context is its LARGEST trustworthy reading: within one turn the\n * prompt only grows, except across a compaction, and the peak is what the\n * turn actually paid for. Exact readings (`context` events, usage frames not\n * flagged as upper bounds) win; a turn whose only reading is codex's turn\n * total contributes that total and flags the statistic as an upper bound —\n * that figure can be many times the real prompt, so it is never mixed in\n * where an exact one exists.\n */\nexport function turnContextStats(events: readonly VerseEvent[]): TurnContextStats {\n const perTurn = new Map<string, { exact: number | null; bound: number | null }>();\n let compactions = 0;\n let lastUsage: VerseUsage | null = null;\n const note = (turnId: string, tokens: number, exact: boolean): void => {\n if (!Number.isFinite(tokens) || tokens < 0) return;\n const entry = perTurn.get(turnId) ?? { exact: null, bound: null };\n if (exact) entry.exact = Math.max(entry.exact ?? 0, tokens);\n else entry.bound = Math.max(entry.bound ?? 0, tokens);\n perTurn.set(turnId, entry);\n };\n for (const event of events) {\n switch (event.type) {\n case 'usage':\n lastUsage = event.usage;\n note(event.turnId, event.usage.contextTokens, event.usage.contextTokensExact !== false);\n break;\n case 'context':\n if (event.turnId !== null) note(event.turnId, event.contextTokens, event.exact);\n break;\n case 'compaction':\n compactions += 1;\n break;\n default:\n break;\n }\n }\n let sum = 0;\n let peak: number | null = null;\n let exact = true;\n let turns = 0;\n for (const entry of perTurn.values()) {\n const value = entry.exact ?? entry.bound;\n if (value === null) continue;\n if (entry.exact === null) exact = false;\n turns += 1;\n sum += value;\n peak = peak === null ? value : Math.max(peak, value);\n }\n return {\n turns,\n average: turns === 0 ? null : Math.round(sum / turns),\n peak,\n exact,\n compactions,\n lastTurnCacheHit: lastUsage === null ? null : reportedCacheHitRatio(lastUsage),\n };\n}\n\nexport interface IdleCacheWarning {\n idleMs: number;\n tokens: number;\n /** A local model: the cost is time, not spend. */\n local: boolean;\n}\n\n/**\n * The next turn of an idle chat re-reads its whole context uncached once the\n * provider's prompt cache has expired (CACHE_IDLE_TTL_MS). Below the fixed\n * prompt every new chat on this engine pays anyway (its estimate) there is\n * nothing worth warning about.\n */\nexport function idleCacheWarning(\n session: Pick<VerseSession, 'status' | 'engine'>,\n tokens: number,\n now: number,\n /**\n * When the chat last TALKED to its provider (`lastTurnActivityAt(events)`),\n * never `session.updatedAt`: a rename or mode switch moves that without\n * warming the provider's cache. Null (no turn yet / log not loaded) → no warning.\n */\n lastActivityAt: string | null,\n): IdleCacheWarning | null {\n if (session.status === 'running' || lastActivityAt === null) return null;\n const last = Date.parse(lastActivityAt);\n if (!Number.isFinite(last)) return null;\n const idleMs = now - last;\n if (idleMs < CACHE_IDLE_TTL_MS || tokens < sessionOverheadTokens(session.engine)) return null;\n return { idleMs, tokens, local: session.engine === 'local' };\n}\n\n// ---------------------------------------------------------------------------\n// Per-seat efficiency across sessions (Usage section)\n// ---------------------------------------------------------------------------\n\nexport interface SeatEfficiencyRow {\n seatId: string;\n label: string;\n engine: VerseEngine;\n /** The seat is no longer in the roster (its sessions remain on disk). */\n retired: boolean;\n sessions: number;\n turns: number;\n /** input + cache read + cache write: every prompt token the seat was sent. */\n promptTokens: number;\n outputTokens: number;\n /** Null when the provider reported no cache activity on any of these sessions. */\n cacheHitRatio: number | null;\n compactions: number;\n expansiveSessions: number;\n /** The fullest context among these sessions right now, as a share of its window. */\n fullest: { sessionId: string; title: string; tokens: number; window: number | null; exact: boolean } | null;\n}\n\n/**\n * \"Fullest\" is a share of the window when both windows are known; a context\n * with a known window outranks one without (its fullness is a fact, the other\n * a size); two unknown windows compare by size.\n */\nfunction fuller(a: NonNullable<SeatEfficiencyRow['fullest']>, b: NonNullable<SeatEfficiencyRow['fullest']>): boolean {\n if (a.window !== null && b.window !== null) return a.tokens / a.window > b.tokens / b.window;\n if (a.window !== null) return true;\n if (b.window !== null) return false;\n return a.tokens > b.tokens;\n}\n\n/**\n * Aggregate every session by seat. Ratios are computed from SUMS, never as a\n * mean of per-session ratios — a two-turn chat must not weigh as much as a\n * two-hundred-turn one. Seats with no sessions are omitted rather than shown\n * as zeros. Sorted by prompt tokens, largest first: that is where efficiency\n * matters most.\n */\nexport function seatEfficiency(sessions: readonly VerseSession[], seats: readonly VerseSeat[]): SeatEfficiencyRow[] {\n const bySeat = new Map<string, VerseSession[]>();\n for (const s of sessions) {\n const list = bySeat.get(s.seatId) ?? [];\n list.push(s);\n bySeat.set(s.seatId, list);\n }\n const rows: SeatEfficiencyRow[] = [];\n for (const [seatId, list] of bySeat) {\n const seat = seats.find((s) => s.id === seatId) ?? null;\n let input = 0;\n let read = 0;\n let write = 0;\n let output = 0;\n let turns = 0;\n let compactions = 0;\n let expansiveSessions = 0;\n let fullest: SeatEfficiencyRow['fullest'] = null;\n for (const s of list) {\n input += s.usage.inputTokens;\n read += s.usage.cacheReadTokens;\n write += s.usage.cacheCreationTokens;\n output += s.usage.outputTokens;\n turns += s.turnCount;\n compactions += s.compactionCount ?? 0;\n // The mode as the meter resolves it (verse-model sessionContextBudget),\n // counted before the empty-reading skip: the mode is a fact about the\n // chat, not about its reading.\n const view = sessionContext(s, seats);\n if (view.mode === 'expansive') expansiveSessions += 1;\n if (view.tokens <= 0) continue;\n const candidate = { sessionId: s.id, title: s.title, tokens: view.tokens, window: view.window, exact: view.exact };\n if (fullest === null || fuller(candidate, fullest)) fullest = candidate;\n }\n rows.push({\n seatId,\n label: seat?.label ?? seatId,\n engine: seat?.engine ?? list[0]!.engine,\n retired: seat === null,\n sessions: list.length,\n turns,\n promptTokens: input + read + write,\n outputTokens: output,\n cacheHitRatio: reportedCacheHitRatio({ inputTokens: input, cacheReadTokens: read, cacheCreationTokens: write }),\n compactions,\n expansiveSessions,\n fullest,\n });\n }\n return rows.sort((a, b) => b.promptTokens - a.promptTokens || a.label.localeCompare(b.label));\n}\n"],"mappings":"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"}
|