@ashlr/hub 3.11.3 → 3.12.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +104 -0
- package/README.md +44 -18
- package/dist/authority-surface.json +74 -59
- package/dist/build-identity.json +2 -2
- package/dist/cli/authority.d.ts +39 -0
- package/dist/cli/authority.js +222 -55
- package/dist/cli/authority.js.map +1 -1
- package/dist/cli/help.js +1 -1
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/verse.d.ts +3 -0
- package/dist/cli/verse.js +10 -0
- package/dist/cli/verse.js.map +1 -1
- package/dist/core/authority/trust-roots.js +7 -1
- package/dist/core/authority/trust-roots.js.map +1 -1
- package/dist/core/authority/types.d.ts +2 -2
- package/dist/core/cloud/cloud-api.js +1 -1
- package/dist/core/cloud/cloud-api.js.map +1 -1
- package/dist/core/cloud/delivery-contract.d.ts +1 -1
- package/dist/core/cloud/delivery-contract.js +25 -15
- package/dist/core/cloud/delivery-contract.js.map +1 -1
- package/dist/core/cloud/store.js +6 -0
- package/dist/core/cloud/store.js.map +1 -1
- package/dist/core/cloud/tracker.d.ts +2 -0
- package/dist/core/cloud/tracker.js +140 -37
- package/dist/core/cloud/tracker.js.map +1 -1
- package/dist/core/cloud/types.d.ts +9 -1
- package/dist/core/cloud/types.js.map +1 -1
- package/dist/core/comms/dispatch.d.ts +5 -0
- package/dist/core/comms/dispatch.js +12 -1
- package/dist/core/comms/dispatch.js.map +1 -1
- package/dist/core/comms/requests.d.ts +27 -1
- package/dist/core/comms/requests.js +50 -1
- package/dist/core/comms/requests.js.map +1 -1
- package/dist/core/daemon/loop.d.ts +14 -0
- package/dist/core/daemon/loop.js +35 -0
- package/dist/core/daemon/loop.js.map +1 -1
- package/dist/core/fabric/claude-usage.js +23 -1
- package/dist/core/fabric/claude-usage.js.map +1 -1
- package/dist/core/fleet/dispatch-router.d.ts +7 -0
- package/dist/core/fleet/dispatch-router.js +4 -1
- package/dist/core/fleet/dispatch-router.js.map +1 -1
- package/dist/core/fleet/tick-hooks-live.d.ts +5 -1
- package/dist/core/fleet/tick-hooks-live.js +10 -1
- package/dist/core/fleet/tick-hooks-live.js.map +1 -1
- package/dist/core/local-runtime/llama/config.d.ts +14 -0
- package/dist/core/local-runtime/llama/config.js +20 -2
- package/dist/core/local-runtime/llama/config.js.map +1 -1
- package/dist/core/local-runtime/llama/process.d.ts +19 -0
- package/dist/core/local-runtime/llama/process.js +67 -17
- package/dist/core/local-runtime/llama/process.js.map +1 -1
- package/dist/core/local-runtime/llama/supervisor.js +14 -3
- package/dist/core/local-runtime/llama/supervisor.js.map +1 -1
- package/dist/core/observability/rollup.d.ts +12 -0
- package/dist/core/observability/rollup.js +37 -2
- package/dist/core/observability/rollup.js.map +1 -1
- package/dist/core/observability/usage-source.js +49 -1
- package/dist/core/observability/usage-source.js.map +1 -1
- package/dist/core/resources/connection-monitor.js +47 -4
- package/dist/core/resources/connection-monitor.js.map +1 -1
- package/dist/core/resources/engineering-mission-store.d.ts +1 -1
- package/dist/core/routing/headroom.js +7 -2
- package/dist/core/routing/headroom.js.map +1 -1
- package/dist/core/routing/router.d.ts +48 -0
- package/dist/core/routing/router.js +129 -13
- package/dist/core/routing/router.js.map +1 -1
- package/dist/core/run/best-of-n.d.ts +7 -0
- package/dist/core/run/best-of-n.js +3 -0
- package/dist/core/run/best-of-n.js.map +1 -1
- package/dist/core/run/harness-dispatch.d.ts +147 -0
- package/dist/core/run/harness-dispatch.js +234 -0
- package/dist/core/run/harness-dispatch.js.map +1 -0
- package/dist/core/run/orchestrator.js +3 -0
- package/dist/core/run/orchestrator.js.map +1 -1
- package/dist/core/run/provider-client.d.ts +8 -0
- package/dist/core/run/provider-client.js +4 -0
- package/dist/core/run/provider-client.js.map +1 -1
- package/dist/core/run/sandboxed-engine.d.ts +8 -0
- package/dist/core/run/sandboxed-engine.js +60 -7
- package/dist/core/run/sandboxed-engine.js.map +1 -1
- package/dist/core/types.d.ts +14 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/universe/builtins/preparation/manifest.json +1 -1
- package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +188 -6
- package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +187 -5
- package/dist/core/universe/firm-demo.d.ts +1 -1
- package/dist/core/universe/firm-graph.d.ts +2 -2
- package/dist/core/util/scrub.js +16 -3
- package/dist/core/util/scrub.js.map +1 -1
- package/dist/core/verse/accounts.d.ts +9 -1
- package/dist/core/verse/accounts.js +52 -11
- package/dist/core/verse/accounts.js.map +1 -1
- package/dist/core/verse/apps-api.d.ts +12 -0
- package/dist/core/verse/apps-api.js +22 -4
- package/dist/core/verse/apps-api.js.map +1 -1
- package/dist/core/verse/apps.js +22 -12
- package/dist/core/verse/apps.js.map +1 -1
- package/dist/core/verse/local-models.js +3 -7
- package/dist/core/verse/local-models.js.map +1 -1
- package/dist/core/verse/model-display-name.d.ts +34 -0
- package/dist/core/verse/model-display-name.js +125 -0
- package/dist/core/verse/model-display-name.js.map +1 -0
- package/dist/core/verse/seats.d.ts +11 -2
- package/dist/core/verse/seats.js +42 -18
- package/dist/core/verse/seats.js.map +1 -1
- package/dist/core/verse/transient-events.d.ts +21 -0
- package/dist/core/verse/transient-events.js +12 -0
- package/dist/core/verse/transient-events.js.map +1 -0
- package/dist/core/verse/types.d.ts +6 -13
- package/dist/core/verse/types.js +5 -36
- package/dist/core/verse/types.js.map +1 -1
- package/dist/core/web/public/next/assets/ActionMenu-B4-39f2S.js +2 -0
- package/dist/core/web/public/next/assets/{ActionMenu-FxXeRbPx.js.map → ActionMenu-B4-39f2S.js.map} +1 -1
- package/dist/core/web/public/next/assets/Advanced-B-LqYXvd.js +2 -0
- package/dist/core/web/public/next/assets/Advanced-B-LqYXvd.js.map +1 -0
- package/dist/core/web/public/next/assets/App-E2zCDRxm.js +7 -0
- package/dist/core/web/public/next/assets/App-E2zCDRxm.js.map +1 -0
- package/dist/core/web/public/next/assets/AppsSection-8wXPPhZb.js +2 -0
- package/dist/core/web/public/next/assets/AppsSection-8wXPPhZb.js.map +1 -0
- package/dist/core/web/public/next/assets/AreaTrend-BFimExYn.js +2 -0
- package/dist/core/web/public/next/assets/{AreaTrend-CDxrQU4b.js.map → AreaTrend-BFimExYn.js.map} +1 -1
- package/dist/core/web/public/next/assets/AutonomyOffState-B5eEkmiz.js +2 -0
- package/dist/core/web/public/next/assets/AutonomyOffState-B5eEkmiz.js.map +1 -0
- package/dist/core/web/public/next/assets/AutonomyOffState-DmbE71vI.css +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-B46igJKR.js +2 -0
- package/dist/core/web/public/next/assets/{AutonomySection-DuQkHGD_.js.map → AutonomySection-B46igJKR.js.map} +1 -1
- package/dist/core/web/public/next/assets/BranchBar-BRkrEQGs.js +2 -0
- package/dist/core/web/public/next/assets/{BranchBar-CLsvOcyK.js.map → BranchBar-BRkrEQGs.js.map} +1 -1
- package/dist/core/web/public/next/assets/BudgetControl-T_RjPrw9.js +2 -0
- package/dist/core/web/public/next/assets/{BudgetControl-TL3FeZ1D.js.map → BudgetControl-T_RjPrw9.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Button-HHXgoXGr.js → Button-BhO-WKPp.js} +2 -2
- package/dist/core/web/public/next/assets/{Button-HHXgoXGr.js.map → Button-BhO-WKPp.js.map} +1 -1
- package/dist/core/web/public/next/assets/CapacityStrip-CkFz5vq2.js +2 -0
- package/dist/core/web/public/next/assets/{CapacityStrip-qReu0RaF.js.map → CapacityStrip-CkFz5vq2.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useChartWidth-BW6SwYIK.css → ChartFrame-BVuBe6RP.css} +1 -1
- package/dist/core/web/public/next/assets/ChartFrame-SygZ7B3x.js +2 -0
- package/dist/core/web/public/next/assets/ChartFrame-SygZ7B3x.js.map +1 -0
- package/dist/core/web/public/next/assets/ChatSection-D6WybBpB.js +3 -0
- package/dist/core/web/public/next/assets/ChatSection-D6WybBpB.js.map +1 -0
- package/dist/core/web/public/next/assets/CloudBudgetForm-Bd91iStN.js +2 -0
- package/dist/core/web/public/next/assets/CloudBudgetForm-Bd91iStN.js.map +1 -0
- package/dist/core/web/public/next/assets/CommandPalette-B6SgDJH-.js +2 -0
- package/dist/core/web/public/next/assets/CommandPalette-B6SgDJH-.js.map +1 -0
- package/dist/core/web/public/next/assets/CommandSection-CvAVd1w4.css +1 -0
- package/dist/core/web/public/next/assets/CommandSection-DgMGoepd.js +2 -0
- package/dist/core/web/public/next/assets/CommandSection-DgMGoepd.js.map +1 -0
- package/dist/core/web/public/next/assets/ConfirmDialog-Bv4hdK2T.js +2 -0
- package/dist/core/web/public/next/assets/{ConfirmDialog-DLrLKM0c.js.map → ConfirmDialog-Bv4hdK2T.js.map} +1 -1
- package/dist/core/web/public/next/assets/DeleteChatDialog-CH1Ix8Eh.js +2 -0
- package/dist/core/web/public/next/assets/DeleteChatDialog-CH1Ix8Eh.js.map +1 -0
- package/dist/core/web/public/next/assets/Dialog-BSsIFNqD.js +2 -0
- package/dist/core/web/public/next/assets/{Dialog-BS9Dxi3G.js.map → Dialog-BSsIFNqD.js.map} +1 -1
- package/dist/core/web/public/next/assets/DiffPane-BpNuJmth.js +2 -0
- package/dist/core/web/public/next/assets/{DiffPane-TOmUf3b2.js.map → DiffPane-BpNuJmth.js.map} +1 -1
- package/dist/core/web/public/next/assets/DiffViewer-CJarUvs0.js +2 -0
- package/dist/core/web/public/next/assets/{DiffViewer-BpH56302.js.map → DiffViewer-CJarUvs0.js.map} +1 -1
- package/dist/core/web/public/next/assets/DockHost-DW9q0NdR.js +2 -0
- package/dist/core/web/public/next/assets/DockHost-DW9q0NdR.js.map +1 -0
- package/dist/core/web/public/next/assets/{EmptyState-BqR5YAmf.js → EmptyState-DPrd2aak.js} +2 -2
- package/dist/core/web/public/next/assets/{EmptyState-BqR5YAmf.js.map → EmptyState-DPrd2aak.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Epistemic-dhvDTwAZ.js → Epistemic-D7MxSmED.js} +2 -2
- package/dist/core/web/public/next/assets/{Epistemic-dhvDTwAZ.js.map → Epistemic-D7MxSmED.js.map} +1 -1
- package/dist/core/web/public/next/assets/FleetSection-BdZN6rGS.js +3 -0
- package/dist/core/web/public/next/assets/FleetSection-BdZN6rGS.js.map +1 -0
- package/dist/core/web/public/next/assets/Funnel-BeNQZWv2.js +2 -0
- package/dist/core/web/public/next/assets/{Funnel-D2u7Wlzc.js.map → Funnel-BeNQZWv2.js.map} +1 -1
- package/dist/core/web/public/next/assets/GearTray-CIPtzeIx.js +2 -0
- package/dist/core/web/public/next/assets/{GearTray-Cb2npoxM.js.map → GearTray-CIPtzeIx.js.map} +1 -1
- package/dist/core/web/public/next/assets/GrowthSection-iiQg6wvK.js +2 -0
- package/dist/core/web/public/next/assets/{GrowthSection-C5aDPs8B.js.map → GrowthSection-iiQg6wvK.js.map} +1 -1
- package/dist/core/web/public/next/assets/HandoffDialog-DrQ6ofuy.js +2 -0
- package/dist/core/web/public/next/assets/{HandoffDialog-BF3AYg-X.js.map → HandoffDialog-DrQ6ofuy.js.map} +1 -1
- package/dist/core/web/public/next/assets/Input-C0MQxEM6.js +2 -0
- package/dist/core/web/public/next/assets/{Input-B5dmGLZx.js.map → Input-C0MQxEM6.js.map} +1 -1
- package/dist/core/web/public/next/assets/LeaderCard-BRr3_yE-.js +2 -0
- package/dist/core/web/public/next/assets/LeaderCard-BRr3_yE-.js.map +1 -0
- package/dist/core/web/public/next/assets/MatrixHeatmap-DZvZeWXL.js +2 -0
- package/dist/core/web/public/next/assets/{MatrixHeatmap-BgEUs2Eu.js.map → MatrixHeatmap-DZvZeWXL.js.map} +1 -1
- package/dist/core/web/public/next/assets/McpSection-BRuCcTjT.js +2 -0
- package/dist/core/web/public/next/assets/{McpSection-DZkiOuoq.js.map → McpSection-BRuCcTjT.js.map} +1 -1
- package/dist/core/web/public/next/assets/MessageMarkdown-bRvD5nSc.js +3 -0
- package/dist/core/web/public/next/assets/{MessageMarkdown-BauY8ZTY.js.map → MessageMarkdown-bRvD5nSc.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DLBNLfsn.js → MessageMarkdownRenderer-FjjkPKA2.js} +4 -4
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DLBNLfsn.js.map → MessageMarkdownRenderer-FjjkPKA2.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Meter-DNeocJnD.js → Meter-CFNLpwA-.js} +2 -2
- package/dist/core/web/public/next/assets/{Meter-DNeocJnD.js.map → Meter-CFNLpwA-.js.map} +1 -1
- package/dist/core/web/public/next/assets/MindSection-BTIiQS8P.js +2 -0
- package/dist/core/web/public/next/assets/MindSection-BTIiQS8P.js.map +1 -0
- package/dist/core/web/public/next/assets/MutationTokenDialog-T7gv3a9r.js +2 -0
- package/dist/core/web/public/next/assets/{MutationTokenDialog-mxrw0Yvy.js.map → MutationTokenDialog-T7gv3a9r.js.map} +1 -1
- package/dist/core/web/public/next/assets/NeedsYouDrawer-lYN4G_aM.js +2 -0
- package/dist/core/web/public/next/assets/{NeedsYouDrawer-CO-Balfp.js.map → NeedsYouDrawer-lYN4G_aM.js.map} +1 -1
- package/dist/core/web/public/next/assets/NeedsYouList-BgH8ezqf.js +2 -0
- package/dist/core/web/public/next/assets/{NeedsYouList-CzDZbzRD.js.map → NeedsYouList-BgH8ezqf.js.map} +1 -1
- package/dist/core/web/public/next/assets/NewChatDialog-Db5Xjrk8.js +3 -0
- package/dist/core/web/public/next/assets/NewChatDialog-Db5Xjrk8.js.map +1 -0
- package/dist/core/web/public/next/assets/OnboardingFlow-HUNQGQuU.css +1 -0
- package/dist/core/web/public/next/assets/OnboardingFlow-LoY-zuSe.js +2 -0
- package/dist/core/web/public/next/assets/OnboardingFlow-LoY-zuSe.js.map +1 -0
- package/dist/core/web/public/next/assets/OnboardingGate-C4VXn7BJ.js +3 -0
- package/dist/core/web/public/next/assets/OnboardingGate-C4VXn7BJ.js.map +1 -0
- package/dist/core/web/public/next/assets/PreviewPane-BPBbcROb.js +2 -0
- package/dist/core/web/public/next/assets/{PreviewPane-BS-CleCd.js.map → PreviewPane-BPBbcROb.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ProviderLogo-C5mBg8i0.js → ProviderLogo-CT2cSfkg.js} +2 -2
- package/dist/core/web/public/next/assets/{ProviderLogo-C5mBg8i0.js.map → ProviderLogo-CT2cSfkg.js.map} +1 -1
- package/dist/core/web/public/next/assets/RailStatus-Vgl0GYtd.js +2 -0
- package/dist/core/web/public/next/assets/{RailStatus-cPRyOmrk.js.map → RailStatus-Vgl0GYtd.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RefreshIndicator-CMwSCiz5.js → RefreshIndicator-CSyqpY_q.js} +2 -2
- package/dist/core/web/public/next/assets/{RefreshIndicator-CMwSCiz5.js.map → RefreshIndicator-CSyqpY_q.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BFi1opsC.js → ResourcePoolConsoleApp-BX2nkdmZ.js} +4 -4
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BFi1opsC.js.map → ResourcePoolConsoleApp-BX2nkdmZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/ResourcesChrome-B2U2lO1H.js +3 -0
- package/dist/core/web/public/next/assets/ResourcesChrome-B2U2lO1H.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-BCFJ2Uq8.css +1 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-DlUKOjl9.js +2 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-DlUKOjl9.js.map +1 -0
- package/dist/core/web/public/next/assets/RouteErrorBoundary-BaC7YVzR.js +2 -0
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-DYtwc2ja.js.map → RouteErrorBoundary-BaC7YVzR.js.map} +1 -1
- package/dist/core/web/public/next/assets/RunInCloudAction-D5PDHJPE.js +2 -0
- package/dist/core/web/public/next/assets/{RunInCloudAction-BEGEEM8O.js.map → RunInCloudAction-D5PDHJPE.js.map} +1 -1
- package/dist/core/web/public/next/assets/SeatSelector-Cg75LInq.js +3 -0
- package/dist/core/web/public/next/assets/{SeatSelector-CYHRR7Wp.js.map → SeatSelector-Cg75LInq.js.map} +1 -1
- package/dist/core/web/public/next/assets/Segmented-CametjLt.js +2 -0
- package/dist/core/web/public/next/assets/{Segmented-BE53BenI.js.map → Segmented-CametjLt.js.map} +1 -1
- package/dist/core/web/public/next/assets/Select-De52fghU.js +2 -0
- package/dist/core/web/public/next/assets/{Select-BwSGkHCS.js.map → Select-De52fghU.js.map} +1 -1
- package/dist/core/web/public/next/assets/SessionGate-CzlcNq3O.js +2 -0
- package/dist/core/web/public/next/assets/{SessionGate-e0dFJm9d.js.map → SessionGate-CzlcNq3O.js.map} +1 -1
- package/dist/core/web/public/next/assets/SessionInsightChip-Bk_Owa7u.js +2 -0
- package/dist/core/web/public/next/assets/{SessionInsightChip-CxlSyueJ.js.map → SessionInsightChip-Bk_Owa7u.js.map} +1 -1
- package/dist/core/web/public/next/assets/SessionSearch-C6C8DHN8.js +2 -0
- package/dist/core/web/public/next/assets/{SessionSearch-_yp7S2TP.js.map → SessionSearch-C6C8DHN8.js.map} +1 -1
- package/dist/core/web/public/next/assets/SettingsSection-mI9wQYZg.js +2 -0
- package/dist/core/web/public/next/assets/SettingsSection-mI9wQYZg.js.map +1 -0
- package/dist/core/web/public/next/assets/Sheet-CJhK9Dqv.js +2 -0
- package/dist/core/web/public/next/assets/{Sheet-DVP2Mgy6.js.map → Sheet-CJhK9Dqv.js.map} +1 -1
- package/dist/core/web/public/next/assets/ShortcutsOverlay-DDW-i9Fc.js +2 -0
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-BcIcoClX.js.map → ShortcutsOverlay-DDW-i9Fc.js.map} +1 -1
- package/dist/core/web/public/next/assets/Sidebar-DT7ykaqS.js +3 -0
- package/dist/core/web/public/next/assets/Sidebar-DT7ykaqS.js.map +1 -0
- package/dist/core/web/public/next/assets/Slider-Bwd9HfXl.js +2 -0
- package/dist/core/web/public/next/assets/{Slider-BypUWjpH.js.map → Slider-Bwd9HfXl.js.map} +1 -1
- package/dist/core/web/public/next/assets/StatTile-DPZ5yyaU.js +2 -0
- package/dist/core/web/public/next/assets/StatTile-DPZ5yyaU.js.map +1 -0
- package/dist/core/web/public/next/assets/{StatusBadge-HCZp416_.js → StatusBadge-DHKRtttH.js} +2 -2
- package/dist/core/web/public/next/assets/{StatusBadge-HCZp416_.js.map → StatusBadge-DHKRtttH.js.map} +1 -1
- package/dist/core/web/public/next/assets/StepBand-DQykLkk_.js +2 -0
- package/dist/core/web/public/next/assets/{StepBand-Duz1PUes.js.map → StepBand-DQykLkk_.js.map} +1 -1
- package/dist/core/web/public/next/assets/Surface-D--LXgQm.js +2 -0
- package/dist/core/web/public/next/assets/Surface-D--LXgQm.js.map +1 -0
- package/dist/core/web/public/next/assets/Surface-e1z6GdZt.css +1 -0
- package/dist/core/web/public/next/assets/Swimlane-BzH6OCee.js +2 -0
- package/dist/core/web/public/next/assets/{Swimlane-DGcIcnNA.js.map → Swimlane-BzH6OCee.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Switch-iveI-8NY.js → Switch-PMixU6b0.js} +2 -2
- package/dist/core/web/public/next/assets/{Switch-iveI-8NY.js.map → Switch-PMixU6b0.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Tag-DH15CUJp.js → Tag-fordBsrJ.js} +2 -2
- package/dist/core/web/public/next/assets/{Tag-DH15CUJp.js.map → Tag-fordBsrJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/TerminalPane-BSnGdUuF.js +7 -0
- package/dist/core/web/public/next/assets/TerminalPane-BSnGdUuF.js.map +1 -0
- package/dist/core/web/public/next/assets/UniverseConsoleApp-DtXFhAhw.js +2 -0
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-C8yQ0AaR.js.map → UniverseConsoleApp-DtXFhAhw.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseView-_nPURPqe.js → UniverseView-sWm3pnTW.js} +3 -3
- package/dist/core/web/public/next/assets/{UniverseView-_nPURPqe.js.map → UniverseView-sWm3pnTW.js.map} +1 -1
- package/dist/core/web/public/next/assets/UsageSection-CiD1DbuF.js +3 -0
- package/dist/core/web/public/next/assets/UsageSection-CiD1DbuF.js.map +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-BCY5uSok.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-BCY5uSok.js.map +1 -0
- package/dist/core/web/public/next/assets/Workspace-BQSZFSeO.js +10 -0
- package/dist/core/web/public/next/assets/Workspace-BQSZFSeO.js.map +1 -0
- package/dist/core/web/public/next/assets/actions-BmIf9avl.css +1 -0
- package/dist/core/web/public/next/assets/actions-Ci6I4C0l.js +2 -0
- package/dist/core/web/public/next/assets/actions-Ci6I4C0l.js.map +1 -0
- package/dist/core/web/public/next/assets/apps-model-DlwnfqwJ.js +2 -0
- package/dist/core/web/public/next/assets/apps-model-DlwnfqwJ.js.map +1 -0
- package/dist/core/web/public/next/assets/authority-model-BFuPezSo.js +2 -0
- package/dist/core/web/public/next/assets/authority-model-BFuPezSo.js.map +1 -0
- package/dist/core/web/public/next/assets/binding-left-DZpq5sLf.js +2 -0
- package/dist/core/web/public/next/assets/binding-left-DZpq5sLf.js.map +1 -0
- package/dist/core/web/public/next/assets/{budget-queries-V3wcJVK_.js → budget-queries-DsAjH8ac.js} +2 -2
- package/dist/core/web/public/next/assets/{budget-queries-V3wcJVK_.js.map → budget-queries-DsAjH8ac.js.map} +1 -1
- package/dist/core/web/public/next/assets/capacity-strip-model-Dn1cNOhz.js +2 -0
- package/dist/core/web/public/next/assets/capacity-strip-model-Dn1cNOhz.js.map +1 -0
- package/dist/core/web/public/next/assets/charts-C_xJbJiw.js +2 -0
- package/dist/core/web/public/next/assets/charts-C_xJbJiw.js.map +1 -0
- package/dist/core/web/public/next/assets/charts-DhKTrQLw.css +1 -0
- package/dist/core/web/public/next/assets/clipboard-DkZdqlxf.js +2 -0
- package/dist/core/web/public/next/assets/clipboard-DkZdqlxf.js.map +1 -0
- package/dist/core/web/public/next/assets/cloud-D-HXms6q.css +1 -0
- package/dist/core/web/public/next/assets/cloud-model-CX407gPY.js +2 -0
- package/dist/core/web/public/next/assets/cloud-model-CX407gPY.js.map +1 -0
- package/dist/core/web/public/next/assets/cloud-queries-QAhpExlz.js +2 -0
- package/dist/core/web/public/next/assets/cloud-queries-QAhpExlz.js.map +1 -0
- package/dist/core/web/public/next/assets/cloud.module-DOP-N4Ch.js +2 -0
- package/dist/core/web/public/next/assets/cloud.module-DOP-N4Ch.js.map +1 -0
- package/dist/core/web/public/next/assets/command-catalog-CF0cQQac.js +2 -0
- package/dist/core/web/public/next/assets/command-catalog-CF0cQQac.js.map +1 -0
- package/dist/core/web/public/next/assets/context-model-Co4wh3SM.js +2 -0
- package/dist/core/web/public/next/assets/context-model-Co4wh3SM.js.map +1 -0
- package/dist/core/web/public/next/assets/context-model-DV1zCfAm.js +3 -0
- package/dist/core/web/public/next/assets/context-model-DV1zCfAm.js.map +1 -0
- package/dist/core/web/public/next/assets/{context-queries-CrPcHWTz.js → context-queries-CktFQqSS.js} +2 -2
- package/dist/core/web/public/next/assets/{context-queries-CrPcHWTz.js.map → context-queries-CktFQqSS.js.map} +1 -1
- package/dist/core/web/public/next/assets/{control-queries-CmgBgKV7.js → control-queries-DAvlh_YM.js} +2 -2
- package/dist/core/web/public/next/assets/{control-queries-CmgBgKV7.js.map → control-queries-DAvlh_YM.js.map} +1 -1
- package/dist/core/web/public/next/assets/copy-setup-CqRSfELB.js +2 -0
- package/dist/core/web/public/next/assets/copy-setup-CqRSfELB.js.map +1 -0
- package/dist/core/web/public/next/assets/dock-icons-BFuBbqJl.js +2 -0
- package/dist/core/web/public/next/assets/{dock-icons-CUh8dOxJ.js.map → dock-icons-BFuBbqJl.js.map} +1 -1
- package/dist/core/web/public/next/assets/fleet-model-Dfd5JyLR.js +2 -0
- package/dist/core/web/public/next/assets/fleet-model-Dfd5JyLR.js.map +1 -0
- package/dist/core/web/public/next/assets/fleet-queries-RtMTd5rR.js +2 -0
- package/dist/core/web/public/next/assets/fleet-queries-RtMTd5rR.js.map +1 -0
- package/dist/core/web/public/next/assets/{focus-trap-HtcoXeEq.js → focus-trap-BdrbWfC4.js} +2 -2
- package/dist/core/web/public/next/assets/{focus-trap-HtcoXeEq.js.map → focus-trap-BdrbWfC4.js.map} +1 -1
- package/dist/core/web/public/next/assets/format-Dk4Fmxax.js +2 -0
- package/dist/core/web/public/next/assets/format-Dk4Fmxax.js.map +1 -0
- package/dist/core/web/public/next/assets/{git-model-bk_RXh3y.js → git-model-_BnI_Ogh.js} +2 -2
- package/dist/core/web/public/next/assets/{git-model-bk_RXh3y.js.map → git-model-_BnI_Ogh.js.map} +1 -1
- package/dist/core/web/public/next/assets/global-CNNGMril.js +2 -0
- package/dist/core/web/public/next/assets/{global-oEl9Qj8u.js.map → global-CNNGMril.js.map} +1 -1
- package/dist/core/web/public/next/assets/{guarded-runners-LHLXmXIk.js → guarded-runners-DPh2d32e.js} +2 -2
- package/dist/core/web/public/next/assets/{guarded-runners-LHLXmXIk.js.map → guarded-runners-DPh2d32e.js.map} +1 -1
- package/dist/core/web/public/next/assets/icons-0haWy6nh.js +2 -0
- package/dist/core/web/public/next/assets/icons-0haWy6nh.js.map +1 -0
- package/dist/core/web/public/next/assets/{index-BVxOlseC.js → index-QesfXBsb.js} +3 -3
- package/dist/core/web/public/next/assets/{index-BVxOlseC.js.map → index-QesfXBsb.js.map} +1 -1
- package/dist/core/web/public/next/assets/live-model-De-q0ZFK.js +2 -0
- package/dist/core/web/public/next/assets/live-model-De-q0ZFK.js.map +1 -0
- package/dist/core/web/public/next/assets/local-model-C9xNi9fN.js +2 -0
- package/dist/core/web/public/next/assets/local-model-C9xNi9fN.js.map +1 -0
- package/dist/core/web/public/next/assets/mind.module-BrK2nFOL.js +2 -0
- package/dist/core/web/public/next/assets/{mind.module-gTGAuJt1.js.map → mind.module-BrK2nFOL.js.map} +1 -1
- package/dist/core/web/public/next/assets/mutations-DTCtKCn_.js +2 -0
- package/dist/core/web/public/next/assets/{mutations-C5S7okTW.js.map → mutations-DTCtKCn_.js.map} +1 -1
- package/dist/core/web/public/next/assets/nav-KmGX0CVz.js +2 -0
- package/dist/core/web/public/next/assets/{nav-NVtnuG7A.js.map → nav-KmGX0CVz.js.map} +1 -1
- package/dist/core/web/public/next/assets/{overnight-queries-DGm3qL1b.js → overnight-queries-mlO0xzsr.js} +2 -2
- package/dist/core/web/public/next/assets/{overnight-queries-DGm3qL1b.js.map → overnight-queries-mlO0xzsr.js.map} +1 -1
- package/dist/core/web/public/next/assets/primitives-D0Fb3TtS.js +1 -0
- package/dist/core/web/public/next/assets/{queries-CYisSAAB.js → queries-CyBE8nsW.js} +2 -2
- package/dist/core/web/public/next/assets/{queries-CYisSAAB.js.map → queries-CyBE8nsW.js.map} +1 -1
- package/dist/core/web/public/next/assets/reasoning-pref-CaoA4_Vl.js +2 -0
- package/dist/core/web/public/next/assets/{reasoning-pref-BUcFF_5G.js.map → reasoning-pref-CaoA4_Vl.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reveal-anchor-D-tV8xau.js → reveal-anchor-BP1VqnPU.js} +2 -2
- package/dist/core/web/public/next/assets/{reveal-anchor-D-tV8xau.js.map → reveal-anchor-BP1VqnPU.js.map} +1 -1
- package/dist/core/web/public/next/assets/seat-subscription-C5Tvr0WQ.js +2 -0
- package/dist/core/web/public/next/assets/{seat-subscription-B-f9ViU2.js.map → seat-subscription-C5Tvr0WQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{sidebar-model-DQ-FyBHW.js → sidebar-model-B5Qk95k_.js} +2 -2
- package/dist/core/web/public/next/assets/{sidebar-model-DQ-FyBHW.js.map → sidebar-model-B5Qk95k_.js.map} +1 -1
- package/dist/core/web/public/next/assets/slots-DHKQDoE6.js +3 -0
- package/dist/core/web/public/next/assets/{slots-BhP8b8tf.js.map → slots-DHKQDoE6.js.map} +1 -1
- package/dist/core/web/public/next/assets/surface-data-CchClvHo.js +2 -0
- package/dist/core/web/public/next/assets/surface-data-CchClvHo.js.map +1 -0
- package/dist/core/web/public/next/assets/surface-prefetch-BWr0LBQn.js +2 -0
- package/dist/core/web/public/next/assets/surface-prefetch-BWr0LBQn.js.map +1 -0
- package/dist/core/web/public/next/assets/{tasks-model-BKDNqmmt.js → tasks-model-D6WFVULI.js} +2 -2
- package/dist/core/web/public/next/assets/{tasks-model-BKDNqmmt.js.map → tasks-model-D6WFVULI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{terminal-icons-D2xe-aM1.js → terminal-icons-BvCvuXk2.js} +2 -2
- package/dist/core/web/public/next/assets/{terminal-icons-D2xe-aM1.js.map → terminal-icons-BvCvuXk2.js.map} +1 -1
- package/dist/core/web/public/next/assets/transient-events-nTLhMBND.js +2 -0
- package/dist/core/web/public/next/assets/transient-events-nTLhMBND.js.map +1 -0
- package/dist/core/web/public/next/assets/types-D5XOdyw8.js.map +1 -1
- package/dist/core/web/public/next/assets/{usage-queries-BZuAANlI.js → usage-queries-D1SU1t7r.js} +2 -2
- package/dist/core/web/public/next/assets/{usage-queries-BZuAANlI.js.map → usage-queries-D1SU1t7r.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-guarded-action-Cf4MeNBa.js → use-guarded-action-BZmBv7CJ.js} +2 -2
- package/dist/core/web/public/next/assets/{use-guarded-action-Cf4MeNBa.js.map → use-guarded-action-BZmBv7CJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-ticker-D9yi49my.js → use-ticker-CkJ4-0wU.js} +2 -2
- package/dist/core/web/public/next/assets/{use-ticker-D9yi49my.js.map → use-ticker-CkJ4-0wU.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-token-gate-DqrSXdX6.js → use-token-gate-CYcfk_GS.js} +2 -2
- package/dist/core/web/public/next/assets/{use-token-gate-DqrSXdX6.js.map → use-token-gate-CYcfk_GS.js.map} +1 -1
- package/dist/core/web/public/next/assets/useOnboarding-CujRS6PK.js +2 -0
- package/dist/core/web/public/next/assets/useOnboarding-CujRS6PK.js.map +1 -0
- package/dist/core/web/public/next/assets/useSeatsRefresh-BEaQdkZs.js +2 -0
- package/dist/core/web/public/next/assets/useSeatsRefresh-BEaQdkZs.js.map +1 -0
- package/dist/core/web/public/next/assets/useVerseTranscript-BQ0J6Xhx.js +2 -0
- package/dist/core/web/public/next/assets/{useVerseTranscript-CDYrrWOO.js.map → useVerseTranscript-BQ0J6Xhx.js.map} +1 -1
- package/dist/core/web/public/next/assets/verse-icons-DndgEgKS.js +2 -0
- package/dist/core/web/public/next/assets/verse-icons-DndgEgKS.js.map +1 -0
- package/dist/core/web/public/next/assets/verse-model-MMySehjj.js +2 -0
- package/dist/core/web/public/next/assets/verse-model-MMySehjj.js.map +1 -0
- package/dist/core/web/public/next/assets/verse-store-DNVRuiJL.js +2 -0
- package/dist/core/web/public/next/assets/verse-store-DNVRuiJL.js.map +1 -0
- package/dist/core/web/public/next/assets/warmup-CNEH_-be.js +3 -0
- package/dist/core/web/public/next/assets/{warmup-HG5vYbsN.js.map → warmup-CNEH_-be.js.map} +1 -1
- package/dist/core/web/public/next/assets/why-seat-model-jlDTwYSc.js +2 -0
- package/dist/core/web/public/next/assets/why-seat-model-jlDTwYSc.js.map +1 -0
- package/dist/core/web/public/next/assets/{workspace-model-CbhdPhei.js → workspace-model-Dukb2wwv.js} +2 -2
- package/dist/core/web/public/next/assets/{workspace-model-CbhdPhei.js.map → workspace-model-Dukb2wwv.js.map} +1 -1
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/docs/README.md +2 -1
- package/package.json +1 -1
- package/dist/core/web/public/next/assets/ActionMenu-FxXeRbPx.js +0 -2
- package/dist/core/web/public/next/assets/Advanced-D_eS4472.js +0 -2
- package/dist/core/web/public/next/assets/Advanced-D_eS4472.js.map +0 -1
- package/dist/core/web/public/next/assets/App-Cj4zKbG3.js +0 -7
- package/dist/core/web/public/next/assets/App-Cj4zKbG3.js.map +0 -1
- package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js +0 -2
- package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js.map +0 -1
- package/dist/core/web/public/next/assets/AreaTrend-CDxrQU4b.js +0 -2
- package/dist/core/web/public/next/assets/AutonomySection-DuQkHGD_.js +0 -2
- package/dist/core/web/public/next/assets/BranchBar-CLsvOcyK.js +0 -2
- package/dist/core/web/public/next/assets/BudgetControl-TL3FeZ1D.js +0 -2
- package/dist/core/web/public/next/assets/BurnDown-sFXkUGdB.js +0 -2
- package/dist/core/web/public/next/assets/BurnDown-sFXkUGdB.js.map +0 -1
- package/dist/core/web/public/next/assets/CapacityStrip-qReu0RaF.js +0 -2
- package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js +0 -3
- package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js.map +0 -1
- package/dist/core/web/public/next/assets/CloudBudgetForm-DJbiT1wi.js +0 -2
- package/dist/core/web/public/next/assets/CloudBudgetForm-DJbiT1wi.js.map +0 -1
- package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js +0 -2
- package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js.map +0 -1
- package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js +0 -2
- package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js.map +0 -1
- package/dist/core/web/public/next/assets/ConfirmDialog-DLrLKM0c.js +0 -2
- package/dist/core/web/public/next/assets/Dialog-BS9Dxi3G.js +0 -2
- package/dist/core/web/public/next/assets/DiffPane-TOmUf3b2.js +0 -2
- package/dist/core/web/public/next/assets/DiffViewer-BpH56302.js +0 -2
- package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js +0 -2
- package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js.map +0 -1
- package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js +0 -3
- package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js.map +0 -1
- package/dist/core/web/public/next/assets/Funnel-D2u7Wlzc.js +0 -2
- package/dist/core/web/public/next/assets/GearTray-Cb2npoxM.js +0 -2
- package/dist/core/web/public/next/assets/GrowthSection-C5aDPs8B.js +0 -2
- package/dist/core/web/public/next/assets/HandoffDialog-BF3AYg-X.js +0 -2
- package/dist/core/web/public/next/assets/Input-B5dmGLZx.js +0 -2
- package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js +0 -2
- package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js.map +0 -1
- package/dist/core/web/public/next/assets/MatrixHeatmap-BgEUs2Eu.js +0 -2
- package/dist/core/web/public/next/assets/McpSection-DZkiOuoq.js +0 -2
- package/dist/core/web/public/next/assets/MessageMarkdown-BauY8ZTY.js +0 -3
- package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js +0 -2
- package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js.map +0 -1
- package/dist/core/web/public/next/assets/MutationTokenDialog-mxrw0Yvy.js +0 -2
- package/dist/core/web/public/next/assets/NeedsYouDrawer-CO-Balfp.js +0 -2
- package/dist/core/web/public/next/assets/NeedsYouList-CzDZbzRD.js +0 -2
- package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js +0 -3
- package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js.map +0 -1
- package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js +0 -2
- package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js.map +0 -1
- package/dist/core/web/public/next/assets/OnboardingFlow-DSpPj8UE.css +0 -1
- package/dist/core/web/public/next/assets/PreviewPane-BS-CleCd.js +0 -2
- package/dist/core/web/public/next/assets/RailStatus-cPRyOmrk.js +0 -2
- package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js +0 -3
- package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js +0 -2
- package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcesDrawer-CSKIO_wZ.css +0 -1
- package/dist/core/web/public/next/assets/RouteErrorBoundary-DYtwc2ja.js +0 -2
- package/dist/core/web/public/next/assets/RunInCloudAction-BEGEEM8O.js +0 -2
- package/dist/core/web/public/next/assets/SeatSelector-CYHRR7Wp.js +0 -3
- package/dist/core/web/public/next/assets/Segmented-BE53BenI.js +0 -2
- package/dist/core/web/public/next/assets/Select-BwSGkHCS.js +0 -2
- package/dist/core/web/public/next/assets/SessionGate-e0dFJm9d.js +0 -2
- package/dist/core/web/public/next/assets/SessionInsightChip-CxlSyueJ.js +0 -2
- package/dist/core/web/public/next/assets/SessionSearch-_yp7S2TP.js +0 -2
- package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js +0 -2
- package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js.map +0 -1
- package/dist/core/web/public/next/assets/Sheet-DVP2Mgy6.js +0 -2
- package/dist/core/web/public/next/assets/ShortcutsOverlay-BcIcoClX.js +0 -2
- package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js +0 -3
- package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js.map +0 -1
- package/dist/core/web/public/next/assets/Slider-BypUWjpH.js +0 -2
- package/dist/core/web/public/next/assets/StepBand-Duz1PUes.js +0 -2
- package/dist/core/web/public/next/assets/Surface-B75lVfzm.js +0 -2
- package/dist/core/web/public/next/assets/Surface-B75lVfzm.js.map +0 -1
- package/dist/core/web/public/next/assets/Surface-DMca0gAe.css +0 -1
- package/dist/core/web/public/next/assets/Swimlane-DGcIcnNA.js +0 -2
- package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js +0 -7
- package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js.map +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-C8yQ0AaR.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js.map +0 -1
- package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js +0 -10
- package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js.map +0 -1
- package/dist/core/web/public/next/assets/actions-Ddfg2iLl.css +0 -1
- package/dist/core/web/public/next/assets/actions-tWevL9HV.js +0 -2
- package/dist/core/web/public/next/assets/actions-tWevL9HV.js.map +0 -1
- package/dist/core/web/public/next/assets/apps-model-CDFvmsQV.js +0 -2
- package/dist/core/web/public/next/assets/apps-model-CDFvmsQV.js.map +0 -1
- package/dist/core/web/public/next/assets/capacity-strip-model-BDbmQ3e3.js +0 -2
- package/dist/core/web/public/next/assets/capacity-strip-model-BDbmQ3e3.js.map +0 -1
- package/dist/core/web/public/next/assets/charts-CfAjuKMv.js +0 -2
- package/dist/core/web/public/next/assets/charts-CfAjuKMv.js.map +0 -1
- package/dist/core/web/public/next/assets/charts-uSX6xVYN.css +0 -1
- package/dist/core/web/public/next/assets/cloud-C1KPNRHC.css +0 -1
- package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js +0 -2
- package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js.map +0 -1
- package/dist/core/web/public/next/assets/cloud.module-ascz58c3.js +0 -2
- package/dist/core/web/public/next/assets/cloud.module-ascz58c3.js.map +0 -1
- package/dist/core/web/public/next/assets/command-bus-xYZoK9nQ.js +0 -2
- package/dist/core/web/public/next/assets/command-bus-xYZoK9nQ.js.map +0 -1
- package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js +0 -2
- package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js.map +0 -1
- package/dist/core/web/public/next/assets/composer-keys-su0g1h9o.js +0 -2
- package/dist/core/web/public/next/assets/composer-keys-su0g1h9o.js.map +0 -1
- package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js +0 -2
- package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js.map +0 -1
- package/dist/core/web/public/next/assets/context-model-CIBmSugV.js +0 -2
- package/dist/core/web/public/next/assets/context-model-CIBmSugV.js.map +0 -1
- package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js +0 -2
- package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js.map +0 -1
- package/dist/core/web/public/next/assets/dock-icons-CUh8dOxJ.js +0 -2
- package/dist/core/web/public/next/assets/dock-store-B2vlxqPu.js +0 -2
- package/dist/core/web/public/next/assets/dock-store-B2vlxqPu.js.map +0 -1
- package/dist/core/web/public/next/assets/fleet-model-7i-FbzKI.js +0 -2
- package/dist/core/web/public/next/assets/fleet-model-7i-FbzKI.js.map +0 -1
- package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js +0 -2
- package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js.map +0 -1
- package/dist/core/web/public/next/assets/format-BkWdOQDL.js +0 -2
- package/dist/core/web/public/next/assets/format-BkWdOQDL.js.map +0 -1
- package/dist/core/web/public/next/assets/global-oEl9Qj8u.js +0 -2
- package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js +0 -3
- package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js.map +0 -1
- package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js +0 -2
- package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js.map +0 -1
- package/dist/core/web/public/next/assets/icons-DEQa2rTx.js +0 -2
- package/dist/core/web/public/next/assets/icons-DEQa2rTx.js.map +0 -1
- package/dist/core/web/public/next/assets/live-model-bmsJgnYD.js +0 -2
- package/dist/core/web/public/next/assets/live-model-bmsJgnYD.js.map +0 -1
- package/dist/core/web/public/next/assets/local-model-DFyjKX0b.js +0 -2
- package/dist/core/web/public/next/assets/local-model-DFyjKX0b.js.map +0 -1
- package/dist/core/web/public/next/assets/mind.module-gTGAuJt1.js +0 -2
- package/dist/core/web/public/next/assets/mutations-C5S7okTW.js +0 -2
- package/dist/core/web/public/next/assets/nav-NVtnuG7A.js +0 -2
- package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js +0 -2
- package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js.map +0 -1
- package/dist/core/web/public/next/assets/primitives-DyCKYSBG.js +0 -1
- package/dist/core/web/public/next/assets/reasoning-pref-BUcFF_5G.js +0 -2
- package/dist/core/web/public/next/assets/seat-subscription-B-f9ViU2.js +0 -2
- package/dist/core/web/public/next/assets/section-visibility-Yctxu-if.js +0 -2
- package/dist/core/web/public/next/assets/section-visibility-Yctxu-if.js.map +0 -1
- package/dist/core/web/public/next/assets/slots-BhP8b8tf.js +0 -3
- package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js +0 -2
- package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js.map +0 -1
- package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js +0 -2
- package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js.map +0 -1
- package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js +0 -2
- package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js.map +0 -1
- package/dist/core/web/public/next/assets/useSeatsRefresh-DgFy-Ph4.js +0 -2
- package/dist/core/web/public/next/assets/useSeatsRefresh-DgFy-Ph4.js.map +0 -1
- package/dist/core/web/public/next/assets/useVerseTranscript-CDYrrWOO.js +0 -2
- package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js +0 -2
- package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js +0 -2
- package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js +0 -3
- package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js +0 -3
- package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js.map +0 -1
- package/dist/core/web/public/next/assets/viewport-nTubFCwf.js +0 -2
- package/dist/core/web/public/next/assets/viewport-nTubFCwf.js.map +0 -1
- package/dist/core/web/public/next/assets/warmup-HG5vYbsN.js +0 -3
- package/dist/core/web/public/next/assets/workbench-types-DzN-5trg.js +0 -2
- package/dist/core/web/public/next/assets/workbench-types-DzN-5trg.js.map +0 -1
- /package/dist/core/web/public/next/assets/{BurnDown-BuLMsJMx.css → StatTile-BuLMsJMx.css} +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"capacity-strip-model-Dn1cNOhz.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/health/health-queries.ts","../../../../../../src/core/routing/policy.ts","../../../../../../src/web-ui/routes/verse/budget/budget-model.ts","../../../../../../src/web-ui/routes/verse/usage/capacity-model.ts","../../../../../../src/web-ui/routes/verse/health/health-model.ts","../../../../../../src/web-ui/routes/verse/usage/capacity-strip-model.ts"],"sourcesContent":["/**\n * routes/verse/health/health-queries.ts — the `/api/verse/health*` calls\n * (V3.10, unit A2). Server: core/verse/health-api.ts.\n *\n * Nothing here ever carries a launcher, a profile path or a credential: the\n * server withholds them, and Reconnect sends only the seat id — the server\n * resolves the seat's own login command privately and opens it in Terminal.\n */\nimport type { VerseHealthResponse } from '../../../../core/verse/health-types.js';\nimport { getMutationToken, touchMutationHold } from '../../../data/auth-store.js';\nimport { refetchQuery } from '../../../data/cache.js';\nimport { apiGet, apiPost } from '../../../data/client.js';\nimport type { QueryDef } from '../../../data/queries.js';\nimport { VerseMutationLockedError } from '../verse-queries.js';\n\nexport const VERSE_HEALTH_KEY = 'verse-health';\nexport const VERSE_HEALTH_URL = '/api/verse/health';\n\nexport const verseHealthQuery: QueryDef<VerseHealthResponse> = {\n key: VERSE_HEALTH_KEY,\n fetch: (signal) => apiGet<VerseHealthResponse>(VERSE_HEALTH_URL, signal),\n};\n\n/**\n * A fetcher that answers ONCE with `first`, then behaves like `fallback`.\n *\n * The cache (data/cache.ts) remembers the last fetcher it ran for a key and\n * re-runs it on every later invalidation. Writing a value we already hold\n * through a constant fetcher would freeze the key on that value forever;\n * this hands the cache the value now and the real read afterwards.\n */\nexport function oneShotFetcher<T>(first: () => Promise<T>, fallback: () => Promise<T>): () => Promise<T> {\n let used = false;\n return () => {\n if (used) return fallback();\n used = true;\n return first();\n };\n}\n\nasync function post<T>(path: string, body: unknown): Promise<T> {\n const token = getMutationToken();\n if (!token) throw new VerseMutationLockedError();\n const result = await apiPost<T>(path, body, token);\n touchMutationHold();\n return result;\n}\n\n/** Run a health sweep now and publish its result to every health reader. */\nexport async function refreshSeatHealth(): Promise<VerseHealthResponse> {\n const body = await post<VerseHealthResponse>(`${VERSE_HEALTH_URL}/refresh`, {});\n await refetchQuery(VERSE_HEALTH_KEY, oneShotFetcher(() => Promise.resolve(body), () => verseHealthQuery.fetch()), true);\n return body;\n}\n\n/**\n * Open the seat's own sign-in in Terminal (macOS). Resolves once the window\n * was asked to open; the sign-in itself is the operator's, in that window.\n */\nexport async function reconnectSeat(seatId: string): Promise<void> {\n await post<{ ok: true; seatId: string }>(`${VERSE_HEALTH_URL}/reconnect`, { seatId });\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 — except that an\n * ISO instant inside it (\"resets 2026-09-26T03:46:56.000Z\") is shown in\n * local time, and \".;\" joins read as \";\" (autonomy/format `tidyProse`).\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';\nimport { percentText, tidyProse } from '../autonomy/format.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 (instants in local time). */\n why: string;\n /** Remaining server reasons, verbatim (instants in local time). */\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 ${percentText(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 ${percentText(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, nowMs: number = Date.now()): 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 ?? []).map((r) => tidyProse(r, nowMs).trim()).filter((r) => r.length > 0);\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/usage/capacity-model.ts — \"what can I run right now\", in one\n * pure projection.\n *\n * The Usage section already answers this per seat, one card at a time. This\n * module answers it for the WHOLE ROSTER in one line, because the operator's\n * first question on opening the view is not \"how is Codex A doing\" — it is\n * \"do I have anything to run, and if not, when does that change\".\n *\n * Four rules, each one a place where the obvious summary would lie:\n *\n * 1. A COUNT IS NOT A CAPACITY. \"3 of 5 seats usable\" is only true if the\n * other two were actually read. Seats with no reading are counted in their\n * own bucket and named in the sentence, never folded into \"blocked\" — an\n * unread seat might be perfectly usable.\n * 2. ONLY A MACHINE-READABLE INSTANT MAY BECOME A COUNTDOWN. Claude's reset\n * is provider prose and `resetsAt` is structurally null\n * (docs/VERSE-TELEMETRY-V2.md), so prose resets travel in their own\n * channel and are rendered verbatim. Nothing here parses a sentence into\n * a time.\n * 3. A RESET IN THE PAST IS NOT A RESET. A `resetsAt` that has already\n * elapsed means the reading predates the rollover; it is reported as\n * overdue rather than as a negative countdown or as \"now\".\n * 4. LOCAL HEADROOM IS NOT \"BUDGET MINUS RESIDENT\" UNLESS BOTH ARE KNOWN.\n * One unknown makes the headroom unknown, and the strip says so.\n *\n * Pure: no React, no I/O, no formatting of currency/percent.\n */\nimport type { AccountCardModel, AccountVerdictState, LocalCardModel, WindowView } from './accounts-model.js';\nimport type { LocalModelsView } from './local-model.js';\n\n/**\n * The four buckets the strip counts in. Deliberately coarser than\n * `AccountVerdictState`: at a glance there are only four useful answers, and\n * the card below carries the nuance.\n */\nexport type CapacityClass = 'ready' | 'tight' | 'blocked' | 'unread';\n\n/**\n * `signed-out` and `probe-unsupported` are BLOCKED-by-action, not unread: in\n * both cases we know exactly why there is no capacity and what to do about\n * it. `unknown` is the only genuinely unread state — nobody told us anything,\n * so counting it as blocked would assert an outage we did not observe.\n */\nexport const CAPACITY_CLASS: Record<AccountVerdictState, CapacityClass> = {\n available: 'ready',\n credits: 'ready',\n tight: 'tight',\n exhausted: 'blocked',\n 'signed-out': 'blocked',\n 'probe-unsupported': 'blocked',\n unknown: 'unread',\n};\n\nexport interface SeatCapacity {\n id: string;\n label: string;\n kind: 'account' | 'local';\n /** Engine hue — used only for the 2px marker, never for text. */\n color: string;\n cls: CapacityClass;\n /** The card's own verdict headline, so the strip and the card agree. */\n headline: string;\n /**\n * The binding window's percent, when it is a real measurement. Null for an\n * unread seat AND for a flagged limit, whose sentinel 100 is not a reading.\n */\n usedPct: number | null;\n /** False when `usedPct` is null because the figure would be a sentinel. */\n measured: boolean;\n}\n\n/** A reset the provider gave as a real instant, so a countdown is honest. */\nexport interface ResetInstant {\n seatLabel: string;\n windowLabel: string;\n /**\n * Epoch ms — the ONLY durable fact here. `inMs`/`overdue` below are a\n * snapshot taken when the model was built; a view that renders a countdown\n * must derive it from `atMs` against a live clock instead, or it will print\n * whatever the elapsed time happened to be when the memo last ran.\n */\n atMs: number;\n /** Signed ms until the reset AT BUILD TIME. Selection only — never rendered. */\n inMs: number;\n /** True when `inMs <= 0` AT BUILD TIME. Selection only — never rendered. */\n overdue: boolean;\n}\n\n/** A reset whose ONLY signal is provider prose. Rendered verbatim, never parsed. */\nexport interface ResetProse {\n seatLabel: string;\n windowLabel: string;\n text: string;\n}\n\nexport interface LocalCapacity {\n reachable: boolean;\n residentCount: number;\n installedCount: number;\n /** Models that can actually drive an agentic session. */\n agenticCount: number;\n /** Models whose runtime did not report a capability list. Never \"cannot\". */\n unknownToolCount: number;\n residentBytes: number | null;\n memoryBudgetBytes: number | null;\n /** Budget minus resident. Null when either side is unknown. */\n headroomBytes: number | null;\n /** The machine's own reported free memory, which is not the same figure. */\n freeMemoryBytes: number | null;\n usedPct: number | null;\n}\n\nexport interface CapacityOverview {\n seats: SeatCapacity[];\n ready: number;\n tight: number;\n blocked: number;\n unread: number;\n total: number;\n /**\n * Every dated reset, so a view can re-select the soonest one against a live\n * clock rather than against the instant this model was built.\n */\n resets: ResetInstant[];\n /** The soonest real reset across every seat, or null when none is dated. */\n nextReset: ResetInstant | null;\n /** Every window whose reset is prose only, deduplicated by sentence. */\n proseResets: ResetProse[];\n local: LocalCapacity | null;\n /** The one-line answer. Never claims anything about an unread seat. */\n headline: string;\n /**\n * True when the roster WAS read and nothing in it is usable.\n *\n * An entirely unread roster is deliberately excluded. `noCapacity` is what\n * tints the headline as a warning, and \"you have no capacity\" over seats\n * nobody managed to probe is an assertion about an unobserved state — the\n * same lie `capacityHeadline` is written case-by-case to avoid, and the same\n * one the `unread` chip word exists to prevent. A PARTLY unread roster still\n * counts: a seat known to be blocked is a measured constraint.\n */\n noCapacity: boolean;\n}\n\nfunction plural(n: number, one: string, many: string): string {\n return n === 1 ? one : many;\n}\n\n/**\n * The strip's sentence. Written by cases rather than by template because each\n * case has a different honest claim to make, and a single interpolated string\n * ended up asserting \"0 usable\" over a roster nobody had read.\n */\nexport function capacityHeadline(input: {\n ready: number;\n tight: number;\n blocked: number;\n unread: number;\n total: number;\n local: LocalCapacity | null;\n}): string {\n const { ready, tight, blocked, unread, total, local } = input;\n if (total === 0) {\n return 'No seats found.';\n }\n\n const localClause =\n local === null\n ? ''\n : local.reachable && local.residentCount > 0\n ? ` ${local.residentCount} local ${plural(local.residentCount, 'model is', 'models are')} resident and answer with no load delay.`\n : local.reachable && local.agenticCount > 0\n ? ` No local model is resident, but ${local.agenticCount} installed ${plural(local.agenticCount, 'one can', 'ones can')} drive a session after a load.`\n : local.reachable\n ? ' No local model is resident.'\n : ' The local runtime did not answer, so local capacity is unknown.';\n\n const unreadClause =\n unread === 0\n ? ''\n : ` ${unread} ${plural(unread, 'seat has', 'seats have')} no reading yet.`;\n\n if (ready > 0) {\n return `${ready} of ${total} ${plural(total, 'seat is', 'seats are')} usable right now.${unreadClause}${localClause}`;\n }\n if (tight > 0) {\n return `No seat is clear: ${tight} ${plural(tight, 'is', 'are')} running tight and ${blocked} ${plural(blocked, 'is', 'are')} blocked.${unreadClause}${localClause}`;\n }\n if (blocked > 0) {\n return `No cloud seat reports headroom — ${blocked} blocked.${unreadClause}${localClause}`;\n }\n return `No seat reported a usable window.${unreadClause}${localClause}`;\n}\n\nfunction seatFromCard(card: AccountCardModel): SeatCapacity {\n const binding = card.binding;\n return {\n id: card.id,\n label: card.label,\n kind: 'account',\n color: card.color,\n cls: CAPACITY_CLASS[card.verdict.state],\n headline: card.verdict.headline,\n usedPct: binding && binding.measured && !binding.limitReached ? binding.usedPct : null,\n measured: binding !== null && binding.measured && !binding.limitReached,\n };\n}\n\nfunction seatFromLocal(card: LocalCardModel): SeatCapacity {\n return {\n id: 'local',\n label: 'Local',\n kind: 'local',\n color: card.color,\n cls: CAPACITY_CLASS[card.verdict.state],\n headline: card.verdict.headline,\n usedPct: card.usedPct,\n measured: card.usedPct !== null,\n };\n}\n\n/**\n * Collect reset signals, keeping the two channels apart.\n *\n * A window contributes to `instants` ONLY through `resetsAt`, an ISO string\n * the provider actually gave. `resetText` alone — Claude's entire reset\n * signal — contributes to `prose` and is never parsed.\n */\nexport function collectResets(\n seats: readonly { label: string; windows: readonly WindowView[] }[],\n nowMs: number,\n): { instants: ResetInstant[]; prose: ResetProse[] } {\n const instants: ResetInstant[] = [];\n const prose: ResetProse[] = [];\n const seenProse = new Set<string>();\n\n for (const seat of seats) {\n for (const w of seat.windows) {\n if (w.resetsAt !== null) {\n const atMs = Date.parse(w.resetsAt);\n if (!Number.isNaN(atMs)) {\n const inMs = atMs - nowMs;\n instants.push({\n seatLabel: seat.label,\n windowLabel: w.label,\n atMs,\n inMs,\n overdue: inMs <= 0,\n });\n continue;\n }\n }\n if (w.resetText !== null) {\n const key = `${seat.label}|${w.label}|${w.resetText}`;\n if (seenProse.has(key)) continue;\n seenProse.add(key);\n prose.push({ seatLabel: seat.label, windowLabel: w.label, text: w.resetText });\n }\n }\n }\n return { instants, prose };\n}\n\n/**\n * The soonest reset still ahead of us. An overdue instant is never chosen as\n * \"next\" — it is in the past — but if EVERY instant is overdue the most recent\n * one is returned so the strip can say the readings predate a rollover rather\n * than silently showing nothing.\n */\nexport function nextReset(instants: readonly ResetInstant[]): ResetInstant | null {\n const ahead = instants.filter((r) => !r.overdue);\n if (ahead.length > 0) {\n return ahead.reduce((soonest, r) => (r.inMs < soonest.inMs ? r : soonest));\n }\n if (instants.length === 0) return null;\n return instants.reduce((latest, r) => (r.atMs > latest.atMs ? r : latest));\n}\n\n/**\n * The same choice as {@link nextReset}, but judged against a clock the caller\n * supplies rather than against the `overdue` flag frozen into each instant.\n * This is what a rendering countdown must use: a reset that was 40s away when\n * the model was built is in the PAST a minute later, and picking it as \"next\"\n * would keep a positive number on screen for a window that already rolled.\n */\nexport function nextResetAt(instants: readonly ResetInstant[], nowMs: number): ResetInstant | null {\n const ahead = instants.filter((r) => r.atMs > nowMs);\n if (ahead.length > 0) {\n return ahead.reduce((soonest, r) => (r.atMs < soonest.atMs ? r : soonest));\n }\n if (instants.length === 0) return null;\n return instants.reduce((latest, r) => (r.atMs > latest.atMs ? r : latest));\n}\n\nfunction buildLocalCapacity(\n card: LocalCardModel | null,\n view: LocalModelsView | null,\n): LocalCapacity | null {\n if (card === null && view === null) return null;\n const residentBytes = card?.residentBytes ?? view?.residentBytes ?? null;\n const budget = card?.memoryBudgetBytes ?? view?.memoryBudgetBytes ?? null;\n return {\n reachable: view?.reachable ?? card?.verdict.state !== 'unknown',\n residentCount: card?.residentCount ?? view?.rows.filter((r) => r.resident).length ?? 0,\n installedCount: card?.installedCount ?? view?.rows.length ?? 0,\n agenticCount: view?.agenticCount ?? 0,\n unknownToolCount: view?.unknownToolCount ?? 0,\n residentBytes,\n memoryBudgetBytes: budget,\n // One unknown side makes the difference unknown. Treating a missing\n // resident figure as 0 would report the whole machine as free.\n headroomBytes:\n residentBytes !== null && budget !== null ? Math.max(0, budget - residentBytes) : null,\n freeMemoryBytes: view?.freeMemoryBytes ?? null,\n usedPct: card?.usedPct ?? view?.memoryUsedPct ?? null,\n };\n}\n\nexport function buildCapacityOverview(input: {\n cards: readonly AccountCardModel[];\n localCard: LocalCardModel | null;\n localView: LocalModelsView | null;\n nowMs?: number;\n}): CapacityOverview {\n const nowMs = input.nowMs ?? Date.now();\n const seats: SeatCapacity[] = input.cards.map(seatFromCard);\n if (input.localCard) seats.push(seatFromLocal(input.localCard));\n\n const count = (cls: CapacityClass): number => seats.filter((s) => s.cls === cls).length;\n const ready = count('ready');\n const tight = count('tight');\n const blocked = count('blocked');\n const unread = count('unread');\n\n const { instants, prose } = collectResets(\n input.cards.map((c) => ({ label: c.label, windows: c.allWindows })),\n nowMs,\n );\n\n const local = buildLocalCapacity(input.localCard, input.localView);\n\n return {\n seats,\n ready,\n tight,\n blocked,\n unread,\n total: seats.length,\n resets: instants,\n nextReset: nextReset(instants),\n proseResets: prose,\n local,\n headline: capacityHeadline({ ready, tight, blocked, unread, total: seats.length, local }),\n // `unread < seats.length` is the whole guard: a roster where every seat\n // came back unread is unobserved, not exhausted.\n noCapacity: seats.length > 0 && ready === 0 && tight === 0 && unread < seats.length,\n };\n}\n\n/**\n * \"in 2h 14m\" material for a dated reset. Kept beside the model rather than in\n * `chartFormat` because it is a duration, not a chart number, and because the\n * overdue case must not read as a negative time.\n */\nexport function formatUntil(inMs: number): string {\n if (!Number.isFinite(inMs)) return '—';\n if (inMs <= 0) return 'overdue';\n const total = Math.floor(inMs / 1000);\n const d = Math.floor(total / 86_400);\n const h = Math.floor((total % 86_400) / 3600);\n const m = Math.floor((total % 3600) / 60);\n if (d > 0) return `${d}d ${h}h`;\n if (h > 0) return `${h}h ${m}m`;\n if (m > 0) return `${m}m`;\n return `${total}s`;\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';\nimport { tidyProse } from '../autonomy/format.js';\nimport { seatReopensAt, seatSubscription } from '../seat-subscription.js';\nimport { formatUntil } from '../usage/capacity-model.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 /** \"usable again in 7h 12m\" for a spent seat whose reset is still ahead; null otherwise. */\n usableAgain: string | null;\n}\n\n/**\n * \"usable again in 7h 12m\" for an instant still ahead of `now`; null when the\n * instant is missing, unparseable or already past (a past reset is a stale\n * reading, not a negative countdown).\n */\nexport function usableAgainPhrase(resetAt: string | null | undefined, now: number = Date.now()): string | null {\n if (typeof resetAt !== 'string') return null;\n const at = Date.parse(resetAt);\n if (!Number.isFinite(at) || at <= now) return null;\n return `usable again in ${formatUntil(at - now)}`;\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 byId = new Map(seats.map((seat) => [seat.id, seat]));\n return reports\n .filter(needsAttention)\n .map((report) => {\n // A spent seat is usable again when its LAST spent window resets, not\n // when the sweep's binding window does (seatReopensAt) — the same instant\n // Accounts and Fleet name. Without the seat's windows, the sweep's own.\n const seat = byId.get(report.seatId);\n const resetAt = report.connection === 'exhausted' && seat !== undefined\n ? seatReopensAt(seatSubscription(seat, now), report.resetAt)\n : report.resetAt;\n const when = describeResetAt(resetAt, now);\n return {\n report,\n label: seat?.label ?? report.seatId,\n word: CONNECTION_WORD[report.connection],\n tone: CONNECTION_TONE[report.connection],\n // Server sentences may carry a raw ISO instant or a \".;\" join; tidyProse fixes exactly those.\n detail: report.reasons[0] ? tidyProse(report.reasons[0], now) : null,\n reset: when === null ? null : `resets ${when}`,\n usableAgain: report.connection === 'exhausted' ? usableAgainPhrase(resetAt, now) : null,\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 { describeResetAt } from '../../../../core/verse/seat-readiness.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 { relativePhrase } from '../context/context-model.js';\nimport { percentText, tidyProse } from '../autonomy/format.js';\nimport { CONNECTION_TONE, CONNECTION_WORD, usableAgainPhrase, type HealthTone } from '../health/health-model.js';\nimport { seatReopensAt, 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 local instant; null when neither. */\n resetText: string | null;\n /** The machine-readable reset instant (ISO), when the provider gave one. */\n resetsAt: 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 /** When this seat was last checked (health sweep, else the usage reading), ISO; null when never. */\n checkedAt: string | null;\n /** The instant a spent seat becomes usable again (ISO), when one is known. */\n resetAt: string | null;\n /** The account is signed out — by the health sweep or by its own capacity record. */\n signedOut: boolean;\n /** A verified, still-fresh window retained only for display after a failed check. */\n lastReading?: boolean;\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 * The clock every reset and reason in the rows is worded against (\"today\n * 11:46 PM\" vs \"Sat 11:46 PM\"); defaults to now. Passed explicitly so the\n * words are a function of the inputs — a row built against the real clock\n * inside a test is a time bomb.\n */\n now?: number;\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\n/**\n * `resetText` comes from seat-subscription as-is: it already words a machine\n * instant the way every other reset in the app does (`describeResetAt`:\n * \"resets Fri 11:46 PM\") and leaves provider prose verbatim — one wording,\n * owned in one place.\n */\nfunction windowRow(w: SeatWindowView, binding: boolean): CapacityWindowRow {\n return {\n id: w.id,\n label: w.label,\n usedPercent: w.usedPercent,\n limitReached: w.limitReached,\n resetText: w.resetText,\n resetsAt: w.resetsAt,\n binding,\n };\n}\n\nfunction parseable(iso: string | null | undefined): iso is string {\n return typeof iso === 'string' && Number.isFinite(Date.parse(iso));\n}\n\nfunction isSpentWindow(w: Pick<SeatWindowView, 'limitReached' | 'usedPercent'>): boolean {\n return w.limitReached || (w.usedPercent !== null && w.usedPercent >= 100);\n}\n\nfunction connectionOf(report: SeatHealthReport | undefined, now: number): 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: readableReasons(report.reasons, now),\n fixKind: report.fix.kind,\n fixCommand: report.fix.command && report.fix.command.length > 0 ? [...report.fix.command] : null,\n };\n}\n\n/** Reasons as printed: server sentences with any ISO instant shown in local time. */\nfunction readableReasons(reasons: readonly string[], now: number): string[] {\n return reasons.map((r) => tidyProse(r, now).trim()).filter((r) => r.length > 0);\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 now: number,\n): CapacityRow {\n const view = seatSubscription(seat, now);\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 report = health.get(seat.id);\n const connection = connectionOf(report, now);\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 checkedAt: parseable(report?.checkedAt) ? report!.checkedAt : parseable(view.observedAt) ? view.observedAt : null,\n // The LATEST reset among ALL the spent windows (not only the ones this row\n // has room to draw) — seat-subscription `seatReopensAt`, which Fleet's\n // \"eligible again\" and the health banner agree with.\n resetAt: seatReopensAt(view, report?.resetAt),\n signedOut: connection?.connection === 'signed-out' || seat.capacity?.usability === 'signed-out',\n lastReading: seat.health.state === 'degraded' && seat.capacity?.usability === 'unknown' && windows.length > 0,\n };\n}\n\nfunction collapsedLocal(seats: readonly VerseSeat[], health: ReadonlyMap<string, SeatHealthReport>, now: number): CapacityRow {\n const rows = seats.map((s) => seatSubscription(s, now));\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, now),\n windows: [],\n credits: null,\n reserve: null,\n notes: [],\n localCount: count,\n checkedAt: parseable(report?.checkedAt)\n ? report!.checkedAt\n : rows.map((r) => r.observedAt).filter(parseable).sort((a, b) => Date.parse(b) - Date.parse(a))[0] ?? null,\n resetAt: null,\n signedOut: false,\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 const now = inputs.now ?? Date.now();\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, now));\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, now) : collapsedLocal(locals, health, now);\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 lastReadings = paid.filter((r) => r.lastReading).length;\n const unread = paid.filter((r) => r.cls === 'unread' && !r.lastReading).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 (lastReadings > 0) parts.push(`${lastReadings} last ${lastReadings === 1 ? 'reading' : 'readings'}`);\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/**\n * The one percent rule lives with the app's other number formats\n * (autonomy/format); re-exported so every capacity view keeps importing it\n * from the capacity model.\n */\nexport { percentText };\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}: ${percentText(w.usedPercent)} used${kept}${reset}`;\n}\n\n// ---------------------------------------------------------------------------\n// Account status (Apps & Accounts)\n// ---------------------------------------------------------------------------\n\n/**\n * - `usable` — connected (or read as usable) with room left;\n * - `low` — usable, but tight: past the warning line, or spent and running on credits;\n * - `spent` — the binding window is used up; comes back at `resetAt`;\n * - `signed-out` — needs the provider's own sign-in (Reconnect);\n * - `unavailable` — blocked for another reason (runtime down, CLI missing);\n * - `not-checked` — the health sweep has answered but said nothing usable about this seat;\n * - `checking` — nothing has answered yet, or a check is running right now.\n */\nexport type AccountStatusKind = 'usable' | 'low' | 'spent' | 'signed-out' | 'unavailable' | 'not-checked' | 'checking';\n\nexport interface AccountStatus {\n kind: AccountStatusKind;\n /** Sentence case, leads the row: \"Connected\", \"Spent\", \"Signed out\", \"Checking…\". */\n label: string;\n /** Rides after a middle dot: \"usable now\", \"resets Fri 11:46 PM\", \"reconnect to use it\". */\n detail: string | null;\n tone: HealthTone;\n /** \"usable again in 7h 12m\" — only for a spent seat whose reset is still ahead. */\n usableAgain: string | null;\n /** \"checked 2m ago\"; null when the seat was never checked. */\n checked: string | null;\n /** The last check as a local date and time, for a tooltip. */\n checkedTitle: string | null;\n /** True when `label` already says what the connection word would (signed out, out of usage). */\n coversConnection: boolean;\n}\n\nexport interface AccountStatusOptions {\n /** False until the health sweep has answered once: an unanswered seat is \"Checking…\", not \"Not checked\". */\n healthRead: boolean;\n /** A check of this seat is running right now. */\n checking?: boolean;\n now?: number;\n}\n\nconst STATUS_TONE: Record<AccountStatusKind, HealthTone> = {\n usable: 'success',\n low: 'warning',\n spent: 'danger',\n 'signed-out': 'danger',\n unavailable: 'danger',\n 'not-checked': 'neutral',\n checking: 'neutral',\n};\n\n/** Usable first, then what will come back by itself, then what needs you. Used by `orderAccountRows`. */\nconst STATUS_RANK: Record<AccountStatusKind, number> = {\n usable: 0,\n low: 1,\n checking: 2,\n 'not-checked': 3,\n spent: 4,\n unavailable: 5,\n 'signed-out': 6,\n};\n\nfunction checkedParts(row: Pick<CapacityRow, 'checkedAt'>, now: number): { checked: string | null; checkedTitle: string | null } {\n const phrase = relativePhrase(row.checkedAt, now);\n if (phrase === null || row.checkedAt === null) return { checked: null, checkedTitle: null };\n const at = new Date(row.checkedAt);\n return {\n checked: `checked ${phrase}`,\n checkedTitle: `Last checked ${at.toLocaleString([], { weekday: 'short', month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' })}`,\n };\n}\n\n/**\n * The one status an account row leads with, in the operator's words:\n *\n * Connected · usable now Spent · resets Fri 11:46 PM\n * Connected · running low Signed out · reconnect to use it\n * Connected · usable on credits Checking…\n *\n * Built from the row alone (no second reading of the seat), against a clock\n * the caller passes, because \"usable again in 7h\" must keep counting down\n * while the rows themselves are memoized on the data.\n */\nexport function accountStatus(row: CapacityRow, opts: AccountStatusOptions): AccountStatus {\n const now = opts.now ?? Date.now();\n const { checked, checkedTitle } = checkedParts(row, now);\n const make = (kind: AccountStatusKind, label: string, detail: string | null, extra: Partial<AccountStatus> = {}): AccountStatus => ({\n kind,\n label,\n detail,\n tone: STATUS_TONE[kind],\n usableAgain: null,\n checked,\n checkedTitle,\n coversConnection: false,\n ...extra,\n });\n\n if (opts.checking) return make('checking', 'Checking…', null);\n\n if (row.kind === 'local') {\n if (row.cls === 'ready') {\n return make('usable', 'Ready', row.localCount > 1 ? `${row.localCount} models on this machine · free` : 'runs on this machine · free');\n }\n if (row.cls === 'blocked') return make('unavailable', 'Not running', row.summary);\n return opts.healthRead ? make('not-checked', 'Not checked', 'readiness not reported yet') : make('checking', 'Checking…', null);\n }\n\n const c = row.connection?.connection ?? null;\n if (row.signedOut) return make('signed-out', 'Signed out', 'reconnect to use it', { coversConnection: true });\n if (row.lastReading) return make('unavailable', 'Last reading', 'latest check failed · access unconfirmed', { coversConnection: true });\n\n const binding = row.windows.find((w) => w.binding) ?? null;\n const spent = c === 'exhausted' || (row.cls === 'blocked' && binding !== null && isSpentWindow(binding));\n if (spent) {\n const when = describeResetAt(row.resetAt, now);\n const ahead = row.resetAt !== null && Date.parse(row.resetAt) > now;\n // No instant: the provider's own reset prose, verbatim, is the next best\n // thing — the prose of the spent window with no instant (the one that\n // holds the seat), never another window's earlier instant, which would\n // promise the seat back before it is.\n const heldBy = row.windows.find((w) => isSpentWindow(w) && !parseable(w.resetsAt) && w.resetText !== null) ?? null;\n const prose = heldBy?.resetText ?? (binding !== null && !parseable(binding.resetsAt) ? binding.resetText : null);\n const detail = when !== null\n ? (ahead ? `resets ${when}` : `was due to reset ${when}`)\n : (prose ?? 'reset time not reported');\n return make('spent', 'Spent', detail, {\n usableAgain: usableAgainPhrase(row.resetAt, now),\n coversConnection: c === 'exhausted',\n });\n }\n\n if (row.cls === 'blocked') return make('unavailable', 'Unavailable', row.summary);\n\n // A seat nobody has read is not \"fine\" and not \"broken\": it is waiting on a check.\n if (row.cls === 'unread') {\n if (!opts.healthRead) return make('checking', 'Checking…', null);\n if (c === null || c === 'unknown') return make('not-checked', 'Not checked', 'no reading yet');\n return make('usable', 'Connected', 'no usage reading yet');\n }\n\n const lead = c === null || c === 'unknown' ? 'Usable' : 'Connected';\n if (row.cls === 'tight') {\n const onCredits = binding !== null && isSpentWindow(binding) && row.credits !== null;\n if (lead === 'Usable') return make('low', 'Usable', onCredits ? 'on credits' : 'running low');\n return make('low', lead, onCredits ? 'usable on credits' : 'running low');\n }\n return lead === 'Usable' ? make('usable', 'Usable now', null) : make('usable', 'Connected', 'usable now');\n}\n\n/**\n * Usable accounts first, then the ones that come back on their own, then the\n * ones that need you — stable within each group (the roster's own order), and\n * paid seats ahead of local ones of the same standing. Ordered on the settled\n * status (never on a running check), so a row does not jump while \"Checking…\".\n */\nexport function orderAccountRows(rows: readonly CapacityRow[], opts: Omit<AccountStatusOptions, 'checking'>): CapacityRow[] {\n const ranked = rows.map((row, index) => ({\n row,\n index,\n rank: STATUS_RANK[accountStatus(row, { ...opts, checking: false }).kind],\n local: row.kind === 'local' ? 1 : 0,\n }));\n ranked.sort((a, b) => a.rank - b.rank || a.local - b.local || a.index - b.index);\n return ranked.map((r) => r.row);\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e,c as t,n}from"./index-QesfXBsb.js";import{C as r,D as i,E as a,L as o,P as s,R as ee,S as c,T as l,_ as u,c as d,d as te,f,g as p,j as m,l as h,m as g,n as _,p as v,s as y,t as ne,u as re,w as ie}from"./ChartFrame-SygZ7B3x.js";import{_ as b,a as x,c as S,t as C,v as ae}from"./colors-BZ3a9wFf.js";import{l as oe,t as se}from"./format-DKrNjdwD.js";import"./Swimlane-BzH6OCee.js";import"./StatTile-DPZ5yyaU.js";import"./AreaTrend-BFimExYn.js";import"./Funnel-BeNQZWv2.js";import"./StepBand-DQykLkk_.js";import"./MatrixHeatmap-DZvZeWXL.js";var w={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`},T=n();function ce({title:e,description:t,caveat:n,children:r,table:i,empty:a,emptyMessage:o=`No data for this window.`}){return(0,T.jsxs)(`figure`,{className:w.figure,children:[(0,T.jsxs)(`figcaption`,{className:w.caption,children:[(0,T.jsx)(`span`,{className:w.title,children:e}),t?(0,T.jsx)(`span`,{className:w.description,children:t}):null]}),n?(0,T.jsx)(`p`,{className:w.caveat,role:`note`,children:n}):null,a?(0,T.jsx)(`p`,{className:w.empty,children:o}):(0,T.jsx)(`div`,{className:w.plot,children:r}),i?(0,T.jsxs)(`details`,{className:w.tableDisclosure,children:[(0,T.jsx)(`summary`,{children:`View as table`}),(0,T.jsx)(`div`,{className:w.tableBody,children:i})]}):null]})}var E={legend:`_legend_4pgvn_1`,item:`_item_4pgvn_10`,swatch:`_swatch_4pgvn_18`,swatchLine:`_swatchLine_4pgvn_25`};function le({items:e}){return e.length<2?null:(0,T.jsx)(`ul`,{className:E.legend,children:e.map(e=>(0,T.jsxs)(`li`,{className:E.item,children:[(0,T.jsx)(`span`,{className:e.kind===`line`?E.swatchLine:E.swatch,style:{background:e.color},"aria-hidden":`true`}),e.label]},e.label))})}var D=t(e(),1),O={svg:`_svg_1jc17_5`,gridline:`_gridline_1jc17_10`,axis:`_axis_1jc17_15`,axisLabel:`_axisLabel_1jc17_20`,line:`_line_1jc17_26`,area:`_area_1jc17_33`,marker:`_marker_1jc17_38`,endLabel:`_endLabel_1jc17_43`,crosshairLine:`_crosshairLine_1jc17_49`,overlay:`_overlay_1jc17_55`,wrap:`_wrap_1jc17_60`,tooltip:`_tooltip_1jc17_66`,tooltipDate:`_tooltipDate_1jc17_82`,tooltipRow:`_tooltipRow_1jc17_87`,tooltipKey:`_tooltipKey_1jc17_93`,tooltipValue:`_tooltipValue_1jc17_99`,tooltipGap:`_tooltipGap_1jc17_104`},k=640,A=44,ue=12,j=12,M=24,N=4,de=6.4,fe=4,pe=150,P=14;function F(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 I({series:e,height:t=200,area:n=!1,formatX:i,formatY:a,ariaLabel:o,width:s}){let c=(0,D.useRef)(null),d=(0,D.useRef)(null),m=re(d,s,k),_=h(),v=ie(_),[y,ne]=(0,D.useState)(null),[S,ae]=(0,D.useState)(null),se=i??(e=>String(e)),w=a??(e=>String(e)),ce=ee(e.flatMap(e=>e.points.map(e=>e.x))),E=e.map(e=>({...e,points:e.points.filter(e=>ce(e.x))})),I=E.flatMap(e=>e.points.map(e=>e.x)),L=E.flatMap(e=>e.points.map(e=>e.y)).filter(e=>e!==null&&Number.isFinite(e));if(I.length===0)return(0,T.jsx)(`div`,{ref:d,className:O.wrap,children:(0,T.jsx)(`p`,{children:`No data.`})});let R=Math.min(...I),z=Math.max(...I),me=r(I),[B,he]=me&&z>R?u(R,z,te):[R,z],ge=he-B||1,_e=g(Math.min(0,...L),Math.max(0,...L),{count:N,integer:L.length>0&&f(L),format:a}),V=_e.ticks,ve=V[0],H=V[V.length-1]-ve||1,U=t-j-M,W=e=>j+U-(e-ve)/H*U,G=Math.max(A,Math.ceil(Math.max(0,..._e.labels.map(e=>e.length))*v)+8),ye=E.length>=1&&E.length<=4,K=ye?Math.max(...E.map(e=>e.label.length))*de*_:0,q=E.flatMap(e=>{for(let t=e.points.length-1;t>=0;t--){let n=e.points[t].y;if(n!==null&&Number.isFinite(n))return[{key:e.id,y:W(n)}]}return[]}),J=ye&&K<=pe?p(q,P*_,j,j+U):null,Y=J!==null&&q.length>0,X=ue+(Y?fe+K:0),Z=E.length>=2,be=Math.max(40,m-G-X),Q=e=>G+(e-B)/ge*be,$=Array.from(new Set(I)).sort((e,t)=>e-t),xe=$.length>1?[$[0],$[$.length-1]]:[],Se=me?oe(R,z,i,xe):[se],Ce=l(xe.map((e,t)=>{let n=Q(e),r=t===0?n<=G+.5:n>=m-X-.5;return{key:t===0?`start`:`end`,x:n,anchor:r?t===0?`start`:`end`:`middle`,priority:t===0?2:3,variants:Se.map(t=>t(e))}}),{min:G,max:m-X,charPx:v});function we(e){let t=c.current;if(!t)return null;let n=t.getBoundingClientRect(),r=(e-n.left)/(n.width||m)*m,i=B+(r-G)/be*ge,a=$[0],o=1/0;for(let e of $){let t=Math.abs(e-i);t<o&&(o=t,a=e)}return a}function Te(e){let t=we(e.clientX);if(t===null)return;ne(t);let n=c.current;if(n){let e=n.getBoundingClientRect(),r=Q(t)/m*(e.width||m);ae({left:r,top:0})}}let Ee=y===null?null:E.map(e=>({series:e,point:e.points.find(e=>e.x===y)??null}));return(0,T.jsxs)(`div`,{ref:d,className:O.wrap,children:[(0,T.jsxs)(`svg`,{ref:c,className:O.svg,width:m,height:t,viewBox:`0 0 ${m} ${t}`,role:`img`,"aria-label":o,onPointerMove:Te,onPointerLeave:()=>ne(null),children:[V.map((e,t)=>(0,T.jsxs)(`g`,{children:[(0,T.jsx)(`line`,{x1:G,x2:m-X,y1:W(e),y2:W(e),className:O.gridline,stroke:x}),(0,T.jsx)(`text`,{x:G-6,y:W(e),dy:`0.32em`,textAnchor:`end`,className:O.axisLabel,children:_e.labels[t]})]},t)),(0,T.jsx)(`line`,{x1:G,x2:m-X,y1:t-M,y2:t-M,className:O.axis,stroke:C}),Ce.map(e=>(0,T.jsx)(`text`,{"data-axis-label":e.key,x:e.x,y:t-6,textAnchor:e.anchor,className:O.axisLabel,children:e.text},e.key)),E.map((e,t)=>{let r=b(t),i=F(e.points);return(0,T.jsxs)(`g`,{children:[n&&E.length===1?i.map((e,t)=>{let n=e.map((e,t)=>`${t===0?`M`:`L`}${Q(e.x)},${W(e.y)}`).join(` `)+` L${Q(e[e.length-1].x)},${W(ve)} L${Q(e[0].x)},${W(ve)} Z`;return(0,T.jsx)(`path`,{d:n,fill:r,className:O.area},t)}):null,i.map((e,t)=>(0,T.jsx)(`path`,{d:e.map((e,t)=>`${t===0?`M`:`L`}${Q(e.x)},${W(e.y)}`).join(` `),stroke:r,className:O.line},t)),Y&&i.length?(()=>{let t=i[i.length-1],n=t[t.length-1];return(0,T.jsx)(`text`,{"data-end-label":e.id,x:Q(n.x)+fe,y:J?.get(e.id)??W(n.y),dy:`0.32em`,className:O.endLabel,fill:r,children:e.label})})():null]},e.id)}),y===null?null:(0,T.jsx)(`line`,{x1:Q(y),x2:Q(y),y1:j,y2:t-M,className:O.crosshairLine}),y===null?null:E.map((e,t)=>{let n=e.points.find(e=>e.x===y);return!n||n.y===null?null:(0,T.jsx)(`circle`,{cx:Q(n.x),cy:W(n.y),r:4,fill:b(t),className:O.marker},e.id)}),(0,T.jsx)(`rect`,{x:G,y:j,width:be,height:U,className:O.overlay,onFocus:()=>ne($[$.length-1]??null)})]}),Ee&&S?(0,T.jsxs)(`div`,{className:O.tooltip,style:{left:S.left,top:S.top},children:[(0,T.jsx)(`div`,{className:O.tooltipDate,children:se(y)}),Ee.map(({series:e,point:t},n)=>(0,T.jsxs)(`div`,{className:O.tooltipRow,children:[(0,T.jsx)(`span`,{className:O.tooltipKey,style:{background:b(n)},"aria-hidden":`true`}),t&&t.y!==null?(0,T.jsxs)(T.Fragment,{children:[(0,T.jsx)(`span`,{className:O.tooltipValue,children:w(t.y)}),Z?(0,T.jsx)(`span`,{children:e.label}):null]}):(0,T.jsxs)(`span`,{className:O.tooltipGap,children:[`no data`,Z?` — ${e.label}`:``]})]},e.id))]}):null,Z?(0,T.jsx)(le,{items:E.map((e,t)=>({label:e.label,color:b(t),kind:`line`}))}):null]})}var L={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`},R=24,z=10;function me({data:e,height:t=160,orientation:n=`vertical`,color:r=S,formatValue:i=e=>String(e),ariaLabel:a,width:o}){let s=(0,D.useId)(),ee=(0,D.useRef)(null),c=re(ee,o,588),[l,u]=(0,D.useState)(null),d=e.map(e=>e.value).filter(e=>e!==null),te=Math.max(0,...d,1e-4),f=Math.min(0,...d),p=te-f||1;if(n===`horizontal`){let n=Math.min(R,Math.max(14,Math.floor((t-z)/e.length)-z)),o=e.length*(n+z)+z,s=c,d=Math.max(40,s-120-48);return(0,T.jsxs)(`div`,{ref:ee,className:L.wrap,children:[(0,T.jsxs)(`svg`,{className:L.svg,width:s,height:o,viewBox:`0 0 ${s} ${o}`,role:`img`,"aria-label":a,children:[(0,T.jsx)(`line`,{x1:120,y1:0,x2:120,y2:o,className:L.baseline,stroke:C}),e.map((e,t)=>{let a=z+t*(n+z),o=e.value===null?0:(e.value-f)/p*d;return(0,T.jsxs)(`g`,{children:[(0,T.jsx)(`text`,{x:112,y:a+n/2,dy:`0.32em`,textAnchor:`end`,className:L.categoryLabel,children:e.label.length>22?`${e.label.slice(0,21)}…`:e.label}),e.value===null?(0,T.jsx)(`line`,{x1:124,y1:a+n/2,x2:134,y2:a+n/2,stroke:x,strokeWidth:2,strokeDasharray:`2 2`}):(0,T.jsxs)(T.Fragment,{children:[(0,T.jsx)(`rect`,{x:120,y:a,width:Math.max(2,o),height:n,rx:4,fill:r,className:L.bar}),(0,T.jsx)(`text`,{x:120+Math.max(2,o)+6,y:a+n/2,dy:`0.32em`,className:L.valueLabel,children:i(e.value)})]}),(0,T.jsx)(`rect`,{className:L.hitArea,x:0,y:a-z/2,width:s,height:n+z,tabIndex:0,role:`img`,"aria-label":`${e.label}: ${e.value===null?`no data`:i(e.value)}`,onPointerEnter:()=>u(t),onPointerLeave:()=>u(e=>e===t?null:e),onFocus:()=>u(t),onBlur:()=>u(e=>e===t?null:e)})]},e.label+t)})]}),l===null?null:(0,T.jsxs)(`div`,{className:L.tooltip,style:{left:128,top:z+l*(n+z)-4},children:[(0,T.jsx)(`span`,{className:L.tooltipValue,children:e[l].value===null?`no data`:i(e[l].value)}),(0,T.jsx)(`span`,{className:L.tooltipLabel,children:e[l].label})]})]})}let m=e.length?Math.max(R,0):R,h=Math.min(R,m),g=t,_=g+20+30,v=e.length*(h+z)+z,y=20+g-(0-f)/p*g;return(0,T.jsxs)(`div`,{className:L.wrap,children:[(0,T.jsxs)(`svg`,{className:L.svg,width:v,height:_,viewBox:`0 0 ${v} ${_}`,role:`img`,"aria-label":a,children:[(0,T.jsx)(`line`,{x1:0,y1:y,x2:v,y2:y,className:L.baseline,stroke:C}),e.map((e,t)=>{let n=z+t*(h+z),a=e.value===null?0:Math.abs(e.value-f)/p*g,o=e.value!==null&&e.value>=0?y-a:y;return(0,T.jsxs)(`g`,{children:[e.value===null?(0,T.jsx)(`line`,{x1:n+h/2-5,y1:y,x2:n+h/2+5,y2:y,stroke:x,strokeWidth:2,strokeDasharray:`2 2`}):(0,T.jsxs)(T.Fragment,{children:[(0,T.jsx)(`rect`,{x:n,y:o,width:h,height:Math.max(2,a),rx:4,fill:r,className:L.bar}),(0,T.jsx)(`text`,{x:n+h/2,y:o-4,textAnchor:`middle`,className:L.valueLabel,children:i(e.value)})]}),(0,T.jsx)(`text`,{x:n+h/2,y:_-8,textAnchor:`middle`,className:L.axisLabel,children:e.label.length>10?`${e.label.slice(0,9)}…`:e.label}),(0,T.jsx)(`rect`,{className:L.hitArea,x:n-z/2,y:0,width:h+z,height:_,tabIndex:0,role:`img`,"aria-label":`${e.label}: ${e.value===null?`no data`:i(e.value)}`,onPointerEnter:()=>u(t),onPointerLeave:()=>u(e=>e===t?null:e),onFocus:()=>u(t),onBlur:()=>u(e=>e===t?null:e)})]},e.label+t)})]}),l===null?null:(0,T.jsxs)(`div`,{className:L.tooltip,style:{left:z+l*(h+z),top:0},id:`${s}-tooltip`,children:[(0,T.jsx)(`span`,{className:L.tooltipValue,children:e[l].value===null?`no data`:i(e[l].value)}),(0,T.jsx)(`span`,{className:L.tooltipLabel,children:e[l].label})]})]})}var B=16,he=26,ge=14;function _e(e){let t=new Date(e);return Number.isNaN(t.getTime())?``:t.toLocaleString(`en-US`,{weekday:`short`,hour:`numeric`,minute:`2-digit`})}function V(e){let t=Math.max(0,Math.round(e/6e4));if(t<60)return`${t}m`;let n=Math.floor(t/60);return n<48?t%60?`${n}h ${t%60}m`:`${n}h`:`${Math.round(n/24)}d`}function ve(e,t,n,r,i){let a=t!==null&&Number.isFinite(t)?t:null;if(e.from&&e.from.remaining<=0)return{text:a===null?`Used up — reset time unknown.`:`Used up — resets ${r(a)}.`,severity:`danger`};if(e.from&&i!==void 0&&e.reserveAt!==null&&e.reserveAt<=e.from.t){let e=a===null?`until it resets (reset time unknown)`:`until ${r(a)}`;return{text:`Inside ${i.toLowerCase()} — autonomy has stopped using this window ${e}.`,severity:`warn`}}return a===null?{text:`Reset time unknown — not projecting this window.`,severity:`unknown`}:e.slopePerMs===null?{text:`Not enough readings to project this window yet.`,severity:`unknown`}:e.exhaustAt===null?e.reserveAt===null?{text:`At this pace: about ${n(e.remainingAtReset??0)} left at reset.`,severity:`ok`}:{text:`At this pace: ${i??`reserve`} reached ${r(e.reserveAt)}, ${V(a-e.reserveAt)} before reset.`,severity:`warn`}:{text:`At this pace: runs out ${r(e.exhaustAt)}, ${V(a-e.exhaustAt)} before reset.`,severity:`danger`}}function H({title:e,description:t,caveat:n,status:r,points:ee,capacity:f,start:p,resetAt:b,now:x,reserve:C,height:w=200,width:ce,formatValue:E,formatTime:le,ariaLabel:O}){let k=E??se,A=le??_e,ue=(0,D.useRef)(null),j=re(ue,ce),M=h(),N=ee.filter(e=>c(e.t)).sort((e,t)=>e.t-t.t),de=N.some(e=>e.remaining!==null),fe=r??(N.length===0?{kind:`empty`,message:`No readings in this window yet.`}:de?{kind:`ready`}:{kind:`unknown`}),pe=c(b),P=pe?b:null,F=m(N,P,{reserve:C?.value??null}),I=ve(F,P,k,A,C?.label),L=N.flatMap(e=>e.remaining!==null&&Number.isFinite(e.remaining)?[e.remaining]:[]),R=g(0,Math.max(f,...L,1),{count:4,integer:Number.isInteger(f)&&L.every(e=>Number.isInteger(e)),format:E}),z=R.ticks,me=z[z.length-1],V=o(R.labels,28,56,M),H=Math.max(40,j-V-ge),U=w-B-he,W=N.length?N[N.length-1].t:x,G=P??Math.max(x,W),ye=c(p)?p:N[0]?.t??G,[K,q]=u(ye,G,te,`end`),J=i(K,q,V,V+H),Y=i(0,me,B+U,B),X=e=>Math.min(q,Math.max(K,e)),Z=oe(K,q,le??_e,[K,q]),be=l([{key:`start`,x:V,anchor:`start`,priority:2,variants:Z.map(e=>e(K))},pe?{key:`reset`,x:V+H,anchor:`end`,priority:3,variants:Z.map(e=>`Resets ${e(q)}`)}:{key:`end`,x:V+H,anchor:`end`,priority:3,variants:Z.map(e=>e(q))}],{min:V,max:V+H,charPx:ie(M)}),Q=s(N.map(e=>({x:X(e.t),y:e.remaining}))).map(e=>e.map(e=>({x:J(e.x),y:Y(Math.max(0,e.y))}))),$=``;if(P!==null&&F.from&&F.slopePerMs!==null){let e=F.exhaustAt??P,t=F.exhaustAt===null?F.remainingAtReset??F.from.remaining:0;e>F.from.t&&($=a([{x:J(X(F.from.t)),y:Y(F.from.remaining)},{x:J(X(e)),y:Y(Math.max(0,t))}]))}let xe=I.severity===`danger`?ae(`danger`):I.severity===`warn`?ae(`warning`):`var(--text-tertiary)`,Se=O??`${e}: ${F.from?`${k(F.from.remaining)} of ${k(f)} left at ${A(F.from.t)}`:`no readings`}; ${P===null?`reset time unknown`:`resets ${A(P)}`}. ${I.text}`,Ce=[{key:`t`,label:`When`,render:e=>A(e.t)},{key:`r`,label:`Remaining`,numeric:!0,render:e=>e.remaining===null?`—`:k(e.remaining)}],we=[{label:`Remaining`,color:S,kind:`line`},...pe?[{label:`Even pace`,color:`var(--text-tertiary)`,kind:`line`}]:[],...$?[{label:`Projection`,color:xe,kind:`line`}]:[]];return(0,T.jsx)(ne,{title:e,description:t,caveat:n,status:fe,table:(0,T.jsx)(d,{caption:e,columns:Ce,rows:N,rowKey:e=>String(e.t)}),footer:(0,T.jsxs)(T.Fragment,{children:[(0,T.jsx)(`p`,{className:y.note,"data-severity":I.severity,role:`status`,children:I.text}),(0,T.jsx)(_,{items:we})]}),children:(0,T.jsx)(`div`,{ref:ue,className:y.plotWrap,children:(0,T.jsxs)(`svg`,{className:y.svg,width:j,height:w,viewBox:`0 0 ${j} ${w}`,role:`img`,"aria-label":Se,children:[z.map((e,t)=>(0,T.jsxs)(`g`,{children:[(0,T.jsx)(`line`,{className:y.grid,x1:V,x2:V+H,y1:Y(e),y2:Y(e)}),(0,T.jsx)(`text`,{className:y.tick,x:V-6,y:Y(e),dy:`0.32em`,textAnchor:`end`,children:R.labels[t]})]},e)),(0,T.jsx)(`line`,{className:y.axis,x1:V,x2:V+H,y1:Y(0),y2:Y(0)}),be.map(e=>(0,T.jsx)(`text`,{"data-axis-label":e.key,className:y.tick,x:e.x,y:w-8,textAnchor:e.anchor,children:e.text},e.key)),pe?(0,T.jsx)(`path`,{"data-role":`pace`,className:y.reference,d:a([{x:J(K),y:Y(f)},{x:J(q),y:Y(0)}])}):null,C?(0,T.jsxs)(`g`,{"data-role":`reserve`,children:[(0,T.jsx)(`line`,{className:y.reference,x1:V,x2:V+H,y1:Y(C.value),y2:Y(C.value)}),(0,T.jsxs)(`text`,{"data-role":`reserve-label`,className:`${y.tick} ${y.halo}`,x:V+4,y:Y(C.value)-5,textAnchor:`start`,children:[C.label,` · `,k(C.value)]})]}):null,x>K&&x<q?(0,T.jsx)(`line`,{className:y.crosshair,x1:J(x),x2:J(x),y1:B,y2:B+U}):null,Q.map((e,t)=>(0,T.jsxs)(`g`,{"data-role":`remaining`,children:[(0,T.jsx)(`path`,{className:y.wash,fill:S,d:v(e,e.map(e=>({x:e.x,y:Y(0)})))}),(0,T.jsx)(`path`,{className:y.line,stroke:S,d:a(e)})]},t)),$?(0,T.jsx)(`path`,{"data-role":`projection`,className:y.projection,stroke:xe,d:$}):null,F.from?(0,T.jsx)(`circle`,{className:y.marker,cx:J(X(F.from.t)),cy:Y(F.from.remaining),r:4,fill:S}):null]})})})}export{ce as a,le as i,me as n,I as r,H as t};
|
|
2
|
+
//# sourceMappingURL=charts-C_xJbJiw.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"charts-C_xJbJiw.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","../../../../../../src/web-ui/components/charts/BurnDown.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","/* Drawn at its measured width and a fixed height (width/height attributes\n set by LineChart). Never `width: 100%; height: auto` — that stretches the\n viewBox, text included, with the window. `max-width` keeps a not-yet-\n measured first paint from pushing its container wider. */\n.svg {\n display: block;\n max-width: 100%;\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 width: 100%;\n min-width: 0;\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 *\n * Sizing (after 3.11.3): the chart draws at its MEASURED pixel width and a fixed\n * pixel `height` — one user unit is one CSS pixel — like the V3.10 kit\n * (useChartWidth). It used to draw into a fixed 640-unit viewBox stretched\n * with `width: 100%; height: auto`, so on a 1900 px window the whole figure,\n * text included, scaled ~2.8×: 12 px tick labels rendered at ~34 px, the\n * 200 px chart stood ~560 px tall, and the end label (\"Tokens in\") dwarfed\n * the card. Now the coordinate system scales and the text never does.\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 {\n MIN_TIME_SPAN_MS,\n allIntegers,\n axisTicks,\n dodgeLabels,\n ensureSpan,\n isTimeAxis,\n labelCharPx,\n layoutAxisLabels,\n xKeeper,\n} from './chart-math.js';\nimport { timeLabelLadder } from './format.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport { useTextScale } from './useTextScale.js';\nimport './chart-tokens.css';\nimport styles from './LineChart.module.css';\n\n/** Width drawn at before the container is measured (jsdom, first paint). */\nconst FALLBACK_W = 640;\n/** Minimum left gutter; it widens when the y tick labels need more (see padL). */\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. User units are CSS\n pixels here (the viewBox matches the measured width), and `--text-xs-size`\n is 12 px, where the UI sans averages a shade over 6 px per character at\n 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 `width - PAD_R + 4` with only PAD_R (12 px) of room and the svg's own\n `overflow: hidden` cropped it to its first glyph — \"Estimated spend\"\n rendered as a lone \"E\".\n Every text measure here (END_LABEL_CH, END_LABEL_GAP_Y, the axis label\n advance) is for 12 px text and is multiplied by the operator's Display\n size (useTextScale): --text-xs-size is 12px × --ui-text-scale, so at\n XLarge the same label is 15 units tall and 25% wider. END_LABEL_MAX is a\n budget of plot width, not a text measure, and stays as it is. */\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/** Line height of a direct end label at 12 px (user units): two closer than this overlap. */\nconst END_LABEL_GAP_Y = 14;\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\nexport function LineChart({\n series: seriesProp,\n height = 200,\n area = false,\n formatX: formatXProp,\n formatY: formatYProp,\n ariaLabel,\n width: fixedWidth,\n}: {\n series: Series[];\n /** Plot height in px, including the x-axis band. Fixed at every width. */\n height?: number;\n /** Fixed width in px (tests, print). Omit to fill the container. */\n width?: 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 wrapRef = useRef<HTMLDivElement>(null);\n const width = useChartWidth(wrapRef, fixedWidth, FALLBACK_W);\n const textScale = useTextScale();\n /* Axis labels' estimated advance per character, at the size they render. */\n const axisLabelCh = labelCharPx(textScale);\n const [hoverX, setHoverX] = useState<number | null>(null);\n const [tooltipPos, setTooltipPos] = useState<{ left: number; top: number } | null>(null);\n\n const formatX = formatXProp ?? ((x: number) => String(x));\n const formatY = formatYProp ?? ((y: number) => String(y));\n /* On a time axis a 0 / NaN / pre-2000 x is a null timestamp that leaked\n through, not a moment: it would start the axis at \"Dec 31\" 1969. Such\n points are left out of the domain AND the drawing. */\n const keepX = xKeeper(seriesProp.flatMap((s) => s.points.map((p) => p.x)));\n const series = seriesProp.map((s) => ({ ...s, points: s.points.filter((p) => keepX(p.x)) }));\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 && Number.isFinite(y));\n if (allX.length === 0) {\n return (\n <div ref={wrapRef} className={styles.wrap}>\n <p>No data.</p>\n </div>\n );\n }\n const rawXMin = Math.min(...allX);\n const rawXMax = Math.max(...allX);\n const timeAxis = isTimeAxis(allX);\n // A burst of points seconds apart is widened to MIN_TIME_SPAN_MS around\n // itself instead of stretched edge to edge under identical labels.\n const [xMin, xMax] = timeAxis && rawXMax > rawXMin ? ensureSpan(rawXMin, rawXMax, MIN_TIME_SPAN_MS) : [rawXMin, rawXMax];\n const xRange = xMax - xMin || 1;\n\n // Nice ticks whose labels are exact: integer data get integer ticks, and a\n // caller's formatter never prints a rounded label on a precise tick.\n const yAxis = axisTicks(Math.min(0, ...knownY), Math.max(0, ...knownY), {\n count: TICKS_Y,\n integer: knownY.length > 0 && allIntegers(knownY),\n format: formatYProp,\n });\n const yTicks = yAxis.ticks;\n const yMin = yTicks[0]!;\n const yMax = yTicks[yTicks.length - 1]!;\n const yRange = yMax - yMin || 1;\n const plotH = height - PAD_T - PAD_B;\n const yScale = (y: number) => PAD_T + plotH - ((y - yMin) / yRange) * plotH;\n /* The y labels hang right-aligned 6 units left of the plot, and the svg\n clips at its edge: the gutter grows to fit the widest one (+2 of air) —\n 44 still fits five 12 px characters, a larger Display size fewer. */\n const padL = Math.max(PAD_L, Math.ceil(Math.max(0, ...yAxis.labels.map((l) => l.length)) * axisLabelCh) + 8);\n\n /* Decided before the x scale, because the reserved gutter is what plotW is\n measured against — and the gridlines and x-axis stop at the same edge.\n End labels are dodged vertically so two lines ending on one value never\n print their names over each other; if they cannot all fit, the legend\n (always present for 2+ series) names them instead. */\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 * textScale\n : 0;\n const endPoints = series.flatMap((s) => {\n for (let i = s.points.length - 1; i >= 0; i--) {\n const y = s.points[i]!.y;\n if (y !== null && Number.isFinite(y)) return [{ key: s.id, y: yScale(y) }];\n }\n return [];\n });\n const dodged = wantEndLabels && endLabelW <= END_LABEL_MAX ? dodgeLabels(endPoints, END_LABEL_GAP_Y * textScale, PAD_T, PAD_T + plotH) : null;\n const showEndLabels = dodged !== null && endPoints.length > 0;\n const padR = PAD_R + (showEndLabels ? END_LABEL_GAP + endLabelW : 0);\n const showLegend = series.length >= 2;\n\n const plotW = Math.max(40, width - padL - padR);\n const xScale = (x: number) => padL + ((x - xMin) / xRange) * plotW;\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 /* First and last x labels, collision-free: the end outranks the start;\n on a time axis both walk one detail ladder (the caller's format → a\n shorter date/time; clock time only inside one day) until they fit. */\n const xEnds = xAxis.length > 1 ? [xAxis[0]!, xAxis[xAxis.length - 1]!] : [];\n const ladder = timeAxis ? timeLabelLadder(rawXMin, rawXMax, formatXProp, xEnds) : [formatX];\n const xLabels = layoutAxisLabels(\n xEnds.map((x, i) => {\n const px = xScale(x);\n const edge = i === 0 ? px <= padL + 0.5 : px >= width - padR - 0.5;\n return {\n key: i === 0 ? 'start' : 'end',\n x: px,\n anchor: edge ? (i === 0 ? 'start' as const : 'end' as const) : 'middle' as const,\n priority: i === 0 ? 2 : 3,\n variants: ladder.map((f) => f(x)),\n };\n }),\n { min: padL, max: width - padR, charPx: axisLabelCh },\n );\n\n function nearestX(clientX: number): number | null {\n const svg = svgRef.current;\n if (!svg) return null;\n const rect = svg.getBoundingClientRect();\n // rect.width equals `width` once measured; the ratio only matters while the\n // fallback width is still being drawn (or a CSS max-width squeezes it).\n const svgX = ((clientX - rect.left) / (rect.width || width)) * width;\n const dataX = xMin + ((svgX - padL) / 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) / width) * (rect.width || 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 ref={wrapRef} className={styles.wrap}>\n <svg\n ref={svgRef}\n className={styles.svg}\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${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={padL}\n x2={width - padR}\n y1={yScale(t)}\n y2={yScale(t)}\n className={styles.gridline}\n stroke={CHART_GRID}\n />\n <text x={padL - 6} y={yScale(t)} dy=\"0.32em\" textAnchor=\"end\" className={styles.axisLabel}>\n {yAxis.labels[i]}\n </text>\n </g>\n ))}\n <line\n x1={padL}\n x2={width - padR}\n y1={height - PAD_B}\n y2={height - PAD_B}\n className={styles.axis}\n stroke={CHART_AXIS}\n />\n {xLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} x={l.x} y={height - 6} textAnchor={l.anchor} className={styles.axisLabel}>\n {l.text}\n </text>\n ))}\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 data-end-label={s.id}\n x={xScale(last.x) + END_LABEL_GAP}\n y={dodged?.get(s.id) ?? 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={padL}\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, useRef, useState } from 'react';\nimport type { CategoricalDatum } from './types.js';\nimport { CHART_SEQUENTIAL, CHART_AXIS, CHART_GRID } from './colors.js';\nimport { useChartWidth } from './useChartWidth.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 width: fixedWidth,\n}: {\n data: CategoricalDatum[];\n height?: number;\n orientation?: 'vertical' | 'horizontal';\n /** Horizontal only: fixed width in px (tests, print). Omit to fill the container. */\n width?: number;\n color?: string;\n formatValue?: (v: number) => string;\n ariaLabel: string;\n}) {\n const uid = useId();\n const wrapRef = useRef<HTMLDivElement>(null);\n // Horizontal bars take the container's measured width (fallback: the old\n // fixed 588 px). A fixed-width svg under the global `svg { max-width: 100% }`\n // was scaled DOWN in a narrower card, shrinking its 10 px labels with it.\n const measuredW = useChartWidth(wrapRef, fixedWidth, 588);\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 svgH = data.length * (rowH + GAP) + GAP;\n const svgW = measuredW;\n const plotW = Math.max(40, svgW - LABEL_W - PAD_R);\n\n return (\n <div ref={wrapRef} 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","/**\n * components/charts/BurnDown.tsx — a quota window burning down to its reset:\n * remaining capacity over time (solid line + wash), the even-pace reference\n * from full at window start to empty at reset (thin dashed), a projection\n * from the recent slope (dashed), an optional reserve line (the headroom kept\n * for interactive use) and the reset marker.\n *\n * The verdict is written in words under the plot — \"At this pace: reserve\n * reached 14:20, 3h 40m before reset\" — so the chart's point never depends on\n * reading slopes. With fewer than two readings it says it cannot project,\n * rather than drawing a guess — and with no plausible reset (0 / NaN /\n * pre-2000) it draws neither pace nor projection and says the reset is\n * unknown, rather than projecting to an invented one.\n */\nimport { useRef } from 'react';\nimport { CHART_SEQUENTIAL, toneColor } from './colors.js';\nimport { ChartFrame, type ChartStatus } from './ChartFrame.js';\nimport { ChartLegend } from './ChartParts.js';\nimport { TableView, type TableColumn } from './TableView.js';\nimport {\n MIN_TIME_SPAN_MS,\n areaPath,\n axisTicks,\n ensureSpan,\n isPlausibleTime,\n labelCharPx,\n layoutAxisLabels,\n linePath,\n linearScale,\n projectBurnDown,\n splitRuns,\n tickGutter,\n type BurnPoint,\n} from './chart-math.js';\nimport { formatCompact, timeLabelLadder } from './format.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport { useTextScale } from './useTextScale.js';\nimport plot from './plot.module.css';\n\nexport interface BurnDownProps {\n title: string;\n description?: string;\n caveat?: string;\n status?: ChartStatus;\n points: BurnPoint[];\n /** Full capacity of the window (e.g. 100 for percent). */\n capacity: number;\n /** Window start and reset, epoch ms. */\n start: number;\n resetAt: number;\n now: number;\n /** Capacity to keep in reserve (same units as `remaining`). */\n reserve?: { value: number; label: string };\n height?: number;\n width?: number;\n formatValue?: (v: number) => string;\n formatTime?: (ms: number) => string;\n ariaLabel?: string;\n}\n\nconst PAD_T = 16;\nconst PAD_B = 26;\nconst PAD_R = 14;\n\nfunction defaultFormatTime(ms: number): string {\n const d = new Date(ms);\n return Number.isNaN(d.getTime()) ? '' : d.toLocaleString('en-US', { weekday: 'short', hour: 'numeric', minute: '2-digit' });\n}\n\nexport function formatLead(ms: number): string {\n const m = Math.max(0, Math.round(ms / 60_000));\n if (m < 60) return `${m}m`;\n const h = Math.floor(m / 60);\n if (h < 48) return m % 60 ? `${h}h ${m % 60}m` : `${h}h`;\n return `${Math.round(h / 24)}d`;\n}\n\n/**\n * The verdict in words. `resetAt` null (or non-finite) is an UNKNOWN reset:\n * what the window has already crossed is still said, but nothing is\n * projected — \"about 40% left at reset\" needs a reset (V3.10.1 review: an\n * epoch-0 reset printed a green verdict for a seat burning 10%/h, and a NaN\n * one printed \"about NaN% left at reset\").\n */\nexport function burnVerdict(\n projection: ReturnType<typeof projectBurnDown>,\n resetAt: number | null,\n formatValue: (v: number) => string,\n formatTime: (ms: number) => string,\n reserveLabel?: string,\n): { text: string; severity: 'ok' | 'warn' | 'danger' | 'unknown' } {\n const reset = resetAt !== null && Number.isFinite(resetAt) ? resetAt : null;\n // Already past a line: say where it IS, not a \"projection\" to a moment\n // that has passed (a used-up seat is not \"running out at 3:02\").\n if (projection.from && projection.from.remaining <= 0) {\n return { text: reset === null ? 'Used up — reset time unknown.' : `Used up — resets ${formatTime(reset)}.`, severity: 'danger' };\n }\n if (projection.from && reserveLabel !== undefined && projection.reserveAt !== null && projection.reserveAt <= projection.from.t) {\n const until = reset === null ? 'until it resets (reset time unknown)' : `until ${formatTime(reset)}`;\n return { text: `Inside ${reserveLabel.toLowerCase()} — autonomy has stopped using this window ${until}.`, severity: 'warn' };\n }\n if (reset === null) return { text: 'Reset time unknown — not projecting this window.', severity: 'unknown' };\n if (projection.slopePerMs === null) return { text: 'Not enough readings to project this window yet.', severity: 'unknown' };\n if (projection.exhaustAt !== null) {\n return {\n text: `At this pace: runs out ${formatTime(projection.exhaustAt)}, ${formatLead(reset - projection.exhaustAt)} before reset.`,\n severity: 'danger',\n };\n }\n if (projection.reserveAt !== null) {\n return {\n text: `At this pace: ${reserveLabel ?? 'reserve'} reached ${formatTime(projection.reserveAt)}, ${formatLead(reset - projection.reserveAt)} before reset.`,\n severity: 'warn',\n };\n }\n return {\n text: `At this pace: about ${formatValue(projection.remainingAtReset ?? 0)} left at reset.`,\n severity: 'ok',\n };\n}\n\nexport function BurnDown({\n title,\n description,\n caveat,\n status,\n points,\n capacity,\n start,\n resetAt,\n now,\n reserve,\n height = 200,\n width: fixedWidth,\n formatValue: formatValueProp,\n formatTime: formatTimeProp,\n ariaLabel,\n}: BurnDownProps) {\n const formatValue = formatValueProp ?? formatCompact;\n const formatTime = formatTimeProp ?? defaultFormatTime;\n const wrapRef = useRef<HTMLDivElement>(null);\n const width = useChartWidth(wrapRef, fixedWidth);\n const textScale = useTextScale();\n // A reading stamped 0 / NaN / pre-2000 is a null timestamp that leaked\n // through: it is not on this window's time axis, and it would drag both\n // the axis and the projection's slope back to 1970.\n const sorted = points.filter((p) => isPlausibleTime(p.t)).sort((a, b) => a.t - b.t);\n const anyKnown = sorted.some((p) => p.remaining !== null);\n const resolvedStatus: ChartStatus = status ?? (sorted.length === 0 ? { kind: 'empty', message: 'No readings in this window yet.' } : anyKnown ? { kind: 'ready' } : { kind: 'unknown' });\n\n // A reset of 0 / NaN / pre-2000 is a null that leaked through (an epoch-0\n // machine reset parses as a finite 0). It is UNKNOWN, not a moment: the\n // axis ends at the latest reading or now with no \"Resets\" on it, no even\n // pace or projection is drawn toward it, and the verdict says the reset is\n // unknown instead of inventing one (V3.10.1 review).\n const resetKnown = isPlausibleTime(resetAt);\n const reset = resetKnown ? resetAt : null;\n const projection = projectBurnDown(sorted, reset, { reserve: reserve?.value ?? null });\n const verdict = burnVerdict(projection, reset, formatValue, formatTime, reserve?.label);\n\n // Always 0 → capacity (100 for percent seats), so sibling cards share one\n // scale; widened only if a reading overshoots, never clipped.\n const known = sorted.flatMap((p) => (p.remaining !== null && Number.isFinite(p.remaining) ? [p.remaining] : []));\n const yAxis = axisTicks(0, Math.max(capacity, ...known, 1), {\n count: 4,\n integer: Number.isInteger(capacity) && known.every((v) => Number.isInteger(v)),\n format: formatValueProp,\n });\n const ticks = yAxis.ticks;\n const top = ticks[ticks.length - 1]!;\n const padL = tickGutter(yAxis.labels, 28, 56, textScale);\n const plotW = Math.max(40, width - padL - PAD_R);\n const plotH = height - PAD_T - PAD_B;\n // The window runs start → reset. An implausible bound (0 / NaN) falls back\n // to the readings; a degenerate one widens to MIN_TIME_SPAN_MS, keeping the\n // right edge where it is.\n const lastT = sorted.length ? sorted[sorted.length - 1]!.t : now;\n const rawEnd = reset ?? Math.max(now, lastT);\n const rawStart = isPlausibleTime(start) ? start : sorted[0]?.t ?? rawEnd;\n const [x0, xEnd] = ensureSpan(rawStart, rawEnd, MIN_TIME_SPAN_MS, 'end');\n const xs = linearScale(x0, xEnd, padL, padL + plotW);\n const ys = linearScale(0, top, PAD_T + plotH, PAD_T);\n const clampX = (t: number) => Math.min(xEnd, Math.max(x0, t));\n\n // x labels: the reset marker outranks the window start. Both walk the same\n // detail ladder (the caller's format → \"Fri 11:46 PM\" → \"Sep 18\"; clock\n // time only inside one day) until they fit side by side; if even the\n // shortest pair collides, the start is dropped rather than overprinted.\n // Widths are budgeted at the operator's Display size. With no known reset\n // the right edge is only the latest reading / now, and says just its time.\n const ladder = timeLabelLadder(x0, xEnd, formatTimeProp ?? defaultFormatTime, [x0, xEnd]);\n const xLabels = layoutAxisLabels(\n [\n { key: 'start', x: padL, anchor: 'start', priority: 2, variants: ladder.map((f) => f(x0)) },\n resetKnown\n ? { key: 'reset', x: padL + plotW, anchor: 'end', priority: 3, variants: ladder.map((f) => `Resets ${f(xEnd)}`) }\n : { key: 'end', x: padL + plotW, anchor: 'end', priority: 3, variants: ladder.map((f) => f(xEnd)) },\n ],\n { min: padL, max: padL + plotW, charPx: labelCharPx(textScale) },\n );\n\n const runs = splitRuns(sorted.map((p) => ({ x: clampX(p.t), y: p.remaining })))\n .map((run) => run.map((p) => ({ x: xs(p.x), y: ys(Math.max(0, p.y)) })));\n\n let projectionPath = '';\n if (reset !== null && projection.from && projection.slopePerMs !== null) {\n const endT = projection.exhaustAt ?? reset;\n const endR = projection.exhaustAt !== null ? 0 : projection.remainingAtReset ?? projection.from.remaining;\n if (endT > projection.from.t) {\n projectionPath = linePath([\n { x: xs(clampX(projection.from.t)), y: ys(projection.from.remaining) },\n { x: xs(clampX(endT)), y: ys(Math.max(0, endR)) },\n ]);\n }\n }\n const projectionColor = verdict.severity === 'danger' ? toneColor('danger') : verdict.severity === 'warn' ? toneColor('warning') : 'var(--text-tertiary)';\n\n const summary = ariaLabel ?? `${title}: ${projection.from ? `${formatValue(projection.from.remaining)} of ${formatValue(capacity)} left at ${formatTime(projection.from.t)}` : 'no readings'}; ${reset === null ? 'reset time unknown' : `resets ${formatTime(reset)}`}. ${verdict.text}`;\n\n const columns: TableColumn<BurnPoint>[] = [\n { key: 't', label: 'When', render: (p) => formatTime(p.t) },\n { key: 'r', label: 'Remaining', numeric: true, render: (p) => (p.remaining === null ? '—' : formatValue(p.remaining)) },\n ];\n\n const legendItems = [\n { label: 'Remaining', color: CHART_SEQUENTIAL, kind: 'line' as const },\n // Even pace runs from full at the window's start to empty AT RESET: with\n // no reset there is no pace to draw.\n ...(resetKnown ? [{ label: 'Even pace', color: 'var(--text-tertiary)', kind: 'line' as const }] : []),\n ...(projectionPath ? [{ label: 'Projection', color: projectionColor, kind: 'line' as const }] : []),\n ];\n\n return (\n <ChartFrame\n title={title}\n description={description}\n caveat={caveat}\n status={resolvedStatus}\n table={<TableView caption={title} columns={columns} rows={sorted} rowKey={(p) => String(p.t)} />}\n footer={\n <>\n <p className={plot.note} data-severity={verdict.severity} role=\"status\">{verdict.text}</p>\n <ChartLegend items={legendItems} />\n </>\n }\n >\n <div ref={wrapRef} className={plot.plotWrap}>\n <svg className={plot.svg} width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={summary}>\n {ticks.map((t, i) => (\n <g key={t}>\n <line className={plot.grid} x1={padL} x2={padL + plotW} y1={ys(t)} y2={ys(t)} />\n <text className={plot.tick} x={padL - 6} y={ys(t)} dy=\"0.32em\" textAnchor=\"end\">{yAxis.labels[i]}</text>\n </g>\n ))}\n <line className={plot.axis} x1={padL} x2={padL + plotW} y1={ys(0)} y2={ys(0)} />\n {xLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} className={plot.tick} x={l.x} y={height - 8} textAnchor={l.anchor}>{l.text}</text>\n ))}\n\n {resetKnown ? (\n <path data-role=\"pace\" className={plot.reference} d={linePath([{ x: xs(x0), y: ys(capacity) }, { x: xs(xEnd), y: ys(0) }])} />\n ) : null}\n {reserve ? (\n <g data-role=\"reserve\">\n <line className={plot.reference} x1={padL} x2={padL + plotW} y1={ys(reserve.value)} y2={ys(reserve.value)} />\n {/* Above-left of the line, over a surface halo (SPEC-310C §6): the\n window's start is the one place the remaining line is always\n high, and the projection only ever runs to the right, so the\n label never sits on the data. */}\n <text data-role=\"reserve-label\" className={`${plot.tick} ${plot.halo}`} x={padL + 4} y={ys(reserve.value) - 5} textAnchor=\"start\">\n {reserve.label} · {formatValue(reserve.value)}\n </text>\n </g>\n ) : null}\n {now > x0 && now < xEnd ? (\n <line className={plot.crosshair} x1={xs(now)} x2={xs(now)} y1={PAD_T} y2={PAD_T + plotH} />\n ) : null}\n {runs.map((run, i) => (\n <g key={i} data-role=\"remaining\">\n <path className={plot.wash} fill={CHART_SEQUENTIAL} d={areaPath(run, run.map((p) => ({ x: p.x, y: ys(0) })))} />\n <path className={plot.line} stroke={CHART_SEQUENTIAL} d={linePath(run)} />\n </g>\n ))}\n {projectionPath ? (\n <path data-role=\"projection\" className={plot.projection} stroke={projectionColor} d={projectionPath} />\n ) : null}\n {projection.from ? (\n <circle className={plot.marker} cx={xs(clampX(projection.from.t))} cy={ys(projection.from.remaining)} r={4} fill={CHART_SEQUENTIAL} />\n ) : null}\n </svg>\n </div>\n </ChartFrame>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._figure_1si9v_1{border:1px solid var(--border-subtle);border-radius:var(--radius-lg);background:var(--bg-surface);padding:var(--space-4);margin:0}._caption_1si9v_12{justify-content:space-between;align-items:baseline;gap:var(--space-3);margin-bottom:var(--space-3);display:flex}._title_1si9v_20{font-size:var(--text-sm-size);font-weight:var(--font-weight-semibold);color:var(--text-primary)}._description_1si9v_26{font-size:var(--text-xs-size);color:var(--text-tertiary)}._plot_1si9v_31{width:100%;overflow-x:auto}._tableDisclosure_1si9v_36{margin-top:var(--space-3);border-top:1px solid var(--border-subtle);padding-top:var(--space-2)}._tableDisclosure_1si9v_36>summary{cursor:pointer;font-size:var(--text-xs-size);color:var(--text-secondary);list-style:none}._tableDisclosure_1si9v_36>summary::-webkit-details-marker{display:none}._tableDisclosure_1si9v_36>summary:before{content:"▸ "}._tableDisclosure_1si9v_36[open]>summary:before{content:"▾ "}._tableBody_1si9v_61{margin-top:var(--space-2)}._caveat_1si9v_65{margin:0 0 var(--space-3);padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);background:var(--status-unknown-bg);color:var(--status-unknown-fg);font-size:var(--text-xs-size);line-height:var(--text-sm-line)}._empty_1si9v_75{color:var(--text-tertiary);font-size:var(--text-sm-size);padding:var(--space-6) 0;text-align:center}._legend_4pgvn_1{gap:var(--space-1) var(--space-4);margin:var(--space-2) 0 0;flex-wrap:wrap;padding:0;list-style:none;display:flex}._item_4pgvn_10{align-items:center;gap:var(--space-2);font-size:var(--text-xs-size);color:var(--text-secondary);display:inline-flex}._swatch_4pgvn_18{border-radius:var(--radius-full);flex:none;width:10px;height:10px}._swatchLine_4pgvn_25{border-radius:var(--radius-full);flex:none;width:14px;height:2px}._svg_1jc17_5{max-width:100%;display:block}._gridline_1jc17_10{stroke:var(--chart-grid);stroke-width:1px}._axis_1jc17_15{stroke:var(--chart-axis);stroke-width:1px}._axisLabel_1jc17_20{font-size:var(--text-xs-size);fill:var(--text-tertiary);font-family:var(--font-ui)}._line_1jc17_26{fill:none;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round}._area_1jc17_33{opacity:.1;stroke:none}._marker_1jc17_38{stroke:var(--chart-surface);stroke-width:2px}._endLabel_1jc17_43{font-size:var(--text-xs-size);font-family:var(--font-ui);font-weight:var(--font-weight-medium)}._crosshairLine_1jc17_49{stroke:var(--chart-axis);stroke-width:1px;pointer-events:none}._overlay_1jc17_55{fill:#0000;cursor:crosshair}._wrap_1jc17_60{width:100%;min-width:0;position:relative}._tooltip_1jc17_66{pointer-events:none;background:var(--chart-tooltip-bg);border:1px solid var(--chart-tooltip-border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);padding:var(--space-2);font-size:var(--text-xs-size);color:var(--text-primary);white-space:nowrap;z-index:var(--z-dropdown);margin-top:-10px;position:absolute;transform:translate(-50%,-100%)}._tooltipDate_1jc17_82{color:var(--text-tertiary);margin-bottom:var(--space-1)}._tooltipRow_1jc17_87{align-items:center;gap:var(--space-1);display:flex}._tooltipKey_1jc17_93{flex:none;width:12px;height:2px}._tooltipValue_1jc17_99{font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums}._tooltipGap_1jc17_104{color:var(--text-tertiary);font-style:italic}._svg_o4jfa_1{display:block;overflow:visible}._bar_o4jfa_6{transition:opacity var(--duration-fast) var(--ease-standard)}._bar_o4jfa_6:hover,._bar_o4jfa_6:focus-visible{opacity:.82}._baseline_o4jfa_15{stroke:var(--chart-axis);stroke-width:1px}._gridline_o4jfa_20{stroke:var(--chart-grid);stroke-width:1px}._axisLabel_o4jfa_25{fill:var(--text-tertiary);font-size:10px;font-family:var(--font-ui)}._valueLabel_o4jfa_31{fill:var(--text-secondary);font-size:10px;font-family:var(--font-ui);font-variant-numeric:tabular-nums}._categoryLabel_o4jfa_38{fill:var(--text-secondary);font-size:10px;font-family:var(--font-ui)}._hitArea_o4jfa_44{fill:#0000;cursor:pointer}._tooltip_o4jfa_49{pointer-events:none;background:var(--chart-tooltip-bg);border:1px solid var(--chart-tooltip-border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);padding:var(--space-1) var(--space-2);font-size:var(--text-xs-size);color:var(--text-primary);white-space:nowrap;z-index:var(--z-dropdown);position:absolute}._tooltipValue_o4jfa_63{font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums}._tooltipLabel_o4jfa_68{color:var(--text-tertiary);margin-left:var(--space-1)}._wrap_o4jfa_73{position:relative}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
async function e(e){try{if(typeof navigator<`u`&&navigator.clipboard&&typeof navigator.clipboard.writeText==`function`)return await navigator.clipboard.writeText(e),!0}catch{}if(typeof document>`u`)return!1;let t=document.createElement(`textarea`);t.value=e,t.setAttribute(`readonly`,``),t.style.position=`fixed`,t.style.opacity=`0`,document.body.appendChild(t),t.select();let n=!1;try{n=typeof document.execCommand==`function`&&document.execCommand(`copy`)}catch{n=!1}return t.remove(),n}export{e as t};
|
|
2
|
+
//# sourceMappingURL=clipboard-DkZdqlxf.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"clipboard-DkZdqlxf.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/clipboard.ts"],"sourcesContent":["/**\n * components/primitives/clipboard.ts — copy text, honestly.\n *\n * The async Clipboard API where the page is allowed it (a secure context,\n * which the desktop webview and localhost are), else a hidden-textarea copy.\n * Resolves false when both fail, so a caller can say \"copy failed\" instead of\n * drawing a check. Style-free on purpose: importing it costs no CSS.\n */\nexport async function copyText(text: string): Promise<boolean> {\n try {\n if (typeof navigator !== 'undefined' && navigator.clipboard && typeof navigator.clipboard.writeText === 'function') {\n await navigator.clipboard.writeText(text);\n return true;\n }\n } catch {\n // fall through to the textarea path\n }\n if (typeof document === 'undefined') return false;\n const area = document.createElement('textarea');\n area.value = text;\n area.setAttribute('readonly', '');\n area.style.position = 'fixed';\n area.style.opacity = '0';\n document.body.appendChild(area);\n area.select();\n let ok = false;\n try {\n ok = typeof document.execCommand === 'function' && document.execCommand('copy');\n } catch {\n ok = false;\n }\n area.remove();\n return ok;\n}\n"],"mappings":"AAQA,eAAsB,EAAS,EAAgC,CAC7D,GAAI,CACF,GAAI,OAAO,UAAc,KAAe,UAAU,WAAa,OAAO,UAAU,UAAU,WAAc,WAEtG,OADA,MAAM,UAAU,UAAU,UAAU,CAAI,EACjC,EAEX,MAAQ,CAER,CACA,GAAI,OAAO,SAAa,IAAa,MAAO,GAC5C,IAAM,EAAO,SAAS,cAAc,UAAU,EAC9C,EAAK,MAAQ,EACb,EAAK,aAAa,WAAY,EAAE,EAChC,EAAK,MAAM,SAAW,QACtB,EAAK,MAAM,QAAU,IACrB,SAAS,KAAK,YAAY,CAAI,EAC9B,EAAK,OAAO,EACZ,IAAI,EAAK,GACT,GAAI,CACF,EAAK,OAAO,SAAS,aAAgB,YAAc,SAAS,YAAY,MAAM,CAChF,MAAQ,CACN,EAAK,EACP,CAEA,OADA,EAAK,OAAO,EACL,CACT"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._body_1kus1_10{gap:var(--space-3);flex-direction:column;min-width:0;display:flex}._actionsRow_1kus1_17{align-items:center;gap:var(--space-2);flex-wrap:wrap;display:flex}._headActions_1kus1_24{align-items:center;gap:var(--space-2);display:inline-flex;position:relative}._meterBlock_1kus1_31{gap:var(--space-1);flex-direction:column;display:flex}._estimateNote_1kus1_37,._muted_1kus1_38{color:var(--text-tertiary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);overflow-wrap:break-word;margin:0}._facts_1kus1_46{color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);overflow-wrap:break-word;margin:0}._link_1kus1_54{color:var(--text-link);font-size:var(--text-xs-size);line-height:var(--text-xs-line);white-space:nowrap;text-decoration:none}._link_1kus1_54:hover{text-decoration:underline}._link_1kus1_54:focus-visible,._linkButton_1kus1_67:focus-visible{outline:2px solid var(--border-focus);outline-offset:2px}._linkButton_1kus1_67{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}._linkButton_1kus1_67:hover{text-decoration:underline}._linkButton_1kus1_67:disabled{color:var(--text-disabled);cursor:default;text-decoration:none}._toggleRow_1kus1_94{align-items:center;gap:var(--space-2) var(--space-3);flex-wrap:wrap;display:flex}._toggleText_1kus1_101{flex:16rem;min-width:0}._tasks_1kus1_108{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}._task_1kus1_108{gap:var(--space-1) var(--space-3);padding:var(--space-2) 0;border-top:1px solid var(--border-subtle);grid-template-columns:auto minmax(0,1fr);display:grid}._task_1kus1_108:first-child{border-top:0}._taskChip_1kus1_128{padding-top:1px}._taskMain_1kus1_132{gap:var(--space-1);flex-direction:column;min-width:0;display:flex}._taskTitle_1kus1_139{color:var(--text-primary);font-size:var(--text-sm-size);line-height:var(--text-sm-line);font-weight:var(--font-weight-medium);overflow-wrap:break-word;margin:0}._taskLinks_1kus1_148{align-items:center;gap:var(--space-1) var(--space-3);flex-wrap:wrap;display:flex}._notice_1kus1_157{padding:var(--space-2) var(--space-3);border:1px solid var(--border-subtle);border-radius:var(--radius-md);background:var(--bg-surface-raised);color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);overflow-wrap:break-word;margin:0}._notice_1kus1_157[data-tone=warning]{border-color:var(--status-warning-solid);background:var(--status-warning-bg);color:var(--status-warning-fg)}._notice_1kus1_157[data-tone=danger]{border-color:var(--status-danger-solid);background:var(--status-danger-bg);color:var(--status-danger-fg)}._notice_1kus1_157[data-tone=success]{border-color:var(--status-success-solid);background:var(--status-success-bg);color:var(--status-success-fg)}._noticeRow_1kus1_187{justify-content:space-between;align-items:baseline;gap:var(--space-1) var(--space-3);flex-wrap:wrap;display:flex}._popover_1kus1_197{top:calc(100% + var(--space-2));z-index:var(--z-dropdown);width:min(26rem, calc(100vw - var(--space-8)));max-height:min(34rem,70vh);padding:var(--space-4);border:1px solid var(--border-default);border-radius:var(--radius-lg);background:var(--bg-surface-raised);box-shadow:var(--shadow-menu);position:absolute;right:0;overflow-y:auto}._popoverTitle_1kus1_212{margin:0 0 var(--space-3);color:var(--text-primary);font-size:var(--text-sm-size);line-height:var(--text-sm-line);font-weight:var(--font-weight-semibold)}._form_1kus1_222{gap:var(--space-3);flex-direction:column;display:flex}._fieldGrid_1kus1_228{gap:var(--space-3);grid-template-columns:repeat(auto-fill,minmax(11rem,1fr));display:grid}._textareaField_1kus1_234{gap:var(--space-1);flex-direction:column;display:flex}._label_1kus1_240{color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);font-weight:var(--font-weight-medium)}._textarea_1kus1_234{min-height:8rem;padding:var(--space-2) var(--space-3);border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--bg-input);color:var(--text-primary);font:inherit;font-size:var(--text-sm-size);line-height:var(--text-sm-line);resize:vertical}._textarea_1kus1_234:focus-visible{outline:2px solid var(--border-focus);outline-offset:0}._textarea_1kus1_234[aria-invalid=true]{border-color:var(--status-danger-solid)}._fieldError_1kus1_269{color:var(--status-danger-fg);font-size:var(--text-xs-size);line-height:var(--text-xs-line);margin:0}._formActions_1kus1_276{justify-content:flex-end;gap:var(--space-2);flex-wrap:wrap;display:flex}._dialogWidth_1kus1_283{width:min(34rem, calc(100vw - var(--space-8)))}._laneChip_1kus1_289[data-active=true]{border-color:var(--status-running-solid)}._sheetAction_1kus1_295{gap:var(--space-2);padding-top:var(--space-3);border-top:1px solid var(--border-subtle);flex-direction:column;display:flex}._standing_1kus1_304{align-items:baseline;gap:var(--space-2);flex-wrap:wrap;min-width:0;margin:0;display:flex}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{o as e}from"./index-QesfXBsb.js";import{D as t}from"./VerseConsoleApp-BCY5uSok.js";import{b as n,y as r}from"./format-Dk4Fmxax.js";import{v as i}from"./context-model-DV1zCfAm.js";import{a,i as o,n as s}from"./types-D5XOdyw8.js";e(((e,t)=>{t.exports={}}))();var c=`[REDACTED]`;function l(e){if(/^[0-9a-fA-F]{40}$/.test(e))return e;let t=e.replace(/^\+/,``).replace(/=+$/,``);return/^(.)\1{39,}$/.test(t)?e:c}var ee=/\d{6,12}:[A-Za-z0-9_-]{33,35}(?![A-Za-z0-9_-])/g;function u(e,t,n){let r=e=>e<0||!/[A-Za-z0-9_]/.test(n[e]);return r(t-1)||n.slice(t-3,t)===`bot`&&r(t-4)?c:e}var d=/(https?:\/\/(?:hooks\.slack\.com\/(?:services|workflows|triggers)|(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks)\/)[A-Za-z0-9_/-]{8,}/gi,f=/(?<![A-Za-z0-9_-])xai-[A-Za-z0-9]{20,}/g,p=String.raw`\s*[=:]\s*["']?[^\s,;'"]{8,}["']?`,m=new RegExp(String.raw`(?<![A-Za-z0-9_$])([A-Z][A-Z0-9_]*_(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|CREDENTIALS?|AUTH|DSN))`+p,`g`),h=new RegExp(String.raw`(?<![A-Za-z0-9_$])([a-z][a-z0-9_]*_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key))`+p,`g`),g=/_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key)\s*[=:]/,_=/(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?)\s*[=:]/,v=new RegExp(String.raw`(?<![A-Za-z0-9_$])([a-z][A-Za-z0-9]*(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?))`+p,`g`),te=/(\\?["'])([A-Za-z0-9_.-]*(?:api[_-]?key|token|secret|password|passwd|pwd|credentials?|private[_-]?key|access[_-]?key|secret[_-]?key|signing[_-]?key|auth|connection[_-]?string))\1(\s*:\s*)(\\?["'])([^"'\s\\]{8,})\4/gi;function y(e){let t=e.replace(/^["']|["']$/g,``);return/^[A-Za-z_$][\w$]*(?:\??\.[A-Za-z_$][\w$]*)+[)\]]*$/.test(t)||/^[A-Za-z_$][\w$.]*\(/.test(t)||/^(?:\$\{|\$[A-Za-z_]|`|<)/.test(t)}function ne(e){let t=e.replace(/^["']|["']$/g,``);return!/\d/.test(t)&&/^[A-Za-z_$][A-Za-z_$.<>[\]|&?!()]*$/.test(t)}function b(e){return e.replace(/^["']|["']$/g,``)===c}function x(e,t,n,r){return b(n)||y(n)||r&&ne(n)?t:`${e}=${c}`}function S(e,t){return e.slice(t.length).replace(/^\s*[=:]\s*/,``)}function C(e){try{let t=e.replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[\s\S]*?-----END[ A-Z]*PRIVATE KEY-----/g,c).replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[^\n]*/g,c).replace(ee,u).replace(d,`$1[REDACTED]`).replace(f,c).replace(/\bsk-[A-Za-z0-9_-]{16,}/g,c).replace(/\bgh[poursa]_[A-Za-z0-9]{16,}/g,c).replace(/\bgithub_pat_[A-Za-z0-9_]{22,}/g,c).replace(/\b(Bearer|Token|Authorization)\s+[A-Za-z0-9\-._~+/]+=*/gi,`$1 [REDACTED]`).replace(/\b(api[_-]?key|api[_-]?token|secret|secret[_-]?key|token|password|passwd|pwd|auth|credential|client[_-]?secret|private[_-]?key|access[_-]?token|auth[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|connection[_-]?string|conn[_-]?str|_?auth[_-]?token|ASHLR_[A-Z_]+)\s*[=:]\s*["']?[^\s,;'"]{8,}["']?/gi,`$1=[REDACTED]`).replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}/gi,c).replace(/\bAKIA[0-9A-Z]{16}\b/g,c).replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,c).replace(/\b[0-9a-fA-F]{64,}\b/g,c).replace(/\bglpat-[A-Za-z0-9_-]{16,}/g,c).replace(/\bhf_[A-Za-z0-9]{16,}\b/g,c).replace(/\bnpm_[A-Za-z0-9]{16,}\b/g,c).replace(/\bAIza[0-9A-Za-z_-]{35}\b/g,c).replace(/(:\/\/[^:\s/@]*:)[^@\s]+(@)/g,`$1[REDACTED]$2`).replace(/(?<![/\w])[A-Za-z0-9+]{40,}={0,2}(?![/\w])/g,l).replace(m,(e,t)=>x(t,e,S(e,t),!1));return g.test(t)&&(t=t.replace(h,(e,t)=>x(t,e,S(e,t),!0))),_.test(t)&&(t=t.replace(v,(e,t)=>x(t,e,S(e,t),!0))),t.replace(te,(e,t,n,r,i,a)=>b(a)||y(a)?e:`${t}${n}${t}${r}${i}${c}${i}`)}catch{return e}}function w(e,t){return r(C(e),t)}var T=a.selfImprove.repo,E=/^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$/,D=/^[A-Za-z0-9._/+-]{1,200}$/;function O(e){return!D.test(e)||e.startsWith(`-`)||e.startsWith(`/`)||e.endsWith(`/`)||e.endsWith(`.`)||e.endsWith(`.lock`)?!1:!e.includes(`..`)&&!e.includes(`//`)}function k(e,t){if(typeof e!=`string`||e.length>2048)return null;try{let n=new URL(e);return n.protocol===`https:`&&n.hostname===t?n.toString():null}catch{return null}}function A(e){if(!Number.isFinite(e))return`—`;let t=Math.abs(e)<.005?0:e,n=Number.isInteger(t)?String(Math.abs(t)):Math.abs(t).toFixed(2);return`${t<0?`−`:``}$${n}`}function j(e){let n=e.creditsTotalUsd,r=e.estimatedRemainingUsd,i=e.budget.selfImprove.reserveUsd,a=n>0?n:null,o=a===null?null:(n-Math.max(0,r))/n*100,s=r<=0?`danger`:r<i?`warning`:`accent`,c=r<=0?`The estimate says the credits are spent. Check the real balance on claude.ai and adjust the budget.`:r<i?`Under the ${A(i)} reserve, so Verse stops launching self-improvement tasks.`:null;return{value:Math.max(0,r),max:a,text:`${A(Math.max(0,r))} of ${A(n)} · estimate`,usedText:o===null?`no credit total set`:`${t(o)} used`,tone:s,warning:c}}function M(e){let t=new Date(e);return t.setHours(24,0,0,0),t.getTime()}function N(e,t=Date.now()){let r=n(new Date(M(t)).toISOString(),t),i=e.running===1?`1 running`:`${e.running} running`;return`${e.sessionsToday} of ${e.budget.maxSessionsPerDay} sessions today · ${i}${r?` · resets ${r}`:``}`}function P(e){let t=e.budget.selfImprove;return t.enabled?`${e.selfImproveToday} of ${t.maxPerDay} self-improvement launches today, on ${t.repo}. Stops under a ${A(t.reserveUsd)} estimated balance.`:`Self-improvement is off. Verse launches cloud tasks only when you ask.`}function F(e,t){return e.ok?null:e.reason?w(e.reason):t}var I=`The Claude seat isn't set up on this Mac.`;function L(e){return e.ready?null:e.reason?w(e.reason):I}var R=`Not set up`;function z(e){return`~$${Number.isFinite(e)?Math.max(0,Math.round(e)):0} credits`}function re(e){return`Cloud: not set up · ${z(e)}`}function B(e,t){return L(e)??F(t.canLaunch,`The cloud budget does not allow another launch right now.`)}var V={queued:`Queued`,launching:`Launching`,running:`Running`,"pr-open":`PR open`,merged:`Merged`,closed:`Closed`,failed:`Failed`,expired:`Expired`},H={queued:`info`,launching:`info`,running:`running`,"pr-open":`warning`,merged:`success`,closed:`neutral`,failed:`danger`,expired:`unknown`};function U(e){return e.state===`pr-open`&&!e.pr?`PR unverified`:e.state===`pr-open`&&e.pr?.draft?`Draft PR`:V[e.state]??e.state}function W(e){return o.includes(e)}function G(e){return e===`queued`||e===`launching`||e===`running`}var K=864e5;function q(e,t=Date.now()){let n=e=>{let n=Date.parse(e.updatedAt);return Number.isFinite(n)&&t-n<K},r=e.filter(e=>!W(e.state)||n(e)).sort((e,t)=>(Date.parse(t.createdAt)||0)-(Date.parse(e.createdAt)||0));return{shown:r.slice(0,6),hidden:Math.max(0,r.length-6)}}function J(e){return e.filter(e=>G(e.state)).length}function Y(e,t=Date.now()){let n=e.state===`queued`||e.state===`launching`?e.createdAt:e.launchedAt??e.createdAt,r=i(n,t),a=e.state===`queued`?`queued`:e.state===`failed`?`tried`:`started`;return`${e.repo} from ${e.baseBranch}${r?` · ${a} ${r}`:``}`}function X(e,t=Date.now()){return e.report?.summary&&(e.state===`pr-open`||e.state===`merged`)?`Cloud session reports (unverified): ${w(e.report.summary,t)}`:e.stateReason?w(e.stateReason,t):null}function ie(e){return e.state!==`merged`&&e.state!==`closed`}var Z=new Intl.NumberFormat(`en-US`);function ae(e){let t={},n=e.repo.trim(),r=e.baseBranch.trim(),i=e.prompt.trim();return n?E.test(n)||(t.repo=`Use the GitHub owner/name form, like ashlrai/ashlr-hub.`):t.repo=`Enter the GitHub repository as owner/name.`,r&&!O(r)&&(t.baseBranch=`That isn't a branch name git accepts.`),i?i.length>2e4&&(t.prompt=`The task is ${Z.format(i.length)} characters; the limit is ${Z.format(s)}.`):t.prompt=`Describe the task for the cloud session.`,Object.keys(t).length>0?{ok:!1,errors:t}:{ok:!0,request:{repo:n,...r?{baseBranch:r}:{},prompt:i}}}var Q=[{field:`total`,label:`Credits on the account`,hint:`What claude.ai says you have.`,money:!0,integer:!1,min:0,max:1e5},{field:`spent`,label:`Already spent`,hint:`Spent before Verse tracked it, or a correction after checking.`,money:!0,integer:!1,min:-1e5,max:1e5},{field:`perSession`,label:`Estimate per session`,hint:`Flat cost Verse counts for each launch.`,money:!0,integer:!1,min:.01,max:1e3},{field:`maxPerDay`,label:`Sessions per day`,hint:`From every origin, counted per local day.`,money:!1,integer:!0,min:0,max:500},{field:`maxConcurrent`,label:`Running at once`,hint:`Launching or running together.`,money:!1,integer:!0,min:1,max:50},{field:`selfImproveMax`,label:`Self-improvement per day`,hint:`Launches Verse may make on its own.`,money:!1,integer:!0,min:0,max:100},{field:`reserve`,label:`Reserve`,hint:`Self-improvement stops under this estimated balance.`,money:!0,integer:!1,min:0,max:1e5}];function $(e){return String(Number.isInteger(e)?e:Math.round(e*100)/100)}function oe(e){return{total:$(e.creditsTotalUsd),spent:$(e.creditsSpentAdjustmentUsd),perSession:$(e.estimatedCostPerSessionUsd),maxPerDay:$(e.maxSessionsPerDay),maxConcurrent:$(e.maxConcurrent),selfImprove:e.selfImprove.enabled,selfImproveMax:$(e.selfImprove.maxPerDay),reserve:$(e.selfImprove.reserveUsd)}}function se(e,t){let n={},r={};for(let t of Q){let i=e[t.field].trim().replace(/^\$/,``),a=i===``?NaN:Number(i);Number.isFinite(a)?t.integer&&!Number.isInteger(a)?n[t.field]=`Enter a whole number.`:a<t.min||a>t.max?n[t.field]=t.money?`Between ${A(t.min)} and ${A(t.max)}.`:`Between ${Z.format(t.min)} and ${Z.format(t.max)}.`:r[t.field]=a:n[t.field]=`Enter a number.`}if(Object.keys(n).length>0)return{ok:!1,errors:n};let i={},a=(e,t)=>Math.abs(e-t)<.005;a(r.total,t.creditsTotalUsd)||(i.creditsTotalUsd=r.total),a(r.spent,t.creditsSpentAdjustmentUsd)||(i.creditsSpentAdjustmentUsd=r.spent),a(r.perSession,t.estimatedCostPerSessionUsd)||(i.estimatedCostPerSessionUsd=r.perSession),a(r.maxPerDay,t.maxSessionsPerDay)||(i.maxSessionsPerDay=r.maxPerDay),a(r.maxConcurrent,t.maxConcurrent)||(i.maxConcurrent=r.maxConcurrent);let o={};return e.selfImprove!==t.selfImprove.enabled&&(o.enabled=e.selfImprove),a(r.selfImproveMax,t.selfImprove.maxPerDay)||(o.maxPerDay=r.selfImproveMax),a(r.reserve,t.selfImprove.reserveUsd)||(o.reserveUsd=r.reserve),Object.keys(o).length>0&&(i.selfImprove=o),{ok:!0,update:i,changed:Object.keys(i).length>0}}function ce(e){return e.overview?L(e.overview.seat)||(e.repo?F(e.overview.budget.canLaunch,`The cloud budget does not allow another launch right now.`)||(e.prompt.trim()?e.prompt.trim().length>2e4?`The message is over ${Z.format(s)} characters — trim it to run it in the cloud.`:null:`Type the task in the message box first.`):e.rootsLoading?`Reading this chat's project…`:`This chat's project has no GitHub origin, so a cloud session has nothing to clone.`):e.overviewReason??`The cloud lane did not answer.`}export{Y as C,X as S,k as _,z as a,N as b,ie as c,A as d,F as f,ce as g,re as h,H as i,q as l,B as m,T as n,oe as o,J as p,R as r,se as s,Q as t,j as u,L as v,ae as w,U as x,P as y};
|
|
2
|
+
//# sourceMappingURL=cloud-model-CX407gPY.js.map
|