@ashlr/hub 3.13.0 → 3.14.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 +74 -0
- package/dist/authority-surface.json +204 -124
- package/dist/build-identity.json +2 -2
- package/dist/cli/authority.js +112 -18
- package/dist/cli/authority.js.map +1 -1
- package/dist/cli/comms.d.ts +33 -19
- package/dist/cli/comms.js +128 -151
- package/dist/cli/comms.js.map +1 -1
- package/dist/cli/completions.js +1 -1
- package/dist/cli/completions.js.map +1 -1
- package/dist/cli/daemon.js +29 -0
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/director.d.ts +8 -12
- package/dist/cli/director.js +17 -52
- package/dist/cli/director.js.map +1 -1
- package/dist/cli/fleet.js +4 -1
- package/dist/cli/fleet.js.map +1 -1
- package/dist/cli/help.js +1 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/leader.d.ts +27 -3
- package/dist/cli/leader.js +253 -4
- package/dist/cli/leader.js.map +1 -1
- package/dist/core/authority/server-enforcement.d.ts +110 -0
- package/dist/core/authority/server-enforcement.js +260 -0
- package/dist/core/authority/server-enforcement.js.map +1 -0
- package/dist/core/authority/standing-grant.d.ts +24 -4
- package/dist/core/authority/standing-grant.js +19 -3
- package/dist/core/authority/standing-grant.js.map +1 -1
- package/dist/core/cloud/timeline.js +13 -7
- package/dist/core/cloud/timeline.js.map +1 -1
- package/dist/core/comms/change-digest.d.ts +130 -0
- package/dist/core/comms/change-digest.js +451 -0
- package/dist/core/comms/change-digest.js.map +1 -0
- package/dist/core/comms/director-prompt.d.ts +4 -5
- package/dist/core/comms/director-prompt.js +4 -71
- package/dist/core/comms/director-prompt.js.map +1 -1
- package/dist/core/comms/director.d.ts +24 -61
- package/dist/core/comms/director.js +29 -382
- package/dist/core/comms/director.js.map +1 -1
- package/dist/core/comms/dispatch.d.ts +37 -12
- package/dist/core/comms/dispatch.js +244 -177
- package/dist/core/comms/dispatch.js.map +1 -1
- package/dist/core/comms/elon-dialogue.d.ts +23 -15
- package/dist/core/comms/elon-dialogue.js +36 -307
- package/dist/core/comms/elon-dialogue.js.map +1 -1
- package/dist/core/comms/fleet-pulse.js +4 -7
- package/dist/core/comms/fleet-pulse.js.map +1 -1
- package/dist/core/comms/handlers.d.ts +10 -6
- package/dist/core/comms/handlers.js +14 -48
- package/dist/core/comms/handlers.js.map +1 -1
- package/dist/core/comms/migrations.d.ts +47 -0
- package/dist/core/comms/migrations.js +125 -0
- package/dist/core/comms/migrations.js.map +1 -0
- package/dist/core/comms/requests.d.ts +32 -5
- package/dist/core/comms/requests.js +101 -5
- package/dist/core/comms/requests.js.map +1 -1
- package/dist/core/comms/telegram-channel.d.ts +104 -0
- package/dist/core/comms/telegram-channel.js +622 -0
- package/dist/core/comms/telegram-channel.js.map +1 -0
- package/dist/core/comms/telegram-thread-map.d.ts +56 -0
- package/dist/core/comms/telegram-thread-map.js +144 -0
- package/dist/core/comms/telegram-thread-map.js.map +1 -0
- package/dist/core/daemon/capacity-publisher.d.ts +8 -1
- package/dist/core/daemon/capacity-publisher.js +40 -2
- package/dist/core/daemon/capacity-publisher.js.map +1 -1
- package/dist/core/daemon/loop.js +18 -4
- package/dist/core/daemon/loop.js.map +1 -1
- package/dist/core/daemon/tick-deadline.d.ts +44 -0
- package/dist/core/daemon/tick-deadline.js +83 -0
- package/dist/core/daemon/tick-deadline.js.map +1 -0
- package/dist/core/daemon/tick-hooks.d.ts +7 -0
- package/dist/core/daemon/tick-hooks.js.map +1 -1
- package/dist/core/daemon/tick-progress.d.ts +39 -0
- package/dist/core/daemon/tick-progress.js +194 -0
- package/dist/core/daemon/tick-progress.js.map +1 -0
- package/dist/core/dashboard.js +3 -1
- package/dist/core/dashboard.js.map +1 -1
- package/dist/core/fleet/fleet-merge-state.d.ts +6 -0
- package/dist/core/fleet/fleet-merge-state.js.map +1 -1
- package/dist/core/fleet/host-merge.d.ts +9 -0
- package/dist/core/fleet/host-merge.js +13 -2
- package/dist/core/fleet/host-merge.js.map +1 -1
- package/dist/core/fleet/merge-gates.d.ts +13 -0
- package/dist/core/fleet/merge-gates.js +14 -0
- package/dist/core/fleet/merge-gates.js.map +1 -1
- package/dist/core/fleet/mirrors.d.ts +162 -6
- package/dist/core/fleet/mirrors.js +1051 -49
- package/dist/core/fleet/mirrors.js.map +1 -1
- package/dist/core/fleet/standing-merge-pass.d.ts +8 -0
- package/dist/core/fleet/standing-merge-pass.js +72 -1
- package/dist/core/fleet/standing-merge-pass.js.map +1 -1
- package/dist/core/fleet/status.d.ts +17 -0
- package/dist/core/fleet/status.js +22 -0
- package/dist/core/fleet/status.js.map +1 -1
- package/dist/core/fleet/tick-hooks-live.d.ts +1 -1
- package/dist/core/fleet/tick-hooks-live.js +13 -3
- package/dist/core/fleet/tick-hooks-live.js.map +1 -1
- package/dist/core/git.d.ts +17 -0
- package/dist/core/git.js +124 -25
- package/dist/core/git.js.map +1 -1
- package/dist/core/goals/open-goals.d.ts +47 -0
- package/dist/core/goals/open-goals.js +33 -0
- package/dist/core/goals/open-goals.js.map +1 -0
- package/dist/core/inbox/merge.d.ts +5 -0
- package/dist/core/inbox/merge.js +58 -2
- package/dist/core/inbox/merge.js.map +1 -1
- package/dist/core/integrations/locus.d.ts +28 -0
- package/dist/core/integrations/locus.js +155 -30
- package/dist/core/integrations/locus.js.map +1 -1
- package/dist/core/integrations/telegram-format.d.ts +40 -0
- package/dist/core/integrations/telegram-format.js +123 -0
- package/dist/core/integrations/telegram-format.js.map +1 -0
- package/dist/core/integrations/telegram.d.ts +60 -4
- package/dist/core/integrations/telegram.js +161 -28
- package/dist/core/integrations/telegram.js.map +1 -1
- package/dist/core/mcp-registry.d.ts +12 -0
- package/dist/core/mcp-registry.js +70 -0
- package/dist/core/mcp-registry.js.map +1 -1
- package/dist/core/observability/rollup.d.ts +12 -10
- package/dist/core/observability/rollup.js +44 -17
- package/dist/core/observability/rollup.js.map +1 -1
- package/dist/core/resources/connection-monitor.d.ts +9 -0
- package/dist/core/resources/connection-monitor.js +19 -9
- package/dist/core/resources/connection-monitor.js.map +1 -1
- package/dist/core/resources/quota-refresh-lease.d.ts +17 -0
- package/dist/core/resources/quota-refresh-lease.js +34 -1
- package/dist/core/resources/quota-refresh-lease.js.map +1 -1
- package/dist/core/routing/budget-api.d.ts +7 -1
- package/dist/core/routing/budget-api.js +56 -2
- package/dist/core/routing/budget-api.js.map +1 -1
- package/dist/core/routing/readiness-types.d.ts +82 -0
- package/dist/core/routing/readiness-types.js +23 -0
- package/dist/core/routing/readiness-types.js.map +1 -0
- package/dist/core/routing/readiness.d.ts +103 -0
- package/dist/core/routing/readiness.js +480 -0
- package/dist/core/routing/readiness.js.map +1 -0
- package/dist/core/sandbox/confine.js +22 -1
- package/dist/core/sandbox/confine.js.map +1 -1
- package/dist/core/sandbox/policy.d.ts +23 -0
- package/dist/core/sandbox/policy.js +100 -0
- package/dist/core/sandbox/policy.js.map +1 -1
- package/dist/core/types.d.ts +13 -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 +1204 -939
- package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +1319 -1054
- package/dist/core/usage/frontier-usage.d.ts +20 -2
- package/dist/core/usage/frontier-usage.js +75 -17
- package/dist/core/usage/frontier-usage.js.map +1 -1
- package/dist/core/verse/accounts.d.ts +45 -0
- package/dist/core/verse/accounts.js +246 -17
- package/dist/core/verse/accounts.js.map +1 -1
- package/dist/core/verse/apps-api.js +23 -11
- package/dist/core/verse/apps-api.js.map +1 -1
- package/dist/core/verse/apps.d.ts +11 -9
- package/dist/core/verse/apps.js +2 -2
- package/dist/core/verse/apps.js.map +1 -1
- package/dist/core/verse/authority-api.d.ts +8 -2
- package/dist/core/verse/authority-api.js +40 -5
- package/dist/core/verse/authority-api.js.map +1 -1
- package/dist/core/verse/autonomy-ladder.d.ts +172 -0
- package/dist/core/verse/autonomy-ladder.js +251 -0
- package/dist/core/verse/autonomy-ladder.js.map +1 -0
- package/dist/core/verse/context-fit.js +7 -5
- package/dist/core/verse/context-fit.js.map +1 -1
- package/dist/core/verse/control-api.d.ts +23 -1
- package/dist/core/verse/control-api.js +117 -10
- package/dist/core/verse/control-api.js.map +1 -1
- package/dist/core/verse/fleet-live-api.js +13 -5
- package/dist/core/verse/fleet-live-api.js.map +1 -1
- package/dist/core/verse/folder-io.d.ts +50 -0
- package/dist/core/verse/folder-io.js +142 -0
- package/dist/core/verse/folder-io.js.map +1 -0
- package/dist/core/verse/git-api.js +5 -4
- package/dist/core/verse/git-api.js.map +1 -1
- package/dist/core/verse/git-ops.d.ts +10 -1
- package/dist/core/verse/git-ops.js +18 -2
- package/dist/core/verse/git-ops.js.map +1 -1
- package/dist/core/verse/github-api.d.ts +1 -1
- package/dist/core/verse/github-api.js +5 -4
- package/dist/core/verse/github-api.js.map +1 -1
- package/dist/core/verse/github-repo.js +118 -14
- package/dist/core/verse/github-repo.js.map +1 -1
- package/dist/core/verse/leader-api.d.ts +5 -4
- package/dist/core/verse/leader-api.js +237 -10
- package/dist/core/verse/leader-api.js.map +1 -1
- package/dist/core/verse/local-models.d.ts +10 -0
- package/dist/core/verse/local-models.js +10 -1
- package/dist/core/verse/local-models.js.map +1 -1
- package/dist/core/verse/login-path.d.ts +73 -0
- package/dist/core/verse/login-path.js +123 -14
- package/dist/core/verse/login-path.js.map +1 -1
- package/dist/core/verse/mcp-control-api.js +4 -4
- package/dist/core/verse/mcp-control-api.js.map +1 -1
- package/dist/core/verse/mcp-scope.d.ts +22 -0
- package/dist/core/verse/mcp-scope.js +41 -1
- package/dist/core/verse/mcp-scope.js.map +1 -1
- package/dist/core/verse/mcp-seat-view.d.ts +10 -0
- package/dist/core/verse/mcp-seat-view.js +30 -4
- package/dist/core/verse/mcp-seat-view.js.map +1 -1
- package/dist/core/verse/overnight-api.js +20 -2
- package/dist/core/verse/overnight-api.js.map +1 -1
- package/dist/core/verse/path-guard.d.ts +24 -0
- package/dist/core/verse/path-guard.js +91 -22
- package/dist/core/verse/path-guard.js.map +1 -1
- package/dist/core/verse/preview-api.js +22 -0
- package/dist/core/verse/preview-api.js.map +1 -1
- package/dist/core/verse/projects.d.ts +21 -0
- package/dist/core/verse/projects.js +82 -0
- package/dist/core/verse/projects.js.map +1 -1
- package/dist/core/verse/session-controls-api.js +5 -3
- package/dist/core/verse/session-controls-api.js.map +1 -1
- package/dist/core/verse/session-handoff.d.ts +26 -0
- package/dist/core/verse/session-handoff.js +90 -12
- package/dist/core/verse/session-handoff.js.map +1 -1
- package/dist/core/verse/terminal-api.js +7 -4
- package/dist/core/verse/terminal-api.js.map +1 -1
- package/dist/core/verse/terminal.js +9 -5
- package/dist/core/verse/terminal.js.map +1 -1
- package/dist/core/verse/verse-api.js +81 -27
- package/dist/core/verse/verse-api.js.map +1 -1
- package/dist/core/verse/workspaces.d.ts +51 -0
- package/dist/core/verse/workspaces.js +177 -47
- package/dist/core/verse/workspaces.js.map +1 -1
- package/dist/core/vision/leader-apply.d.ts +40 -0
- package/dist/core/vision/leader-apply.js +101 -30
- package/dist/core/vision/leader-apply.js.map +1 -1
- package/dist/core/vision/leader-cadence.d.ts +114 -0
- package/dist/core/vision/leader-cadence.js +127 -0
- package/dist/core/vision/leader-cadence.js.map +1 -0
- package/dist/core/vision/leader-goal-evidence.d.ts +25 -0
- package/dist/core/vision/leader-goal-evidence.js +36 -0
- package/dist/core/vision/leader-goal-evidence.js.map +1 -0
- package/dist/core/vision/leader-health.d.ts +53 -0
- package/dist/core/vision/leader-health.js +92 -0
- package/dist/core/vision/leader-health.js.map +1 -0
- package/dist/core/vision/leader-operator.d.ts +176 -0
- package/dist/core/vision/leader-operator.js +355 -0
- package/dist/core/vision/leader-operator.js.map +1 -0
- package/dist/core/vision/leader-run-chain.d.ts +41 -0
- package/dist/core/vision/leader-run-chain.js +54 -0
- package/dist/core/vision/leader-run-chain.js.map +1 -0
- package/dist/core/vision/leader-seat-plan.d.ts +68 -0
- package/dist/core/vision/leader-seat-plan.js +93 -0
- package/dist/core/vision/leader-seat-plan.js.map +1 -0
- package/dist/core/vision/leader-seat.d.ts +71 -5
- package/dist/core/vision/leader-seat.js +235 -33
- package/dist/core/vision/leader-seat.js.map +1 -1
- package/dist/core/vision/leader-thread-types.d.ts +104 -0
- package/dist/core/vision/leader-thread-types.js +9 -0
- package/dist/core/vision/leader-thread-types.js.map +1 -0
- package/dist/core/vision/leader-thread.d.ts +138 -0
- package/dist/core/vision/leader-thread.js +926 -0
- package/dist/core/vision/leader-thread.js.map +1 -0
- package/dist/core/vision/leader-types.d.ts +75 -1
- package/dist/core/vision/leader.d.ts +88 -18
- package/dist/core/vision/leader.js +269 -69
- package/dist/core/vision/leader.js.map +1 -1
- package/dist/core/web/public/next/assets/{ActionMenu-Dwjk6rUQ.js → ActionMenu-CIiX2X8w.js} +2 -2
- package/dist/core/web/public/next/assets/{ActionMenu-Dwjk6rUQ.js.map → ActionMenu-CIiX2X8w.js.map} +1 -1
- package/dist/core/web/public/next/assets/Advanced-DHsysoIL.js +2 -0
- package/dist/core/web/public/next/assets/{Advanced-cVYTAsfB.js.map → Advanced-DHsysoIL.js.map} +1 -1
- package/dist/core/web/public/next/assets/{App-IsaWDsdF.js → App-CMeAocmW.js} +5 -5
- package/dist/core/web/public/next/assets/{App-IsaWDsdF.js.map → App-CMeAocmW.js.map} +1 -1
- package/dist/core/web/public/next/assets/AppsSection-DISYnMnc.js +2 -0
- package/dist/core/web/public/next/assets/{AppsSection-DDqeSrty.js.map → AppsSection-DISYnMnc.js.map} +1 -1
- package/dist/core/web/public/next/assets/AreaTrend-DK2Y2TbZ.js +2 -0
- package/dist/core/web/public/next/assets/AreaTrend-DK2Y2TbZ.js.map +1 -0
- package/dist/core/web/public/next/assets/{AutonomyOffState-CpFYS3tQ.js → AutonomyOffState-CEPSZToP.js} +3 -3
- package/dist/core/web/public/next/assets/{AutonomyOffState-CpFYS3tQ.js.map → AutonomyOffState-CEPSZToP.js.map} +1 -1
- package/dist/core/web/public/next/assets/AutonomySection-DWc3ciAD.js +2 -0
- package/dist/core/web/public/next/assets/{AutonomySection-Dwn8UtOy.js.map → AutonomySection-DWc3ciAD.js.map} +1 -1
- package/dist/core/web/public/next/assets/AutonomyStatus-CYaHjJ9U.js +2 -0
- package/dist/core/web/public/next/assets/AutonomyStatus-CYaHjJ9U.js.map +1 -0
- package/dist/core/web/public/next/assets/{BranchBar-ISZ7xUCj.js → BranchBar-BxhdiIpx.js} +2 -2
- package/dist/core/web/public/next/assets/{BranchBar-ISZ7xUCj.js.map → BranchBar-BxhdiIpx.js.map} +1 -1
- package/dist/core/web/public/next/assets/{BudgetControl-BARVp-En.js → BudgetControl-C-0KhjRS.js} +2 -2
- package/dist/core/web/public/next/assets/{BudgetControl-BARVp-En.js.map → BudgetControl-C-0KhjRS.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Button-DtE0rlWD.js → Button-D90dzI_o.js} +2 -2
- package/dist/core/web/public/next/assets/{Button-DtE0rlWD.js.map → Button-D90dzI_o.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CapacityStrip-DKbKA_Aa.js → CapacityStrip-qKDBC65C.js} +2 -2
- package/dist/core/web/public/next/assets/{CapacityStrip-DKbKA_Aa.js.map → CapacityStrip-qKDBC65C.js.map} +1 -1
- package/dist/core/web/public/next/assets/ChartFrame-DY-GVUb3.js +2 -0
- package/dist/core/web/public/next/assets/ChartFrame-DY-GVUb3.js.map +1 -0
- package/dist/core/web/public/next/assets/ChartFrame-DyjmyV8N.css +1 -0
- package/dist/core/web/public/next/assets/ChatSection-DlT4QU6a.js +3 -0
- package/dist/core/web/public/next/assets/{ChatSection-C9myY4ei.js.map → ChatSection-DlT4QU6a.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CloudBudgetForm-CvjK4Oh6.js → CloudBudgetForm-BrNun_Yu.js} +2 -2
- package/dist/core/web/public/next/assets/{CloudBudgetForm-CvjK4Oh6.js.map → CloudBudgetForm-BrNun_Yu.js.map} +1 -1
- package/dist/core/web/public/next/assets/CommandPalette-C5lDDKN0.js +2 -0
- package/dist/core/web/public/next/assets/CommandPalette-C5lDDKN0.js.map +1 -0
- package/dist/core/web/public/next/assets/CommandSection-B0xuU-yZ.css +1 -0
- package/dist/core/web/public/next/assets/CommandSection-DXFvPgKp.js +3 -0
- package/dist/core/web/public/next/assets/CommandSection-DXFvPgKp.js.map +1 -0
- package/dist/core/web/public/next/assets/{ConfirmDialog-CLUhzaBj.js → ConfirmDialog-BR4nZQ2D.js} +2 -2
- package/dist/core/web/public/next/assets/{ConfirmDialog-CLUhzaBj.js.map → ConfirmDialog-BR4nZQ2D.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DeleteChatDialog-C_eDhV8b.js → DeleteChatDialog-BCfP12GH.js} +2 -2
- package/dist/core/web/public/next/assets/{DeleteChatDialog-C_eDhV8b.js.map → DeleteChatDialog-BCfP12GH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Dialog-BRd_B9OE.js → Dialog-D3msQlCj.js} +2 -2
- package/dist/core/web/public/next/assets/{Dialog-BRd_B9OE.js.map → Dialog-D3msQlCj.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffPane-Cpr9soB2.js → DiffPane-Ix6hvXlY.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffPane-Cpr9soB2.js.map → DiffPane-Ix6hvXlY.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffViewer-CNwd0W3Q.js → DiffViewer-C4WKsCIe.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffViewer-CNwd0W3Q.js.map → DiffViewer-C4WKsCIe.js.map} +1 -1
- package/dist/core/web/public/next/assets/DockHost-aWP7liri.js +2 -0
- package/dist/core/web/public/next/assets/{DockHost-BcEq2qaS.js.map → DockHost-aWP7liri.js.map} +1 -1
- package/dist/core/web/public/next/assets/{EmptyState-DsN1H6MC.js → EmptyState-D2IRy3Cg.js} +2 -2
- package/dist/core/web/public/next/assets/{EmptyState-DsN1H6MC.js.map → EmptyState-D2IRy3Cg.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Epistemic-fycQTBRO.js → Epistemic-DMr18muX.js} +2 -2
- package/dist/core/web/public/next/assets/{Epistemic-fycQTBRO.js.map → Epistemic-DMr18muX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{EvidenceTimeline-sCCAdnBK.js → EvidenceTimeline-DXmmz6Fi.js} +2 -2
- package/dist/core/web/public/next/assets/{EvidenceTimeline-sCCAdnBK.js.map → EvidenceTimeline-DXmmz6Fi.js.map} +1 -1
- package/dist/core/web/public/next/assets/FleetSection-BfplcwFU.js +3 -0
- package/dist/core/web/public/next/assets/FleetSection-BfplcwFU.js.map +1 -0
- package/dist/core/web/public/next/assets/Funnel-Dh2yVHws.js +2 -0
- package/dist/core/web/public/next/assets/Funnel-Dh2yVHws.js.map +1 -0
- package/dist/core/web/public/next/assets/{GearTray-CpDt0xwj.js → GearTray-Dt-ee32-.js} +2 -2
- package/dist/core/web/public/next/assets/{GearTray-CpDt0xwj.js.map → GearTray-Dt-ee32-.js.map} +1 -1
- package/dist/core/web/public/next/assets/GrowthSection-P9EUfGeA.js +2 -0
- package/dist/core/web/public/next/assets/{GrowthSection-BvZezOsX.js.map → GrowthSection-P9EUfGeA.js.map} +1 -1
- package/dist/core/web/public/next/assets/{HandoffDialog-B1G6gQyk.js → HandoffDialog-CLJQLe7M.js} +2 -2
- package/dist/core/web/public/next/assets/{HandoffDialog-B1G6gQyk.js.map → HandoffDialog-CLJQLe7M.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Input-CI0yBHmn.js → Input-D_KRJA9V.js} +2 -2
- package/dist/core/web/public/next/assets/{Input-CI0yBHmn.js.map → Input-D_KRJA9V.js.map} +1 -1
- package/dist/core/web/public/next/assets/LeaderCard-D-7DlJuR.js +2 -0
- package/dist/core/web/public/next/assets/LeaderCard-D-7DlJuR.js.map +1 -0
- package/dist/core/web/public/next/assets/LeaderCard-DNsbLwY3.css +1 -0
- package/dist/core/web/public/next/assets/LeaderConversation-DGZjWI-E.js +2 -0
- package/dist/core/web/public/next/assets/LeaderConversation-DGZjWI-E.js.map +1 -0
- package/dist/core/web/public/next/assets/LeaderConversation-DPHUTq6W.css +1 -0
- package/dist/core/web/public/next/assets/MatrixHeatmap-C7BCG2d7.js +2 -0
- package/dist/core/web/public/next/assets/MatrixHeatmap-C7BCG2d7.js.map +1 -0
- package/dist/core/web/public/next/assets/McpSection-DGbRcyv8.js +2 -0
- package/dist/core/web/public/next/assets/{McpSection-nuXer4K-.js.map → McpSection-DGbRcyv8.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdown-BCe4TsXk.js → MessageMarkdown-DFvk06qG.js} +3 -3
- package/dist/core/web/public/next/assets/{MessageMarkdown-BCe4TsXk.js.map → MessageMarkdown-DFvk06qG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DL3LU5kL.js → MessageMarkdownRenderer-BAv4oEUf.js} +2 -2
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DL3LU5kL.js.map → MessageMarkdownRenderer-BAv4oEUf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Meter-b69LM0mU.js → Meter-CMj-VafN.js} +2 -2
- package/dist/core/web/public/next/assets/{Meter-b69LM0mU.js.map → Meter-CMj-VafN.js.map} +1 -1
- package/dist/core/web/public/next/assets/MindSection-C6kLPIjt.js +3 -0
- package/dist/core/web/public/next/assets/MindSection-C6kLPIjt.js.map +1 -0
- package/dist/core/web/public/next/assets/{MutationTokenDialog-Bm34BNVV.js → MutationTokenDialog-DbnO8aYi.js} +2 -2
- package/dist/core/web/public/next/assets/{MutationTokenDialog-Bm34BNVV.js.map → MutationTokenDialog-DbnO8aYi.js.map} +1 -1
- package/dist/core/web/public/next/assets/NeedsYouDrawer-crsiX-Nc.js +3 -0
- package/dist/core/web/public/next/assets/NeedsYouDrawer-crsiX-Nc.js.map +1 -0
- package/dist/core/web/public/next/assets/{NeedsYouList-D5Kk549g.js → NeedsYouList-CCsijdWt.js} +2 -2
- package/dist/core/web/public/next/assets/{NeedsYouList-D5Kk549g.js.map → NeedsYouList-CCsijdWt.js.map} +1 -1
- package/dist/core/web/public/next/assets/NewChatDialog-BlCHtOIr.js +3 -0
- package/dist/core/web/public/next/assets/{NewChatDialog-BqFTWgHU.js.map → NewChatDialog-BlCHtOIr.js.map} +1 -1
- package/dist/core/web/public/next/assets/{OnboardingFlow-DcDsguAM.js → OnboardingFlow-Cy9BA9eR.js} +3 -3
- package/dist/core/web/public/next/assets/{OnboardingFlow-DcDsguAM.js.map → OnboardingFlow-Cy9BA9eR.js.map} +1 -1
- package/dist/core/web/public/next/assets/OnboardingGate-BXpNFoLt.js +3 -0
- package/dist/core/web/public/next/assets/{OnboardingGate-BZafM1Vf.js.map → OnboardingGate-BXpNFoLt.js.map} +1 -1
- package/dist/core/web/public/next/assets/PreviewPane-COid5A0f.js +2 -0
- package/dist/core/web/public/next/assets/{PreviewPane-zT3gK9TD.js.map → PreviewPane-COid5A0f.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ProviderLogo-AwHn2sKm.js → ProviderLogo-Cq-CYIwT.js} +2 -2
- package/dist/core/web/public/next/assets/{ProviderLogo-AwHn2sKm.js.map → ProviderLogo-Cq-CYIwT.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RailStatus-xHrovWvI.js → RailStatus-Co5UB6We.js} +2 -2
- package/dist/core/web/public/next/assets/{RailStatus-xHrovWvI.js.map → RailStatus-Co5UB6We.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RefreshIndicator-SEFZlMB2.js → RefreshIndicator-DO9ibnSq.js} +2 -2
- package/dist/core/web/public/next/assets/{RefreshIndicator-SEFZlMB2.js.map → RefreshIndicator-DO9ibnSq.js.map} +1 -1
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-Dr2WRgkq.js +7 -0
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-CAxPQ4sZ.js.map → ResourcePoolConsoleApp-Dr2WRgkq.js.map} +1 -1
- package/dist/core/web/public/next/assets/ResourcesChrome-CwMnbqI1.js +3 -0
- package/dist/core/web/public/next/assets/ResourcesChrome-CwMnbqI1.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-B_Xp_JNc.js +2 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-B_Xp_JNc.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-DrGoO8KG.css +1 -0
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-C8WGiixc.js → RouteErrorBoundary-SkNhhUbt.js} +2 -2
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-C8WGiixc.js.map → RouteErrorBoundary-SkNhhUbt.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RunInCloudAction-1-IPLYhf.js → RunInCloudAction-BXPlZwJQ.js} +2 -2
- package/dist/core/web/public/next/assets/{RunInCloudAction-1-IPLYhf.js.map → RunInCloudAction-BXPlZwJQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SeatSelector-DpwNiX8F.js → SeatSelector-J5R3zDkB.js} +3 -3
- package/dist/core/web/public/next/assets/{SeatSelector-DpwNiX8F.js.map → SeatSelector-J5R3zDkB.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Segmented-Wt1ATod9.js → Segmented-CGh_-tBb.js} +2 -2
- package/dist/core/web/public/next/assets/{Segmented-Wt1ATod9.js.map → Segmented-CGh_-tBb.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Select-By-V9lMc.js → Select-CWnmUzs3.js} +2 -2
- package/dist/core/web/public/next/assets/{Select-By-V9lMc.js.map → Select-CWnmUzs3.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionGate-WROS02tK.js → SessionGate-sp4KsnUo.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionGate-WROS02tK.js.map → SessionGate-sp4KsnUo.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionInsightChip-DNUcruwp.js → SessionInsightChip-DLFAzdbi.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionInsightChip-DNUcruwp.js.map → SessionInsightChip-DLFAzdbi.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionSearch-UHtt7a8f.js → SessionSearch-DbFjwR1h.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionSearch-UHtt7a8f.js.map → SessionSearch-DbFjwR1h.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SettingsSection-Bf74l0Gj.js → SettingsSection-Ch23msJ5.js} +2 -2
- package/dist/core/web/public/next/assets/SettingsSection-Ch23msJ5.js.map +1 -0
- package/dist/core/web/public/next/assets/{SetupChecklist-CzpEcfOl.js → SetupChecklist-Bd76MBAR.js} +2 -2
- package/dist/core/web/public/next/assets/{SetupChecklist-CzpEcfOl.js.map → SetupChecklist-Bd76MBAR.js.map} +1 -1
- package/dist/core/web/public/next/assets/ShadowDecisions-C5RAY91f.js +3 -0
- package/dist/core/web/public/next/assets/ShadowDecisions-C5RAY91f.js.map +1 -0
- package/dist/core/web/public/next/assets/{Sheet-HkBOBMTT.js → Sheet-BZ2AG4Eo.js} +2 -2
- package/dist/core/web/public/next/assets/{Sheet-HkBOBMTT.js.map → Sheet-BZ2AG4Eo.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-DiigiT8H.js → ShortcutsOverlay-C8n8y3zf.js} +2 -2
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-DiigiT8H.js.map → ShortcutsOverlay-C8n8y3zf.js.map} +1 -1
- package/dist/core/web/public/next/assets/Sidebar-DN--cPYN.js +3 -0
- package/dist/core/web/public/next/assets/{Sidebar-C9YtBYVZ.js.map → Sidebar-DN--cPYN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Slider-DaEDws-b.js → Slider-KVoJLDD6.js} +2 -2
- package/dist/core/web/public/next/assets/{Slider-DaEDws-b.js.map → Slider-KVoJLDD6.js.map} +1 -1
- package/dist/core/web/public/next/assets/StatTile-C4KgjltA.js +2 -0
- package/dist/core/web/public/next/assets/StatTile-C4KgjltA.js.map +1 -0
- package/dist/core/web/public/next/assets/StatTile-CNCqDoPO.css +1 -0
- package/dist/core/web/public/next/assets/{StatusBadge-CXG3iNL4.js → StatusBadge-CXsYqmdU.js} +2 -2
- package/dist/core/web/public/next/assets/{StatusBadge-CXG3iNL4.js.map → StatusBadge-CXsYqmdU.js.map} +1 -1
- package/dist/core/web/public/next/assets/StepBand-BMtVOFpK.js +2 -0
- package/dist/core/web/public/next/assets/StepBand-BMtVOFpK.js.map +1 -0
- package/dist/core/web/public/next/assets/{Surface-5bNA08tK.js → Surface-BfDmQcKe.js} +2 -2
- package/dist/core/web/public/next/assets/{Surface-5bNA08tK.js.map → Surface-BfDmQcKe.js.map} +1 -1
- package/dist/core/web/public/next/assets/Swimlane-B9Exxekk.js +2 -0
- package/dist/core/web/public/next/assets/Swimlane-B9Exxekk.js.map +1 -0
- package/dist/core/web/public/next/assets/Swimlane-Bf4Rjoy9.css +1 -0
- package/dist/core/web/public/next/assets/{Switch-BmCzfFnu.js → Switch-9NtO_6Lj.js} +2 -2
- package/dist/core/web/public/next/assets/{Switch-BmCzfFnu.js.map → Switch-9NtO_6Lj.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Tag-WSUIaMVy.js → Tag-DscCRFcN.js} +2 -2
- package/dist/core/web/public/next/assets/{Tag-WSUIaMVy.js.map → Tag-DscCRFcN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{TerminalPane-BVFgYX6K.js → TerminalPane-B668-DJW.js} +5 -5
- package/dist/core/web/public/next/assets/{TerminalPane-BVFgYX6K.js.map → TerminalPane-B668-DJW.js.map} +1 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-BUV_brY7.js +2 -0
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-BpphLqoz.js.map → UniverseConsoleApp-BUV_brY7.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseView-DbpbSMwO.js → UniverseView-DG70zH0W.js} +4 -4
- package/dist/core/web/public/next/assets/{UniverseView-DbpbSMwO.js.map → UniverseView-DG70zH0W.js.map} +1 -1
- package/dist/core/web/public/next/assets/UsageSection-DY7uOTm1.js +3 -0
- package/dist/core/web/public/next/assets/UsageSection-DY7uOTm1.js.map +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CWU6R3By.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CWU6R3By.js.map +1 -0
- package/dist/core/web/public/next/assets/Workspace-D1nP9BhD.js +10 -0
- package/dist/core/web/public/next/assets/{Workspace-RXy0pqp6.js.map → Workspace-D1nP9BhD.js.map} +1 -1
- package/dist/core/web/public/next/assets/actions-CY-PjpGc.js +2 -0
- package/dist/core/web/public/next/assets/{actions-BZTidCXZ.js.map → actions-CY-PjpGc.js.map} +1 -1
- package/dist/core/web/public/next/assets/actions-DkWhhWIg.css +1 -0
- package/dist/core/web/public/next/assets/{apps-model-CHO133qt.js → apps-model-Du02KhAf.js} +2 -2
- package/dist/core/web/public/next/assets/{apps-model-CHO133qt.js.map → apps-model-Du02KhAf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{authority-model-8NeAEwAF.js → authority-model-79SeuKlJ.js} +2 -2
- package/dist/core/web/public/next/assets/{authority-model-8NeAEwAF.js.map → authority-model-79SeuKlJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/autonomy-ladder-BGWmZzP7.css +1 -0
- package/dist/core/web/public/next/assets/autonomy-ladder.module-ArDv4bkr.js +2 -0
- package/dist/core/web/public/next/assets/autonomy-ladder.module-ArDv4bkr.js.map +1 -0
- package/dist/core/web/public/next/assets/budget-queries-D8QV5XtH.js +2 -0
- package/dist/core/web/public/next/assets/{budget-queries-DFF-3ICg.js.map → budget-queries-D8QV5XtH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{capacity-strip-model-5ViUgUlP.js → capacity-strip-model-BwZ1ZbkU.js} +2 -2
- package/dist/core/web/public/next/assets/{capacity-strip-model-5ViUgUlP.js.map → capacity-strip-model-BwZ1ZbkU.js.map} +1 -1
- package/dist/core/web/public/next/assets/charts-BZ50mZD_.js +2 -0
- package/dist/core/web/public/next/assets/charts-BZ50mZD_.js.map +1 -0
- package/dist/core/web/public/next/assets/charts-ClCB18la.css +1 -0
- package/dist/core/web/public/next/assets/{cloud-model-CfRydq8N.js → cloud-model-BDivRMqv.js} +2 -2
- package/dist/core/web/public/next/assets/{cloud-model-CfRydq8N.js.map → cloud-model-BDivRMqv.js.map} +1 -1
- package/dist/core/web/public/next/assets/{cloud-queries-DmptbjS8.js → cloud-queries-BPQQ5_pJ.js} +2 -2
- package/dist/core/web/public/next/assets/{cloud-queries-DmptbjS8.js.map → cloud-queries-BPQQ5_pJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{colors-BZ3a9wFf.js → colors-DvK0wMHH.js} +2 -2
- package/dist/core/web/public/next/assets/{colors-BZ3a9wFf.js.map → colors-DvK0wMHH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{command-catalog-ffCAijVY.js → command-catalog-BIntSa9l.js} +2 -2
- package/dist/core/web/public/next/assets/command-catalog-BIntSa9l.js.map +1 -0
- package/dist/core/web/public/next/assets/{context-model-CDeyP0cA.js → context-model-Br8t9jgG.js} +2 -2
- package/dist/core/web/public/next/assets/{context-model-CDeyP0cA.js.map → context-model-Br8t9jgG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{context-model-Bb15chFt.js → context-model-CokrgEUq.js} +3 -3
- package/dist/core/web/public/next/assets/{context-model-Bb15chFt.js.map → context-model-CokrgEUq.js.map} +1 -1
- package/dist/core/web/public/next/assets/context-queries-eL3caKVG.js +2 -0
- package/dist/core/web/public/next/assets/{context-queries-_9bFWb9v.js.map → context-queries-eL3caKVG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{control-queries-CXtmZZH6.js → control-queries-B9K-wmcB.js} +2 -2
- package/dist/core/web/public/next/assets/{control-queries-CXtmZZH6.js.map → control-queries-B9K-wmcB.js.map} +1 -1
- package/dist/core/web/public/next/assets/{copy-setup-BIp0iaiZ.js → copy-setup-XMgCC5f8.js} +2 -2
- package/dist/core/web/public/next/assets/{copy-setup-BIp0iaiZ.js.map → copy-setup-XMgCC5f8.js.map} +1 -1
- package/dist/core/web/public/next/assets/{dock-icons-Cc43W7r4.js → dock-icons-BJ6ZqB2t.js} +2 -2
- package/dist/core/web/public/next/assets/{dock-icons-Cc43W7r4.js.map → dock-icons-BJ6ZqB2t.js.map} +1 -1
- package/dist/core/web/public/next/assets/{fleet-model-DOK8ZtEt.js → fleet-model-BvDR3gjp.js} +2 -2
- package/dist/core/web/public/next/assets/{fleet-model-DOK8ZtEt.js.map → fleet-model-BvDR3gjp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{fleet-queries-BeEAqD6y.js → fleet-queries-W2UFVMZJ.js} +2 -2
- package/dist/core/web/public/next/assets/{fleet-queries-BeEAqD6y.js.map → fleet-queries-W2UFVMZJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{focus-trap-ChZ5EFfM.js → focus-trap-CtI1SlMX.js} +2 -2
- package/dist/core/web/public/next/assets/{focus-trap-ChZ5EFfM.js.map → focus-trap-CtI1SlMX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{format-BmH2yWL6.js → format-CH4g_sl1.js} +2 -2
- package/dist/core/web/public/next/assets/{format-BmH2yWL6.js.map → format-CH4g_sl1.js.map} +1 -1
- package/dist/core/web/public/next/assets/{format-DKrNjdwD.js → format-D7nBg2bn.js} +2 -2
- package/dist/core/web/public/next/assets/{format-DKrNjdwD.js.map → format-D7nBg2bn.js.map} +1 -1
- package/dist/core/web/public/next/assets/{git-model-BFwAVbxF.js → git-model-Dnkd1TnK.js} +2 -2
- package/dist/core/web/public/next/assets/{git-model-BFwAVbxF.js.map → git-model-Dnkd1TnK.js.map} +1 -1
- package/dist/core/web/public/next/assets/global-CMNW_dqn.js +2 -0
- package/dist/core/web/public/next/assets/{global-y_exIyAP.js.map → global-CMNW_dqn.js.map} +1 -1
- package/dist/core/web/public/next/assets/guarded-runners-YeAc9wLQ.js +2 -0
- package/dist/core/web/public/next/assets/{guarded-runners-Cd4POBtI.js.map → guarded-runners-YeAc9wLQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{icons-CygCEFWs.js → icons-D1sYbCTQ.js} +2 -2
- package/dist/core/web/public/next/assets/{icons-CygCEFWs.js.map → icons-D1sYbCTQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{index-CyK31YRm.js → index-DZ-UQ7v8.js} +3 -3
- package/dist/core/web/public/next/assets/{index-CyK31YRm.js.map → index-DZ-UQ7v8.js.map} +1 -1
- package/dist/core/web/public/next/assets/leader-focus-BjeJv7CW.js +2 -0
- package/dist/core/web/public/next/assets/leader-focus-BjeJv7CW.js.map +1 -0
- package/dist/core/web/public/next/assets/leader-thread-types-CDb-VPPO.js +2 -0
- package/dist/core/web/public/next/assets/leader-thread-types-CDb-VPPO.js.map +1 -0
- package/dist/core/web/public/next/assets/{live-model-D7hilYFk.js → live-model-D_32RAOR.js} +2 -2
- package/dist/core/web/public/next/assets/{live-model-D7hilYFk.js.map → live-model-D_32RAOR.js.map} +1 -1
- package/dist/core/web/public/next/assets/{mind.module-B15k0Y9q.js → mind.module-7hA92hRg.js} +2 -2
- package/dist/core/web/public/next/assets/{mind.module-B15k0Y9q.js.map → mind.module-7hA92hRg.js.map} +1 -1
- package/dist/core/web/public/next/assets/mutations-DQPbFdRJ.js +2 -0
- package/dist/core/web/public/next/assets/{mutations-CWlxEMEm.js.map → mutations-DQPbFdRJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{nav-mimleI0R.js → nav-0dOYe2rJ.js} +2 -2
- package/dist/core/web/public/next/assets/{nav-mimleI0R.js.map → nav-0dOYe2rJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{overnight-queries-DJ4mZKSj.js → overnight-queries-C4wOnFtE.js} +2 -2
- package/dist/core/web/public/next/assets/{overnight-queries-DJ4mZKSj.js.map → overnight-queries-C4wOnFtE.js.map} +1 -1
- package/dist/core/web/public/next/assets/primitives-2A5Eq8FQ.js +1 -0
- package/dist/core/web/public/next/assets/{queries-Bw1McHTj.js → queries-BTXWdZzU.js} +2 -2
- package/dist/core/web/public/next/assets/{queries-Bw1McHTj.js.map → queries-BTXWdZzU.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reasoning-pref-KkhI_5-j.js → reasoning-pref-Ca6lN6x_.js} +2 -2
- package/dist/core/web/public/next/assets/{reasoning-pref-KkhI_5-j.js.map → reasoning-pref-Ca6lN6x_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reveal-anchor-CCCx_kfT.js → reveal-anchor-DfNLgK_I.js} +2 -2
- package/dist/core/web/public/next/assets/{reveal-anchor-CCCx_kfT.js.map → reveal-anchor-DfNLgK_I.js.map} +1 -1
- package/dist/core/web/public/next/assets/seat-subscription-C5uPHBsN.js +2 -0
- package/dist/core/web/public/next/assets/{seat-subscription-BhUUz7VL.js.map → seat-subscription-C5uPHBsN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{sidebar-model-Dcd437cf.js → sidebar-model-CLCdqwkR.js} +2 -2
- package/dist/core/web/public/next/assets/{sidebar-model-Dcd437cf.js.map → sidebar-model-CLCdqwkR.js.map} +1 -1
- package/dist/core/web/public/next/assets/{slots-BL_J5mmV.js → slots-C-qBeu-8.js} +3 -3
- package/dist/core/web/public/next/assets/{slots-BL_J5mmV.js.map → slots-C-qBeu-8.js.map} +1 -1
- package/dist/core/web/public/next/assets/{surface-data-C3UAQ4QX.js → surface-data-Dj71tdD-.js} +2 -2
- package/dist/core/web/public/next/assets/{surface-data-C3UAQ4QX.js.map → surface-data-Dj71tdD-.js.map} +1 -1
- package/dist/core/web/public/next/assets/surface-prefetch-B0WdJOJG.js +2 -0
- package/dist/core/web/public/next/assets/surface-prefetch-B0WdJOJG.js.map +1 -0
- package/dist/core/web/public/next/assets/{tasks-model-CzHvclVm.js → tasks-model-O8yR5YXp.js} +2 -2
- package/dist/core/web/public/next/assets/{tasks-model-CzHvclVm.js.map → tasks-model-O8yR5YXp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{terminal-icons-BwgQTQP0.js → terminal-icons-CoRZq9iO.js} +2 -2
- package/dist/core/web/public/next/assets/{terminal-icons-BwgQTQP0.js.map → terminal-icons-CoRZq9iO.js.map} +1 -1
- package/dist/core/web/public/next/assets/thread-data-DQB_g66d.js +2 -0
- package/dist/core/web/public/next/assets/thread-data-DQB_g66d.js.map +1 -0
- package/dist/core/web/public/next/assets/{usage-queries-pXxvy54x.js → usage-queries-AdjEyEtn.js} +2 -2
- package/dist/core/web/public/next/assets/{usage-queries-pXxvy54x.js.map → usage-queries-AdjEyEtn.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-guarded-action-EgVWjM5c.js → use-guarded-action-CuuMHeDX.js} +2 -2
- package/dist/core/web/public/next/assets/{use-guarded-action-EgVWjM5c.js.map → use-guarded-action-CuuMHeDX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-ticker-BoqFxRFG.js → use-ticker-BBcp02SZ.js} +2 -2
- package/dist/core/web/public/next/assets/{use-ticker-BoqFxRFG.js.map → use-ticker-BBcp02SZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-token-gate-DSNIIpI6.js → use-token-gate-CbXVYQYI.js} +2 -2
- package/dist/core/web/public/next/assets/{use-token-gate-DSNIIpI6.js.map → use-token-gate-CbXVYQYI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useOnboarding-Bk0VnkxQ.js → useOnboarding-C_Fpe_sH.js} +2 -2
- package/dist/core/web/public/next/assets/{useOnboarding-Bk0VnkxQ.js.map → useOnboarding-C_Fpe_sH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useSeatsRefresh-q7Id9RcW.js → useSeatsRefresh-Co1CnxLc.js} +2 -2
- package/dist/core/web/public/next/assets/{useSeatsRefresh-q7Id9RcW.js.map → useSeatsRefresh-Co1CnxLc.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useVerseTranscript-CqH51rt9.js → useVerseTranscript-DgbigUlV.js} +2 -2
- package/dist/core/web/public/next/assets/{useVerseTranscript-CqH51rt9.js.map → useVerseTranscript-DgbigUlV.js.map} +1 -1
- package/dist/core/web/public/next/assets/{verse-icons-DsG1dOQx.js → verse-icons-S56hIiXS.js} +2 -2
- package/dist/core/web/public/next/assets/{verse-icons-DsG1dOQx.js.map → verse-icons-S56hIiXS.js.map} +1 -1
- package/dist/core/web/public/next/assets/verse-model-DAVevkNe.js +2 -0
- package/dist/core/web/public/next/assets/{verse-model-JTuvRBVK.js.map → verse-model-DAVevkNe.js.map} +1 -1
- package/dist/core/web/public/next/assets/{warmup-Bv1RumVq.js → warmup-B_RAtNZ_.js} +3 -3
- package/dist/core/web/public/next/assets/{warmup-Bv1RumVq.js.map → warmup-B_RAtNZ_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{why-seat-model-Cau8qG6O.js → why-seat-model-M_r0wX3b.js} +2 -2
- package/dist/core/web/public/next/assets/{why-seat-model-Cau8qG6O.js.map → why-seat-model-M_r0wX3b.js.map} +1 -1
- package/dist/core/web/public/next/assets/{workspace-model-D-SLfads.js → workspace-model-dji5-Al3.js} +2 -2
- package/dist/core/web/public/next/assets/{workspace-model-D-SLfads.js.map → workspace-model-dji5-Al3.js.map} +1 -1
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/core/web/read-projection-worker.js +2 -1
- package/dist/core/web/read-projection-worker.js.map +1 -1
- package/dist/core/web/read-projections.d.ts +3 -0
- package/dist/core/web/read-projections.js +2 -2
- package/dist/core/web/read-projections.js.map +1 -1
- package/dist/core/web/visibility.js +3 -4
- package/dist/core/web/visibility.js.map +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/package.json +3 -2
- package/dist/core/web/public/next/assets/Advanced-cVYTAsfB.js +0 -2
- package/dist/core/web/public/next/assets/AppsSection-DDqeSrty.js +0 -2
- package/dist/core/web/public/next/assets/AreaTrend-C32rUaxm.js +0 -2
- package/dist/core/web/public/next/assets/AreaTrend-C32rUaxm.js.map +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-Dwn8UtOy.js +0 -2
- package/dist/core/web/public/next/assets/ChartFrame-BVuBe6RP.css +0 -1
- package/dist/core/web/public/next/assets/ChartFrame-DK_BDXCt.js +0 -2
- package/dist/core/web/public/next/assets/ChartFrame-DK_BDXCt.js.map +0 -1
- package/dist/core/web/public/next/assets/ChatSection-C9myY4ei.js +0 -3
- package/dist/core/web/public/next/assets/CommandPalette-DzPsth0u.js +0 -2
- package/dist/core/web/public/next/assets/CommandPalette-DzPsth0u.js.map +0 -1
- package/dist/core/web/public/next/assets/CommandSection-Brp73iox.js +0 -3
- package/dist/core/web/public/next/assets/CommandSection-Brp73iox.js.map +0 -1
- package/dist/core/web/public/next/assets/CommandSection-CvAVd1w4.css +0 -1
- package/dist/core/web/public/next/assets/DockHost-BcEq2qaS.js +0 -2
- package/dist/core/web/public/next/assets/FleetSection-BG8iGraG.js +0 -3
- package/dist/core/web/public/next/assets/FleetSection-BG8iGraG.js.map +0 -1
- package/dist/core/web/public/next/assets/Funnel-B88_wpA4.js +0 -2
- package/dist/core/web/public/next/assets/Funnel-B88_wpA4.js.map +0 -1
- package/dist/core/web/public/next/assets/GrowthSection-BvZezOsX.js +0 -2
- package/dist/core/web/public/next/assets/LeaderCard-BxxiEg4e.js +0 -2
- package/dist/core/web/public/next/assets/LeaderCard-BxxiEg4e.js.map +0 -1
- package/dist/core/web/public/next/assets/MatrixHeatmap-iPFEU2Tv.js +0 -2
- package/dist/core/web/public/next/assets/MatrixHeatmap-iPFEU2Tv.js.map +0 -1
- package/dist/core/web/public/next/assets/McpSection-nuXer4K-.js +0 -2
- package/dist/core/web/public/next/assets/MindSection-Dc5v5rH3.js +0 -2
- package/dist/core/web/public/next/assets/MindSection-Dc5v5rH3.js.map +0 -1
- package/dist/core/web/public/next/assets/NeedsYouDrawer-N1cWJjpz.js +0 -3
- package/dist/core/web/public/next/assets/NeedsYouDrawer-N1cWJjpz.js.map +0 -1
- package/dist/core/web/public/next/assets/NewChatDialog-BqFTWgHU.js +0 -3
- package/dist/core/web/public/next/assets/OnboardingGate-BZafM1Vf.js +0 -3
- package/dist/core/web/public/next/assets/PreviewPane-zT3gK9TD.js +0 -2
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-CAxPQ4sZ.js +0 -7
- package/dist/core/web/public/next/assets/ResourcesChrome-BnhnEdJe.js +0 -3
- package/dist/core/web/public/next/assets/ResourcesChrome-BnhnEdJe.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcesDrawer-BAFGodny.js +0 -2
- package/dist/core/web/public/next/assets/ResourcesDrawer-BAFGodny.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcesDrawer-BCFJ2Uq8.css +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-Bf74l0Gj.js.map +0 -1
- package/dist/core/web/public/next/assets/Sidebar-C9YtBYVZ.js +0 -3
- package/dist/core/web/public/next/assets/StatTile-BuLMsJMx.css +0 -1
- package/dist/core/web/public/next/assets/StatTile-CTX41O6y.js +0 -2
- package/dist/core/web/public/next/assets/StatTile-CTX41O6y.js.map +0 -1
- package/dist/core/web/public/next/assets/StepBand-jJTqYIdX.js +0 -2
- package/dist/core/web/public/next/assets/StepBand-jJTqYIdX.js.map +0 -1
- package/dist/core/web/public/next/assets/Swimlane-LrslsGxw.js +0 -2
- package/dist/core/web/public/next/assets/Swimlane-LrslsGxw.js.map +0 -1
- package/dist/core/web/public/next/assets/Swimlane-o6_Zsrnr.css +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-BpphLqoz.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-CUlaKtws.js +0 -3
- package/dist/core/web/public/next/assets/UsageSection-CUlaKtws.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-DXDv1aOi.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-DXDv1aOi.js.map +0 -1
- package/dist/core/web/public/next/assets/Workspace-RXy0pqp6.js +0 -10
- package/dist/core/web/public/next/assets/actions-BZTidCXZ.js +0 -2
- package/dist/core/web/public/next/assets/actions-BmIf9avl.css +0 -1
- package/dist/core/web/public/next/assets/budget-queries-DFF-3ICg.js +0 -2
- package/dist/core/web/public/next/assets/charts-CzxWrZn7.js +0 -2
- package/dist/core/web/public/next/assets/charts-CzxWrZn7.js.map +0 -1
- package/dist/core/web/public/next/assets/charts-DhKTrQLw.css +0 -1
- package/dist/core/web/public/next/assets/command-catalog-ffCAijVY.js.map +0 -1
- package/dist/core/web/public/next/assets/context-queries-_9bFWb9v.js +0 -2
- package/dist/core/web/public/next/assets/global-y_exIyAP.js +0 -2
- package/dist/core/web/public/next/assets/guarded-runners-Cd4POBtI.js +0 -2
- package/dist/core/web/public/next/assets/mutations-CWlxEMEm.js +0 -2
- package/dist/core/web/public/next/assets/primitives-DMijqcu0.js +0 -1
- package/dist/core/web/public/next/assets/seat-subscription-BhUUz7VL.js +0 -2
- package/dist/core/web/public/next/assets/surface-prefetch-BXKjPsV5.js +0 -2
- package/dist/core/web/public/next/assets/surface-prefetch-BXKjPsV5.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-model-JTuvRBVK.js +0 -2
package/dist/core/web/public/next/assets/{CloudBudgetForm-CvjK4Oh6.js → CloudBudgetForm-BrNun_Yu.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,c as t,n}from"./index-CyK31YRm.js";import{b as r,n as i}from"./format-BmH2yWL6.js";import{t as a}from"./Button-DtE0rlWD.js";import{t as o}from"./Switch-BmCzfFnu.js";import{o as s,s as c,t as l}from"./cloud-model-CfRydq8N.js";import{t as u}from"./cloud.module-DOP-N4Ch.js";import{t as d}from"./Input-CI0yBHmn.js";import{o as f,s as p}from"./why-seat-model-Cau8qG6O.js";function m(e,t){if(!e.resetsAt)return null;let n=Date.parse(e.resetsAt);return Number.isFinite(n)?n-t:null}function h(e,t,n){let r=t.id;if(e===`claude`){if(r===`five_hour`)return`session`;if(r===`seven_day`)return`weekly`;if(r.startsWith(`seven_day_`))return`model`}if(e===`grok`)return`weekly`;let i=m(t,n);if(e===`codex`){if(r.endsWith(`_secondary`))return`weekly`;if(r.endsWith(`_primary`))return i!==null&&i>189e5?`weekly`:`session`}return i!==null&&i<=189e5?`session`:`weekly`}var g=864e5,_=36e5;function v(e,t,n,r=0){let i=e.length-r,a=i-n;if(a<0||n<=0)return null;let o=0;for(let n=a;n<i;n++){let r=t(e[n]);if(r===null||!Number.isFinite(r))return null;o+=r}return o}function y(e,t,n){return e.slice(Math.max(0,e.length-n)).map(t)}function b(e){let t=e.filter(e=>e!==null&&Number.isFinite(e));return t.length?t.reduce((e,t)=>e+t,0)/t.length:null}function x(e){let t=e.meteredCostUsd;return typeof t==`number`&&Number.isFinite(t)&&t>=0?t:null}var ee=e=>e>0?`+${e}`:String(e),S=e=>`${e>0?`+`:``}${e.toFixed(1)}`,C=e=>`${e>0?`+`:e<0?`−`:``}$${Math.abs(e).toFixed(2)}`;function w(e){if(e===null||!Number.isFinite(e)||e<0)return`—`;let t=Math.round(e/6e4);if(t<60)return`${t}m`;let n=Math.floor(t/60);if(n<48)return t%60?`${n}h ${t%60}m`:`${n}h`;let r=Math.floor(n/24);return n%24?`${r}d ${n%24}h`:`${r}d`}function te(e){if(!e||e.repos.length===0)return[];let t=Math.max(...e.repos.map(e=>e.greenTrend.length));return Array.from({length:t},(n,r)=>b(e.repos.map(e=>e.greenTrend[r-(t-e.greenTrend.length)]??null)))}function T({fleet:e,history:t,learning:n,policy:r}){let i=t?.days??[],a=e=>e.merges.realized,o=x,s=e?.summary.merged7d??v(i,a,7),c=v(i,a,7,7),l=v(i,a,7),u=l!==null&&c!==null?l-c:null,d=e?.summary.postMergeGreenPct7d??null,f=te(e),p=f.length>=14?b(f.slice(-7)):null,m=f.length>=14?b(f.slice(-14,-7)):null,h=p!==null&&m!==null?p-m:null,g=v(i,o,7),_=v(i,o,7,7),T=r?r.spend.meteredUsdPerDay:null,E=g===null?`—`:`$${g.toFixed(2)}${T===null?``:` / $${(T*7).toFixed(0)}`}`,D=i.some(e=>x(e)!==null),O=T===null?`per-token APIs only`:T===0?`metered APIs off`:`cap $${T}/day`,k=D?O:`${O} · not reported yet`,A=n?.active??null,j=(A?.experimentId?n?.experiments.find(e=>e.id===A.experimentId)??null:null)?.lift??null;return[{id:`merged`,label:`Merged · 7d`,value:s===null?`—`:String(s),delta:u===null?null:{value:u,unit:Math.abs(u)===1?`merge`:`merges`,versus:`vs prior 7d`,goodWhenPositive:!0,format:ee},trend:i.length?y(i,a,14):void 0,trendLabel:`Merges per day, last 14 days`,caption:e?.summary.mergedToday==null?`fleet merges on default branches`:`${e.summary.mergedToday} today`},{id:`green`,label:`Post-merge green`,value:d===null?`—`:`${Math.round(d)}%`,delta:h===null?null:{value:h,unit:`pts`,versus:`vs prior 7d`,goodWhenPositive:!0,format:S},trend:f.length?f:void 0,trendLabel:`Post-merge green percent per day`,caption:d===null?`no completed post-merge watch yet`:`CI + suite 2 h after each merge`},{id:`cycle`,label:`Cycle time`,value:w(e?.summary.cycleTimeP50Ms7d??null),delta:null,trend:void 0,trendLabel:`Cycle time`,caption:`median, proposal → merge, 7d`},{id:`spend`,label:`Metered spend · 7d`,value:E,delta:g!==null&&_!==null?{value:g-_,versus:`vs prior 7d`,goodWhenPositive:!1,format:C}:null,trend:D?y(i,o,14):void 0,trendLabel:`Metered (per-token API) spend per day`,caption:k},{id:`lift`,label:`Lift`,value:j?`${S(j.mean)} pts`:`—`,delta:null,trend:void 0,trendLabel:`Harness lift`,caption:A?`harness ${A.id} vs baseline${j?` (95% ${S(j.ciLow)} to ${S(j.ciHigh)})`:``}`:`no harness adopted — defaults in force`}]}function E({fleet:e,history:t,learning:n}){let r=t?.days??[],i=e=>e.merges.realized,a=e?.summary.merged7d??v(r,i,7),o=v(r,i,7,7),s=n?.active??null,c=s?.experimentId?n?.experiments.find(e=>e.id===s.experimentId)?.lift??null:null;return(a??0)===0&&(o??0)===0&&(e?.summary.postMergeGreenPct7d??null)===null&&(e?.summary.cycleTimeP50Ms7d??null)===null&&(v(r,x,7)??0)===0&&c===null}var D=(e,t)=>e!==null&&Date.parse(e)>t;function O({lastLookedAt:e,fleet:t,leader:n,activity:r}){if(!e)return[];let i=Date.parse(e);if(!Number.isFinite(i))return[];let a=[],o=(t?.runs??[]).filter(e=>D(e.endedAt,i)),s=e=>o.filter(t=>t.outcome===e).length,c=s(`merged`),l=s(`reverted`),u=s(`failed`)+s(`refused`);c&&a.push({id:`merged`,text:`${c} merged`,tone:`success`}),l&&a.push({id:`reverted`,text:`${l} reverted`,tone:`danger`}),u&&a.push({id:`failed`,text:`${u} refused or failed`,tone:`warning`});let d=(n?.timeline??[]).filter(e=>Date.parse(e.at)>i&&e.status===`ok`).length;d&&a.push({id:`memos`,text:`${d} new memo${d===1?``:`s`}`,tone:`info`});let f=(r?.needsYou??[]).filter(e=>Date.parse(e.since)>i).length;return f&&a.push({id:`needs`,text:`${f} new for you`,tone:`warning`}),a}var k={high:0,warn:1,info:2};function A(e){return[...e].sort((e,t)=>k[e.severity]-k[t.severity]||Date.parse(t.since)-Date.parse(e.since))}function j(e,t){let n=new Map,r=(e,t)=>{typeof e==`string`&&typeof t==`string`&&t.trim().length>0&&n.set(e,t.trim())};for(let e of t?.seatInfo??[])r(e.seatId,e.label);for(let t of e??[])r(t.id,t.label);return n}function M(e){return e?Object.entries(e.sources).filter(([,e])=>e!==`ok`).map(([e])=>e):[]}function N(e,t){return`${e}#${t}`}var P=20;function F(e,t){let n=e.length;return n>=2&&e[n-1].used===t&&e[n-2].used===t}function I(e,t){if(!t)return{...e};let n=Date.parse(t.sampledAt);if(!Number.isFinite(n))return{...e};let r={...e};for(let e of t.headroom){let t=[[`session`,e.sessionUsedPercent],[`weekly`,e.weeklyUsedPercent]];for(let[i,a]of t){if(a===null||!Number.isFinite(a))continue;let t=N(e.seatId,i),o=r[t]??[];if(o.length&&o[o.length-1].t>=n)continue;let s=o.length&&a+P<o[o.length-1].used?[]:o;r[t]=[...F(s,a)?s.slice(0,-1):s,{t:n,used:a}].slice(-240)}}return r}function L(e,t){let n=typeof t?.generatedAt==`string`?Date.parse(t.generatedAt):NaN,r=new Map;for(let e of Array.isArray(t?.series)?t.series:[]){if(!e||typeof e.seatId!=`string`||e.window!==`session`&&e.window!==`weekly`||!Array.isArray(e.points))continue;let t=[];for(let n of e.points){if(!Array.isArray(n))continue;let[e,r]=n;typeof e==`number`&&Number.isFinite(e)&&typeof r==`number`&&Number.isFinite(r)&&r>=0&&r<=100&&t.push({t:e,used:r})}if(t.length===0)continue;let n=N(e.seatId,e.window);r.set(n,[...r.get(n)??[],...t])}let i={},a=new Set;for(let t of new Set([...Object.keys(e),...r.keys()])){let o=r.get(t)??[],s=e[t]??[];if(o.length>0){a.add(t);let e=Math.max(...o.map(e=>e.t)),r=Number.isFinite(n)?Math.max(n,e):e;s=s.filter(e=>e.t>r)}let c=new Map;for(let e of o)c.set(e.t,e);for(let e of s)c.set(e.t,e);let l=[...c.values()].sort((e,t)=>e.t-t.t),u=0;for(let e=1;e<l.length;e++)l[e].used+P<l[e-1].used&&(u=e);let d=[];for(let e of l.slice(u))F(d,e.used)&&d.pop(),d.push(e);i[t]=d.slice(-2e3)}return{readings:i,recorded:a}}var R={session:5*_,weekly:7*g};function z(e,t){if(!t||e.bindingWindow===null)return null;let n=100-t.reservePercent,r=t.maxSessionWindowPercent??100,i,a;e.bindingWindow===`weekly`||e.weeklyUsedPercent===null&&n<r?(i=n,a=`Reserved for you`):(i=r,a=`5-hour ceiling`);let o=100-i;return o>0?{value:o,label:a}:null}function B(e){let t=e===`session`?{weekday:`short`,hour:`numeric`,minute:`2-digit`}:{month:`short`,day:`numeric`,hour:`numeric`,minute:`2-digit`};return e=>{let n=new Date(e);return Number.isNaN(n.getTime())?``:n.toLocaleString(`en-US`,t)}}function V(e,t,n,r){if(!e?.capacity||n===null||t===`local`)return null;for(let i of e.capacity.windows){let e=typeof i.resetDescription==`string`?i.resetDescription.trim():``;if(e.length!==0&&h(t,{id:i.id,usedPercent:i.usedPercent,resetsAt:i.resetsAt,resetDescription:i.resetDescription,limitReached:i.limitReached},r)===n)return e}return null}function H(e){return`resets ${e.replace(/^resets\s+/i,``)}`}var U=[`jan`,`feb`,`mar`,`apr`,`may`,`jun`,`jul`,`aug`,`sep`,`oct`,`nov`,`dec`],W=/^(?:resets\s+)?(?:([A-Za-z]{3}) ([1-9]|[12]\d|3[01]) at )?([1-9]|1[0-2])(?::([0-5]\d))?(am|pm) \(([A-Za-z0-9_+-]+(?:\/[A-Za-z0-9_+-]+){0,2})\)$/i;function G(e,t){let n=t.formatToParts(new Date(e)),r=e=>Number(n.find(t=>t.type===e)?.value),i={y:r(`year`),mo:r(`month`)-1,d:r(`day`),h:r(`hour`)%24,mi:r(`minute`)};return Object.values(i).every(Number.isFinite)?i:null}var K=e=>Date.UTC(e.y,e.mo,e.d,e.h,e.mi);function q(e,t){let n=K(e),r=n;for(let e=0;e<3;e++){let e=G(r,t);if(!e)return null;let i=n-K(e);if(i===0)return r;r+=i}return null}function J(e,t){let n=W.exec(e.trim());if(!n||!Number.isFinite(t))return null;let[,r,i,a,o,s,c]=n,l;try{l=new Intl.DateTimeFormat(`en-US`,{timeZone:c,hourCycle:`h23`,year:`numeric`,month:`numeric`,day:`numeric`,hour:`numeric`,minute:`numeric`})}catch{return null}let u=G(t,l);if(!u)return null;let d=Number(a)%12+(s.toLowerCase()===`pm`?12:0),f=o===void 0?0:Number(o),p=[];if(r!==void 0){let e=U.indexOf(r.toLowerCase()),t=Number(i);if(e<0)return null;for(let n of[u.y-1,u.y,u.y+1])new Date(Date.UTC(n,e,t)).getUTCDate()===t&&p.push({y:n,mo:e,d:t,h:d,mi:f})}else for(let e of[-1,0,1]){let t=new Date(Date.UTC(u.y,u.mo,u.d+e));p.push({y:t.getUTCFullYear(),mo:t.getUTCMonth(),d:t.getUTCDate(),h:d,mi:f})}let m=null;for(let e of p){let n=q(e,l);n!==null&&(m===null||Math.abs(n-t)<Math.abs(m-t))&&(m=n)}return m}var Y=9e5,X=Date.UTC(2e3,0,1);function ne(e,t,n,r){let i=e?Date.parse(e):NaN;if(Number.isFinite(i)&&i>=X)return{at:i,from:`provider`};if(t===null||n===null)return null;let a=J(t,r);return a===null||a<r-Y||a>r+n+Y?null:{at:a,from:`words`}}function re(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`&&e.trim().length>0).map(p):[]}var ie=6e4,ae=new Set([`reserve`,`session-ceiling`]);function Z(e){return typeof e==`string`?e.trim().replace(/^resets\s+/i,``):``}function oe(e){for(let t of e){if(!ae.has(t.kind))continue;let e=Z(t.resetDescription);if(e)return e}return null}function se(e,t,n){let i=typeof e.resetsAt==`string`?Date.parse(e.resetsAt):NaN;if(Number.isFinite(i))return t.resetAt!==null&&Math.abs(i-t.resetAt)<=ie?null:r(e.resetsAt,n);let a=Z(e.resetDescription);return!a||t.resetText!==null&&Z(t.resetText).toLowerCase()===a.toLowerCase()?null:a}function ce(e,t,n){if(!e)return null;let r=i(f(e.text,n));if(!r)return null;let a=se(e,t,n);return a?`${r} Resets ${a}.`:r}function le(e,t,n,r){if(!e)return[];let i=new Map(e.seatInfo.map(e=>[e.seatId,e])),a=new Map((n??[]).map(e=>[e.id,e])),o=Date.parse(e.sampledAt),s=Number.isFinite(o)?o:Date.now();return e.headroom.map(n=>{let o=i.get(n.seatId),c=o?.engine??`local`,l=n.bindingWindow?R[n.bindingWindow]:null,u=re(n.reasons),d=V(a.get(n.seatId),c,n.bindingWindow,s)??(n.bindingWindow===null||c===`local`?null:oe(u)),f=l===null?null:ne(n.resetAt,d,l,s),p=f&&l!==null?f.at-l:null,m=n.bindingWindow?N(n.seatId,n.bindingWindow):null,h=m?t[m]??[]:[];return{seatId:n.seatId,label:o?.label??n.seatId,engine:c,window:n.bindingWindow,points:h.filter(e=>p===null||e.t>=p).map(e=>({t:e.t,remaining:Math.max(0,100-e.used)})),start:p,resetAt:f?.at??null,resetFrom:f?.from??null,resetText:d,reservePercent:e.effective[n.seatId]?.reservePercent??0,line:z(n,e.effective[n.seatId]),enabled:e.effective[n.seatId]?.enabled??!1,free:o?.free??!1,eligible:n.eligibleForAutonomy,reason:ce(u[0],{resetAt:f?.at??null,resetText:d},s),recorded:m!==null&&(r?.has(m)??!1)}}).sort((e,t)=>Number(e.free)-Number(t.free)||e.label.localeCompare(t.label))}function ue(e){if(!e)return null;let t=e.seatInfo.find(e=>e.engine===`claude`);if(!t)return null;let n=e.effective[t.seatId];return n?{label:`Claude`,percent:n.reservePercent}:null}var Q=t(e(),1),$=n();function de({budget:e,onSave:t,onCancel:n,busy:r,disabled:i=!1,idPrefix:f}){let[p,m]=(0,Q.useState)(()=>s(e)),[h,g]=(0,Q.useState)({}),[_,v]=(0,Q.useState)(null),y=(0,Q.useRef)(!1);(0,Q.useEffect)(()=>{y.current||m(s(e))},[e]);let b=e=>{y.current=!0,v(null),m(t=>({...t,...e}))};return(0,$.jsxs)(`form`,{className:u.form,onSubmit:n=>{n.preventDefault();let r=c(p,e);if(!r.ok){g(r.errors);return}if(g({}),!r.changed){v(`Nothing changed.`);return}y.current=!1,t(r.update)},noValidate:!0,"aria-label":`Cloud budget`,children:[(0,$.jsx)(`div`,{className:u.fieldGrid,children:l.map(e=>(0,$.jsx)(d,{id:`${f}-${e.field}`,label:e.label,hint:e.hint,error:h[e.field],size:`sm`,inputMode:e.integer?`numeric`:`decimal`,prefix:e.money?`$`:void 0,value:p[e.field],disabled:i||r,onChange:t=>b({[e.field]:t.target.value})},e.field))}),(0,$.jsx)(o,{checked:p.selfImprove,onChange:e=>b({selfImprove:e}),label:`Verse may launch self-improvement tasks on its own`,disabled:i||r}),_?(0,$.jsx)(`p`,{className:u.muted,role:`status`,children:_}):null,(0,$.jsxs)(`div`,{className:u.formActions,children:[n?(0,$.jsx)(a,{variant:`ghost`,size:`sm`,onClick:n,disabled:r,children:`Cancel`}):null,(0,$.jsx)(a,{type:`submit`,variant:`primary`,size:`sm`,busy:r,disabled:i,children:`Save budget`})]})]})}export{ue as a,A as c,le as d,j as f,B as i,I as l,O as m,R as n,E as o,M as p,T as r,L as s,de as t,H as u};
|
|
2
|
-
//# sourceMappingURL=CloudBudgetForm-
|
|
1
|
+
import{a as e,c as t,n}from"./index-DZ-UQ7v8.js";import{b as r,n as i}from"./format-CH4g_sl1.js";import{t as a}from"./Button-D90dzI_o.js";import{t as o}from"./Switch-9NtO_6Lj.js";import{o as s,s as c,t as l}from"./cloud-model-BDivRMqv.js";import{t as u}from"./cloud.module-DOP-N4Ch.js";import{t as d}from"./Input-D_KRJA9V.js";import{o as f,s as p}from"./why-seat-model-M_r0wX3b.js";function m(e,t){if(!e.resetsAt)return null;let n=Date.parse(e.resetsAt);return Number.isFinite(n)?n-t:null}function h(e,t,n){let r=t.id;if(e===`claude`){if(r===`five_hour`)return`session`;if(r===`seven_day`)return`weekly`;if(r.startsWith(`seven_day_`))return`model`}if(e===`grok`)return`weekly`;let i=m(t,n);if(e===`codex`){if(r.endsWith(`_secondary`))return`weekly`;if(r.endsWith(`_primary`))return i!==null&&i>189e5?`weekly`:`session`}return i!==null&&i<=189e5?`session`:`weekly`}var g=864e5,_=36e5;function v(e,t,n,r=0){let i=e.length-r,a=i-n;if(a<0||n<=0)return null;let o=0;for(let n=a;n<i;n++){let r=t(e[n]);if(r===null||!Number.isFinite(r))return null;o+=r}return o}function y(e,t,n){return e.slice(Math.max(0,e.length-n)).map(t)}function b(e){let t=e.filter(e=>e!==null&&Number.isFinite(e));return t.length?t.reduce((e,t)=>e+t,0)/t.length:null}function x(e){let t=e.meteredCostUsd;return typeof t==`number`&&Number.isFinite(t)&&t>=0?t:null}var ee=e=>e>0?`+${e}`:String(e),S=e=>`${e>0?`+`:``}${e.toFixed(1)}`,C=e=>`${e>0?`+`:e<0?`−`:``}$${Math.abs(e).toFixed(2)}`;function w(e){if(e===null||!Number.isFinite(e)||e<0)return`—`;let t=Math.round(e/6e4);if(t<60)return`${t}m`;let n=Math.floor(t/60);if(n<48)return t%60?`${n}h ${t%60}m`:`${n}h`;let r=Math.floor(n/24);return n%24?`${r}d ${n%24}h`:`${r}d`}function te(e){if(!e||e.repos.length===0)return[];let t=Math.max(...e.repos.map(e=>e.greenTrend.length));return Array.from({length:t},(n,r)=>b(e.repos.map(e=>e.greenTrend[r-(t-e.greenTrend.length)]??null)))}function T({fleet:e,history:t,learning:n,policy:r}){let i=t?.days??[],a=e=>e.merges.realized,o=x,s=e?.summary.merged7d??v(i,a,7),c=v(i,a,7,7),l=v(i,a,7),u=l!==null&&c!==null?l-c:null,d=e?.summary.postMergeGreenPct7d??null,f=te(e),p=f.length>=14?b(f.slice(-7)):null,m=f.length>=14?b(f.slice(-14,-7)):null,h=p!==null&&m!==null?p-m:null,g=v(i,o,7),_=v(i,o,7,7),T=r?r.spend.meteredUsdPerDay:null,E=g===null?`—`:`$${g.toFixed(2)}${T===null?``:` / $${(T*7).toFixed(0)}`}`,D=i.some(e=>x(e)!==null),O=T===null?`per-token APIs only`:T===0?`metered APIs off`:`cap $${T}/day`,k=D?O:`${O} · not reported yet`,A=n?.active??null,j=(A?.experimentId?n?.experiments.find(e=>e.id===A.experimentId)??null:null)?.lift??null;return[{id:`merged`,label:`Merged · 7d`,value:s===null?`—`:String(s),delta:u===null?null:{value:u,unit:Math.abs(u)===1?`merge`:`merges`,versus:`vs prior 7d`,goodWhenPositive:!0,format:ee},trend:i.length?y(i,a,14):void 0,trendLabel:`Merges per day, last 14 days`,caption:e?.summary.mergedToday==null?`fleet merges on default branches`:`${e.summary.mergedToday} today`},{id:`green`,label:`Post-merge green`,value:d===null?`—`:`${Math.round(d)}%`,delta:h===null?null:{value:h,unit:`pts`,versus:`vs prior 7d`,goodWhenPositive:!0,format:S},trend:f.length?f:void 0,trendLabel:`Post-merge green percent per day`,caption:d===null?`no completed post-merge watch yet`:`CI + suite 2 h after each merge`},{id:`cycle`,label:`Cycle time`,value:w(e?.summary.cycleTimeP50Ms7d??null),delta:null,trend:void 0,trendLabel:`Cycle time`,caption:`median, proposal → merge, 7d`},{id:`spend`,label:`Metered spend · 7d`,value:E,delta:g!==null&&_!==null?{value:g-_,versus:`vs prior 7d`,goodWhenPositive:!1,format:C}:null,trend:D?y(i,o,14):void 0,trendLabel:`Metered (per-token API) spend per day`,caption:k},{id:`lift`,label:`Lift`,value:j?`${S(j.mean)} pts`:`—`,delta:null,trend:void 0,trendLabel:`Harness lift`,caption:A?`harness ${A.id} vs baseline${j?` (95% ${S(j.ciLow)} to ${S(j.ciHigh)})`:``}`:`no harness adopted — defaults in force`}]}function E({fleet:e,history:t,learning:n}){let r=t?.days??[],i=e=>e.merges.realized,a=e?.summary.merged7d??v(r,i,7),o=v(r,i,7,7),s=n?.active??null,c=s?.experimentId?n?.experiments.find(e=>e.id===s.experimentId)?.lift??null:null;return(a??0)===0&&(o??0)===0&&(e?.summary.postMergeGreenPct7d??null)===null&&(e?.summary.cycleTimeP50Ms7d??null)===null&&(v(r,x,7)??0)===0&&c===null}var D=(e,t)=>e!==null&&Date.parse(e)>t;function O({lastLookedAt:e,fleet:t,leader:n,activity:r}){if(!e)return[];let i=Date.parse(e);if(!Number.isFinite(i))return[];let a=[],o=(t?.runs??[]).filter(e=>D(e.endedAt,i)),s=e=>o.filter(t=>t.outcome===e).length,c=s(`merged`),l=s(`reverted`),u=s(`failed`)+s(`refused`);c&&a.push({id:`merged`,text:`${c} merged`,tone:`success`}),l&&a.push({id:`reverted`,text:`${l} reverted`,tone:`danger`}),u&&a.push({id:`failed`,text:`${u} refused or failed`,tone:`warning`});let d=(n?.timeline??[]).filter(e=>Date.parse(e.at)>i&&e.status===`ok`).length;d&&a.push({id:`memos`,text:`${d} new memo${d===1?``:`s`}`,tone:`info`});let f=(r?.needsYou??[]).filter(e=>Date.parse(e.since)>i).length;return f&&a.push({id:`needs`,text:`${f} new for you`,tone:`warning`}),a}var k={high:0,warn:1,info:2};function A(e){return[...e].sort((e,t)=>k[e.severity]-k[t.severity]||Date.parse(t.since)-Date.parse(e.since))}function j(e,t){let n=new Map,r=(e,t)=>{typeof e==`string`&&typeof t==`string`&&t.trim().length>0&&n.set(e,t.trim())};for(let e of t?.seatInfo??[])r(e.seatId,e.label);for(let t of e??[])r(t.id,t.label);return n}function M(e){return e?Object.entries(e.sources).filter(([,e])=>e!==`ok`).map(([e])=>e):[]}function N(e,t){return`${e}#${t}`}var P=20;function F(e,t){let n=e.length;return n>=2&&e[n-1].used===t&&e[n-2].used===t}function I(e,t){if(!t)return{...e};let n=Date.parse(t.sampledAt);if(!Number.isFinite(n))return{...e};let r={...e};for(let e of t.headroom){let t=[[`session`,e.sessionUsedPercent],[`weekly`,e.weeklyUsedPercent]];for(let[i,a]of t){if(a===null||!Number.isFinite(a))continue;let t=N(e.seatId,i),o=r[t]??[];if(o.length&&o[o.length-1].t>=n)continue;let s=o.length&&a+P<o[o.length-1].used?[]:o;r[t]=[...F(s,a)?s.slice(0,-1):s,{t:n,used:a}].slice(-240)}}return r}function L(e,t){let n=typeof t?.generatedAt==`string`?Date.parse(t.generatedAt):NaN,r=new Map;for(let e of Array.isArray(t?.series)?t.series:[]){if(!e||typeof e.seatId!=`string`||e.window!==`session`&&e.window!==`weekly`||!Array.isArray(e.points))continue;let t=[];for(let n of e.points){if(!Array.isArray(n))continue;let[e,r]=n;typeof e==`number`&&Number.isFinite(e)&&typeof r==`number`&&Number.isFinite(r)&&r>=0&&r<=100&&t.push({t:e,used:r})}if(t.length===0)continue;let n=N(e.seatId,e.window);r.set(n,[...r.get(n)??[],...t])}let i={},a=new Set;for(let t of new Set([...Object.keys(e),...r.keys()])){let o=r.get(t)??[],s=e[t]??[];if(o.length>0){a.add(t);let e=Math.max(...o.map(e=>e.t)),r=Number.isFinite(n)?Math.max(n,e):e;s=s.filter(e=>e.t>r)}let c=new Map;for(let e of o)c.set(e.t,e);for(let e of s)c.set(e.t,e);let l=[...c.values()].sort((e,t)=>e.t-t.t),u=0;for(let e=1;e<l.length;e++)l[e].used+P<l[e-1].used&&(u=e);let d=[];for(let e of l.slice(u))F(d,e.used)&&d.pop(),d.push(e);i[t]=d.slice(-2e3)}return{readings:i,recorded:a}}var R={session:5*_,weekly:7*g};function z(e,t){if(!t||e.bindingWindow===null)return null;let n=100-t.reservePercent,r=t.maxSessionWindowPercent??100,i,a;e.bindingWindow===`weekly`||e.weeklyUsedPercent===null&&n<r?(i=n,a=`Reserved for you`):(i=r,a=`5-hour ceiling`);let o=100-i;return o>0?{value:o,label:a}:null}function B(e){let t=e===`session`?{weekday:`short`,hour:`numeric`,minute:`2-digit`}:{month:`short`,day:`numeric`,hour:`numeric`,minute:`2-digit`};return e=>{let n=new Date(e);return Number.isNaN(n.getTime())?``:n.toLocaleString(`en-US`,t)}}function V(e,t,n,r){if(!e?.capacity||n===null||t===`local`)return null;for(let i of e.capacity.windows){let e=typeof i.resetDescription==`string`?i.resetDescription.trim():``;if(e.length!==0&&h(t,{id:i.id,usedPercent:i.usedPercent,resetsAt:i.resetsAt,resetDescription:i.resetDescription,limitReached:i.limitReached},r)===n)return e}return null}function H(e){return`resets ${e.replace(/^resets\s+/i,``)}`}var U=[`jan`,`feb`,`mar`,`apr`,`may`,`jun`,`jul`,`aug`,`sep`,`oct`,`nov`,`dec`],W=/^(?:resets\s+)?(?:([A-Za-z]{3}) ([1-9]|[12]\d|3[01]) at )?([1-9]|1[0-2])(?::([0-5]\d))?(am|pm) \(([A-Za-z0-9_+-]+(?:\/[A-Za-z0-9_+-]+){0,2})\)$/i;function G(e,t){let n=t.formatToParts(new Date(e)),r=e=>Number(n.find(t=>t.type===e)?.value),i={y:r(`year`),mo:r(`month`)-1,d:r(`day`),h:r(`hour`)%24,mi:r(`minute`)};return Object.values(i).every(Number.isFinite)?i:null}var K=e=>Date.UTC(e.y,e.mo,e.d,e.h,e.mi);function q(e,t){let n=K(e),r=n;for(let e=0;e<3;e++){let e=G(r,t);if(!e)return null;let i=n-K(e);if(i===0)return r;r+=i}return null}function J(e,t){let n=W.exec(e.trim());if(!n||!Number.isFinite(t))return null;let[,r,i,a,o,s,c]=n,l;try{l=new Intl.DateTimeFormat(`en-US`,{timeZone:c,hourCycle:`h23`,year:`numeric`,month:`numeric`,day:`numeric`,hour:`numeric`,minute:`numeric`})}catch{return null}let u=G(t,l);if(!u)return null;let d=Number(a)%12+(s.toLowerCase()===`pm`?12:0),f=o===void 0?0:Number(o),p=[];if(r!==void 0){let e=U.indexOf(r.toLowerCase()),t=Number(i);if(e<0)return null;for(let n of[u.y-1,u.y,u.y+1])new Date(Date.UTC(n,e,t)).getUTCDate()===t&&p.push({y:n,mo:e,d:t,h:d,mi:f})}else for(let e of[-1,0,1]){let t=new Date(Date.UTC(u.y,u.mo,u.d+e));p.push({y:t.getUTCFullYear(),mo:t.getUTCMonth(),d:t.getUTCDate(),h:d,mi:f})}let m=null;for(let e of p){let n=q(e,l);n!==null&&(m===null||Math.abs(n-t)<Math.abs(m-t))&&(m=n)}return m}var Y=9e5,X=Date.UTC(2e3,0,1);function ne(e,t,n,r){let i=e?Date.parse(e):NaN;if(Number.isFinite(i)&&i>=X)return{at:i,from:`provider`};if(t===null||n===null)return null;let a=J(t,r);return a===null||a<r-Y||a>r+n+Y?null:{at:a,from:`words`}}function re(e){return Array.isArray(e)?e.filter(e=>typeof e==`string`&&e.trim().length>0).map(p):[]}var ie=6e4,ae=new Set([`reserve`,`session-ceiling`]);function Z(e){return typeof e==`string`?e.trim().replace(/^resets\s+/i,``):``}function oe(e){for(let t of e){if(!ae.has(t.kind))continue;let e=Z(t.resetDescription);if(e)return e}return null}function se(e,t,n){let i=typeof e.resetsAt==`string`?Date.parse(e.resetsAt):NaN;if(Number.isFinite(i))return t.resetAt!==null&&Math.abs(i-t.resetAt)<=ie?null:r(e.resetsAt,n);let a=Z(e.resetDescription);return!a||t.resetText!==null&&Z(t.resetText).toLowerCase()===a.toLowerCase()?null:a}function ce(e,t,n){if(!e)return null;let r=i(f(e.text,n));if(!r)return null;let a=se(e,t,n);return a?`${r} Resets ${a}.`:r}function le(e,t,n,r){if(!e)return[];let i=new Map(e.seatInfo.map(e=>[e.seatId,e])),a=new Map((n??[]).map(e=>[e.id,e])),o=Date.parse(e.sampledAt),s=Number.isFinite(o)?o:Date.now();return e.headroom.map(n=>{let o=i.get(n.seatId),c=o?.engine??`local`,l=n.bindingWindow?R[n.bindingWindow]:null,u=re(n.reasons),d=V(a.get(n.seatId),c,n.bindingWindow,s)??(n.bindingWindow===null||c===`local`?null:oe(u)),f=l===null?null:ne(n.resetAt,d,l,s),p=f&&l!==null?f.at-l:null,m=n.bindingWindow?N(n.seatId,n.bindingWindow):null,h=m?t[m]??[]:[];return{seatId:n.seatId,label:o?.label??n.seatId,engine:c,window:n.bindingWindow,points:h.filter(e=>p===null||e.t>=p).map(e=>({t:e.t,remaining:Math.max(0,100-e.used)})),start:p,resetAt:f?.at??null,resetFrom:f?.from??null,resetText:d,reservePercent:e.effective[n.seatId]?.reservePercent??0,line:z(n,e.effective[n.seatId]),enabled:e.effective[n.seatId]?.enabled??!1,free:o?.free??!1,eligible:n.eligibleForAutonomy,reason:ce(u[0],{resetAt:f?.at??null,resetText:d},s),recorded:m!==null&&(r?.has(m)??!1)}}).sort((e,t)=>Number(e.free)-Number(t.free)||e.label.localeCompare(t.label))}function ue(e){if(!e)return null;let t=e.seatInfo.find(e=>e.engine===`claude`);if(!t)return null;let n=e.effective[t.seatId];return n?{label:`Claude`,percent:n.reservePercent}:null}var Q=t(e(),1),$=n();function de({budget:e,onSave:t,onCancel:n,busy:r,disabled:i=!1,idPrefix:f}){let[p,m]=(0,Q.useState)(()=>s(e)),[h,g]=(0,Q.useState)({}),[_,v]=(0,Q.useState)(null),y=(0,Q.useRef)(!1);(0,Q.useEffect)(()=>{y.current||m(s(e))},[e]);let b=e=>{y.current=!0,v(null),m(t=>({...t,...e}))};return(0,$.jsxs)(`form`,{className:u.form,onSubmit:n=>{n.preventDefault();let r=c(p,e);if(!r.ok){g(r.errors);return}if(g({}),!r.changed){v(`Nothing changed.`);return}y.current=!1,t(r.update)},noValidate:!0,"aria-label":`Cloud budget`,children:[(0,$.jsx)(`div`,{className:u.fieldGrid,children:l.map(e=>(0,$.jsx)(d,{id:`${f}-${e.field}`,label:e.label,hint:e.hint,error:h[e.field],size:`sm`,inputMode:e.integer?`numeric`:`decimal`,prefix:e.money?`$`:void 0,value:p[e.field],disabled:i||r,onChange:t=>b({[e.field]:t.target.value})},e.field))}),(0,$.jsx)(o,{checked:p.selfImprove,onChange:e=>b({selfImprove:e}),label:`Verse may launch self-improvement tasks on its own`,disabled:i||r}),_?(0,$.jsx)(`p`,{className:u.muted,role:`status`,children:_}):null,(0,$.jsxs)(`div`,{className:u.formActions,children:[n?(0,$.jsx)(a,{variant:`ghost`,size:`sm`,onClick:n,disabled:r,children:`Cancel`}):null,(0,$.jsx)(a,{type:`submit`,variant:`primary`,size:`sm`,busy:r,disabled:i,children:`Save budget`})]})]})}export{ue as a,A as c,le as d,j as f,B as i,I as l,O as m,R as n,E as o,M as p,T as r,L as s,de as t,H as u};
|
|
2
|
+
//# sourceMappingURL=CloudBudgetForm-BrNun_Yu.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"CloudBudgetForm-CvjK4Oh6.js","names":[],"sources":["../../../../../../src/core/routing/headroom.ts","../../../../../../src/web-ui/routes/verse/command/command-model.ts","../../../../../../src/web-ui/routes/verse/cloud/CloudBudgetForm.tsx"],"sourcesContent":["/**\n * Live headroom per seat — how much of each seat autonomy may still use under\n * its budget policy (V3.10 unit A9).\n *\n * INPUT is a `SeatCapacity`: the public Verse seat projection (the same\n * windows `GET /api/verse/accounts` serves — Claude `five_hour`/`seven_day`,\n * Codex `codex_<bucket>_{primary,secondary}`, Grok's billing period) reduced to\n * what budgeting needs. OUTPUT is the contract's `SeatHeadroom`, plus the\n * reopening time the router needs for `SeatExclusion.nextEligibleAt`.\n *\n * HONESTY RULES (docs/VERSE-TELEMETRY-V2.md, and Mason's decision):\n * - Unknown usage is NOT headroom. A paid seat with no reading, a reported\n * account window with a null percent, or a reading older than\n * `readingMaxAgeMs` is ineligible for autonomy. This is the fix for the old\n * Claude fail-open, where \"no signal\" was treated as \"go ahead\".\n * - A spent PER-MODEL window is not a spent account. Claude's\n * `seven_day_fable` can read 100% while `five_hour` reads 15%; only the\n * account-wide windows bind (seats.ts `seatUsability` has the same rule).\n * - Claude publishes no machine-readable reset. Its reset is quoted in the\n * provider's own words and never turned into a timestamp or a countdown.\n * - Codex credits are paid overage. Autonomy never spends them, so a spent\n * Codex window blocks autonomy even when a balance exists.\n *\n * WINDOW SEMANTICS\n * - `reservePercent` keeps that share of the LONG (weekly / billing-period)\n * window for Mason: autonomy stops at `100 − reserve` used. A seat that\n * reports only a short window applies the reserve to that one.\n * - `maxSessionWindowPercent` is the ceiling on the SHORT (5-hour) window, so\n * a live interactive session is never starved (\"never touch Claude while\n * its 5-hour window is above 70%\").\n * - The binding window is whichever of the two leaves autonomy LESS room.\n *\n * BROWSER-SAFE and PURE: type-only imports, no clock reads (callers pass\n * `nowMs`), no I/O.\n */\nimport type { VerseSeat, VerseSeatCapacity } from '../verse/types.js';\nimport type { BudgetEngine } from './policy.js';\nimport { reasonSentences } from './seat-reasons.js';\nimport type { SeatBudgetPolicy, SeatHeadroom, SeatReason } from './types.js';\n\n/** A reading older than this is too stale to spend against (the collector polls every 30 s when active). */\nexport const HEADROOM_READING_MAX_AGE_MS = 15 * 60_000;\n\n/**\n * A window whose reset is further away than this cannot be a 5-hour window,\n * whatever its id says. Codex's `primary` bucket is USUALLY the 5-hour window,\n * but on 2026-09-24 both accounts reported a `primary` resetting ~42 h out —\n * so the reset distance, when known, overrides the id.\n */\nexport const SESSION_WINDOW_MAX_MS = 5 * 60 * 60_000 + 15 * 60_000;\n\nexport type SeatWindowClass = 'session' | 'weekly' | 'model';\n\nexport interface CapacityWindow {\n id: string;\n /** Provider percent; null = NO SIGNAL (not zero). */\n usedPercent: number | null;\n /** Machine reset; always null for Claude. */\n resetsAt: string | null;\n /** The provider's own reset wording (Claude), verbatim. */\n resetDescription: string | null;\n /** Provider explicitly flagged the limit (a denial, not a measurement). */\n limitReached: boolean;\n}\n\n/** What the budget layer needs to know about one seat. JSON-safe; persisted in the capacity snapshot. */\nexport interface SeatCapacity {\n seatId: string;\n engine: BudgetEngine;\n label: string;\n /** True for local runtime seats: $0 and no provider window. */\n free: boolean;\n windows: CapacityWindow[];\n /** The account reports no usable login. */\n signedOut: boolean;\n /** Can a turn reach this seat at all? Null when unknown. */\n reachable: boolean | null;\n /** Default model's context window in tokens; null when unknown. */\n contextWindow: number | null;\n /** When the windows were read; null when never. */\n observedAt: string | null;\n /** Today's metered spend in USD; null when unknown or not metered. */\n spentTodayUsd: number | null;\n}\n\n/** `SeatHeadroom` plus the facts the router needs but the wire shape does not carry. */\nexport interface SeatAssessment {\n headroom: SeatHeadroom;\n /** When the blocking condition is expected to lift; null when unknown / never / not blocked. */\n reopensAt: string | null;\n /** True when usage is known to be spent (limit flagged or ≥ 100%) on an account window. */\n exhausted: boolean;\n /** True when usage evidence is missing, partial or stale. */\n unknownUsage: boolean;\n /** The sentences naming each spent account window (a subset of `headroom.reasons`). */\n spentReasons: string[];\n /** `headroom.reasons` as data (same order): each sentence without its reset clause, plus the reset. */\n details: SeatReason[];\n /** `spentReasons` as data. */\n spentDetails: SeatReason[];\n}\n\nexport interface AssessOptions {\n nowMs: number;\n readingMaxAgeMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Projection from the public seat shape\n// ---------------------------------------------------------------------------\n\n/**\n * Reduce a public `VerseSeat` to a `SeatCapacity`. `liveCapacity`, when given,\n * replaces the seat's own (possibly cached) capacity — the caller re-reads\n * telemetry per request exactly as verse-api's `liveSeats` does.\n */\nexport function capacityFromSeat(seat: VerseSeat, liveCapacity?: VerseSeatCapacity | null): SeatCapacity {\n const free = seat.engine === 'local';\n const capacity = liveCapacity === undefined ? seat.capacity ?? null : liveCapacity;\n // A failed account check may retain a verified window for display until its\n // original expiry. Autonomy cannot spend against that prior reading.\n const current = !free && capacity &&\n (capacity.usability === 'ready' || capacity.usability === 'tight' || capacity.usability === 'exhausted')\n ? capacity : null;\n const windows: CapacityWindow[] = current === null ? [] : current.windows.map((w) => ({\n id: w.id,\n usedPercent: typeof w.usedPercent === 'number' && Number.isFinite(w.usedPercent)\n ? Math.max(0, Math.min(100, w.usedPercent))\n : null,\n resetsAt: w.resetsAt,\n resetDescription: w.resetDescription,\n limitReached: w.limitReached === true,\n }));\n const signedOut = !free && capacity?.usability === 'signed-out';\n return {\n seatId: seat.id,\n engine: seat.engine,\n label: seat.label,\n free,\n windows,\n signedOut,\n // A local seat is only listed when the runtime answered discovery. A\n // native seat is reachable unless signed out; \"no reading\" is a usage\n // question, not a reachability one.\n reachable: free ? true : signedOut ? false : null,\n contextWindow: typeof seat.contextWindow === 'number' && seat.contextWindow > 0 ? seat.contextWindow : null,\n observedAt: current === null ? null : current.observedAt ?? seat.health.observedAt ?? null,\n spentTodayUsd: null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Window classification\n// ---------------------------------------------------------------------------\n\nfunction resetDistanceMs(window: CapacityWindow, nowMs: number): number | null {\n if (!window.resetsAt) return null;\n const at = Date.parse(window.resetsAt);\n return Number.isFinite(at) ? at - nowMs : null;\n}\n\n/** Which role a window plays for budgeting. Per-model windows never bind. */\nexport function classifyWindow(engine: BudgetEngine, window: CapacityWindow, nowMs: number): SeatWindowClass {\n const id = window.id;\n if (engine === 'claude') {\n if (id === 'five_hour') return 'session';\n if (id === 'seven_day') return 'weekly';\n if (id.startsWith('seven_day_')) return 'model';\n }\n if (engine === 'grok') return 'weekly';\n const distance = resetDistanceMs(window, nowMs);\n if (engine === 'codex') {\n if (id.endsWith('_secondary')) return 'weekly';\n if (id.endsWith('_primary')) return distance !== null && distance > SESSION_WINDOW_MAX_MS ? 'weekly' : 'session';\n }\n // Unknown id: only a reset we can SEE inside five hours makes it short.\n return distance !== null && distance <= SESSION_WINDOW_MAX_MS ? 'session' : 'weekly';\n}\n\n/** Human name for a window, for reasons. */\nexport function windowName(engine: BudgetEngine, window: CapacityWindow, cls: SeatWindowClass): string {\n if (cls === 'session') return '5-hour window';\n if (cls === 'model') {\n const model = window.id.startsWith('seven_day_') ? window.id.slice('seven_day_'.length) : window.id;\n return `${model.charAt(0).toUpperCase()}${model.slice(1)}-only weekly window`;\n }\n if (engine === 'grok' || window.id.endsWith('_monthly')) {\n return window.id.endsWith('_monthly') ? 'monthly billing window' : window.id.endsWith('_weekly') ? 'weekly window' : 'billing-period window';\n }\n return 'weekly window';\n}\n\n/**\n * A window's reset as data: the machine instant when there is one, else\n * Claude's own words, verbatim — never a synthesized time. `reasonSentence`\n * turns it back into the \" (resets …)\" clause the string form has always had.\n */\nfunction resetOf(window: CapacityWindow): Pick<SeatReason, 'resetsAt' | 'resetDescription'> {\n if (window.resetsAt) return { resetsAt: window.resetsAt, resetDescription: null };\n return { resetsAt: null, resetDescription: window.resetDescription ?? null };\n}\n\nfunction isSpent(window: CapacityWindow): boolean {\n return window.limitReached || (window.usedPercent !== null && window.usedPercent >= 100);\n}\n\nfunction pct(value: number): string {\n return `${Math.round(value)}%`;\n}\n\nfunction formatAge(ms: number): string {\n const minutes = Math.round(ms / 60_000);\n if (minutes < 120) return `${minutes} min`;\n const hours = Math.round(minutes / 60);\n return hours < 48 ? `${hours} h` : `${Math.round(hours / 24)} days`;\n}\n\n// ---------------------------------------------------------------------------\n// Assessment\n// ---------------------------------------------------------------------------\n\ninterface ClassedWindow {\n window: CapacityWindow;\n cls: SeatWindowClass;\n}\n\n/** The highest reading among `rows`, with its window; null when none carried a percent. */\nfunction peak(rows: ClassedWindow[]): ClassedWindow | null {\n let best: ClassedWindow | null = null;\n for (const row of rows) {\n if (row.window.usedPercent === null) continue;\n if (best === null || row.window.usedPercent > best.window.usedPercent!) best = row;\n }\n return best;\n}\n\n/**\n * When EVERY spent window in `rows` has reset — the seat is blocked until the\n * last of them does, so this is the latest reset. Null unless every row has a\n * machine-readable reset (one unknown reset makes the reopening unknown).\n */\nfunction lastReset(rows: ClassedWindow[]): string | null {\n const times: string[] = [];\n for (const row of rows) {\n const at = row.window.resetsAt;\n if (!at || !Number.isFinite(Date.parse(at))) return null;\n times.push(at);\n }\n times.sort((a, b) => Date.parse(b) - Date.parse(a));\n return times[0] ?? null;\n}\n\n/** Full assessment of one seat for AUTONOMOUS use under `policy`. Pure. */\nexport function assessSeat(capacity: SeatCapacity, policy: SeatBudgetPolicy, opts: AssessOptions): SeatAssessment {\n const { nowMs } = opts;\n const maxAge = opts.readingMaxAgeMs ?? HEADROOM_READING_MAX_AGE_MS;\n // Reasons are built as data; `headroom.reasons` is derived from them.\n const details: SeatReason[] = [];\n\n // ── Local: free, windowless, bounded only by reachability ──────────────\n if (capacity.free) {\n const reachable = capacity.reachable !== false;\n if (!policy.enabled) details.push({ kind: 'switched-off', text: 'Autonomy is switched off for this seat.' });\n if (!reachable) details.push({ kind: 'unreachable', text: 'The local model runtime is not reachable.' });\n const eligible = policy.enabled && reachable;\n if (eligible) details.push({ kind: 'headroom', text: 'Local model — free, with no usage window to protect.' });\n return {\n headroom: {\n seatId: capacity.seatId,\n sessionUsedPercent: null,\n weeklyUsedPercent: null,\n bindingWindow: null,\n // No window binds a local seat; \"all of it\" is the honest number while\n // the runtime answers, and unknown while it does not.\n autonomyHeadroomPercent: reachable ? 100 : null,\n resetAt: null,\n eligibleForAutonomy: eligible,\n reasons: reasonSentences(details),\n },\n reopensAt: null,\n exhausted: false,\n unknownUsage: false,\n spentReasons: [],\n details,\n spentDetails: [],\n };\n }\n\n // ── Paid seat ──────────────────────────────────────────────────────────\n const classed: ClassedWindow[] = capacity.windows.map((window) => ({\n window,\n cls: classifyWindow(capacity.engine, window, nowMs),\n }));\n const account = classed.filter((row) => row.cls !== 'model');\n const sessionRows = account.filter((row) => row.cls === 'session');\n const weeklyRows = account.filter((row) => row.cls === 'weekly');\n const sessionPeak = peak(sessionRows);\n const weeklyPeak = peak(weeklyRows);\n const sessionUsed = sessionPeak?.window.usedPercent ?? null;\n const weeklyUsed = weeklyPeak?.window.usedPercent ?? null;\n\n // Evidence quality.\n const observedMs = capacity.observedAt ? Date.parse(capacity.observedAt) : NaN;\n const ageMs = Number.isFinite(observedMs) ? nowMs - observedMs : null;\n const stale = ageMs === null || ageMs > maxAge;\n const hasReading = sessionUsed !== null || weeklyUsed !== null;\n const nullWindow = account.find((row) => row.window.usedPercent === null && !row.window.limitReached);\n\n // Ceilings. The reserve protects the LONG window; with no long window it\n // protects the short one. The session ceiling protects a live session.\n const reserveCeiling = 100 - policy.reservePercent;\n const sessionCeiling = policy.maxSessionWindowPercent ?? 100;\n // With no long window the short one carries BOTH limits; say which one bit.\n const sessionLimitIsReserve = weeklyRows.length === 0 && reserveCeiling < sessionCeiling;\n const sessionLimit = sessionLimitIsReserve ? reserveCeiling : sessionCeiling;\n let weeklyRoom: number | null = null;\n let sessionRoom: number | null = null;\n if (weeklyUsed !== null) weeklyRoom = reserveCeiling - weeklyUsed;\n if (sessionUsed !== null) sessionRoom = sessionLimit - sessionUsed;\n let bindingWindow: SeatHeadroom['bindingWindow'] = null;\n let room: number | null = null;\n if (weeklyRoom !== null && (sessionRoom === null || weeklyRoom <= sessionRoom)) {\n bindingWindow = 'weekly';\n room = weeklyRoom;\n } else if (sessionRoom !== null) {\n bindingWindow = 'session';\n room = sessionRoom;\n }\n const bindingRow = bindingWindow === 'weekly' ? weeklyPeak : bindingWindow === 'session' ? sessionPeak : null;\n\n // Blockers, most fundamental first. Every one gets a plain sentence.\n let reopensAt: string | null = null;\n const spentRows = account.filter((row) => isSpent(row.window));\n const exhausted = spentRows.length > 0;\n const unknownUsage = !hasReading || stale || nullWindow !== undefined;\n\n if (!policy.enabled) details.push({ kind: 'switched-off', text: 'Autonomy is switched off for this seat.' });\n if (capacity.signedOut) {\n details.push({ kind: 'signed-out', text: 'Signed out — reconnect this account before anything can run on it.' });\n }\n\n const spentDetails: SeatReason[] = [];\n if (exhausted) {\n for (const row of spentRows) {\n const used = row.window.limitReached ? 'limit reached' : `${pct(row.window.usedPercent!)} used`;\n spentDetails.push({\n kind: 'spent',\n text: `The ${windowName(capacity.engine, row.window, row.cls)} is spent — ${used}.`,\n ...resetOf(row.window),\n });\n }\n details.push(...spentDetails);\n reopensAt = lastReset(spentRows);\n }\n\n if (!hasReading) {\n details.push({\n kind: 'unknown-usage',\n text: account.length === 0\n ? 'No usage reading for this seat — unknown usage is not headroom, so autonomy stays off it.'\n : 'Its usage windows carried no percentage — unknown usage is not headroom, so autonomy stays off it.',\n });\n } else if (stale) {\n details.push({\n kind: 'unknown-usage',\n text: ageMs === null\n ? 'The usage reading has no timestamp — too uncertain to spend against.'\n : `The usage reading is ${formatAge(ageMs)} old — too stale to spend against (limit ${formatAge(maxAge)}).`,\n });\n } else if (nullWindow) {\n details.push({\n kind: 'unknown-usage',\n text: `The ${windowName(capacity.engine, nullWindow.window, nullWindow.cls)} carried no percentage — `\n + 'unknown usage is not headroom.',\n });\n }\n\n const usdCap = policy.dailyUsdCap;\n let overUsd = false;\n if (usdCap !== undefined) {\n if (capacity.spentTodayUsd === null) {\n overUsd = true;\n details.push({ kind: 'spend-cap', text: `A $${usdCap.toFixed(2)} daily cap is set but today's spend on this seat is unknown.` });\n } else if (capacity.spentTodayUsd >= usdCap) {\n overUsd = true;\n details.push({ kind: 'spend-cap', text: `Spent $${capacity.spentTodayUsd.toFixed(2)} of its $${usdCap.toFixed(2)} daily cap.` });\n }\n }\n\n // Ceiling reasons only matter when the reading itself is trustworthy.\n const ceilingBlocked = !exhausted && !unknownUsage && room !== null && room <= 0;\n if (ceilingBlocked && bindingRow) {\n const name = windowName(capacity.engine, bindingRow.window, bindingRow.cls);\n const used = pct(bindingRow.window.usedPercent!);\n if (bindingWindow === 'session' && !sessionLimitIsReserve) {\n details.push({\n kind: 'session-ceiling',\n text: `The ${name} is ${used} used; autonomy stops at ${pct(sessionLimit)} to protect your live session.`,\n ...resetOf(bindingRow.window),\n });\n } else {\n details.push({\n kind: 'reserve',\n text: `The ${name} is ${used} used; ${pct(policy.reservePercent)} is kept for you, so autonomy `\n + `stops at ${pct(reserveCeiling)}.`,\n ...resetOf(bindingRow.window),\n });\n }\n reopensAt = bindingRow.window.resetsAt;\n }\n\n // Model-scoped windows are facts worth showing, never blockers.\n for (const row of classed) {\n if (row.cls === 'model' && isSpent(row.window)) {\n details.push({\n kind: 'model-window',\n text: `The ${windowName(capacity.engine, row.window, row.cls)} is spent — it limits that model only, not the account.`,\n });\n }\n }\n\n const eligible = policy.enabled && !capacity.signedOut && !exhausted && !unknownUsage && !overUsd\n && room !== null && room > 0;\n if (eligible && bindingRow) {\n const name = windowName(capacity.engine, bindingRow.window, bindingRow.cls);\n const kept = bindingWindow === 'weekly' || sessionLimitIsReserve\n ? policy.reservePercent > 0 ? ` (${pct(policy.reservePercent)} kept for you)` : ''\n : sessionLimit < 100 ? ` (autonomy stops at ${pct(sessionLimit)} to protect your live session)` : '';\n details.unshift({ kind: 'headroom', text: `${pct(room!)} of the ${name} is left for autonomy${kept}.` });\n }\n\n return {\n headroom: {\n seatId: capacity.seatId,\n sessionUsedPercent: sessionUsed,\n weeklyUsedPercent: weeklyUsed,\n bindingWindow,\n autonomyHeadroomPercent: room === null ? null : Math.max(0, Math.round(room)),\n resetAt: bindingRow?.window.resetsAt ?? null,\n eligibleForAutonomy: eligible,\n reasons: reasonSentences(details),\n },\n // A seat that is merely switched off, signed out, or unknown has no\n // known reopening — only a window reset is a date we can name.\n reopensAt: !policy.enabled || capacity.signedOut || unknownUsage || overUsd ? null : reopensAt,\n exhausted,\n unknownUsage,\n spentReasons: reasonSentences(spentDetails),\n details,\n spentDetails,\n };\n}\n\n/** The contract's `SeatHeadroom` for one seat. */\nexport function computeHeadroom(capacity: SeatCapacity, policy: SeatBudgetPolicy, opts: AssessOptions): SeatHeadroom {\n return assessSeat(capacity, policy, opts).headroom;\n}\n","/**\n * routes/verse/command/command-model.ts — the pure numbers behind Command's\n * KPI row, \"Since you looked\" strip, seat burn-downs and the Needs-you card\n * (unit C7; SPEC-310B §6, SPEC-310C §5).\n *\n * Honesty (docs/VERSE-TELEMETRY-V2.md): a KPI whose source did not answer\n * is \"—\", and a delta is computed only when BOTH windows are fully known — a\n * week with one unreadable day has no honest \"vs prior 7d\". Framework-free;\n * tested directly.\n */\nimport type { FleetLiveSnapshotV1, FleetLiveRun } from '../../../../core/fleet/fleet-types.js';\nimport type { LeaderStateV1 } from '../../../../core/vision/leader-types.js';\nimport type { LearningStateV1 } from '../../../../core/learn/harness-types.js';\nimport type { NeedsYouItem, NeedsYouSeverity, VerseActivityResponse } from '../../../../core/verse/workbench-types.js';\nimport type { FleetHistoryDay, FleetHistoryResponse } from '../../../../core/verse/fleet-history-types.js';\nimport type { BudgetView } from '../../../../core/routing/policy.js';\nimport type { CapacityHistoryResponse } from '../../../../core/routing/capacity-history-types.js';\nimport type { SeatReason, SeatReasonKind } from '../../../../core/routing/types.js';\nimport type { VerseSeat } from '../../../../core/verse/types.js';\nimport { classifyWindow } from '../../../../core/routing/headroom.js';\nimport { describeResetAt } from '../../../../core/verse/seat-readiness.js';\nimport type { EffectivePolicy } from '../../../../core/authority/types.js';\nimport type { StatTileDelta } from '../../../components/charts/StatTile.js';\nimport { asSentence, localTimes, parseLegacyReason } from '../fleet/why-seat-model.js';\n\nconst DAY = 86_400_000;\nconst HOUR = 3_600_000;\n\n// ---------------------------------------------------------------------------\n// Windows over the daily history\n// ---------------------------------------------------------------------------\n\n/** Sum of `pick` over days [end-len, end); null if any day in the window is unknown or missing. */\nexport function windowSum(days: readonly FleetHistoryDay[], pick: (d: FleetHistoryDay) => number | null, len: number, endOffset = 0): number | null {\n const end = days.length - endOffset;\n const start = end - len;\n if (start < 0 || len <= 0) return null;\n let total = 0;\n for (let i = start; i < end; i++) {\n const v = pick(days[i]!);\n if (v === null || !Number.isFinite(v)) return null;\n total += v;\n }\n return total;\n}\n\n/** The last `len` values of `pick`, oldest first (nulls kept — the sparkline breaks there). */\nexport function lastValues(days: readonly FleetHistoryDay[], pick: (d: FleetHistoryDay) => number | null, len: number): (number | null)[] {\n return days.slice(Math.max(0, days.length - len)).map(pick);\n}\n\nfunction mean(values: readonly (number | null)[]): number | null {\n const known = values.filter((v): v is number => v !== null && Number.isFinite(v));\n return known.length ? known.reduce((a, b) => a + b, 0) / known.length : null;\n}\n\n// ---------------------------------------------------------------------------\n// KPI row\n// ---------------------------------------------------------------------------\n\nexport interface Kpi {\n id: 'merged' | 'green' | 'cycle' | 'spend' | 'lift';\n label: string;\n /** Display string; \"—\" when unknown. */\n value: string;\n delta: StatTileDelta | null;\n trend: (number | null)[] | undefined;\n trendLabel: string;\n caption: string;\n}\n\nexport interface KpiInputs {\n fleet: FleetLiveSnapshotV1 | null;\n history: FleetHistoryResponse | null;\n learning: LearningStateV1 | null;\n policy: EffectivePolicy | null;\n /**\n * Accepted but no longer read: the spend caption used to list every paid\n * seat's window usage, which the seat burn-downs already show. Kept so\n * callers need not change.\n */\n budget?: BudgetView | null;\n}\n\n/**\n * The per-token (metered API) part of a day's spend, when the server splits\n * it out. WHY not `estCostUsd`: that field prices EVERY run's tokens from a\n * static table — Claude/Codex/Grok subscription CLI runs included — so\n * showing it as \"spend vs the metered cap\" reported subscription work as a\n * budget breach (review 3.10 c10; the default grant's cap is $0/day).\n * Subscriptions are not billed per token: their cost is window usage, shown\n * as percent. fleet-history reports `meteredCostUsd` per day (per-token API\n * engines only — core/verse/fleet-history.ts `runBilling`); a server that\n * predates it leaves the figure unknown — \"—\", never the mixed estimate.\n */\nexport function meteredCost(d: FleetHistoryDay): number | null {\n const v = (d as FleetHistoryDay & { meteredCostUsd?: number | null }).meteredCostUsd;\n return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : null;\n}\n\nconst signedInt = (v: number) => (v > 0 ? `+${v}` : String(v));\nconst signedPts = (v: number) => `${v > 0 ? '+' : ''}${v.toFixed(1)}`;\nconst signedUsd = (v: number) => `${v > 0 ? '+' : v < 0 ? '−' : ''}$${Math.abs(v).toFixed(2)}`;\n\n/** \"2h 14m\", \"38m\", \"3d 2h\". */\nexport function formatSpan(ms: number | null): string {\n if (ms === null || !Number.isFinite(ms) || ms < 0) return '—';\n const m = 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 const d = Math.floor(h / 24);\n return h % 24 ? `${d}d ${h % 24}h` : `${d}d`;\n}\n\n/** Mean daily post-merge green % across repos, per day (oldest first, 14 days). */\nexport function greenTrend(fleet: FleetLiveSnapshotV1 | null): (number | null)[] {\n if (!fleet || fleet.repos.length === 0) return [];\n const len = Math.max(...fleet.repos.map((r) => r.greenTrend.length));\n return Array.from({ length: len }, (_, i) => mean(fleet.repos.map((r) => r.greenTrend[i - (len - r.greenTrend.length)] ?? null)));\n}\n\nexport function buildKpis({ fleet, history, learning, policy }: KpiInputs): Kpi[] {\n const days = history?.days ?? [];\n const merges = (d: FleetHistoryDay) => d.merges.realized;\n const spend = meteredCost;\n\n // Merged · 7d — the live summary when the daemon answers, else the history window.\n const merged7 = fleet?.summary.merged7d ?? windowSum(days, merges, 7);\n const mergedPrior = windowSum(days, merges, 7, 7);\n const mergedNow = windowSum(days, merges, 7);\n const mergedDelta = mergedNow !== null && mergedPrior !== null ? mergedNow - mergedPrior : null;\n\n // Post-merge green — the 7-day figure plus the 14-day repo trend.\n const green = fleet?.summary.postMergeGreenPct7d ?? null;\n const gTrend = greenTrend(fleet);\n const gNow = gTrend.length >= 14 ? mean(gTrend.slice(-7)) : null;\n const gPrior = gTrend.length >= 14 ? mean(gTrend.slice(-14, -7)) : null;\n const greenDelta = gNow !== null && gPrior !== null ? gNow - gPrior : null;\n\n // Metered spend vs cap — per-token API spend ONLY (see meteredCost).\n const spend7 = windowSum(days, spend, 7);\n const spendPrior = windowSum(days, spend, 7, 7);\n const capPerDay = policy ? policy.spend.meteredUsdPerDay : null;\n const spendValue = spend7 === null ? '—' : `$${spend7.toFixed(2)}${capPerDay !== null ? ` / $${(capPerDay * 7).toFixed(0)}` : ''}`;\n const meteredKnown = days.some((d) => meteredCost(d) !== null);\n // One short line. Subscriptions are window usage, not dollars: they live\n // on the seat burn-downs, not in this caption.\n const capWords = capPerDay === null ? 'per-token APIs only' : capPerDay === 0 ? 'metered APIs off' : `cap $${capPerDay}/day`;\n const spendCaption = meteredKnown ? capWords : `${capWords} · not reported yet`;\n\n // Lift — the active harness's own experiment (null = baseline in force).\n const active = learning?.active ?? null;\n const activeExp = active?.experimentId ? learning?.experiments.find((e) => e.id === active.experimentId) ?? null : null;\n const lift = activeExp?.lift ?? null;\n\n return [\n {\n id: 'merged',\n label: 'Merged · 7d',\n value: merged7 === null ? '—' : String(merged7),\n delta: mergedDelta === null ? null : { value: mergedDelta, unit: Math.abs(mergedDelta) === 1 ? 'merge' : 'merges', versus: 'vs prior 7d', goodWhenPositive: true, format: signedInt },\n trend: days.length ? lastValues(days, merges, 14) : undefined,\n trendLabel: 'Merges per day, last 14 days',\n caption: fleet?.summary.mergedToday != null ? `${fleet.summary.mergedToday} today` : 'fleet merges on default branches',\n },\n {\n id: 'green',\n label: 'Post-merge green',\n value: green === null ? '—' : `${Math.round(green)}%`,\n delta: greenDelta === null ? null : { value: greenDelta, unit: 'pts', versus: 'vs prior 7d', goodWhenPositive: true, format: signedPts },\n trend: gTrend.length ? gTrend : undefined,\n trendLabel: 'Post-merge green percent per day',\n caption: green === null ? 'no completed post-merge watch yet' : 'CI + suite 2 h after each merge',\n },\n {\n id: 'cycle',\n label: 'Cycle time',\n value: formatSpan(fleet?.summary.cycleTimeP50Ms7d ?? null),\n delta: null,\n trend: undefined,\n trendLabel: 'Cycle time',\n caption: 'median, proposal → merge, 7d',\n },\n {\n id: 'spend',\n label: 'Metered spend · 7d',\n value: spendValue,\n delta: spend7 !== null && spendPrior !== null ? { value: spend7 - spendPrior, versus: 'vs prior 7d', goodWhenPositive: false, format: signedUsd } : null,\n trend: meteredKnown ? lastValues(days, spend, 14) : undefined,\n trendLabel: 'Metered (per-token API) spend per day',\n caption: spendCaption,\n },\n {\n id: 'lift',\n label: 'Lift',\n value: lift ? `${signedPts(lift.mean)} pts` : '—',\n delta: null,\n trend: undefined,\n trendLabel: 'Harness lift',\n caption: active ? `harness ${active.id} vs baseline${lift ? ` (95% ${signedPts(lift.ciLow)} to ${signedPts(lift.ciHigh)})` : ''}` : 'no harness adopted — defaults in force',\n },\n ];\n}\n\n/**\n * True when the KPI row would say nothing: no merge this week or last, no\n * post-merge reading, no cycle time, no metered spend, no lift — \"0\", four\n * dashes and \"$0.00\". Command drops the row then while its \"Autonomy is off\"\n * banner explains why; a row with any real figure is always kept.\n */\nexport function kpisSayNothing({ fleet, history, learning }: Pick<KpiInputs, 'fleet' | 'history' | 'learning'>): boolean {\n const days = history?.days ?? [];\n const merges = (d: FleetHistoryDay) => d.merges.realized;\n const merged7 = fleet?.summary.merged7d ?? windowSum(days, merges, 7);\n const mergedPrior = windowSum(days, merges, 7, 7);\n const active = learning?.active ?? null;\n const lift = active?.experimentId ? (learning?.experiments.find((e) => e.id === active.experimentId)?.lift ?? null) : null;\n return (\n (merged7 ?? 0) === 0 &&\n (mergedPrior ?? 0) === 0 &&\n (fleet?.summary.postMergeGreenPct7d ?? null) === null &&\n (fleet?.summary.cycleTimeP50Ms7d ?? null) === null &&\n (windowSum(days, meteredCost, 7) ?? 0) === 0 &&\n lift === null\n );\n}\n\n// ---------------------------------------------------------------------------\n// Since you looked\n// ---------------------------------------------------------------------------\n\nexport interface SinceItem {\n id: string;\n text: string;\n tone: 'success' | 'danger' | 'warning' | 'neutral' | 'info';\n}\n\nexport interface SinceInputs {\n /** ISO of the previous visit; null = first visit (nothing is \"new\"). */\n lastLookedAt: string | null;\n fleet: FleetLiveSnapshotV1 | null;\n leader: LeaderStateV1 | null;\n activity: VerseActivityResponse | null;\n}\n\nconst after = (iso: string | null, t: number) => iso !== null && Date.parse(iso) > t;\n\n/** What changed since the operator last opened Command, newest kinds first. */\nexport function sinceYouLooked({ lastLookedAt, fleet, leader, activity }: SinceInputs): SinceItem[] {\n if (!lastLookedAt) return [];\n const t = Date.parse(lastLookedAt);\n if (!Number.isFinite(t)) return [];\n const out: SinceItem[] = [];\n const ended = (fleet?.runs ?? []).filter((r) => after(r.endedAt, t));\n const count = (o: FleetLiveRun['outcome']) => ended.filter((r) => r.outcome === o).length;\n const merged = count('merged');\n const reverted = count('reverted');\n const failed = count('failed') + count('refused');\n if (merged) out.push({ id: 'merged', text: `${merged} merged`, tone: 'success' });\n if (reverted) out.push({ id: 'reverted', text: `${reverted} reverted`, tone: 'danger' });\n if (failed) out.push({ id: 'failed', text: `${failed} refused or failed`, tone: 'warning' });\n const memos = (leader?.timeline ?? []).filter((m) => Date.parse(m.at) > t && m.status === 'ok').length;\n if (memos) out.push({ id: 'memos', text: `${memos} new memo${memos === 1 ? '' : 's'}`, tone: 'info' });\n const fresh = (activity?.needsYou ?? []).filter((i) => Date.parse(i.since) > t).length;\n if (fresh) out.push({ id: 'needs', text: `${fresh} new for you`, tone: 'warning' });\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Needs you (Command card)\n// ---------------------------------------------------------------------------\n\nconst SEVERITY_RANK: Record<NeedsYouSeverity, number> = { high: 0, warn: 1, info: 2 };\n\n/** Most severe first, then newest. Pure — the drawer (C1) owns the full list. */\nexport function rankNeedsYou(items: readonly NeedsYouItem[]): NeedsYouItem[] {\n return [...items].sort((a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity] || Date.parse(b.since) - Date.parse(a.since));\n}\n\n/**\n * Seat id → the label every other surface names that seat by (\"Claude Max\",\n * never \"claude-a\"): the live roster when the cache holds it, else the\n * budget route's seat info (polled on Command, so present when the roster is\n * not). Both carry the same `VerseSeat.label` for the same id.\n */\nexport function seatNames(\n seats: readonly Pick<VerseSeat, 'id' | 'label'>[] | null | undefined,\n view: Pick<BudgetView, 'seatInfo'> | null | undefined,\n): Map<string, string> {\n const names = new Map<string, string>();\n const put = (id: unknown, label: unknown) => {\n if (typeof id === 'string' && typeof label === 'string' && label.trim().length > 0) names.set(id, label.trim());\n };\n for (const s of view?.seatInfo ?? []) put(s.seatId, s.label);\n for (const s of seats ?? []) put(s.id, s.label);\n return names;\n}\n\n/** Sources that did not answer — the card must not say \"All clear\" while any is listed. */\nexport function silentSources(activity: VerseActivityResponse | null): string[] {\n if (!activity) return [];\n return Object.entries(activity.sources).filter(([, state]) => state !== 'ok').map(([source]) => source);\n}\n\n// ---------------------------------------------------------------------------\n// Seat burn-downs\n// ---------------------------------------------------------------------------\n\nexport type SeatWindow = 'session' | 'weekly';\n\nexport interface SeatReading {\n t: number;\n /** Percent of the window used, 0–100. */\n used: number;\n}\n\n/**\n * Readings are kept per seat WINDOW, not per seat: the binding window can flip\n * between the 5-hour and the weekly window from one poll to the next, and a\n * line that mixed the two would draw a jump that never happened. Seat ids may\n * contain `:` and `/`, never `#` (the server keys its history the same way).\n */\nexport function seriesKey(seatId: string, window: SeatWindow): string {\n return `${seatId}#${window}`;\n}\n\n/**\n * The readings this page has seen since Verse opened, per seat window. The\n * budget route serves ONE reading per seat, so on their own these start the\n * burn-down empty on every load; `mergeSeatHistory` adds the server's recorded\n * history (GET /api/verse/budget/history — core/routing/capacity-history.ts,\n * written by the capacity publishers), so a reload keeps the whole window.\n * Memory only, bounded; never a guessed history.\n *\n * The bound counts CHANGES, not polls: a flat run keeps only its two ends\n * (see `recordReading`). At one poll per 30 s a plain 240-reading ring held\n * two hours — a sliver of a 7-day window — while window percent moves in\n * whole points a few times an hour.\n */\nexport const SEAT_READINGS_MAX = 240;\n/** A merged line (recorded history + this page's readings), flat runs collapsed: a week of changes fits. */\nexport const SEAT_HISTORY_MAX = 2000;\n/** A drop this large between consecutive readings is a window reset: the line starts again. */\nconst RESET_DROP = 20;\n\nfunction isFlatEnd(line: readonly SeatReading[], used: number): boolean {\n const n = line.length;\n return n >= 2 && line[n - 1]!.used === used && line[n - 2]!.used === used;\n}\n\nexport function recordReading(history: Readonly<Record<string, SeatReading[]>>, view: BudgetView | null): Record<string, SeatReading[]> {\n if (!view) return { ...history };\n const t = Date.parse(view.sampledAt);\n if (!Number.isFinite(t)) return { ...history };\n const next: Record<string, SeatReading[]> = { ...history };\n for (const h of view.headroom) {\n const windows: [SeatWindow, number | null][] = [['session', h.sessionUsedPercent], ['weekly', h.weeklyUsedPercent]];\n for (const [window, used] of windows) {\n if (used === null || !Number.isFinite(used)) continue;\n const key = seriesKey(h.seatId, window);\n const prev = next[key] ?? [];\n if (prev.length && prev[prev.length - 1]!.t >= t) continue;\n // A reset (used dropped sharply) starts a new window — drop the old one.\n const fresh = prev.length && used + RESET_DROP < prev[prev.length - 1]!.used ? [] : prev;\n // A flat run keeps only its first and latest reading: the line through\n // them is identical, and the ring then spans hours or days, not minutes.\n next[key] = [...(isFlatEnd(fresh, used) ? fresh.slice(0, -1) : fresh), { t, used }].slice(-SEAT_READINGS_MAX);\n }\n }\n return next;\n}\n\nexport interface MergedSeatHistory {\n /** One line per seat window, oldest first, starting after its last reset. */\n readings: Record<string, SeatReading[]>;\n /** Series keys the server's recorded history contributed readings to. */\n recorded: ReadonlySet<string>;\n}\n\n/**\n * The server's recorded history merged with this page's live readings, per\n * seat window: oldest first, one reading per instant, cut after the last\n * reset drop and with flat runs collapsed — the same rules `recordReading`\n * applies, so the line reads the same either way. `server` is untrusted wire\n * data: malformed series and points are skipped.\n *\n * ONE CLOCK PER STRETCH OF LINE (review 3.10.1). The two sources stamp the\n * same observation differently: a recorded row carries the provider\n * reading's `observedAt` (capacity-history.ts), a live reading the budget\n * route's `sampledAt` — when it was ASKED, which is later, and the budget\n * wire carries no `observedAt` to do better. Interleaved, the same value\n * lands at two instants and an older value can sort after a newer one: a\n * poll just after a reset still serving 85% drew 85 → 3 → 85 → 3. So the\n * recorded history is authoritative for every instant it covers — up to the\n * moment the server answered (`generatedAt`), or its newest row when that is\n * later or `generatedAt` is unreadable — and live readings only extend a\n * recorded line past that point. The server records the snapshot behind\n * each budget read (capacity-history-api.ts, throttled to 15 s), so a live\n * reading hidden this way is recorded at its own `observedAt` by the next\n * history read, and until then the next live poll carries the same value.\n * A live reading after `generatedAt` came from a collector that had already\n * seen every recorded observation, so the extension never runs backwards.\n * Both instants are the Verse server's own clock. A window with no recorded\n * series keeps every live reading.\n */\nexport function mergeSeatHistory(live: Readonly<Record<string, SeatReading[]>>, server: CapacityHistoryResponse | null): MergedSeatHistory {\n const generatedAt = typeof server?.generatedAt === 'string' ? Date.parse(server.generatedAt) : Number.NaN;\n const persisted = new Map<string, SeatReading[]>();\n for (const series of Array.isArray(server?.series) ? server!.series : []) {\n if (!series || typeof series.seatId !== 'string' || (series.window !== 'session' && series.window !== 'weekly') || !Array.isArray(series.points)) continue;\n const points: SeatReading[] = [];\n for (const p of series.points) {\n if (!Array.isArray(p)) continue;\n const [t, used] = p as unknown[];\n if (typeof t === 'number' && Number.isFinite(t) && typeof used === 'number' && Number.isFinite(used) && used >= 0 && used <= 100) points.push({ t, used });\n }\n if (points.length === 0) continue;\n const key = seriesKey(series.seatId, series.window);\n persisted.set(key, [...(persisted.get(key) ?? []), ...points]);\n }\n const readings: Record<string, SeatReading[]> = {};\n const recorded = new Set<string>();\n for (const key of new Set([...Object.keys(live), ...persisted.keys()])) {\n const fromServer = persisted.get(key) ?? [];\n let fromPage = live[key] ?? [];\n if (fromServer.length > 0) {\n recorded.add(key);\n const newestRecorded = Math.max(...fromServer.map((r) => r.t));\n const coveredTo = Number.isFinite(generatedAt) ? Math.max(generatedAt, newestRecorded) : newestRecorded;\n fromPage = fromPage.filter((r) => r.t > coveredTo);\n }\n // Recorded rows can repeat an instant (two series under one key); the\n // last one read stands. Live readings are strictly later than all of them.\n const byT = new Map<number, SeatReading>();\n for (const r of fromServer) byT.set(r.t, r);\n for (const r of fromPage) byT.set(r.t, r);\n const sorted = [...byT.values()].sort((a, b) => a.t - b.t);\n let start = 0;\n for (let i = 1; i < sorted.length; i++) if (sorted[i]!.used + RESET_DROP < sorted[i - 1]!.used) start = i;\n const line: SeatReading[] = [];\n for (const r of sorted.slice(start)) {\n if (isFlatEnd(line, r.used)) line.pop();\n line.push(r);\n }\n readings[key] = line.slice(-SEAT_HISTORY_MAX);\n }\n return { readings, recorded };\n}\n\nexport interface SeatBurn {\n seatId: string;\n label: string;\n engine: 'claude' | 'codex' | 'grok' | 'local';\n window: 'session' | 'weekly' | null;\n /** Remaining percent readings (100 − used), inside [start, resetAt] when the reset is known. */\n points: { t: number; remaining: number | null }[];\n /** `resetAt` minus the window's length; null exactly when `resetAt` is. */\n start: number | null;\n resetAt: number | null;\n /**\n * Where `resetAt` came from: the budget route's machine instant\n * ('provider'), the provider's own reset words read on the clock they name\n * ('words' — see `resetInstantFromWords`), or nowhere (null).\n */\n resetFrom: 'provider' | 'words' | null;\n /**\n * The provider's own reset wording for the binding window, verbatim\n * (\"Sep 25 at 7pm (America/New_York)\"), when the seat roster carries it.\n * Claude publishes ONLY this — never a machine instant. The card always\n * shows the words; when they name a clock time inside this window they\n * also place the reset (`resetFrom: 'words'`), otherwise the card draws the\n * readings with no reset point or projection.\n */\n resetText: string | null;\n reservePercent: number;\n /**\n * The line autonomy stops at IN THE WINDOW THIS CHART DRAWS, as remaining\n * percent (see `bindingLine`); null when that window has no limit.\n */\n line: { value: number; label: string } | null;\n enabled: boolean;\n free: boolean;\n eligible: boolean;\n /**\n * The router's first reason for this seat in words (`seatReasonText`):\n * complete sentences, local times, never the log form's \" (resets <ISO>).\"\n * clause. Null when the route gave none.\n */\n reason: string | null;\n /**\n * True when the server's recorded history contributed to this window's\n * line; false when every point is one this page saw since Verse opened.\n * Picks the card's note when the line starts late in the window.\n */\n recorded: boolean;\n}\n\n/** Length of each provider window, for the chart domain (reset − length → reset). */\nexport const WINDOW_MS = { session: 5 * HOUR, weekly: 7 * DAY } as const;\n\n/**\n * The stop line for the binding window, mirroring core/routing/headroom.ts\n * exactly (review 3.10 d2). The reserve protects the LONG (weekly) window;\n * the 5-hour window is capped by `maxSessionWindowPercent` — except when the\n * seat has no weekly window at all, where the short one carries both limits\n * and the tighter one wins. Drawing the weekly reserve on a 5-hour chart put\n * Mason's balanced cutoff at 60% used instead of 70% and made the verdict say\n * \"autonomy has stopped\" while the server still had the seat eligible.\n *\n * `weeklyUsedPercent === null` stands in for \"no weekly window\": a weekly\n * window whose reading is unknown makes the seat ineligible server-side\n * anyway (unknown usage is never headroom), and the card shows that reason.\n */\nexport function bindingLine(\n h: { bindingWindow: 'session' | 'weekly' | null; weeklyUsedPercent: number | null },\n policy: { reservePercent: number; maxSessionWindowPercent?: number } | undefined,\n): { value: number; label: string } | null {\n if (!policy || h.bindingWindow === null) return null;\n const reserveCeiling = 100 - policy.reservePercent;\n const sessionCeiling = policy.maxSessionWindowPercent ?? 100;\n let ceiling: number;\n let label: string;\n if (h.bindingWindow === 'weekly') {\n ceiling = reserveCeiling;\n label = 'Reserved for you';\n } else if (h.weeklyUsedPercent === null && reserveCeiling < sessionCeiling) {\n ceiling = reserveCeiling;\n label = 'Reserved for you';\n } else {\n ceiling = sessionCeiling;\n label = '5-hour ceiling';\n }\n const value = 100 - ceiling;\n return value > 0 ? { value, label } : null;\n}\n\n/**\n * Axis/verdict time format per window (review 3.10 c17). A weekly window\n * starts exactly seven days before it resets, so weekday + time alone printed\n * \"Sat 10:27 AM … Resets Sat 10:27 AM\"; the weekly form carries the date.\n * It carries ONLY the date (3.10.1): inside one week the weekday repeats what\n * the date says, and at a quarter-width card \"Fri, Sep 18 at 11:46 PM\" +\n * \"Resets Fri, Sep 25 at 11:46 PM\" were wider than the plot and collided.\n */\nexport function burnTimeFormat(window: 'session' | 'weekly' | null): (ms: number) => string {\n const opts: Intl.DateTimeFormatOptions =\n window === 'session'\n ? { weekday: 'short', hour: 'numeric', minute: '2-digit' }\n : { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' };\n return (ms) => {\n const d = new Date(ms);\n return Number.isNaN(d.getTime()) ? '' : d.toLocaleString('en-US', opts);\n };\n}\n\n/**\n * The provider's reset wording for the seat window that plays `binding`'s\n * role. WHY the seat roster and not the budget route: `SeatHeadroom` (the\n * frozen budget wire shape) carries only a machine `resetAt`, which is\n * structurally null for Claude — the provider's sentence lives on the seat's\n * capacity windows. The window is picked with the SAME classifier the server\n * used to choose the binding window (core/routing/headroom.ts), so the words\n * belong to the window the chart draws, not to a per-model window beside it.\n */\nexport function bindingResetText(\n seat: Pick<VerseSeat, 'capacity'> | undefined,\n engine: SeatBurn['engine'],\n binding: 'session' | 'weekly' | null,\n nowMs: number,\n): string | null {\n if (!seat?.capacity || binding === null || engine === 'local') return null;\n for (const w of seat.capacity.windows) {\n const text = typeof w.resetDescription === 'string' ? w.resetDescription.trim() : '';\n if (text.length === 0) continue;\n if (classifyWindow(engine, { id: w.id, usedPercent: w.usedPercent, resetsAt: w.resetsAt, resetDescription: w.resetDescription, limitReached: w.limitReached }, nowMs) === binding) return text;\n }\n return null;\n}\n\n/**\n * \"resets Sep 25 at 7pm (America/New_York)\" from the provider's words. The\n * collector strips the leading \"resets\" (claude-account-usage.ts) but other\n * paths keep it; either way the sentence itself is shown verbatim.\n */\nexport function resetWords(text: string): string {\n return `resets ${text.replace(/^resets\\s+/i, '')}`;\n}\n\nconst MONTHS: readonly string[] = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];\n\n/**\n * The collector's own reset grammar (core/resources/claude-account-usage.ts\n * `RESET`), with the leading \"resets\" optional because other paths keep it.\n * Anything outside it — a changed native format, free prose — stays words.\n */\nconst RESET_WORDS_RE = /^(?:resets\\s+)?(?:([A-Za-z]{3}) ([1-9]|[12]\\d|3[01]) at )?([1-9]|1[0-2])(?::([0-5]\\d))?(am|pm) \\(([A-Za-z0-9_+-]+(?:\\/[A-Za-z0-9_+-]+){0,2})\\)$/i;\n\ninterface WallClock { y: number; mo: number; d: number; h: number; mi: number }\n\nfunction wallClock(ms: number, fmt: Intl.DateTimeFormat): WallClock | null {\n const parts = fmt.formatToParts(new Date(ms));\n const n = (type: Intl.DateTimeFormatPartTypes) => Number(parts.find((p) => p.type === type)?.value);\n const c = { y: n('year'), mo: n('month') - 1, d: n('day'), h: n('hour') % 24, mi: n('minute') };\n return Object.values(c).every(Number.isFinite) ? c : null;\n}\n\nconst wallAsUtc = (c: WallClock) => Date.UTC(c.y, c.mo, c.d, c.h, c.mi);\n\n/**\n * The instant whose wall clock in `fmt`'s zone reads `want`: start from the\n * wall time as if it were UTC and correct by the zone's offset until the\n * clock agrees. Null when it never does — a time skipped by a DST jump.\n */\nfunction instantAt(want: WallClock, fmt: Intl.DateTimeFormat): number | null {\n const target = wallAsUtc(want);\n let at = target;\n for (let i = 0; i < 3; i++) {\n const seen = wallClock(at, fmt);\n if (!seen) return null;\n const drift = target - wallAsUtc(seen);\n if (drift === 0) return at;\n at += drift;\n }\n return null;\n}\n\n/**\n * The instant named by the provider's reset words — \"Sep 25 at 6:59pm\n * (America/New_York)\" or \"1:40am (America/New_York)\" — or null when the words\n * are not in the collector's grammar or name an unknown zone.\n *\n * WHY this is not \"synthesizing a countdown from a description\"\n * (core/verse/types.ts): the words ARE an instant — a wall-clock minute in a\n * named IANA zone — so reading them on that zone's clock adds nothing the\n * provider did not say. The only thing the words leave out is the year (or,\n * for \"1:40am\", the day), and the candidate nearest `nowMs` is taken; the\n * caller still refuses an instant outside the window's own span\n * (`seatBurns`), so a misread can never stretch or shift the chart by more\n * than the window it draws. Without this, Claude — the seat that matters\n * most — was the one card with no window, no pace line and no projection.\n */\nexport function resetInstantFromWords(text: string, nowMs: number): number | null {\n const m = RESET_WORDS_RE.exec(text.trim());\n if (!m || !Number.isFinite(nowMs)) return null;\n const [, month, day, hour, minute, meridiem, zone] = m;\n let fmt: Intl.DateTimeFormat;\n try {\n fmt = new Intl.DateTimeFormat('en-US', { timeZone: zone, hourCycle: 'h23', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric' });\n } catch {\n return null; // RangeError: not a zone this runtime knows.\n }\n const today = wallClock(nowMs, fmt);\n if (!today) return null;\n const h = (Number(hour) % 12) + (meridiem!.toLowerCase() === 'pm' ? 12 : 0);\n const mi = minute === undefined ? 0 : Number(minute);\n const candidates: WallClock[] = [];\n if (month !== undefined) {\n const mo = MONTHS.indexOf(month.toLowerCase());\n const d = Number(day);\n if (mo < 0) return null;\n for (const y of [today.y - 1, today.y, today.y + 1]) {\n // Feb 30 would roll into March — refuse it rather than move the reset.\n if (new Date(Date.UTC(y, mo, d)).getUTCDate() === d) candidates.push({ y, mo, d, h, mi });\n }\n } else {\n for (const k of [-1, 0, 1]) {\n const date = new Date(Date.UTC(today.y, today.mo, today.d + k));\n candidates.push({ y: date.getUTCFullYear(), mo: date.getUTCMonth(), d: date.getUTCDate(), h, mi });\n }\n }\n let best: number | null = null;\n for (const c of candidates) {\n const at = instantAt(c, fmt);\n if (at !== null && (best === null || Math.abs(at - nowMs) < Math.abs(best - nowMs))) best = at;\n }\n return best;\n}\n\n/**\n * How far a words-derived reset may sit in the past (a reading taken just\n * before the rollover) or beyond one window ahead (the provider rounds its\n * words to the minute or the hour).\n */\nconst WORDS_RESET_SLACK_MS = 15 * 60_000;\n\n/**\n * The binding window's reset instant: the budget route's machine instant when\n * there is one, else the provider's words read on their own clock — but only\n * when that instant can close the window the current reading sits in (no\n * more than one window ahead, no more than a few minutes past). Words that\n * fail either test stay words, and the card says the reset is not placed.\n */\n/** Earliest instant accepted as a real reset (2000-01-01T00:00:00Z). */\nconst PLAUSIBLE_RESET_FLOOR_MS = Date.UTC(2000, 0, 1);\n\nexport function bindingReset(\n machine: string | null,\n resetText: string | null,\n windowMs: number | null,\n nowMs: number,\n): { at: number; from: 'provider' | 'words' } | null {\n const at = machine ? Date.parse(machine) : NaN;\n // A placeholder instant (epoch 0 or anything before 2000) is not a reset —\n // fall through to the provider's words, as if no instant were sent.\n if (Number.isFinite(at) && at >= PLAUSIBLE_RESET_FLOOR_MS) return { at, from: 'provider' };\n if (resetText === null || windowMs === null) return null;\n const words = resetInstantFromWords(resetText, nowMs);\n if (words === null || words < nowMs - WORDS_RESET_SLACK_MS || words > nowMs + windowMs + WORDS_RESET_SLACK_MS) return null;\n return { at: words, from: 'words' };\n}\n\n// ---------------------------------------------------------------------------\n// Seat reasons, in words (3.10.1)\n// ---------------------------------------------------------------------------\n\n/**\n * The budget route's reasons as data. `SeatHeadroom.reasons` carries each\n * one in the router's LOG form — \"… so autonomy stops at 92% (resets\n * 2026-09-26T03:46:56.000Z).\" (core/routing/seat-reasons.ts\n * `reasonSentence`) — so the reset clause is split back off with the Fleet\n * surface's own parser: an instant → `resetsAt`, Claude's words →\n * `resetDescription`. Non-strings and blanks are skipped (wire data).\n */\nexport function seatReasons(reasons: readonly unknown[] | null | undefined): SeatReason[] {\n if (!Array.isArray(reasons)) return [];\n return reasons.filter((r): r is string => typeof r === 'string' && r.trim().length > 0).map(parseLegacyReason);\n}\n\n/** Two resets this close are the same one (the router and the chart read the same window). */\nconst SAME_RESET_MS = 60_000;\n\n/**\n * Reasons whose reset is, by construction, the BINDING window's: headroom.ts\n * attaches `resetOf(bindingRow.window)` to exactly these. A `spent` reason\n * can name the other window (a spent 5-hour window beside a weekly one that\n * is even further past its reserve), so it is never taken for the chart's.\n */\nconst BINDING_RESET_KINDS: ReadonlySet<SeatReasonKind> = new Set<SeatReasonKind>(['reserve', 'session-ceiling']);\n\n/** Claude's words without the \"resets\" some paths lead with. */\nfunction bareResetWords(text: string | null | undefined): string {\n return typeof text === 'string' ? text.trim().replace(/^resets\\s+/i, '') : '';\n}\n\n/**\n * The binding window's reset words from the router's own reasons — the\n * fallback when the roster (read from cache, never fetched here) has none,\n * so a card never says \"reset time not reported\" beside a reason that names\n * the reset.\n */\nexport function reasonResetText(reasons: readonly SeatReason[]): string | null {\n for (const r of reasons) {\n if (!BINDING_RESET_KINDS.has(r.kind)) continue;\n const words = bareResetWords(r.resetDescription);\n if (words) return words;\n }\n return null;\n}\n\n/**\n * When `reason` lifts, in the viewer's words — or null when the card already\n * says it: the chart's reset marker (\"Resets Sep 26, 11:46 PM\", a machine\n * instant or Claude's words placed on their clock) or the header's verbatim\n * words. A reset the card does NOT show (another window's) is kept: a machine\n * instant in the viewer's zone (`describeResetAt`, as Fleet and Accounts\n * word it), Claude's words verbatim.\n */\nfunction unshownReset(reason: SeatReason, card: { resetAt: number | null; resetText: string | null }, nowMs: number): string | null {\n const at = typeof reason.resetsAt === 'string' ? Date.parse(reason.resetsAt) : Number.NaN;\n if (Number.isFinite(at)) {\n if (card.resetAt !== null && Math.abs(at - card.resetAt) <= SAME_RESET_MS) return null;\n return describeResetAt(reason.resetsAt, nowMs);\n }\n const words = bareResetWords(reason.resetDescription);\n if (!words) return null;\n if (card.resetText !== null && bareResetWords(card.resetText).toLowerCase() === words.toLowerCase()) return null;\n return words;\n}\n\n/**\n * What a card says about why the router holds a seat back: the reason's own\n * sentence (any instant inside it in local time — Fleet's `localTimes`),\n * closed by exactly one full stop, then \"Resets ….\" only when the card does\n * not already show that reset (`unshownReset`). Never the log form: held-back\n * cards printed \"… stops at 92% (resets 2026-09-26T03:46:56.000Z).\" and, for\n * Claude, \"… (resets Sep 25 at 7pm (America/New_York)).\" verbatim.\n */\nexport function seatReasonText(reason: SeatReason | undefined, card: { resetAt: number | null; resetText: string | null }, nowMs: number): string | null {\n if (!reason) return null;\n const text = asSentence(localTimes(reason.text, nowMs));\n if (!text) return null;\n const when = unshownReset(reason, card, nowMs);\n return when ? `${text} Resets ${when}.` : text;\n}\n\n/**\n * One burn-down per seat, paid seats first (they are the ones that run out).\n * `history` is keyed by `seriesKey` (seat + window); each card draws its\n * BINDING window's line. `seats` (the live roster, optional) supplies the\n * provider's reset wording for seats that publish no machine reset time (see\n * `bindingResetText`), which also places their reset when it names a clock\n * time (`bindingReset`); without a roster, a reason held at the binding\n * window's reserve or ceiling supplies the same words (`reasonResetText`).\n * `recorded` (from `mergeSeatHistory`) names the lines the server's recorded\n * history contributed to. Each card's `reason` is the router's first reason\n * in words (`seatReasonText`).\n */\nexport function seatBurns(\n view: BudgetView | null,\n history: Readonly<Record<string, SeatReading[]>>,\n seats?: readonly VerseSeat[] | null,\n recorded?: ReadonlySet<string> | null,\n): SeatBurn[] {\n if (!view) return [];\n const info = new Map(view.seatInfo.map((s) => [s.seatId, s]));\n const roster = new Map((seats ?? []).map((s) => [s.id, s]));\n const sampled = Date.parse(view.sampledAt);\n const nowMs = Number.isFinite(sampled) ? sampled : Date.now();\n return view.headroom\n .map((h): SeatBurn => {\n const i = info.get(h.seatId);\n const engine = i?.engine ?? 'local';\n const windowMs = h.bindingWindow ? WINDOW_MS[h.bindingWindow] : null;\n const reasons = seatReasons(h.reasons);\n const resetText =\n bindingResetText(roster.get(h.seatId), engine, h.bindingWindow, nowMs) ??\n (h.bindingWindow === null || engine === 'local' ? null : reasonResetText(reasons));\n // A reset is only placed on a chart that has a window to put before it.\n const reset = windowMs === null ? null : bindingReset(h.resetAt, resetText, windowMs, nowMs);\n const start = reset && windowMs !== null ? reset.at - windowMs : null;\n const key = h.bindingWindow ? seriesKey(h.seatId, h.bindingWindow) : null;\n const readings = key ? history[key] ?? [] : [];\n return {\n seatId: h.seatId,\n label: i?.label ?? h.seatId,\n engine,\n window: h.bindingWindow,\n points: readings.filter((r) => start === null || r.t >= start).map((r) => ({ t: r.t, remaining: Math.max(0, 100 - r.used) })),\n start,\n resetAt: reset?.at ?? null,\n resetFrom: reset?.from ?? null,\n resetText,\n reservePercent: view.effective[h.seatId]?.reservePercent ?? 0,\n line: bindingLine(h, view.effective[h.seatId]),\n enabled: view.effective[h.seatId]?.enabled ?? false,\n free: i?.free ?? false,\n eligible: h.eligibleForAutonomy,\n reason: seatReasonText(reasons[0], { resetAt: reset?.at ?? null, resetText }, nowMs),\n recorded: key !== null && (recorded?.has(key) ?? false),\n };\n })\n .sort((a, b) => Number(a.free) - Number(b.free) || a.label.localeCompare(b.label));\n}\n\n/** \"Claude 40% reserved for you\" — the first enabled Claude seat's reserve, from the live budget. */\nexport function claudeReserve(view: BudgetView | null): { label: string; percent: number } | null {\n if (!view) return null;\n const seat = view.seatInfo.find((s) => s.engine === 'claude');\n if (!seat) return null;\n const policy = view.effective[seat.seatId];\n return policy ? { label: 'Claude', percent: policy.reservePercent } : null;\n}\n","/**\n * routes/verse/cloud/CloudBudgetForm.tsx — the cloud budget's fields, shared\n * by Command's \"Edit budget\" popover and the Usage \"Cloud credits\" panel\n * (3.11 unit C3), so both edit the same numbers the same way.\n *\n * Save sends ONE update with only the fields that changed (cloud-model\n * budgetPatch). The form re-seeds from the server's budget whenever that\n * budget changes and nothing has been typed, so a save elsewhere (the CLI,\n * the other surface) shows up instead of being silently overwritten.\n */\nimport { useEffect, useRef, useState, type FormEvent } from 'react';\nimport type { CloudBudgetUpdate, CloudBudgetV1 } from '../../../../core/cloud/types.js';\nimport { Button } from '../../../components/primitives/Button.js';\nimport { Input } from '../../../components/primitives/Input.js';\nimport { Switch } from '../../../components/primitives/Switch.js';\nimport { BUDGET_FIELDS, budgetFormFrom, budgetPatch, type BudgetErrors, type BudgetForm } from './cloud-model.js';\nimport styles from './cloud.module.css';\n\nexport interface CloudBudgetFormProps {\n budget: CloudBudgetV1;\n /** Runs the save (through the caller's token gate); the form keeps its values until the new budget lands. */\n onSave: (update: CloudBudgetUpdate) => void;\n onCancel?: () => void;\n busy: boolean;\n disabled?: boolean;\n /** The id prefix, so two forms on one page never share field ids. */\n idPrefix: string;\n}\n\nexport function CloudBudgetForm({ budget, onSave, onCancel, busy, disabled = false, idPrefix }: CloudBudgetFormProps) {\n const [form, setForm] = useState<BudgetForm>(() => budgetFormFrom(budget));\n const [errors, setErrors] = useState<BudgetErrors>({});\n const [note, setNote] = useState<string | null>(null);\n const dirty = useRef(false);\n\n // A newer budget from the server replaces the fields only while the\n // operator has not started typing — never under their fingers.\n useEffect(() => {\n if (!dirty.current) setForm(budgetFormFrom(budget));\n }, [budget]);\n\n const edit = (patch: Partial<BudgetForm>) => {\n dirty.current = true;\n setNote(null);\n setForm((prev) => ({ ...prev, ...patch }));\n };\n\n const submit = (event: FormEvent) => {\n event.preventDefault();\n const result = budgetPatch(form, budget);\n if (!result.ok) {\n setErrors(result.errors);\n return;\n }\n setErrors({});\n if (!result.changed) {\n setNote('Nothing changed.');\n return;\n }\n dirty.current = false;\n onSave(result.update);\n };\n\n return (\n <form className={styles.form} onSubmit={submit} noValidate aria-label=\"Cloud budget\">\n <div className={styles.fieldGrid}>\n {BUDGET_FIELDS.map((spec) => (\n <Input\n key={spec.field}\n id={`${idPrefix}-${spec.field}`}\n label={spec.label}\n hint={spec.hint}\n error={errors[spec.field]}\n size=\"sm\"\n inputMode={spec.integer ? 'numeric' : 'decimal'}\n prefix={spec.money ? '$' : undefined}\n value={form[spec.field]}\n disabled={disabled || busy}\n onChange={(e) => edit({ [spec.field]: e.target.value } as Partial<BudgetForm>)}\n />\n ))}\n </div>\n <Switch\n checked={form.selfImprove}\n onChange={(next) => edit({ selfImprove: next })}\n label=\"Verse may launch self-improvement tasks on its own\"\n disabled={disabled || busy}\n />\n {note ? <p className={styles.muted} role=\"status\">{note}</p> : null}\n <div className={styles.formActions}>\n {onCancel ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={onCancel} disabled={busy}>\n Cancel\n </Button>\n ) : null}\n <Button type=\"submit\" variant=\"primary\" size=\"sm\" busy={busy} disabled={disabled}>\n Save budget\n </Button>\n </div>\n </form>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"CloudBudgetForm-BrNun_Yu.js","names":[],"sources":["../../../../../../src/core/routing/headroom.ts","../../../../../../src/web-ui/routes/verse/command/command-model.ts","../../../../../../src/web-ui/routes/verse/cloud/CloudBudgetForm.tsx"],"sourcesContent":["/**\n * Live headroom per seat — how much of each seat autonomy may still use under\n * its budget policy (V3.10 unit A9).\n *\n * INPUT is a `SeatCapacity`: the public Verse seat projection (the same\n * windows `GET /api/verse/accounts` serves — Claude `five_hour`/`seven_day`,\n * Codex `codex_<bucket>_{primary,secondary}`, Grok's billing period) reduced to\n * what budgeting needs. OUTPUT is the contract's `SeatHeadroom`, plus the\n * reopening time the router needs for `SeatExclusion.nextEligibleAt`.\n *\n * HONESTY RULES (docs/VERSE-TELEMETRY-V2.md, and Mason's decision):\n * - Unknown usage is NOT headroom. A paid seat with no reading, a reported\n * account window with a null percent, or a reading older than\n * `readingMaxAgeMs` is ineligible for autonomy. This is the fix for the old\n * Claude fail-open, where \"no signal\" was treated as \"go ahead\".\n * - A spent PER-MODEL window is not a spent account. Claude's\n * `seven_day_fable` can read 100% while `five_hour` reads 15%; only the\n * account-wide windows bind (seats.ts `seatUsability` has the same rule).\n * - Claude publishes no machine-readable reset. Its reset is quoted in the\n * provider's own words and never turned into a timestamp or a countdown.\n * - Codex credits are paid overage. Autonomy never spends them, so a spent\n * Codex window blocks autonomy even when a balance exists.\n *\n * WINDOW SEMANTICS\n * - `reservePercent` keeps that share of the LONG (weekly / billing-period)\n * window for Mason: autonomy stops at `100 − reserve` used. A seat that\n * reports only a short window applies the reserve to that one.\n * - `maxSessionWindowPercent` is the ceiling on the SHORT (5-hour) window, so\n * a live interactive session is never starved (\"never touch Claude while\n * its 5-hour window is above 70%\").\n * - The binding window is whichever of the two leaves autonomy LESS room.\n *\n * BROWSER-SAFE and PURE: type-only imports, no clock reads (callers pass\n * `nowMs`), no I/O.\n */\nimport type { VerseSeat, VerseSeatCapacity } from '../verse/types.js';\nimport type { BudgetEngine } from './policy.js';\nimport { reasonSentences } from './seat-reasons.js';\nimport type { SeatBudgetPolicy, SeatHeadroom, SeatReason } from './types.js';\n\n/** A reading older than this is too stale to spend against (the collector polls every 30 s when active). */\nexport const HEADROOM_READING_MAX_AGE_MS = 15 * 60_000;\n\n/**\n * A window whose reset is further away than this cannot be a 5-hour window,\n * whatever its id says. Codex's `primary` bucket is USUALLY the 5-hour window,\n * but on 2026-09-24 both accounts reported a `primary` resetting ~42 h out —\n * so the reset distance, when known, overrides the id.\n */\nexport const SESSION_WINDOW_MAX_MS = 5 * 60 * 60_000 + 15 * 60_000;\n\nexport type SeatWindowClass = 'session' | 'weekly' | 'model';\n\nexport interface CapacityWindow {\n id: string;\n /** Provider percent; null = NO SIGNAL (not zero). */\n usedPercent: number | null;\n /** Machine reset; always null for Claude. */\n resetsAt: string | null;\n /** The provider's own reset wording (Claude), verbatim. */\n resetDescription: string | null;\n /** Provider explicitly flagged the limit (a denial, not a measurement). */\n limitReached: boolean;\n}\n\n/** What the budget layer needs to know about one seat. JSON-safe; persisted in the capacity snapshot. */\nexport interface SeatCapacity {\n seatId: string;\n engine: BudgetEngine;\n label: string;\n /** True for local runtime seats: $0 and no provider window. */\n free: boolean;\n windows: CapacityWindow[];\n /** The account reports no usable login. */\n signedOut: boolean;\n /** Can a turn reach this seat at all? Null when unknown. */\n reachable: boolean | null;\n /** Default model's context window in tokens; null when unknown. */\n contextWindow: number | null;\n /** When the windows were read; null when never. */\n observedAt: string | null;\n /** Today's metered spend in USD; null when unknown or not metered. */\n spentTodayUsd: number | null;\n}\n\n/** `SeatHeadroom` plus the facts the router needs but the wire shape does not carry. */\nexport interface SeatAssessment {\n headroom: SeatHeadroom;\n /** When the blocking condition is expected to lift; null when unknown / never / not blocked. */\n reopensAt: string | null;\n /** True when usage is known to be spent (limit flagged or ≥ 100%) on an account window. */\n exhausted: boolean;\n /** True when usage evidence is missing, partial or stale. */\n unknownUsage: boolean;\n /** The sentences naming each spent account window (a subset of `headroom.reasons`). */\n spentReasons: string[];\n /** `headroom.reasons` as data (same order): each sentence without its reset clause, plus the reset. */\n details: SeatReason[];\n /** `spentReasons` as data. */\n spentDetails: SeatReason[];\n}\n\nexport interface AssessOptions {\n nowMs: number;\n readingMaxAgeMs?: number;\n}\n\n// ---------------------------------------------------------------------------\n// Projection from the public seat shape\n// ---------------------------------------------------------------------------\n\n/**\n * Reduce a public `VerseSeat` to a `SeatCapacity`. `liveCapacity`, when given,\n * replaces the seat's own (possibly cached) capacity — the caller re-reads\n * telemetry per request exactly as verse-api's `liveSeats` does.\n */\nexport function capacityFromSeat(seat: VerseSeat, liveCapacity?: VerseSeatCapacity | null): SeatCapacity {\n const free = seat.engine === 'local';\n const capacity = liveCapacity === undefined ? seat.capacity ?? null : liveCapacity;\n // A failed account check may retain a verified window for display until its\n // original expiry. Autonomy cannot spend against that prior reading.\n const current = !free && capacity &&\n (capacity.usability === 'ready' || capacity.usability === 'tight' || capacity.usability === 'exhausted')\n ? capacity : null;\n const windows: CapacityWindow[] = current === null ? [] : current.windows.map((w) => ({\n id: w.id,\n usedPercent: typeof w.usedPercent === 'number' && Number.isFinite(w.usedPercent)\n ? Math.max(0, Math.min(100, w.usedPercent))\n : null,\n resetsAt: w.resetsAt,\n resetDescription: w.resetDescription,\n limitReached: w.limitReached === true,\n }));\n const signedOut = !free && capacity?.usability === 'signed-out';\n return {\n seatId: seat.id,\n engine: seat.engine,\n label: seat.label,\n free,\n windows,\n signedOut,\n // A local seat is only listed when the runtime answered discovery. A\n // native seat is reachable unless signed out; \"no reading\" is a usage\n // question, not a reachability one.\n reachable: free ? true : signedOut ? false : null,\n contextWindow: typeof seat.contextWindow === 'number' && seat.contextWindow > 0 ? seat.contextWindow : null,\n observedAt: current === null ? null : current.observedAt ?? seat.health.observedAt ?? null,\n spentTodayUsd: null,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Window classification\n// ---------------------------------------------------------------------------\n\nfunction resetDistanceMs(window: CapacityWindow, nowMs: number): number | null {\n if (!window.resetsAt) return null;\n const at = Date.parse(window.resetsAt);\n return Number.isFinite(at) ? at - nowMs : null;\n}\n\n/** Which role a window plays for budgeting. Per-model windows never bind. */\nexport function classifyWindow(engine: BudgetEngine, window: CapacityWindow, nowMs: number): SeatWindowClass {\n const id = window.id;\n if (engine === 'claude') {\n if (id === 'five_hour') return 'session';\n if (id === 'seven_day') return 'weekly';\n if (id.startsWith('seven_day_')) return 'model';\n }\n if (engine === 'grok') return 'weekly';\n const distance = resetDistanceMs(window, nowMs);\n if (engine === 'codex') {\n if (id.endsWith('_secondary')) return 'weekly';\n if (id.endsWith('_primary')) return distance !== null && distance > SESSION_WINDOW_MAX_MS ? 'weekly' : 'session';\n }\n // Unknown id: only a reset we can SEE inside five hours makes it short.\n return distance !== null && distance <= SESSION_WINDOW_MAX_MS ? 'session' : 'weekly';\n}\n\n/** Human name for a window, for reasons. */\nexport function windowName(engine: BudgetEngine, window: CapacityWindow, cls: SeatWindowClass): string {\n if (cls === 'session') return '5-hour window';\n if (cls === 'model') {\n const model = window.id.startsWith('seven_day_') ? window.id.slice('seven_day_'.length) : window.id;\n return `${model.charAt(0).toUpperCase()}${model.slice(1)}-only weekly window`;\n }\n if (engine === 'grok' || window.id.endsWith('_monthly')) {\n return window.id.endsWith('_monthly') ? 'monthly billing window' : window.id.endsWith('_weekly') ? 'weekly window' : 'billing-period window';\n }\n return 'weekly window';\n}\n\n/**\n * A window's reset as data: the machine instant when there is one, else\n * Claude's own words, verbatim — never a synthesized time. `reasonSentence`\n * turns it back into the \" (resets …)\" clause the string form has always had.\n */\nfunction resetOf(window: CapacityWindow): Pick<SeatReason, 'resetsAt' | 'resetDescription'> {\n if (window.resetsAt) return { resetsAt: window.resetsAt, resetDescription: null };\n return { resetsAt: null, resetDescription: window.resetDescription ?? null };\n}\n\nfunction isSpent(window: CapacityWindow): boolean {\n return window.limitReached || (window.usedPercent !== null && window.usedPercent >= 100);\n}\n\nfunction pct(value: number): string {\n return `${Math.round(value)}%`;\n}\n\nfunction formatAge(ms: number): string {\n const minutes = Math.round(ms / 60_000);\n if (minutes < 120) return `${minutes} min`;\n const hours = Math.round(minutes / 60);\n return hours < 48 ? `${hours} h` : `${Math.round(hours / 24)} days`;\n}\n\n// ---------------------------------------------------------------------------\n// Assessment\n// ---------------------------------------------------------------------------\n\ninterface ClassedWindow {\n window: CapacityWindow;\n cls: SeatWindowClass;\n}\n\n/** The highest reading among `rows`, with its window; null when none carried a percent. */\nfunction peak(rows: ClassedWindow[]): ClassedWindow | null {\n let best: ClassedWindow | null = null;\n for (const row of rows) {\n if (row.window.usedPercent === null) continue;\n if (best === null || row.window.usedPercent > best.window.usedPercent!) best = row;\n }\n return best;\n}\n\n/**\n * When EVERY spent window in `rows` has reset — the seat is blocked until the\n * last of them does, so this is the latest reset. Null unless every row has a\n * machine-readable reset (one unknown reset makes the reopening unknown).\n */\nfunction lastReset(rows: ClassedWindow[]): string | null {\n const times: string[] = [];\n for (const row of rows) {\n const at = row.window.resetsAt;\n if (!at || !Number.isFinite(Date.parse(at))) return null;\n times.push(at);\n }\n times.sort((a, b) => Date.parse(b) - Date.parse(a));\n return times[0] ?? null;\n}\n\n/** Full assessment of one seat for AUTONOMOUS use under `policy`. Pure. */\nexport function assessSeat(capacity: SeatCapacity, policy: SeatBudgetPolicy, opts: AssessOptions): SeatAssessment {\n const { nowMs } = opts;\n const maxAge = opts.readingMaxAgeMs ?? HEADROOM_READING_MAX_AGE_MS;\n // Reasons are built as data; `headroom.reasons` is derived from them.\n const details: SeatReason[] = [];\n\n // ── Local: free, windowless, bounded only by reachability ──────────────\n if (capacity.free) {\n const reachable = capacity.reachable !== false;\n if (!policy.enabled) details.push({ kind: 'switched-off', text: 'Autonomy is switched off for this seat.' });\n if (!reachable) details.push({ kind: 'unreachable', text: 'The local model runtime is not reachable.' });\n const eligible = policy.enabled && reachable;\n if (eligible) details.push({ kind: 'headroom', text: 'Local model — free, with no usage window to protect.' });\n return {\n headroom: {\n seatId: capacity.seatId,\n sessionUsedPercent: null,\n weeklyUsedPercent: null,\n bindingWindow: null,\n // No window binds a local seat; \"all of it\" is the honest number while\n // the runtime answers, and unknown while it does not.\n autonomyHeadroomPercent: reachable ? 100 : null,\n resetAt: null,\n eligibleForAutonomy: eligible,\n reasons: reasonSentences(details),\n },\n reopensAt: null,\n exhausted: false,\n unknownUsage: false,\n spentReasons: [],\n details,\n spentDetails: [],\n };\n }\n\n // ── Paid seat ──────────────────────────────────────────────────────────\n const classed: ClassedWindow[] = capacity.windows.map((window) => ({\n window,\n cls: classifyWindow(capacity.engine, window, nowMs),\n }));\n const account = classed.filter((row) => row.cls !== 'model');\n const sessionRows = account.filter((row) => row.cls === 'session');\n const weeklyRows = account.filter((row) => row.cls === 'weekly');\n const sessionPeak = peak(sessionRows);\n const weeklyPeak = peak(weeklyRows);\n const sessionUsed = sessionPeak?.window.usedPercent ?? null;\n const weeklyUsed = weeklyPeak?.window.usedPercent ?? null;\n\n // Evidence quality.\n const observedMs = capacity.observedAt ? Date.parse(capacity.observedAt) : NaN;\n const ageMs = Number.isFinite(observedMs) ? nowMs - observedMs : null;\n const stale = ageMs === null || ageMs > maxAge;\n const hasReading = sessionUsed !== null || weeklyUsed !== null;\n const nullWindow = account.find((row) => row.window.usedPercent === null && !row.window.limitReached);\n\n // Ceilings. The reserve protects the LONG window; with no long window it\n // protects the short one. The session ceiling protects a live session.\n const reserveCeiling = 100 - policy.reservePercent;\n const sessionCeiling = policy.maxSessionWindowPercent ?? 100;\n // With no long window the short one carries BOTH limits; say which one bit.\n const sessionLimitIsReserve = weeklyRows.length === 0 && reserveCeiling < sessionCeiling;\n const sessionLimit = sessionLimitIsReserve ? reserveCeiling : sessionCeiling;\n let weeklyRoom: number | null = null;\n let sessionRoom: number | null = null;\n if (weeklyUsed !== null) weeklyRoom = reserveCeiling - weeklyUsed;\n if (sessionUsed !== null) sessionRoom = sessionLimit - sessionUsed;\n let bindingWindow: SeatHeadroom['bindingWindow'] = null;\n let room: number | null = null;\n if (weeklyRoom !== null && (sessionRoom === null || weeklyRoom <= sessionRoom)) {\n bindingWindow = 'weekly';\n room = weeklyRoom;\n } else if (sessionRoom !== null) {\n bindingWindow = 'session';\n room = sessionRoom;\n }\n const bindingRow = bindingWindow === 'weekly' ? weeklyPeak : bindingWindow === 'session' ? sessionPeak : null;\n\n // Blockers, most fundamental first. Every one gets a plain sentence.\n let reopensAt: string | null = null;\n const spentRows = account.filter((row) => isSpent(row.window));\n const exhausted = spentRows.length > 0;\n const unknownUsage = !hasReading || stale || nullWindow !== undefined;\n\n if (!policy.enabled) details.push({ kind: 'switched-off', text: 'Autonomy is switched off for this seat.' });\n if (capacity.signedOut) {\n details.push({ kind: 'signed-out', text: 'Signed out — reconnect this account before anything can run on it.' });\n }\n\n const spentDetails: SeatReason[] = [];\n if (exhausted) {\n for (const row of spentRows) {\n const used = row.window.limitReached ? 'limit reached' : `${pct(row.window.usedPercent!)} used`;\n spentDetails.push({\n kind: 'spent',\n text: `The ${windowName(capacity.engine, row.window, row.cls)} is spent — ${used}.`,\n ...resetOf(row.window),\n });\n }\n details.push(...spentDetails);\n reopensAt = lastReset(spentRows);\n }\n\n if (!hasReading) {\n details.push({\n kind: 'unknown-usage',\n text: account.length === 0\n ? 'No usage reading for this seat — unknown usage is not headroom, so autonomy stays off it.'\n : 'Its usage windows carried no percentage — unknown usage is not headroom, so autonomy stays off it.',\n });\n } else if (stale) {\n details.push({\n kind: 'unknown-usage',\n text: ageMs === null\n ? 'The usage reading has no timestamp — too uncertain to spend against.'\n : `The usage reading is ${formatAge(ageMs)} old — too stale to spend against (limit ${formatAge(maxAge)}).`,\n });\n } else if (nullWindow) {\n details.push({\n kind: 'unknown-usage',\n text: `The ${windowName(capacity.engine, nullWindow.window, nullWindow.cls)} carried no percentage — `\n + 'unknown usage is not headroom.',\n });\n }\n\n const usdCap = policy.dailyUsdCap;\n let overUsd = false;\n if (usdCap !== undefined) {\n if (capacity.spentTodayUsd === null) {\n overUsd = true;\n details.push({ kind: 'spend-cap', text: `A $${usdCap.toFixed(2)} daily cap is set but today's spend on this seat is unknown.` });\n } else if (capacity.spentTodayUsd >= usdCap) {\n overUsd = true;\n details.push({ kind: 'spend-cap', text: `Spent $${capacity.spentTodayUsd.toFixed(2)} of its $${usdCap.toFixed(2)} daily cap.` });\n }\n }\n\n // Ceiling reasons only matter when the reading itself is trustworthy.\n const ceilingBlocked = !exhausted && !unknownUsage && room !== null && room <= 0;\n if (ceilingBlocked && bindingRow) {\n const name = windowName(capacity.engine, bindingRow.window, bindingRow.cls);\n const used = pct(bindingRow.window.usedPercent!);\n if (bindingWindow === 'session' && !sessionLimitIsReserve) {\n details.push({\n kind: 'session-ceiling',\n text: `The ${name} is ${used} used; autonomy stops at ${pct(sessionLimit)} to protect your live session.`,\n ...resetOf(bindingRow.window),\n });\n } else {\n details.push({\n kind: 'reserve',\n text: `The ${name} is ${used} used; ${pct(policy.reservePercent)} is kept for you, so autonomy `\n + `stops at ${pct(reserveCeiling)}.`,\n ...resetOf(bindingRow.window),\n });\n }\n reopensAt = bindingRow.window.resetsAt;\n }\n\n // Model-scoped windows are facts worth showing, never blockers.\n for (const row of classed) {\n if (row.cls === 'model' && isSpent(row.window)) {\n details.push({\n kind: 'model-window',\n text: `The ${windowName(capacity.engine, row.window, row.cls)} is spent — it limits that model only, not the account.`,\n });\n }\n }\n\n const eligible = policy.enabled && !capacity.signedOut && !exhausted && !unknownUsage && !overUsd\n && room !== null && room > 0;\n if (eligible && bindingRow) {\n const name = windowName(capacity.engine, bindingRow.window, bindingRow.cls);\n const kept = bindingWindow === 'weekly' || sessionLimitIsReserve\n ? policy.reservePercent > 0 ? ` (${pct(policy.reservePercent)} kept for you)` : ''\n : sessionLimit < 100 ? ` (autonomy stops at ${pct(sessionLimit)} to protect your live session)` : '';\n details.unshift({ kind: 'headroom', text: `${pct(room!)} of the ${name} is left for autonomy${kept}.` });\n }\n\n return {\n headroom: {\n seatId: capacity.seatId,\n sessionUsedPercent: sessionUsed,\n weeklyUsedPercent: weeklyUsed,\n bindingWindow,\n autonomyHeadroomPercent: room === null ? null : Math.max(0, Math.round(room)),\n resetAt: bindingRow?.window.resetsAt ?? null,\n eligibleForAutonomy: eligible,\n reasons: reasonSentences(details),\n },\n // A seat that is merely switched off, signed out, or unknown has no\n // known reopening — only a window reset is a date we can name.\n reopensAt: !policy.enabled || capacity.signedOut || unknownUsage || overUsd ? null : reopensAt,\n exhausted,\n unknownUsage,\n spentReasons: reasonSentences(spentDetails),\n details,\n spentDetails,\n };\n}\n\n/** The contract's `SeatHeadroom` for one seat. */\nexport function computeHeadroom(capacity: SeatCapacity, policy: SeatBudgetPolicy, opts: AssessOptions): SeatHeadroom {\n return assessSeat(capacity, policy, opts).headroom;\n}\n","/**\n * routes/verse/command/command-model.ts — the pure numbers behind Command's\n * KPI row, \"Since you looked\" strip, seat burn-downs and the Needs-you card\n * (unit C7; SPEC-310B §6, SPEC-310C §5).\n *\n * Honesty (docs/VERSE-TELEMETRY-V2.md): a KPI whose source did not answer\n * is \"—\", and a delta is computed only when BOTH windows are fully known — a\n * week with one unreadable day has no honest \"vs prior 7d\". Framework-free;\n * tested directly.\n */\nimport type { FleetLiveSnapshotV1, FleetLiveRun } from '../../../../core/fleet/fleet-types.js';\nimport type { LeaderStateV1 } from '../../../../core/vision/leader-types.js';\nimport type { LearningStateV1 } from '../../../../core/learn/harness-types.js';\nimport type { NeedsYouItem, NeedsYouSeverity, VerseActivityResponse } from '../../../../core/verse/workbench-types.js';\nimport type { FleetHistoryDay, FleetHistoryResponse } from '../../../../core/verse/fleet-history-types.js';\nimport type { BudgetView } from '../../../../core/routing/policy.js';\nimport type { CapacityHistoryResponse } from '../../../../core/routing/capacity-history-types.js';\nimport type { SeatReason, SeatReasonKind } from '../../../../core/routing/types.js';\nimport type { VerseSeat } from '../../../../core/verse/types.js';\nimport { classifyWindow } from '../../../../core/routing/headroom.js';\nimport { describeResetAt } from '../../../../core/verse/seat-readiness.js';\nimport type { EffectivePolicy } from '../../../../core/authority/types.js';\nimport type { StatTileDelta } from '../../../components/charts/StatTile.js';\nimport { asSentence, localTimes, parseLegacyReason } from '../fleet/why-seat-model.js';\n\nconst DAY = 86_400_000;\nconst HOUR = 3_600_000;\n\n// ---------------------------------------------------------------------------\n// Windows over the daily history\n// ---------------------------------------------------------------------------\n\n/** Sum of `pick` over days [end-len, end); null if any day in the window is unknown or missing. */\nexport function windowSum(days: readonly FleetHistoryDay[], pick: (d: FleetHistoryDay) => number | null, len: number, endOffset = 0): number | null {\n const end = days.length - endOffset;\n const start = end - len;\n if (start < 0 || len <= 0) return null;\n let total = 0;\n for (let i = start; i < end; i++) {\n const v = pick(days[i]!);\n if (v === null || !Number.isFinite(v)) return null;\n total += v;\n }\n return total;\n}\n\n/** The last `len` values of `pick`, oldest first (nulls kept — the sparkline breaks there). */\nexport function lastValues(days: readonly FleetHistoryDay[], pick: (d: FleetHistoryDay) => number | null, len: number): (number | null)[] {\n return days.slice(Math.max(0, days.length - len)).map(pick);\n}\n\nfunction mean(values: readonly (number | null)[]): number | null {\n const known = values.filter((v): v is number => v !== null && Number.isFinite(v));\n return known.length ? known.reduce((a, b) => a + b, 0) / known.length : null;\n}\n\n// ---------------------------------------------------------------------------\n// KPI row\n// ---------------------------------------------------------------------------\n\nexport interface Kpi {\n id: 'merged' | 'green' | 'cycle' | 'spend' | 'lift';\n label: string;\n /** Display string; \"—\" when unknown. */\n value: string;\n delta: StatTileDelta | null;\n trend: (number | null)[] | undefined;\n trendLabel: string;\n caption: string;\n}\n\nexport interface KpiInputs {\n fleet: FleetLiveSnapshotV1 | null;\n history: FleetHistoryResponse | null;\n learning: LearningStateV1 | null;\n policy: EffectivePolicy | null;\n /**\n * Accepted but no longer read: the spend caption used to list every paid\n * seat's window usage, which the seat burn-downs already show. Kept so\n * callers need not change.\n */\n budget?: BudgetView | null;\n}\n\n/**\n * The per-token (metered API) part of a day's spend, when the server splits\n * it out. WHY not `estCostUsd`: that field prices EVERY run's tokens from a\n * static table — Claude/Codex/Grok subscription CLI runs included — so\n * showing it as \"spend vs the metered cap\" reported subscription work as a\n * budget breach (review 3.10 c10; the default grant's cap is $0/day).\n * Subscriptions are not billed per token: their cost is window usage, shown\n * as percent. fleet-history reports `meteredCostUsd` per day (per-token API\n * engines only — core/verse/fleet-history.ts `runBilling`); a server that\n * predates it leaves the figure unknown — \"—\", never the mixed estimate.\n */\nexport function meteredCost(d: FleetHistoryDay): number | null {\n const v = (d as FleetHistoryDay & { meteredCostUsd?: number | null }).meteredCostUsd;\n return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? v : null;\n}\n\nconst signedInt = (v: number) => (v > 0 ? `+${v}` : String(v));\nconst signedPts = (v: number) => `${v > 0 ? '+' : ''}${v.toFixed(1)}`;\nconst signedUsd = (v: number) => `${v > 0 ? '+' : v < 0 ? '−' : ''}$${Math.abs(v).toFixed(2)}`;\n\n/** \"2h 14m\", \"38m\", \"3d 2h\". */\nexport function formatSpan(ms: number | null): string {\n if (ms === null || !Number.isFinite(ms) || ms < 0) return '—';\n const m = 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 const d = Math.floor(h / 24);\n return h % 24 ? `${d}d ${h % 24}h` : `${d}d`;\n}\n\n/** Mean daily post-merge green % across repos, per day (oldest first, 14 days). */\nexport function greenTrend(fleet: FleetLiveSnapshotV1 | null): (number | null)[] {\n if (!fleet || fleet.repos.length === 0) return [];\n const len = Math.max(...fleet.repos.map((r) => r.greenTrend.length));\n return Array.from({ length: len }, (_, i) => mean(fleet.repos.map((r) => r.greenTrend[i - (len - r.greenTrend.length)] ?? null)));\n}\n\nexport function buildKpis({ fleet, history, learning, policy }: KpiInputs): Kpi[] {\n const days = history?.days ?? [];\n const merges = (d: FleetHistoryDay) => d.merges.realized;\n const spend = meteredCost;\n\n // Merged · 7d — the live summary when the daemon answers, else the history window.\n const merged7 = fleet?.summary.merged7d ?? windowSum(days, merges, 7);\n const mergedPrior = windowSum(days, merges, 7, 7);\n const mergedNow = windowSum(days, merges, 7);\n const mergedDelta = mergedNow !== null && mergedPrior !== null ? mergedNow - mergedPrior : null;\n\n // Post-merge green — the 7-day figure plus the 14-day repo trend.\n const green = fleet?.summary.postMergeGreenPct7d ?? null;\n const gTrend = greenTrend(fleet);\n const gNow = gTrend.length >= 14 ? mean(gTrend.slice(-7)) : null;\n const gPrior = gTrend.length >= 14 ? mean(gTrend.slice(-14, -7)) : null;\n const greenDelta = gNow !== null && gPrior !== null ? gNow - gPrior : null;\n\n // Metered spend vs cap — per-token API spend ONLY (see meteredCost).\n const spend7 = windowSum(days, spend, 7);\n const spendPrior = windowSum(days, spend, 7, 7);\n const capPerDay = policy ? policy.spend.meteredUsdPerDay : null;\n const spendValue = spend7 === null ? '—' : `$${spend7.toFixed(2)}${capPerDay !== null ? ` / $${(capPerDay * 7).toFixed(0)}` : ''}`;\n const meteredKnown = days.some((d) => meteredCost(d) !== null);\n // One short line. Subscriptions are window usage, not dollars: they live\n // on the seat burn-downs, not in this caption.\n const capWords = capPerDay === null ? 'per-token APIs only' : capPerDay === 0 ? 'metered APIs off' : `cap $${capPerDay}/day`;\n const spendCaption = meteredKnown ? capWords : `${capWords} · not reported yet`;\n\n // Lift — the active harness's own experiment (null = baseline in force).\n const active = learning?.active ?? null;\n const activeExp = active?.experimentId ? learning?.experiments.find((e) => e.id === active.experimentId) ?? null : null;\n const lift = activeExp?.lift ?? null;\n\n return [\n {\n id: 'merged',\n label: 'Merged · 7d',\n value: merged7 === null ? '—' : String(merged7),\n delta: mergedDelta === null ? null : { value: mergedDelta, unit: Math.abs(mergedDelta) === 1 ? 'merge' : 'merges', versus: 'vs prior 7d', goodWhenPositive: true, format: signedInt },\n trend: days.length ? lastValues(days, merges, 14) : undefined,\n trendLabel: 'Merges per day, last 14 days',\n caption: fleet?.summary.mergedToday != null ? `${fleet.summary.mergedToday} today` : 'fleet merges on default branches',\n },\n {\n id: 'green',\n label: 'Post-merge green',\n value: green === null ? '—' : `${Math.round(green)}%`,\n delta: greenDelta === null ? null : { value: greenDelta, unit: 'pts', versus: 'vs prior 7d', goodWhenPositive: true, format: signedPts },\n trend: gTrend.length ? gTrend : undefined,\n trendLabel: 'Post-merge green percent per day',\n caption: green === null ? 'no completed post-merge watch yet' : 'CI + suite 2 h after each merge',\n },\n {\n id: 'cycle',\n label: 'Cycle time',\n value: formatSpan(fleet?.summary.cycleTimeP50Ms7d ?? null),\n delta: null,\n trend: undefined,\n trendLabel: 'Cycle time',\n caption: 'median, proposal → merge, 7d',\n },\n {\n id: 'spend',\n label: 'Metered spend · 7d',\n value: spendValue,\n delta: spend7 !== null && spendPrior !== null ? { value: spend7 - spendPrior, versus: 'vs prior 7d', goodWhenPositive: false, format: signedUsd } : null,\n trend: meteredKnown ? lastValues(days, spend, 14) : undefined,\n trendLabel: 'Metered (per-token API) spend per day',\n caption: spendCaption,\n },\n {\n id: 'lift',\n label: 'Lift',\n value: lift ? `${signedPts(lift.mean)} pts` : '—',\n delta: null,\n trend: undefined,\n trendLabel: 'Harness lift',\n caption: active ? `harness ${active.id} vs baseline${lift ? ` (95% ${signedPts(lift.ciLow)} to ${signedPts(lift.ciHigh)})` : ''}` : 'no harness adopted — defaults in force',\n },\n ];\n}\n\n/**\n * True when the KPI row would say nothing: no merge this week or last, no\n * post-merge reading, no cycle time, no metered spend, no lift — \"0\", four\n * dashes and \"$0.00\". Command drops the row then while its \"Autonomy is off\"\n * banner explains why; a row with any real figure is always kept.\n */\nexport function kpisSayNothing({ fleet, history, learning }: Pick<KpiInputs, 'fleet' | 'history' | 'learning'>): boolean {\n const days = history?.days ?? [];\n const merges = (d: FleetHistoryDay) => d.merges.realized;\n const merged7 = fleet?.summary.merged7d ?? windowSum(days, merges, 7);\n const mergedPrior = windowSum(days, merges, 7, 7);\n const active = learning?.active ?? null;\n const lift = active?.experimentId ? (learning?.experiments.find((e) => e.id === active.experimentId)?.lift ?? null) : null;\n return (\n (merged7 ?? 0) === 0 &&\n (mergedPrior ?? 0) === 0 &&\n (fleet?.summary.postMergeGreenPct7d ?? null) === null &&\n (fleet?.summary.cycleTimeP50Ms7d ?? null) === null &&\n (windowSum(days, meteredCost, 7) ?? 0) === 0 &&\n lift === null\n );\n}\n\n// ---------------------------------------------------------------------------\n// Since you looked\n// ---------------------------------------------------------------------------\n\nexport interface SinceItem {\n id: string;\n text: string;\n tone: 'success' | 'danger' | 'warning' | 'neutral' | 'info';\n}\n\nexport interface SinceInputs {\n /** ISO of the previous visit; null = first visit (nothing is \"new\"). */\n lastLookedAt: string | null;\n fleet: FleetLiveSnapshotV1 | null;\n leader: LeaderStateV1 | null;\n activity: VerseActivityResponse | null;\n}\n\nconst after = (iso: string | null, t: number) => iso !== null && Date.parse(iso) > t;\n\n/** What changed since the operator last opened Command, newest kinds first. */\nexport function sinceYouLooked({ lastLookedAt, fleet, leader, activity }: SinceInputs): SinceItem[] {\n if (!lastLookedAt) return [];\n const t = Date.parse(lastLookedAt);\n if (!Number.isFinite(t)) return [];\n const out: SinceItem[] = [];\n const ended = (fleet?.runs ?? []).filter((r) => after(r.endedAt, t));\n const count = (o: FleetLiveRun['outcome']) => ended.filter((r) => r.outcome === o).length;\n const merged = count('merged');\n const reverted = count('reverted');\n const failed = count('failed') + count('refused');\n if (merged) out.push({ id: 'merged', text: `${merged} merged`, tone: 'success' });\n if (reverted) out.push({ id: 'reverted', text: `${reverted} reverted`, tone: 'danger' });\n if (failed) out.push({ id: 'failed', text: `${failed} refused or failed`, tone: 'warning' });\n const memos = (leader?.timeline ?? []).filter((m) => Date.parse(m.at) > t && m.status === 'ok').length;\n if (memos) out.push({ id: 'memos', text: `${memos} new memo${memos === 1 ? '' : 's'}`, tone: 'info' });\n const fresh = (activity?.needsYou ?? []).filter((i) => Date.parse(i.since) > t).length;\n if (fresh) out.push({ id: 'needs', text: `${fresh} new for you`, tone: 'warning' });\n return out;\n}\n\n// ---------------------------------------------------------------------------\n// Needs you (Command card)\n// ---------------------------------------------------------------------------\n\nconst SEVERITY_RANK: Record<NeedsYouSeverity, number> = { high: 0, warn: 1, info: 2 };\n\n/** Most severe first, then newest. Pure — the drawer (C1) owns the full list. */\nexport function rankNeedsYou(items: readonly NeedsYouItem[]): NeedsYouItem[] {\n return [...items].sort((a, b) => SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity] || Date.parse(b.since) - Date.parse(a.since));\n}\n\n/**\n * Seat id → the label every other surface names that seat by (\"Claude Max\",\n * never \"claude-a\"): the live roster when the cache holds it, else the\n * budget route's seat info (polled on Command, so present when the roster is\n * not). Both carry the same `VerseSeat.label` for the same id.\n */\nexport function seatNames(\n seats: readonly Pick<VerseSeat, 'id' | 'label'>[] | null | undefined,\n view: Pick<BudgetView, 'seatInfo'> | null | undefined,\n): Map<string, string> {\n const names = new Map<string, string>();\n const put = (id: unknown, label: unknown) => {\n if (typeof id === 'string' && typeof label === 'string' && label.trim().length > 0) names.set(id, label.trim());\n };\n for (const s of view?.seatInfo ?? []) put(s.seatId, s.label);\n for (const s of seats ?? []) put(s.id, s.label);\n return names;\n}\n\n/** Sources that did not answer — the card must not say \"All clear\" while any is listed. */\nexport function silentSources(activity: VerseActivityResponse | null): string[] {\n if (!activity) return [];\n return Object.entries(activity.sources).filter(([, state]) => state !== 'ok').map(([source]) => source);\n}\n\n// ---------------------------------------------------------------------------\n// Seat burn-downs\n// ---------------------------------------------------------------------------\n\nexport type SeatWindow = 'session' | 'weekly';\n\nexport interface SeatReading {\n t: number;\n /** Percent of the window used, 0–100. */\n used: number;\n}\n\n/**\n * Readings are kept per seat WINDOW, not per seat: the binding window can flip\n * between the 5-hour and the weekly window from one poll to the next, and a\n * line that mixed the two would draw a jump that never happened. Seat ids may\n * contain `:` and `/`, never `#` (the server keys its history the same way).\n */\nexport function seriesKey(seatId: string, window: SeatWindow): string {\n return `${seatId}#${window}`;\n}\n\n/**\n * The readings this page has seen since Verse opened, per seat window. The\n * budget route serves ONE reading per seat, so on their own these start the\n * burn-down empty on every load; `mergeSeatHistory` adds the server's recorded\n * history (GET /api/verse/budget/history — core/routing/capacity-history.ts,\n * written by the capacity publishers), so a reload keeps the whole window.\n * Memory only, bounded; never a guessed history.\n *\n * The bound counts CHANGES, not polls: a flat run keeps only its two ends\n * (see `recordReading`). At one poll per 30 s a plain 240-reading ring held\n * two hours — a sliver of a 7-day window — while window percent moves in\n * whole points a few times an hour.\n */\nexport const SEAT_READINGS_MAX = 240;\n/** A merged line (recorded history + this page's readings), flat runs collapsed: a week of changes fits. */\nexport const SEAT_HISTORY_MAX = 2000;\n/** A drop this large between consecutive readings is a window reset: the line starts again. */\nconst RESET_DROP = 20;\n\nfunction isFlatEnd(line: readonly SeatReading[], used: number): boolean {\n const n = line.length;\n return n >= 2 && line[n - 1]!.used === used && line[n - 2]!.used === used;\n}\n\nexport function recordReading(history: Readonly<Record<string, SeatReading[]>>, view: BudgetView | null): Record<string, SeatReading[]> {\n if (!view) return { ...history };\n const t = Date.parse(view.sampledAt);\n if (!Number.isFinite(t)) return { ...history };\n const next: Record<string, SeatReading[]> = { ...history };\n for (const h of view.headroom) {\n const windows: [SeatWindow, number | null][] = [['session', h.sessionUsedPercent], ['weekly', h.weeklyUsedPercent]];\n for (const [window, used] of windows) {\n if (used === null || !Number.isFinite(used)) continue;\n const key = seriesKey(h.seatId, window);\n const prev = next[key] ?? [];\n if (prev.length && prev[prev.length - 1]!.t >= t) continue;\n // A reset (used dropped sharply) starts a new window — drop the old one.\n const fresh = prev.length && used + RESET_DROP < prev[prev.length - 1]!.used ? [] : prev;\n // A flat run keeps only its first and latest reading: the line through\n // them is identical, and the ring then spans hours or days, not minutes.\n next[key] = [...(isFlatEnd(fresh, used) ? fresh.slice(0, -1) : fresh), { t, used }].slice(-SEAT_READINGS_MAX);\n }\n }\n return next;\n}\n\nexport interface MergedSeatHistory {\n /** One line per seat window, oldest first, starting after its last reset. */\n readings: Record<string, SeatReading[]>;\n /** Series keys the server's recorded history contributed readings to. */\n recorded: ReadonlySet<string>;\n}\n\n/**\n * The server's recorded history merged with this page's live readings, per\n * seat window: oldest first, one reading per instant, cut after the last\n * reset drop and with flat runs collapsed — the same rules `recordReading`\n * applies, so the line reads the same either way. `server` is untrusted wire\n * data: malformed series and points are skipped.\n *\n * ONE CLOCK PER STRETCH OF LINE (review 3.10.1). The two sources stamp the\n * same observation differently: a recorded row carries the provider\n * reading's `observedAt` (capacity-history.ts), a live reading the budget\n * route's `sampledAt` — when it was ASKED, which is later, and the budget\n * wire carries no `observedAt` to do better. Interleaved, the same value\n * lands at two instants and an older value can sort after a newer one: a\n * poll just after a reset still serving 85% drew 85 → 3 → 85 → 3. So the\n * recorded history is authoritative for every instant it covers — up to the\n * moment the server answered (`generatedAt`), or its newest row when that is\n * later or `generatedAt` is unreadable — and live readings only extend a\n * recorded line past that point. The server records the snapshot behind\n * each budget read (capacity-history-api.ts, throttled to 15 s), so a live\n * reading hidden this way is recorded at its own `observedAt` by the next\n * history read, and until then the next live poll carries the same value.\n * A live reading after `generatedAt` came from a collector that had already\n * seen every recorded observation, so the extension never runs backwards.\n * Both instants are the Verse server's own clock. A window with no recorded\n * series keeps every live reading.\n */\nexport function mergeSeatHistory(live: Readonly<Record<string, SeatReading[]>>, server: CapacityHistoryResponse | null): MergedSeatHistory {\n const generatedAt = typeof server?.generatedAt === 'string' ? Date.parse(server.generatedAt) : Number.NaN;\n const persisted = new Map<string, SeatReading[]>();\n for (const series of Array.isArray(server?.series) ? server!.series : []) {\n if (!series || typeof series.seatId !== 'string' || (series.window !== 'session' && series.window !== 'weekly') || !Array.isArray(series.points)) continue;\n const points: SeatReading[] = [];\n for (const p of series.points) {\n if (!Array.isArray(p)) continue;\n const [t, used] = p as unknown[];\n if (typeof t === 'number' && Number.isFinite(t) && typeof used === 'number' && Number.isFinite(used) && used >= 0 && used <= 100) points.push({ t, used });\n }\n if (points.length === 0) continue;\n const key = seriesKey(series.seatId, series.window);\n persisted.set(key, [...(persisted.get(key) ?? []), ...points]);\n }\n const readings: Record<string, SeatReading[]> = {};\n const recorded = new Set<string>();\n for (const key of new Set([...Object.keys(live), ...persisted.keys()])) {\n const fromServer = persisted.get(key) ?? [];\n let fromPage = live[key] ?? [];\n if (fromServer.length > 0) {\n recorded.add(key);\n const newestRecorded = Math.max(...fromServer.map((r) => r.t));\n const coveredTo = Number.isFinite(generatedAt) ? Math.max(generatedAt, newestRecorded) : newestRecorded;\n fromPage = fromPage.filter((r) => r.t > coveredTo);\n }\n // Recorded rows can repeat an instant (two series under one key); the\n // last one read stands. Live readings are strictly later than all of them.\n const byT = new Map<number, SeatReading>();\n for (const r of fromServer) byT.set(r.t, r);\n for (const r of fromPage) byT.set(r.t, r);\n const sorted = [...byT.values()].sort((a, b) => a.t - b.t);\n let start = 0;\n for (let i = 1; i < sorted.length; i++) if (sorted[i]!.used + RESET_DROP < sorted[i - 1]!.used) start = i;\n const line: SeatReading[] = [];\n for (const r of sorted.slice(start)) {\n if (isFlatEnd(line, r.used)) line.pop();\n line.push(r);\n }\n readings[key] = line.slice(-SEAT_HISTORY_MAX);\n }\n return { readings, recorded };\n}\n\nexport interface SeatBurn {\n seatId: string;\n label: string;\n engine: 'claude' | 'codex' | 'grok' | 'local';\n window: 'session' | 'weekly' | null;\n /** Remaining percent readings (100 − used), inside [start, resetAt] when the reset is known. */\n points: { t: number; remaining: number | null }[];\n /** `resetAt` minus the window's length; null exactly when `resetAt` is. */\n start: number | null;\n resetAt: number | null;\n /**\n * Where `resetAt` came from: the budget route's machine instant\n * ('provider'), the provider's own reset words read on the clock they name\n * ('words' — see `resetInstantFromWords`), or nowhere (null).\n */\n resetFrom: 'provider' | 'words' | null;\n /**\n * The provider's own reset wording for the binding window, verbatim\n * (\"Sep 25 at 7pm (America/New_York)\"), when the seat roster carries it.\n * Claude publishes ONLY this — never a machine instant. The card always\n * shows the words; when they name a clock time inside this window they\n * also place the reset (`resetFrom: 'words'`), otherwise the card draws the\n * readings with no reset point or projection.\n */\n resetText: string | null;\n reservePercent: number;\n /**\n * The line autonomy stops at IN THE WINDOW THIS CHART DRAWS, as remaining\n * percent (see `bindingLine`); null when that window has no limit.\n */\n line: { value: number; label: string } | null;\n enabled: boolean;\n free: boolean;\n eligible: boolean;\n /**\n * The router's first reason for this seat in words (`seatReasonText`):\n * complete sentences, local times, never the log form's \" (resets <ISO>).\"\n * clause. Null when the route gave none.\n */\n reason: string | null;\n /**\n * True when the server's recorded history contributed to this window's\n * line; false when every point is one this page saw since Verse opened.\n * Picks the card's note when the line starts late in the window.\n */\n recorded: boolean;\n}\n\n/** Length of each provider window, for the chart domain (reset − length → reset). */\nexport const WINDOW_MS = { session: 5 * HOUR, weekly: 7 * DAY } as const;\n\n/**\n * The stop line for the binding window, mirroring core/routing/headroom.ts\n * exactly (review 3.10 d2). The reserve protects the LONG (weekly) window;\n * the 5-hour window is capped by `maxSessionWindowPercent` — except when the\n * seat has no weekly window at all, where the short one carries both limits\n * and the tighter one wins. Drawing the weekly reserve on a 5-hour chart put\n * Mason's balanced cutoff at 60% used instead of 70% and made the verdict say\n * \"autonomy has stopped\" while the server still had the seat eligible.\n *\n * `weeklyUsedPercent === null` stands in for \"no weekly window\": a weekly\n * window whose reading is unknown makes the seat ineligible server-side\n * anyway (unknown usage is never headroom), and the card shows that reason.\n */\nexport function bindingLine(\n h: { bindingWindow: 'session' | 'weekly' | null; weeklyUsedPercent: number | null },\n policy: { reservePercent: number; maxSessionWindowPercent?: number } | undefined,\n): { value: number; label: string } | null {\n if (!policy || h.bindingWindow === null) return null;\n const reserveCeiling = 100 - policy.reservePercent;\n const sessionCeiling = policy.maxSessionWindowPercent ?? 100;\n let ceiling: number;\n let label: string;\n if (h.bindingWindow === 'weekly') {\n ceiling = reserveCeiling;\n label = 'Reserved for you';\n } else if (h.weeklyUsedPercent === null && reserveCeiling < sessionCeiling) {\n ceiling = reserveCeiling;\n label = 'Reserved for you';\n } else {\n ceiling = sessionCeiling;\n label = '5-hour ceiling';\n }\n const value = 100 - ceiling;\n return value > 0 ? { value, label } : null;\n}\n\n/**\n * Axis/verdict time format per window (review 3.10 c17). A weekly window\n * starts exactly seven days before it resets, so weekday + time alone printed\n * \"Sat 10:27 AM … Resets Sat 10:27 AM\"; the weekly form carries the date.\n * It carries ONLY the date (3.10.1): inside one week the weekday repeats what\n * the date says, and at a quarter-width card \"Fri, Sep 18 at 11:46 PM\" +\n * \"Resets Fri, Sep 25 at 11:46 PM\" were wider than the plot and collided.\n */\nexport function burnTimeFormat(window: 'session' | 'weekly' | null): (ms: number) => string {\n const opts: Intl.DateTimeFormatOptions =\n window === 'session'\n ? { weekday: 'short', hour: 'numeric', minute: '2-digit' }\n : { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' };\n return (ms) => {\n const d = new Date(ms);\n return Number.isNaN(d.getTime()) ? '' : d.toLocaleString('en-US', opts);\n };\n}\n\n/**\n * The provider's reset wording for the seat window that plays `binding`'s\n * role. WHY the seat roster and not the budget route: `SeatHeadroom` (the\n * frozen budget wire shape) carries only a machine `resetAt`, which is\n * structurally null for Claude — the provider's sentence lives on the seat's\n * capacity windows. The window is picked with the SAME classifier the server\n * used to choose the binding window (core/routing/headroom.ts), so the words\n * belong to the window the chart draws, not to a per-model window beside it.\n */\nexport function bindingResetText(\n seat: Pick<VerseSeat, 'capacity'> | undefined,\n engine: SeatBurn['engine'],\n binding: 'session' | 'weekly' | null,\n nowMs: number,\n): string | null {\n if (!seat?.capacity || binding === null || engine === 'local') return null;\n for (const w of seat.capacity.windows) {\n const text = typeof w.resetDescription === 'string' ? w.resetDescription.trim() : '';\n if (text.length === 0) continue;\n if (classifyWindow(engine, { id: w.id, usedPercent: w.usedPercent, resetsAt: w.resetsAt, resetDescription: w.resetDescription, limitReached: w.limitReached }, nowMs) === binding) return text;\n }\n return null;\n}\n\n/**\n * \"resets Sep 25 at 7pm (America/New_York)\" from the provider's words. The\n * collector strips the leading \"resets\" (claude-account-usage.ts) but other\n * paths keep it; either way the sentence itself is shown verbatim.\n */\nexport function resetWords(text: string): string {\n return `resets ${text.replace(/^resets\\s+/i, '')}`;\n}\n\nconst MONTHS: readonly string[] = ['jan', 'feb', 'mar', 'apr', 'may', 'jun', 'jul', 'aug', 'sep', 'oct', 'nov', 'dec'];\n\n/**\n * The collector's own reset grammar (core/resources/claude-account-usage.ts\n * `RESET`), with the leading \"resets\" optional because other paths keep it.\n * Anything outside it — a changed native format, free prose — stays words.\n */\nconst RESET_WORDS_RE = /^(?:resets\\s+)?(?:([A-Za-z]{3}) ([1-9]|[12]\\d|3[01]) at )?([1-9]|1[0-2])(?::([0-5]\\d))?(am|pm) \\(([A-Za-z0-9_+-]+(?:\\/[A-Za-z0-9_+-]+){0,2})\\)$/i;\n\ninterface WallClock { y: number; mo: number; d: number; h: number; mi: number }\n\nfunction wallClock(ms: number, fmt: Intl.DateTimeFormat): WallClock | null {\n const parts = fmt.formatToParts(new Date(ms));\n const n = (type: Intl.DateTimeFormatPartTypes) => Number(parts.find((p) => p.type === type)?.value);\n const c = { y: n('year'), mo: n('month') - 1, d: n('day'), h: n('hour') % 24, mi: n('minute') };\n return Object.values(c).every(Number.isFinite) ? c : null;\n}\n\nconst wallAsUtc = (c: WallClock) => Date.UTC(c.y, c.mo, c.d, c.h, c.mi);\n\n/**\n * The instant whose wall clock in `fmt`'s zone reads `want`: start from the\n * wall time as if it were UTC and correct by the zone's offset until the\n * clock agrees. Null when it never does — a time skipped by a DST jump.\n */\nfunction instantAt(want: WallClock, fmt: Intl.DateTimeFormat): number | null {\n const target = wallAsUtc(want);\n let at = target;\n for (let i = 0; i < 3; i++) {\n const seen = wallClock(at, fmt);\n if (!seen) return null;\n const drift = target - wallAsUtc(seen);\n if (drift === 0) return at;\n at += drift;\n }\n return null;\n}\n\n/**\n * The instant named by the provider's reset words — \"Sep 25 at 6:59pm\n * (America/New_York)\" or \"1:40am (America/New_York)\" — or null when the words\n * are not in the collector's grammar or name an unknown zone.\n *\n * WHY this is not \"synthesizing a countdown from a description\"\n * (core/verse/types.ts): the words ARE an instant — a wall-clock minute in a\n * named IANA zone — so reading them on that zone's clock adds nothing the\n * provider did not say. The only thing the words leave out is the year (or,\n * for \"1:40am\", the day), and the candidate nearest `nowMs` is taken; the\n * caller still refuses an instant outside the window's own span\n * (`seatBurns`), so a misread can never stretch or shift the chart by more\n * than the window it draws. Without this, Claude — the seat that matters\n * most — was the one card with no window, no pace line and no projection.\n */\nexport function resetInstantFromWords(text: string, nowMs: number): number | null {\n const m = RESET_WORDS_RE.exec(text.trim());\n if (!m || !Number.isFinite(nowMs)) return null;\n const [, month, day, hour, minute, meridiem, zone] = m;\n let fmt: Intl.DateTimeFormat;\n try {\n fmt = new Intl.DateTimeFormat('en-US', { timeZone: zone, hourCycle: 'h23', year: 'numeric', month: 'numeric', day: 'numeric', hour: 'numeric', minute: 'numeric' });\n } catch {\n return null; // RangeError: not a zone this runtime knows.\n }\n const today = wallClock(nowMs, fmt);\n if (!today) return null;\n const h = (Number(hour) % 12) + (meridiem!.toLowerCase() === 'pm' ? 12 : 0);\n const mi = minute === undefined ? 0 : Number(minute);\n const candidates: WallClock[] = [];\n if (month !== undefined) {\n const mo = MONTHS.indexOf(month.toLowerCase());\n const d = Number(day);\n if (mo < 0) return null;\n for (const y of [today.y - 1, today.y, today.y + 1]) {\n // Feb 30 would roll into March — refuse it rather than move the reset.\n if (new Date(Date.UTC(y, mo, d)).getUTCDate() === d) candidates.push({ y, mo, d, h, mi });\n }\n } else {\n for (const k of [-1, 0, 1]) {\n const date = new Date(Date.UTC(today.y, today.mo, today.d + k));\n candidates.push({ y: date.getUTCFullYear(), mo: date.getUTCMonth(), d: date.getUTCDate(), h, mi });\n }\n }\n let best: number | null = null;\n for (const c of candidates) {\n const at = instantAt(c, fmt);\n if (at !== null && (best === null || Math.abs(at - nowMs) < Math.abs(best - nowMs))) best = at;\n }\n return best;\n}\n\n/**\n * How far a words-derived reset may sit in the past (a reading taken just\n * before the rollover) or beyond one window ahead (the provider rounds its\n * words to the minute or the hour).\n */\nconst WORDS_RESET_SLACK_MS = 15 * 60_000;\n\n/**\n * The binding window's reset instant: the budget route's machine instant when\n * there is one, else the provider's words read on their own clock — but only\n * when that instant can close the window the current reading sits in (no\n * more than one window ahead, no more than a few minutes past). Words that\n * fail either test stay words, and the card says the reset is not placed.\n */\n/** Earliest instant accepted as a real reset (2000-01-01T00:00:00Z). */\nconst PLAUSIBLE_RESET_FLOOR_MS = Date.UTC(2000, 0, 1);\n\nexport function bindingReset(\n machine: string | null,\n resetText: string | null,\n windowMs: number | null,\n nowMs: number,\n): { at: number; from: 'provider' | 'words' } | null {\n const at = machine ? Date.parse(machine) : NaN;\n // A placeholder instant (epoch 0 or anything before 2000) is not a reset —\n // fall through to the provider's words, as if no instant were sent.\n if (Number.isFinite(at) && at >= PLAUSIBLE_RESET_FLOOR_MS) return { at, from: 'provider' };\n if (resetText === null || windowMs === null) return null;\n const words = resetInstantFromWords(resetText, nowMs);\n if (words === null || words < nowMs - WORDS_RESET_SLACK_MS || words > nowMs + windowMs + WORDS_RESET_SLACK_MS) return null;\n return { at: words, from: 'words' };\n}\n\n// ---------------------------------------------------------------------------\n// Seat reasons, in words (3.10.1)\n// ---------------------------------------------------------------------------\n\n/**\n * The budget route's reasons as data. `SeatHeadroom.reasons` carries each\n * one in the router's LOG form — \"… so autonomy stops at 92% (resets\n * 2026-09-26T03:46:56.000Z).\" (core/routing/seat-reasons.ts\n * `reasonSentence`) — so the reset clause is split back off with the Fleet\n * surface's own parser: an instant → `resetsAt`, Claude's words →\n * `resetDescription`. Non-strings and blanks are skipped (wire data).\n */\nexport function seatReasons(reasons: readonly unknown[] | null | undefined): SeatReason[] {\n if (!Array.isArray(reasons)) return [];\n return reasons.filter((r): r is string => typeof r === 'string' && r.trim().length > 0).map(parseLegacyReason);\n}\n\n/** Two resets this close are the same one (the router and the chart read the same window). */\nconst SAME_RESET_MS = 60_000;\n\n/**\n * Reasons whose reset is, by construction, the BINDING window's: headroom.ts\n * attaches `resetOf(bindingRow.window)` to exactly these. A `spent` reason\n * can name the other window (a spent 5-hour window beside a weekly one that\n * is even further past its reserve), so it is never taken for the chart's.\n */\nconst BINDING_RESET_KINDS: ReadonlySet<SeatReasonKind> = new Set<SeatReasonKind>(['reserve', 'session-ceiling']);\n\n/** Claude's words without the \"resets\" some paths lead with. */\nfunction bareResetWords(text: string | null | undefined): string {\n return typeof text === 'string' ? text.trim().replace(/^resets\\s+/i, '') : '';\n}\n\n/**\n * The binding window's reset words from the router's own reasons — the\n * fallback when the roster (read from cache, never fetched here) has none,\n * so a card never says \"reset time not reported\" beside a reason that names\n * the reset.\n */\nexport function reasonResetText(reasons: readonly SeatReason[]): string | null {\n for (const r of reasons) {\n if (!BINDING_RESET_KINDS.has(r.kind)) continue;\n const words = bareResetWords(r.resetDescription);\n if (words) return words;\n }\n return null;\n}\n\n/**\n * When `reason` lifts, in the viewer's words — or null when the card already\n * says it: the chart's reset marker (\"Resets Sep 26, 11:46 PM\", a machine\n * instant or Claude's words placed on their clock) or the header's verbatim\n * words. A reset the card does NOT show (another window's) is kept: a machine\n * instant in the viewer's zone (`describeResetAt`, as Fleet and Accounts\n * word it), Claude's words verbatim.\n */\nfunction unshownReset(reason: SeatReason, card: { resetAt: number | null; resetText: string | null }, nowMs: number): string | null {\n const at = typeof reason.resetsAt === 'string' ? Date.parse(reason.resetsAt) : Number.NaN;\n if (Number.isFinite(at)) {\n if (card.resetAt !== null && Math.abs(at - card.resetAt) <= SAME_RESET_MS) return null;\n return describeResetAt(reason.resetsAt, nowMs);\n }\n const words = bareResetWords(reason.resetDescription);\n if (!words) return null;\n if (card.resetText !== null && bareResetWords(card.resetText).toLowerCase() === words.toLowerCase()) return null;\n return words;\n}\n\n/**\n * What a card says about why the router holds a seat back: the reason's own\n * sentence (any instant inside it in local time — Fleet's `localTimes`),\n * closed by exactly one full stop, then \"Resets ….\" only when the card does\n * not already show that reset (`unshownReset`). Never the log form: held-back\n * cards printed \"… stops at 92% (resets 2026-09-26T03:46:56.000Z).\" and, for\n * Claude, \"… (resets Sep 25 at 7pm (America/New_York)).\" verbatim.\n */\nexport function seatReasonText(reason: SeatReason | undefined, card: { resetAt: number | null; resetText: string | null }, nowMs: number): string | null {\n if (!reason) return null;\n const text = asSentence(localTimes(reason.text, nowMs));\n if (!text) return null;\n const when = unshownReset(reason, card, nowMs);\n return when ? `${text} Resets ${when}.` : text;\n}\n\n/**\n * One burn-down per seat, paid seats first (they are the ones that run out).\n * `history` is keyed by `seriesKey` (seat + window); each card draws its\n * BINDING window's line. `seats` (the live roster, optional) supplies the\n * provider's reset wording for seats that publish no machine reset time (see\n * `bindingResetText`), which also places their reset when it names a clock\n * time (`bindingReset`); without a roster, a reason held at the binding\n * window's reserve or ceiling supplies the same words (`reasonResetText`).\n * `recorded` (from `mergeSeatHistory`) names the lines the server's recorded\n * history contributed to. Each card's `reason` is the router's first reason\n * in words (`seatReasonText`).\n */\nexport function seatBurns(\n view: BudgetView | null,\n history: Readonly<Record<string, SeatReading[]>>,\n seats?: readonly VerseSeat[] | null,\n recorded?: ReadonlySet<string> | null,\n): SeatBurn[] {\n if (!view) return [];\n const info = new Map(view.seatInfo.map((s) => [s.seatId, s]));\n const roster = new Map((seats ?? []).map((s) => [s.id, s]));\n const sampled = Date.parse(view.sampledAt);\n const nowMs = Number.isFinite(sampled) ? sampled : Date.now();\n return view.headroom\n .map((h): SeatBurn => {\n const i = info.get(h.seatId);\n const engine = i?.engine ?? 'local';\n const windowMs = h.bindingWindow ? WINDOW_MS[h.bindingWindow] : null;\n const reasons = seatReasons(h.reasons);\n const resetText =\n bindingResetText(roster.get(h.seatId), engine, h.bindingWindow, nowMs) ??\n (h.bindingWindow === null || engine === 'local' ? null : reasonResetText(reasons));\n // A reset is only placed on a chart that has a window to put before it.\n const reset = windowMs === null ? null : bindingReset(h.resetAt, resetText, windowMs, nowMs);\n const start = reset && windowMs !== null ? reset.at - windowMs : null;\n const key = h.bindingWindow ? seriesKey(h.seatId, h.bindingWindow) : null;\n const readings = key ? history[key] ?? [] : [];\n return {\n seatId: h.seatId,\n label: i?.label ?? h.seatId,\n engine,\n window: h.bindingWindow,\n points: readings.filter((r) => start === null || r.t >= start).map((r) => ({ t: r.t, remaining: Math.max(0, 100 - r.used) })),\n start,\n resetAt: reset?.at ?? null,\n resetFrom: reset?.from ?? null,\n resetText,\n reservePercent: view.effective[h.seatId]?.reservePercent ?? 0,\n line: bindingLine(h, view.effective[h.seatId]),\n enabled: view.effective[h.seatId]?.enabled ?? false,\n free: i?.free ?? false,\n eligible: h.eligibleForAutonomy,\n reason: seatReasonText(reasons[0], { resetAt: reset?.at ?? null, resetText }, nowMs),\n recorded: key !== null && (recorded?.has(key) ?? false),\n };\n })\n .sort((a, b) => Number(a.free) - Number(b.free) || a.label.localeCompare(b.label));\n}\n\n/** \"Claude 40% reserved for you\" — the first enabled Claude seat's reserve, from the live budget. */\nexport function claudeReserve(view: BudgetView | null): { label: string; percent: number } | null {\n if (!view) return null;\n const seat = view.seatInfo.find((s) => s.engine === 'claude');\n if (!seat) return null;\n const policy = view.effective[seat.seatId];\n return policy ? { label: 'Claude', percent: policy.reservePercent } : null;\n}\n","/**\n * routes/verse/cloud/CloudBudgetForm.tsx — the cloud budget's fields, shared\n * by Command's \"Edit budget\" popover and the Usage \"Cloud credits\" panel\n * (3.11 unit C3), so both edit the same numbers the same way.\n *\n * Save sends ONE update with only the fields that changed (cloud-model\n * budgetPatch). The form re-seeds from the server's budget whenever that\n * budget changes and nothing has been typed, so a save elsewhere (the CLI,\n * the other surface) shows up instead of being silently overwritten.\n */\nimport { useEffect, useRef, useState, type FormEvent } from 'react';\nimport type { CloudBudgetUpdate, CloudBudgetV1 } from '../../../../core/cloud/types.js';\nimport { Button } from '../../../components/primitives/Button.js';\nimport { Input } from '../../../components/primitives/Input.js';\nimport { Switch } from '../../../components/primitives/Switch.js';\nimport { BUDGET_FIELDS, budgetFormFrom, budgetPatch, type BudgetErrors, type BudgetForm } from './cloud-model.js';\nimport styles from './cloud.module.css';\n\nexport interface CloudBudgetFormProps {\n budget: CloudBudgetV1;\n /** Runs the save (through the caller's token gate); the form keeps its values until the new budget lands. */\n onSave: (update: CloudBudgetUpdate) => void;\n onCancel?: () => void;\n busy: boolean;\n disabled?: boolean;\n /** The id prefix, so two forms on one page never share field ids. */\n idPrefix: string;\n}\n\nexport function CloudBudgetForm({ budget, onSave, onCancel, busy, disabled = false, idPrefix }: CloudBudgetFormProps) {\n const [form, setForm] = useState<BudgetForm>(() => budgetFormFrom(budget));\n const [errors, setErrors] = useState<BudgetErrors>({});\n const [note, setNote] = useState<string | null>(null);\n const dirty = useRef(false);\n\n // A newer budget from the server replaces the fields only while the\n // operator has not started typing — never under their fingers.\n useEffect(() => {\n if (!dirty.current) setForm(budgetFormFrom(budget));\n }, [budget]);\n\n const edit = (patch: Partial<BudgetForm>) => {\n dirty.current = true;\n setNote(null);\n setForm((prev) => ({ ...prev, ...patch }));\n };\n\n const submit = (event: FormEvent) => {\n event.preventDefault();\n const result = budgetPatch(form, budget);\n if (!result.ok) {\n setErrors(result.errors);\n return;\n }\n setErrors({});\n if (!result.changed) {\n setNote('Nothing changed.');\n return;\n }\n dirty.current = false;\n onSave(result.update);\n };\n\n return (\n <form className={styles.form} onSubmit={submit} noValidate aria-label=\"Cloud budget\">\n <div className={styles.fieldGrid}>\n {BUDGET_FIELDS.map((spec) => (\n <Input\n key={spec.field}\n id={`${idPrefix}-${spec.field}`}\n label={spec.label}\n hint={spec.hint}\n error={errors[spec.field]}\n size=\"sm\"\n inputMode={spec.integer ? 'numeric' : 'decimal'}\n prefix={spec.money ? '$' : undefined}\n value={form[spec.field]}\n disabled={disabled || busy}\n onChange={(e) => edit({ [spec.field]: e.target.value } as Partial<BudgetForm>)}\n />\n ))}\n </div>\n <Switch\n checked={form.selfImprove}\n onChange={(next) => edit({ selfImprove: next })}\n label=\"Verse may launch self-improvement tasks on its own\"\n disabled={disabled || busy}\n />\n {note ? <p className={styles.muted} role=\"status\">{note}</p> : null}\n <div className={styles.formActions}>\n {onCancel ? (\n <Button variant=\"ghost\" size=\"sm\" onClick={onCancel} disabled={busy}>\n Cancel\n </Button>\n ) : null}\n <Button type=\"submit\" variant=\"primary\" size=\"sm\" busy={busy} disabled={disabled}>\n Save budget\n </Button>\n </div>\n </form>\n );\n}\n"],"mappings":"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"}
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
import{a as e,c as t,i as n,n as r}from"./index-DZ-UQ7v8.js";import{h as i}from"./global-CMNW_dqn.js";import{t as a}from"./focus-trap-CtI1SlMX.js";import{t as o}from"./ProviderLogo-Cq-CYIwT.js";import{Ht as s,I as c,N as l,S as u,T as d,X as f,_n as p,at as m,hn as h,rt as g,tt as _,z as v}from"./VerseConsoleApp-CWU6R3By.js";import{o as y}from"./verse-icons-S56hIiXS.js";import{a as b,n as x,r as S,s as C}from"./command-catalog-BIntSa9l.js";var w=t(e(),1),T=t(n(),1),E={...Object.fromEntries(x.map(e=>[e.id,e.label])),recent:`Recent`},D=[`needs-you`,`recent`,...x.map(e=>e.id).filter(e=>e!==`needs-you`)],O={"needs-you":5,recent:5,chats:8,actions:8,"go-to":6,"seats-apps":5,projects:5};function k(e,t){if(t===0)return!0;let n=e[t-1];return/[\s\-_/.:·›,(]/.test(n)||/[a-z]/.test(n)&&/[A-Z]/.test(e[t])}function A(e,t){let n=e.toLowerCase();if(!n)return 0;let r=t.toLowerCase(),i=r.indexOf(n);if(i>=0){let e=1e3-i*4;return k(t,i)&&(e+=400),i===0&&(e+=200),e}let a=0,o=0,s=-2;for(let e of n){let n=r.indexOf(e,o);if(n<0)return null;a+=n===s+1?30:5,k(t,n)&&(a+=20),a-=Math.min(20,n-o),s=n,o=n+1}return a}function j(e,t){let n=t.trim().split(/\s+/).filter(Boolean);if(n.length===0)return 0;let r=0;for(let t of n){let n=A(t,e.title);for(let r of[e.subtitle??``,...e.keywords]){if(!r)continue;let e=A(t,r);e!==null&&(n=Math.max(n??-1/0,e*.6))}if(n===null)return null;r+=n}return r}function M(e,t){let n=Math.max(0,Math.round((t-Date.parse(e))/1e3));if(!Number.isFinite(n))return`running`;if(n<60)return`running ${n}s`;let r=Math.floor(n/60);return r<60?`running ${r}m ${String(n%60).padStart(2,`0`)}s`:`running ${Math.floor(r/60)}h ${r%60}m`}function N(e,t){let n=Date.parse(e);if(!Number.isFinite(n))return``;let r=Math.round((t-n)/6e4);if(r<1)return`just now`;if(r<60)return`${r}m ago`;let i=Math.round(r/60);return i<36?`${i}h ago`:`${Math.round(i/24)}d ago`}function P(e){let t=e.split(/[\\/]/).filter(Boolean);return t[t.length-1]??e}function F(e,t,n){let r=e.keys[0];return{key:`${n}:cmd:${e.id}`,kind:`command`,group:n,title:e.title,subtitle:e.scope===`chat`||e.scope===`composer`?`in Chat`:e.surface===`command`?`on Command`:e.surface===`mind`?`on Mind`:null,shortcut:r?p(r,t):null,monogram:null,engine:null,keywords:[...e.keywords??[],e.section.toLowerCase()],argument:e.argument?{...e.argument}:null,tone:e.guard?.confirm.destructive?`danger`:`neutral`,payload:{kind:`command`,commandId:e.id}}}function I(e){let t=e.now??Date.now(),n=[];for(let t of e.needsYou)n.push({key:`needs-you:${t.id}`,kind:`needs-you`,group:`needs-you`,title:t.title,subtitle:t.subject.repo??t.subject.seatId??null,shortcut:null,monogram:t.subject.engine?s[t.subject.engine]:null,engine:t.subject.engine,keywords:[t.kind.replace(/-/g,` `),t.source,`needs you`],argument:null,tone:t.severity===`high`?`danger`:t.severity===`warn`?`warn`:`neutral`,payload:{kind:`needs-you`,itemId:t.id}});let r=new Map(e.running.map(e=>[e.sessionId,e])),i=[...e.sessions].sort((e,t)=>{let n=r.has(e.id)||e.status===`running`?0:1,i=r.has(t.id)||t.status===`running`?0:1;return n===i?e.updatedAt<t.updatedAt?1:e.updatedAt>t.updatedAt?-1:0:n-i});for(let e of i){let i=r.get(e.id),a=!!i||e.status===`running`,o=a?i?M(i.startedAt,t):`running`:e.status===`error`?`failed`:N(e.updatedAt,t);n.push({key:`chat:${e.id}`,kind:`chat`,group:`chats`,title:e.title||`Untitled chat`,subtitle:[P(e.projectPath),o].filter(Boolean).join(` · `),shortcut:null,monogram:s[e.engine],engine:e.engine,keywords:[e.model,e.seatId,P(e.projectPath)],argument:null,tone:a?`running`:e.status===`error`?`warn`:`neutral`,payload:{kind:`chat`,sessionId:e.id}})}for(let t of C(`actions`))n.push(F(t,e.platform,`actions`));for(let t of C(`go-to`))n.push(F(t,e.platform,`go-to`));for(let t of e.seats)n.push({key:`seat:${t.id}`,kind:`seat`,group:`seats-apps`,title:`New chat on ${t.label}`,subtitle:t.id,shortcut:null,monogram:s[t.engine],engine:t.engine,keywords:[t.engine,t.label,`seat`,`account`],argument:null,tone:`neutral`,payload:{kind:`seat`,seatId:t.id,label:t.label}});for(let t of e.projects)n.push({key:`project:${t.path}`,kind:`project`,group:`projects`,title:`New chat in ${t.name||P(t.path)}`,subtitle:t.enrolled?`enrolled in the fleet`:null,shortcut:null,monogram:null,engine:null,keywords:[t.name,P(t.path)],argument:null,tone:`neutral`,payload:{kind:`project`,path:t.path,name:t.name||P(t.path)}});return n}function L(e,t){let n=(t,n,r,i,a)=>({key:`arg:${e}:${t}`,kind:`argument`,group:`actions`,title:n,subtitle:r,shortcut:null,monogram:i,engine:a,keywords:[t],argument:null,tone:`neutral`,payload:{kind:`argument`,argument:{kind:e,id:t,label:n}}});switch(e){case`seat`:return t.seats.map(e=>n(e.id,e.label,e.id,s[e.engine],e.engine));case`project`:return t.projects.map(e=>n(e.path,e.name||P(e.path),null,null,null));case`session`:return t.sessions.map(e=>n(e.id,e.title||`Untitled chat`,P(e.projectPath),s[e.engine],e.engine));case`section`:return[];default:return[]}}function R(e,t,n,r){let i=t,a=null,o=i.trimStart().charAt(0);(o===`>`||o===`#`)&&(a=o,i=i.trimStart().slice(1));let s=a?S[a]:null,c=i.trim(),l=new Map,u=(e,t,n)=>{let r=l.get(e.group)??[];r.push({item:e,score:t,order:n}),l.set(e.group,r)};if(c===``&&!a){e.filter(e=>e.group===`needs-you`).slice(0,3).forEach((e,t)=>u(e,0,t));let t=n.map(e=>b(e)).filter(e=>e!==null&&e.group!==null);(t.length>0?t:[`chat.new`,`needs-you.open`,`shortcuts.open`].map(e=>b(e))).slice(0,5).forEach((e,t)=>u(F(e,r,`recent`),0,t))}else e.forEach((e,t)=>{if(s&&e.group!==s)return;let n=c===``?0:j(e,c);n!==null&&u(e,n,t)});let d=[],f=[];for(let e of D){let t=l.get(e);if(!t||t.length===0)continue;let n=t=>e===`chats`&&t.item.tone===`running`?0:1;t.sort((e,t)=>n(e)-n(t)||t.score-e.score||e.order-t.order);let r=a?50:O[e],i=t.slice(0,r);for(let e of i)f.push(e.score);d.push({id:e,label:E[e],items:i.map(e=>e.item)})}let p=0;return c!==``&&f.forEach((e,t)=>{e>f[p]&&(p=t)}),{groups:d,flat:d.flatMap(e=>e.items),prefix:a,best:p}}var z={backdrop:`_backdrop_qk7b5_4`,fade:`_fade_qk7b5_1`,panel:`_panel_qk7b5_16`,rise:`_rise_qk7b5_1`,field:`_field_qk7b5_29`,crumb:`_crumb_qk7b5_37`,input:`_input_qk7b5_49`,list:`_list_qk7b5_66`,group:`_group_qk7b5_74`,groupLabel:`_groupLabel_qk7b5_76`,item:`_item_qk7b5_86`,lead:`_lead_qk7b5_100`,monogram:`_monogram_qk7b5_109`,bullet:`_bullet_qk7b5_128`,text:`_text_qk7b5_136`,title:`_title_qk7b5_143`,subtitle:`_subtitle_qk7b5_153`,trail:`_trail_qk7b5_168`,key:`_key_qk7b5_175`,empty:`_empty_qk7b5_190`,foot:`_foot_qk7b5_197`},B=r();function V({onClose:e=f}){let t=l(),n=c(),r=i(d),s=i(u),p=(0,w.useMemo)(()=>h(),[]),[x,S]=(0,w.useState)(``),[C,E]=(0,w.useState)(0),[D,O]=(0,w.useState)(null),k=(0,w.useRef)(null),A=(0,w.useRef)(null),j=(0,w.useRef)(null),M=(0,w.useId)(),N=(0,w.useId)(),P=(0,w.useRef)(null);P.current=D;let F=(0,w.useCallback)(()=>{P.current?O(null):e()},[e]);a({open:!0,containerRef:k,onClose:F,initialFocusRef:A});let V=(0,w.useMemo)(()=>({needsYou:n.data?.needsYou??[],running:n.data?.running??[],sessions:r.data??s.data?.sessions??[],seats:s.data?.seats??[],projects:s.data?.projects??[],recentActions:t.recentActions,platform:p}),[n.data,r.data,s.data,t.recentActions,p]),H=(0,w.useMemo)(()=>D?.argument?{...R(L(D.argument.kind,V),`>${x}`,[],p),prefix:null}:R(I(V),x,t.recentActions,p),[D,V,x,t.recentActions,p]),U=(0,w.useRef)(!1);(0,w.useEffect)(()=>{if(U.current){U.current=!1,E(H.best);return}E(e=>H.flat.length===0?0:Math.min(e,H.flat.length-1))},[H]),(0,w.useEffect)(()=>{(j.current?.querySelector(`[data-index="${C}"]`))?.scrollIntoView?.({block:`nearest`})},[C]);function W(e){O(e),S(``),E(0)}function G(t){if(!t)return;let n=t.payload;if(n.kind===`command`){let t=b(n.commandId);if(t?.argument){W(t);return}e(),v(n.commandId,{via:`palette`});return}switch(e(),n.kind){case`needs-you`:_({split:`all`,focusId:n.itemId});break;case`chat`:g(n.sessionId);break;case`seat`:v(`chat.new-on`,{via:`palette`,argument:{kind:`seat`,id:n.seatId,label:n.label}});break;case`project`:m(`new-chat`,{projectPath:n.path});break;case`argument`:D&&v(D.id,{via:`palette`,argument:n.argument})}}function K(t){let n=H.flat.length,r=t.key;if((t.metaKey||t.ctrlKey)&&r.toLowerCase()===`k`){t.preventDefault(),e();return}switch(r){case`ArrowDown`:t.preventDefault(),n>0&&E(e=>(e+1)%n);return;case`ArrowUp`:t.preventDefault(),n>0&&E(e=>(e-1+n)%n);return;case`Home`:n>0&&(t.preventDefault(),E(0));return;case`End`:n>0&&(t.preventDefault(),E(n-1));return;case`Enter`:t.preventDefault(),G(H.flat[C]);return;case`Tab`:{t.preventDefault();let e=H.flat[C],n=e?.payload.kind===`command`?b(e.payload.commandId):null;n?.argument&&W(n);return}case`Backspace`:D&&x===``&&(t.preventDefault(),O(null));return;case`Escape`:t.preventDefault(),t.stopPropagation(),D?O(null):e();return;default:return}}let q=H.flat[C],J=D?.argument?`${D.argument.prompt}…`:`Search chats, actions and places`,Y=-1;return(0,T.createPortal)((0,B.jsx)(`div`,{className:z.backdrop,onMouseDown:t=>t.target===t.currentTarget&&e(),children:(0,B.jsxs)(`div`,{ref:k,className:z.panel,role:`dialog`,"aria-modal":`true`,"aria-labelledby":N,"data-verse-overlay":`palette`,children:[(0,B.jsx)(`h2`,{id:N,className:`visually-hidden`,children:`Command palette`}),(0,B.jsxs)(`div`,{className:z.field,children:[D?(0,B.jsxs)(`span`,{className:z.crumb,children:[D.title.replace(/…$/,``),(0,B.jsx)(`span`,{"aria-hidden":`true`,children:` ›`})]}):null,(0,B.jsx)(`input`,{ref:A,className:z.input,value:x,placeholder:J,"aria-label":D?.argument?D.argument.prompt:`Search commands`,role:`combobox`,"aria-expanded":`true`,"aria-controls":M,"aria-autocomplete":`list`,"aria-activedescendant":q?`${M}-${C}`:void 0,autoComplete:`off`,autoCorrect:`off`,spellCheck:!1,onChange:e=>{S(e.target.value),U.current=!0},onKeyDown:K})]}),(0,B.jsx)(`div`,{ref:j,id:M,className:z.list,role:`listbox`,"aria-label":`Results`,children:H.flat.length===0?(0,B.jsx)(`p`,{className:z.empty,children:D?`No ${D.argument?.prompt.toLowerCase()??`match`} matches “${x}”.`:`Nothing matches “${x.trim()}”.`}):H.groups.map(e=>(0,B.jsxs)(`div`,{role:`group`,"aria-label":D?D.argument?.prompt??e.label:e.label,className:z.group,children:[(0,B.jsx)(`div`,{className:z.groupLabel,"aria-hidden":`true`,children:D?D.argument?.prompt:e.label}),e.items.map(e=>{Y+=1;let t=Y;return(0,B.jsxs)(`div`,{id:`${M}-${t}`,"data-index":t,role:`option`,"aria-selected":t===C,className:z.item,"data-tone":e.tone,onMouseMove:()=>t!==C&&E(t),onMouseDown:e=>e.preventDefault(),onClick:()=>G(e),children:[(0,B.jsx)(`span`,{className:z.lead,"aria-hidden":`true`,children:e.monogram?(0,B.jsx)(`span`,{className:z.monogram,"data-engine":e.engine??void 0,children:e.engine?(0,B.jsx)(o,{engine:e.engine,size:13}):e.monogram}):(0,B.jsx)(`span`,{className:z.bullet,"data-kind":e.kind})}),(0,B.jsxs)(`span`,{className:z.text,children:[(0,B.jsx)(`span`,{className:z.title,children:e.title}),e.subtitle?(0,B.jsx)(`span`,{className:z.subtitle,children:e.subtitle}):null]}),(0,B.jsxs)(`span`,{className:z.trail,children:[e.argument?(0,B.jsx)(`kbd`,{className:z.key,children:`⇥`}):null,e.shortcut?(0,B.jsx)(`kbd`,{className:z.key,children:e.shortcut}):null]})]},e.key)})]},e.id))}),(0,B.jsxs)(`div`,{className:z.foot,"aria-hidden":`true`,children:[(0,B.jsxs)(`span`,{children:[(0,B.jsx)(`kbd`,{className:z.key,children:`↑↓`}),` move`]}),(0,B.jsxs)(`span`,{children:[(0,B.jsx)(`kbd`,{className:z.key,children:(0,B.jsx)(y,{})}),` run`]}),q?.argument?(0,B.jsxs)(`span`,{children:[(0,B.jsx)(`kbd`,{className:z.key,children:`⇥`}),` `,q.argument.prompt.toLowerCase()]}):null,(0,B.jsxs)(`span`,{children:[(0,B.jsx)(`kbd`,{className:z.key,children:`esc`}),` `,D?`back`:`close`]}),D?null:(0,B.jsxs)(`span`,{children:[(0,B.jsx)(`kbd`,{className:z.key,children:`>`}),` actions only · `,(0,B.jsx)(`kbd`,{className:z.key,children:`#`}),` chats only`]})]}),(0,B.jsx)(`p`,{className:`visually-hidden`,role:`status`,"aria-live":`polite`,children:H.flat.length===1?`1 result`:`${H.flat.length} results`})]})}),document.body)}export{V as CommandPalette};
|
|
2
|
+
//# sourceMappingURL=CommandPalette-C5lDDKN0.js.map
|