@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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"charts-BZ50mZD_.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/ChartContainer.module.css","../../../../../../src/web-ui/components/charts/ChartContainer.tsx","../../../../../../src/web-ui/components/charts/Legend.module.css","../../../../../../src/web-ui/components/charts/Legend.tsx","../../../../../../src/web-ui/components/charts/LineChart.module.css","../../../../../../src/web-ui/components/charts/LineChart.tsx","../../../../../../src/web-ui/components/charts/BarChart.module.css","../../../../../../src/web-ui/components/charts/BarChart.tsx","../../../../../../src/web-ui/components/charts/BurnDown.tsx"],"sourcesContent":[".figure {\n margin: 0;\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-lg);\n background: var(--bg-surface);\n padding: var(--space-4);\n /* Fixed heights must include the axis-label band — this container instead\n grows with its content so a chart's x-axis labels never get clipped or\n forced into a nested scroll (dataviz anti-patterns). */\n}\n\n.caption {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-3);\n margin-bottom: var(--space-3);\n}\n\n.title {\n font-size: var(--text-sm-size);\n font-weight: var(--font-weight-semibold);\n color: var(--text-primary);\n}\n\n.description {\n font-size: var(--text-xs-size);\n color: var(--text-tertiary);\n}\n\n.plot {\n width: 100%;\n overflow-x: auto;\n}\n\n.tableDisclosure {\n margin-top: var(--space-3);\n border-top: 1px solid var(--border-subtle);\n padding-top: var(--space-2);\n}\n\n.tableDisclosure > summary {\n cursor: pointer;\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n list-style: none;\n}\n\n.tableDisclosure > summary::-webkit-details-marker {\n display: none;\n}\n\n.tableDisclosure > summary::before {\n content: '▸ ';\n}\n\n.tableDisclosure[open] > summary::before {\n content: '▾ ';\n}\n\n.tableBody {\n margin-top: var(--space-2);\n}\n\n.caveat {\n margin: 0 0 var(--space-3);\n padding: var(--space-2) var(--space-3);\n border-radius: var(--radius-md);\n background: var(--status-unknown-bg);\n color: var(--status-unknown-fg);\n font-size: var(--text-xs-size);\n line-height: var(--text-sm-line);\n}\n\n.empty {\n color: var(--text-tertiary);\n font-size: var(--text-sm-size);\n padding: var(--space-6) 0;\n text-align: center;\n}\n","/**\n * components/charts/ChartContainer.tsx — the figure every chart mounts\n * inside: title/description, the plot itself, an optional caveat banner\n * (epistemic-honesty-adjacent: for a chart built on data with a known,\n * disclosed limitation — see ProductionView's judge-verdict caveat), an\n * optional table-view twin (the WCAG-clean accessibility equivalent every\n * chart should ship per the dataviz skill), and an empty state that never\n * lies about missing data.\n */\nimport type { ReactNode } from 'react';\nimport './chart-tokens.css';\nimport styles from './ChartContainer.module.css';\n\nexport interface ChartContainerProps {\n title: string;\n description?: string;\n /** A short, honest note about a known limitation of the data behind this\n * chart (e.g. \"counts may include X, not yet separable\"). Never omit a\n * caveat to make a chart look cleaner than the data actually is. */\n caveat?: string;\n /** The chart itself (SVG + legend). */\n children: ReactNode;\n /** The accessibility twin — same data as a real HTML table. Omit only\n * when the chart already IS a table. */\n table?: ReactNode;\n /** When true, renders the empty state instead of `children`. */\n empty?: boolean;\n emptyMessage?: string;\n}\n\nexport function ChartContainer({\n title,\n description,\n caveat,\n children,\n table,\n empty,\n emptyMessage = 'No data for this window.',\n}: ChartContainerProps) {\n return (\n <figure className={styles.figure}>\n <figcaption className={styles.caption}>\n <span className={styles.title}>{title}</span>\n {description ? <span className={styles.description}>{description}</span> : null}\n </figcaption>\n {caveat ? (\n <p className={styles.caveat} role=\"note\">\n {caveat}\n </p>\n ) : null}\n {empty ? (\n <p className={styles.empty}>{emptyMessage}</p>\n ) : (\n <div className={styles.plot}>{children}</div>\n )}\n {table ? (\n <details className={styles.tableDisclosure}>\n <summary>View as table</summary>\n <div className={styles.tableBody}>{table}</div>\n </details>\n ) : null}\n </figure>\n );\n}\n",".legend {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-1) var(--space-4);\n margin: var(--space-2) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.item {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n}\n\n.swatch {\n width: 10px;\n height: 10px;\n border-radius: var(--radius-full);\n flex: none;\n}\n\n.swatchLine {\n width: 14px;\n height: 2px;\n border-radius: var(--radius-full);\n flex: none;\n}\n","/**\n * components/charts/Legend.tsx — the dependable identity channel. A legend\n * is always present for two or more series (never rely on color-matching\n * alone); a single series needs no legend box because the chart's own title\n * already names it (see marks-and-anatomy.md \"Labels & legend\").\n */\nimport styles from './Legend.module.css';\n\nexport interface LegendItem {\n label: string;\n color: string;\n /** 'line' for line charts (a short stroke key), 'swatch' for bar/area. */\n kind?: 'line' | 'swatch';\n}\n\nexport function Legend({ items }: { items: LegendItem[] }) {\n if (items.length < 2) return null;\n return (\n <ul className={styles.legend}>\n {items.map((it) => (\n <li key={it.label} className={styles.item}>\n <span\n className={it.kind === 'line' ? styles.swatchLine : styles.swatch}\n style={{ background: it.color }}\n aria-hidden=\"true\"\n />\n {it.label}\n </li>\n ))}\n </ul>\n );\n}\n","/* Drawn at its measured width and a fixed height (width/height attributes\n set by LineChart). Never `width: 100%; height: auto` — that stretches the\n viewBox, text included, with the window. `max-width` keeps a not-yet-\n measured first paint from pushing its container wider. */\n.svg {\n display: block;\n max-width: 100%;\n font-variant-numeric: tabular-nums;\n}\n\n/* Hairlines, snapped to the pixel grid by LineChart (chart-math crisp). */\n.gridline {\n stroke: var(--chart-grid);\n stroke-width: 1;\n shape-rendering: crispEdges;\n}\n\n.axis {\n stroke: var(--chart-axis);\n stroke-width: 1;\n shape-rendering: crispEdges;\n}\n\n.axisLabel {\n font-size: var(--text-xs-size);\n fill: var(--text-tertiary);\n font-family: var(--font-ui);\n font-variant-numeric: tabular-nums;\n}\n\n.line {\n fill: none;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n/* The wash is a gradient (ChartParts AreaGradient) — its opacity lives in\n the gradient stops, never here. */\n.area {\n stroke: none;\n}\n\n.marker {\n stroke: var(--chart-surface);\n stroke-width: 2;\n}\n\n.endLabel {\n font-size: var(--text-xs-size);\n font-family: var(--font-ui);\n font-weight: var(--font-weight-medium);\n}\n\n.crosshairLine {\n stroke: var(--chart-axis);\n stroke-width: 1;\n shape-rendering: crispEdges;\n pointer-events: none;\n}\n\n.overlay {\n fill: transparent;\n cursor: crosshair;\n}\n\n.wrap {\n position: relative;\n width: 100%;\n min-width: 0;\n}\n","/**\n * components/charts/LineChart.tsx — trend over time. A gap (`null` y) is\n * split into a separate path segment so it renders as a visible break in\n * the line, never as a straight line through a missing value and never as\n * a silent zero. Single series gets an optional soft area fill; two-plus\n * series always render a legend (never color-matching alone).\n *\n * Sizing (after 3.11.3): the chart draws at its MEASURED pixel width and a fixed\n * pixel `height` — one user unit is one CSS pixel — like the V3.10 kit\n * (useChartWidth). It used to draw into a fixed 640-unit viewBox stretched\n * with `width: 100%; height: auto`, so on a 1900 px window the whole figure,\n * text included, scaled ~2.8×: 12 px tick labels rendered at ~34 px, the\n * 200 px chart stood ~560 px tall, and the end label (\"Tokens in\") dwarfed\n * the card. Now the coordinate system scales and the text never does.\n *\n * Polish (verse-visual-quality), matching the V3.10 kit's AreaTrend:\n * - monotone curves through every reading (chart-math monotoneSegments:\n * they never overshoot, so smoothing cannot invent a peak or a dip);\n * - `area` fills a gradient of the series ink (up to three series, on one\n * shared scale), not a flat 10% wash;\n * - interior x ticks at the same density as the kit (~one per 84 px);\n * - gridlines snapped to the pixel grid (crisp 1 px), tabular numerals;\n * - the latest reading carries a ringed dot;\n * - hover crosshair + the kit's ChartTooltip with EXACT values and the\n * local day / instant; the plot is a keyboard stop too (arrow keys,\n * Home/End) and announces each reading through a live region;\n * - it draws itself in once on mount, unless reduced motion (motion.ts).\n */\nimport { useId, useRef, useState, type KeyboardEvent, type PointerEvent } from 'react';\nimport type { Series } from './types.js';\nimport { gradientId, seriesColor, CHART_GRID, CHART_AXIS } from './colors.js';\nimport { AreaGradient, ChartTooltip, clampTooltipLeft, tooltipSide } from './ChartParts.js';\nimport { Legend } from './Legend.js';\nimport {\n MIN_TIME_SPAN_MS,\n allIntegers,\n axisTicks,\n crisp,\n dodgeLabels,\n ensureSpan,\n isTimeAxis,\n labelCharPx,\n layoutAxisLabels,\n smoothAreaPath,\n smoothPath,\n thinIndexes,\n xKeeper,\n} from './chart-math.js';\nimport { formatExact, formatTimeLabel, timeLabelLadder, tooltipTimeFormatter } from './format.js';\nimport { useChartMotion } from './motion.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport { useTextScale } from './useTextScale.js';\nimport './chart-tokens.css';\nimport styles from './LineChart.module.css';\nimport plot from './plot.module.css';\n\n/** Width drawn at before the container is measured (jsdom, first paint). */\nconst FALLBACK_W = 640;\n/** Minimum left gutter; it widens when the y tick labels need more (see padL). */\nconst PAD_L = 44;\nconst PAD_R = 12;\nconst PAD_T = 12;\nconst PAD_B = 24;\nconst TICKS_Y = 4;\n/* Direct end-of-line labels need a gutter of their own. User units are CSS\n pixels here (the viewBox matches the measured width), and `--text-xs-size`\n is 12 px, where the UI sans averages a shade over 6 px per character at\n medium weight. 6.4 rounds that up so the reserve errs\n wide rather than clipping. Without the reserve the label was drawn at\n `width - PAD_R + 4` with only PAD_R (12 px) of room and the svg's own\n `overflow: hidden` cropped it to its first glyph — \"Estimated spend\"\n rendered as a lone \"E\".\n Every text measure here (END_LABEL_CH, END_LABEL_GAP_Y, the axis label\n advance) is for 12 px text and is multiplied by the operator's Display\n size (useTextScale): --text-xs-size is 12px × --ui-text-scale, so at\n XLarge the same label is 15 units tall and 25% wider. END_LABEL_MAX is a\n budget of plot width, not a text measure, and stays as it is. */\nconst END_LABEL_CH = 6.4;\nconst END_LABEL_GAP = 4;\n/* Past this the gutter would cost more plot than the label is worth, so the\n label is dropped rather than shrinking the chart around it. Nothing is lost:\n Legend.tsx deliberately renders nothing below two series because the panel\n heading already names a lone series, and two-plus series always have the\n legend regardless. */\nconst END_LABEL_MAX = 150;\n/** Line height of a direct end label at 12 px (user units): two closer than this overlap. */\nconst END_LABEL_GAP_Y = 14;\n\ninterface Run {\n x: number;\n y: number;\n}\n\nfunction splitRuns(points: Series['points']): Run[][] {\n const runs: Run[][] = [];\n let current: Run[] = [];\n for (const p of points) {\n if (p.y === null) {\n if (current.length) runs.push(current);\n current = [];\n continue;\n }\n current.push({ x: p.x, y: p.y });\n }\n if (current.length) runs.push(current);\n return runs;\n}\n\nexport function LineChart({\n series: seriesProp,\n height = 200,\n area = false,\n formatX: formatXProp,\n formatY: formatYProp,\n formatTooltip: formatTooltipProp,\n formatTooltipX: formatTooltipXProp,\n ariaLabel,\n width: fixedWidth,\n}: {\n series: Series[];\n /** Plot height in px, including the x-axis band. Fixed at every width. */\n height?: number;\n /** Fixed width in px (tests, print). Omit to fill the container. */\n width?: number;\n /** A gradient wash under each line (up to three series). */\n area?: boolean;\n formatX?: (x: number) => string;\n formatY?: (y: number) => string;\n /** Tooltip value format. Default: `formatY` when given, else formatExact (\"12,934\", not \"13K\"). */\n formatTooltip?: (y: number) => string;\n /** Tooltip title format. Default: `formatX` when given, else the local day / instant on a time axis. */\n formatTooltipX?: (x: number) => string;\n ariaLabel: string;\n}) {\n const svgRef = useRef<SVGSVGElement>(null);\n const wrapRef = useRef<HTMLDivElement>(null);\n const width = useChartWidth(wrapRef, fixedWidth, FALLBACK_W);\n const textScale = useTextScale();\n const motion = useChartMotion();\n const gradKey = useId();\n const liveId = useId();\n /* Axis labels' estimated advance per character, at the size they render. */\n const axisLabelCh = labelCharPx(textScale);\n const [hoverX, setHoverX] = useState<number | null>(null);\n\n const formatTip = formatTooltipProp ?? formatYProp ?? formatExact;\n /* On a time axis a 0 / NaN / pre-2000 x is a null timestamp that leaked\n through, not a moment: it would start the axis at \"Dec 31\" 1969. Such\n points are left out of the domain AND the drawing. */\n const keepX = xKeeper(seriesProp.flatMap((s) => s.points.map((p) => p.x)));\n const series = seriesProp.map((s) => ({ ...s, points: s.points.filter((p) => keepX(p.x)) }));\n const allX = series.flatMap((s) => s.points.map((p) => p.x));\n const knownY = series.flatMap((s) => s.points.map((p) => p.y)).filter((y): y is number => y !== null && Number.isFinite(y));\n if (allX.length === 0) {\n return (\n <div ref={wrapRef} className={styles.wrap}>\n <p>No data.</p>\n </div>\n );\n }\n const rawXMin = Math.min(...allX);\n const rawXMax = Math.max(...allX);\n const timeAxis = isTimeAxis(allX);\n // An epoch-ms x printed with String() read \"1758960000000\" in the tooltip.\n const formatX = formatXProp ?? (timeAxis ? formatTimeLabel : (x: number) => String(x));\n const formatTipX = formatTooltipXProp ?? formatXProp ?? (timeAxis ? tooltipTimeFormatter(allX) : formatX);\n // A burst of points seconds apart is widened to MIN_TIME_SPAN_MS around\n // itself instead of stretched edge to edge under identical labels.\n const [xMin, xMax] = timeAxis && rawXMax > rawXMin ? ensureSpan(rawXMin, rawXMax, MIN_TIME_SPAN_MS) : [rawXMin, rawXMax];\n const xRange = xMax - xMin || 1;\n\n // Nice ticks whose labels are exact: integer data get integer ticks, and a\n // caller's formatter never prints a rounded label on a precise tick.\n const yAxis = axisTicks(Math.min(0, ...knownY), Math.max(0, ...knownY), {\n count: TICKS_Y,\n integer: knownY.length > 0 && allIntegers(knownY),\n format: formatYProp,\n });\n const yTicks = yAxis.ticks;\n const yMin = yTicks[0]!;\n const yMax = yTicks[yTicks.length - 1]!;\n const yRange = yMax - yMin || 1;\n const plotH = height - PAD_T - PAD_B;\n const yScale = (y: number) => PAD_T + plotH - ((y - yMin) / yRange) * plotH;\n /* The y labels hang right-aligned 6 units left of the plot, and the svg\n clips at its edge: the gutter grows to fit the widest one (+2 of air) —\n 44 still fits five 12 px characters, a larger Display size fewer. */\n const padL = Math.max(PAD_L, Math.ceil(Math.max(0, ...yAxis.labels.map((l) => l.length)) * axisLabelCh) + 8);\n\n /* Decided before the x scale, because the reserved gutter is what plotW is\n measured against — and the gridlines and x-axis stop at the same edge.\n End labels are dodged vertically so two lines ending on one value never\n print their names over each other; if they cannot all fit, the legend\n (always present for 2+ series) names them instead. */\n const wantEndLabels = series.length >= 1 && series.length <= 4;\n const endLabelW = wantEndLabels\n ? Math.max(...series.map((s) => s.label.length)) * END_LABEL_CH * textScale\n : 0;\n const endPoints = series.flatMap((s) => {\n for (let i = s.points.length - 1; i >= 0; i--) {\n const y = s.points[i]!.y;\n if (y !== null && Number.isFinite(y)) return [{ key: s.id, y: yScale(y) }];\n }\n return [];\n });\n const dodged = wantEndLabels && endLabelW <= END_LABEL_MAX ? dodgeLabels(endPoints, END_LABEL_GAP_Y * textScale, PAD_T, PAD_T + plotH) : null;\n const showEndLabels = dodged !== null && endPoints.length > 0;\n const padR = PAD_R + (showEndLabels ? END_LABEL_GAP + endLabelW : 0);\n const showLegend = series.length >= 2;\n\n const plotW = Math.max(40, width - padL - padR);\n const xScale = (x: number) => padL + ((x - xMin) / xRange) * plotW;\n\n // Nearest-x lookup across a reference axis (the union of all distinct x\n // values, since series may not share every point).\n const xAxis = Array.from(new Set(allX)).sort((a, b) => a - b);\n\n /* X labels, collision-free, at the kit's density (about one per 84 px —\n the same as AreaTrend, so sibling cards read alike): the end outranks\n the start and both outrank the interior ticks, which are simply dropped\n when they collide. On a time axis every label walks one detail ladder\n (the caller's format → a shorter date/time; clock time only inside one\n day) until the ends fit. */\n const tickIdx = xAxis.length > 1 ? thinIndexes(xAxis.length, Math.max(2, Math.floor(plotW / 84))) : [];\n const ladder = timeAxis ? timeLabelLadder(rawXMin, rawXMax, formatXProp, tickIdx.map((i) => xAxis[i]!)) : [formatX];\n const xLabels = layoutAxisLabels(\n tickIdx.map((idx, n) => {\n const x = xAxis[idx]!;\n const px = xScale(x);\n const isFirst = n === 0;\n const isLast = n === tickIdx.length - 1;\n const anchor = isFirst && px <= padL + 0.5 ? 'start' as const : isLast && px >= width - padR - 0.5 ? 'end' as const : 'middle' as const;\n return {\n key: isFirst ? 'start' : isLast ? 'end' : `t${idx}`,\n x: px,\n anchor,\n priority: isLast ? 3 : isFirst ? 2 : 1,\n required: isFirst || isLast,\n variants: ladder.map((f) => f(x)),\n };\n }),\n { min: padL, max: width - padR, charPx: axisLabelCh },\n );\n\n function nearestX(clientX: number): number | null {\n const svg = svgRef.current;\n if (!svg) return null;\n const rect = svg.getBoundingClientRect();\n // rect.width equals `width` once measured; the ratio only matters while the\n // fallback width is still being drawn (or a CSS max-width squeezes it).\n const svgX = ((clientX - rect.left) / (rect.width || width)) * width;\n const dataX = xMin + ((svgX - padL) / plotW) * xRange;\n let nearest = xAxis[0];\n let best = Infinity;\n for (const x of xAxis) {\n const d = Math.abs(x - dataX);\n if (d < best) {\n best = d;\n nearest = x;\n }\n }\n return nearest;\n }\n\n function handleMove(e: PointerEvent<SVGSVGElement>) {\n const x = nearestX(e.clientX);\n if (x === null) return;\n setHoverX(x);\n }\n\n function onKey(e: KeyboardEvent<HTMLDivElement>): void {\n if (xAxis.length === 0) return;\n const cur = hoverX === null ? xAxis.length - 1 : Math.max(0, xAxis.indexOf(hoverX));\n const next = e.key === 'ArrowLeft' ? cur - 1 : e.key === 'ArrowRight' ? cur + 1 : e.key === 'Home' ? 0 : e.key === 'End' ? xAxis.length - 1 : null;\n if (next === null) return;\n e.preventDefault();\n setHoverX(xAxis[Math.max(0, Math.min(xAxis.length - 1, next))]!);\n }\n\n const areaOn = area && series.length <= 3;\n\n const hoverPoints =\n hoverX !== null\n ? series.map((s) => ({\n series: s,\n point: s.points.find((p) => p.x === hoverX) ?? null,\n }))\n : null;\n\n return (\n <div\n ref={wrapRef}\n className={`${styles.wrap} ${plot.focusable}`}\n data-motion={motion}\n tabIndex={0}\n role=\"group\"\n aria-label={`${ariaLabel}. Use the left and right arrow keys to read values.`}\n aria-describedby={liveId}\n onFocus={() => setHoverX((h) => h ?? xAxis[xAxis.length - 1] ?? null)}\n onBlur={() => setHoverX(null)}\n onKeyDown={onKey}\n >\n <svg\n ref={svgRef}\n className={styles.svg}\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n role=\"img\"\n aria-label={ariaLabel}\n onPointerMove={handleMove}\n onPointerLeave={() => setHoverX(null)}\n >\n {areaOn ? (\n <defs>\n {series.map((s, si) => (\n <AreaGradient key={s.id} id={gradientId(gradKey, s.id)} color={seriesColor(si)} top={PAD_T} bottom={height - PAD_B} from={series.length > 1 ? 0.16 : 0.22} />\n ))}\n </defs>\n ) : null}\n {yTicks.map((t, i) => (\n <g key={i}>\n <line\n x1={padL}\n x2={width - padR}\n y1={crisp(yScale(t))}\n y2={crisp(yScale(t))}\n className={styles.gridline}\n stroke={CHART_GRID}\n />\n <text x={padL - 6} y={yScale(t)} dy=\"0.32em\" textAnchor=\"end\" className={styles.axisLabel}>\n {yAxis.labels[i]}\n </text>\n </g>\n ))}\n <line\n x1={padL}\n x2={width - padR}\n y1={crisp(height - PAD_B)}\n y2={crisp(height - PAD_B)}\n className={styles.axis}\n stroke={CHART_AXIS}\n />\n {xLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} x={l.x} y={height - 6} textAnchor={l.anchor} className={styles.axisLabel}>\n {l.text}\n </text>\n ))}\n\n {series.map((s, si) => {\n const color = seriesColor(si);\n const runs = splitRuns(s.points);\n return (\n <g key={s.id}>\n {areaOn\n ? runs.map((run, ri) => {\n const top = run.map((p) => ({ x: xScale(p.x), y: yScale(p.y) }));\n const base = top.map((p) => ({ x: p.x, y: yScale(Math.max(yMin, 0)) }));\n return (\n <path\n key={ri}\n data-role=\"area\"\n d={smoothAreaPath(top, base)}\n fill={`url(#${gradientId(gradKey, s.id)})`}\n className={`${styles.area} ${plot.fadeIn}`}\n />\n );\n })\n : null}\n {runs.map((run, ri) =>\n run.length === 1 ? (\n <circle key={ri} cx={xScale(run[0].x)} cy={yScale(run[0].y)} r={3} fill={color} />\n ) : (\n <path\n key={ri}\n data-role=\"line\"\n d={smoothPath(run.map((p) => ({ x: xScale(p.x), y: yScale(p.y) })))}\n pathLength={1}\n stroke={color}\n className={`${styles.line} ${plot.draw}`}\n />\n ),\n )}\n {hoverX === null && runs.length && runs[runs.length - 1].length > 1 ? (() => {\n // The latest reading, ringed — the \"you are here\" of a trend.\n const lastRun = runs[runs.length - 1];\n const last = lastRun[lastRun.length - 1];\n return <circle data-role=\"end-dot\" className={`${plot.endDot} ${plot.fadeIn}`} cx={xScale(last.x)} cy={yScale(last.y)} r={3.5} fill={color} />;\n })() : null}\n {showEndLabels && runs.length ? (\n (() => {\n const lastRun = runs[runs.length - 1];\n const last = lastRun[lastRun.length - 1];\n return (\n <text\n data-end-label={s.id}\n x={xScale(last.x) + END_LABEL_GAP}\n y={dodged?.get(s.id) ?? yScale(last.y)}\n dy=\"0.32em\"\n className={styles.endLabel}\n fill={color}\n >\n {s.label}\n </text>\n );\n })()\n ) : null}\n </g>\n );\n })}\n\n {hoverX !== null ? (\n <line\n data-role=\"crosshair\"\n x1={crisp(xScale(hoverX))}\n x2={crisp(xScale(hoverX))}\n y1={PAD_T}\n y2={height - PAD_B}\n className={styles.crosshairLine}\n />\n ) : null}\n {hoverX !== null\n ? series.map((s, si) => {\n const p = s.points.find((pt) => pt.x === hoverX);\n if (!p || p.y === null) return null;\n return (\n <circle\n key={s.id}\n cx={xScale(p.x)}\n cy={yScale(p.y)}\n r={4}\n fill={seriesColor(si)}\n className={styles.marker}\n />\n );\n })\n : null}\n\n <rect\n x={padL}\n y={PAD_T}\n width={plotW}\n height={plotH}\n className={styles.overlay}\n />\n </svg>\n <span id={liveId} className={plot.srOnly} aria-live=\"polite\">\n {hoverPoints\n ? `${formatTipX(hoverX as number)}: ${hoverPoints.map(({ series: s, point }) => `${s.label} ${point && point.y !== null ? formatTip(point.y) : 'no data'}`).join(', ')}`\n : ''}\n </span>\n {hoverPoints && hoverX !== null ? (\n <ChartTooltip\n left={tooltipSide(xScale(hoverX), width) ? xScale(hoverX) : clampTooltipLeft(xScale(hoverX), width)}\n side={tooltipSide(xScale(hoverX), width)}\n top={PAD_T}\n title={formatTipX(hoverX)}\n rows={hoverPoints.map(({ series: s, point }, i) => ({\n key: s.id,\n label: s.label,\n value: point && point.y !== null ? formatTip(point.y) : null,\n color: seriesColor(i),\n kind: 'line' as const,\n }))}\n />\n ) : null}\n {showLegend ? (\n <Legend items={series.map((s, i) => ({ label: s.label, color: seriesColor(i), kind: 'line' }))} />\n ) : null}\n </div>\n );\n}\n",".svg {\n display: block;\n overflow: visible;\n}\n\n.bar {\n transition: opacity var(--duration-fast) var(--ease-standard);\n}\n\n.bar:hover,\n.bar:focus-visible {\n opacity: 0.82;\n}\n\n.baseline {\n stroke: var(--chart-axis);\n stroke-width: 1;\n}\n\n.gridline {\n stroke: var(--chart-grid);\n stroke-width: 1;\n}\n\n.axisLabel {\n font-size: 10px;\n fill: var(--text-tertiary);\n font-family: var(--font-ui);\n}\n\n.valueLabel {\n font-size: 10px;\n fill: var(--text-secondary);\n font-family: var(--font-ui);\n font-variant-numeric: tabular-nums;\n}\n\n.categoryLabel {\n font-size: 10px;\n fill: var(--text-secondary);\n font-family: var(--font-ui);\n}\n\n.hitArea {\n fill: transparent;\n cursor: pointer;\n}\n\n.tooltip {\n position: absolute;\n pointer-events: none;\n background: var(--chart-tooltip-bg);\n border: 1px solid var(--chart-tooltip-border);\n border-radius: var(--radius-sm);\n box-shadow: var(--shadow-md);\n padding: var(--space-1) var(--space-2);\n font-size: var(--text-xs-size);\n color: var(--text-primary);\n white-space: nowrap;\n z-index: var(--z-dropdown);\n}\n\n.tooltipValue {\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n}\n\n.tooltipLabel {\n color: var(--text-tertiary);\n margin-left: var(--space-1);\n}\n\n.wrap {\n position: relative;\n}\n","/**\n * components/charts/BarChart.tsx — categorical magnitude comparison.\n * Single hue by default (nominal categories never get a value-ramp — see\n * dataviz anti-patterns \"a value-ramp on nominal categories\"). Vertical for\n * a handful of short-named categories, horizontal for many or long-named\n * ones (dataviz choosing-a-form.md). Null values render as an explicit\n * \"no data\" dash, never a silent zero-height bar indistinguishable from a\n * real zero.\n */\nimport { useId, useRef, useState } from 'react';\nimport type { CategoricalDatum } from './types.js';\nimport { CHART_SEQUENTIAL, CHART_AXIS, CHART_GRID } from './colors.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport './chart-tokens.css';\nimport styles from './BarChart.module.css';\n\nconst BAR_MAX = 24;\nconst GAP = 10;\n\nexport function BarChart({\n data,\n height = 160,\n orientation = 'vertical',\n color = CHART_SEQUENTIAL,\n formatValue = (v: number) => String(v),\n ariaLabel,\n width: fixedWidth,\n}: {\n data: CategoricalDatum[];\n height?: number;\n orientation?: 'vertical' | 'horizontal';\n /** Horizontal only: fixed width in px (tests, print). Omit to fill the container. */\n width?: number;\n color?: string;\n formatValue?: (v: number) => string;\n ariaLabel: string;\n}) {\n const uid = useId();\n const wrapRef = useRef<HTMLDivElement>(null);\n // Horizontal bars take the container's measured width (fallback: the old\n // fixed 588 px). A fixed-width svg under the global `svg { max-width: 100% }`\n // was scaled DOWN in a narrower card, shrinking its 10 px labels with it.\n const measuredW = useChartWidth(wrapRef, fixedWidth, 588);\n const [hover, setHover] = useState<number | null>(null);\n\n const known = data.map((d) => d.value).filter((v): v is number => v !== null);\n const maxVal = Math.max(0, ...known, 0.0001);\n const minVal = Math.min(0, ...known);\n const range = maxVal - minVal || 1;\n\n if (orientation === 'horizontal') {\n const LABEL_W = 120;\n const PAD_R = 48;\n const rowH = Math.min(BAR_MAX, Math.max(14, Math.floor((height - GAP) / data.length) - GAP));\n const svgH = data.length * (rowH + GAP) + GAP;\n const svgW = measuredW;\n const plotW = Math.max(40, svgW - LABEL_W - PAD_R);\n\n return (\n <div ref={wrapRef} className={styles.wrap}>\n <svg\n className={styles.svg}\n width={svgW}\n height={svgH}\n viewBox={`0 0 ${svgW} ${svgH}`}\n role=\"img\"\n aria-label={ariaLabel}\n >\n <line x1={LABEL_W} y1={0} x2={LABEL_W} y2={svgH} className={styles.baseline} stroke={CHART_AXIS} />\n {data.map((d, i) => {\n const y = GAP + i * (rowH + GAP);\n const barW = d.value !== null ? ((d.value - minVal) / range) * plotW : 0;\n return (\n <g key={d.label + i}>\n <text\n x={LABEL_W - 8}\n y={y + rowH / 2}\n dy=\"0.32em\"\n textAnchor=\"end\"\n className={styles.categoryLabel}\n >\n {d.label.length > 22 ? `${d.label.slice(0, 21)}…` : d.label}\n </text>\n {d.value === null ? (\n <line\n x1={LABEL_W + 4}\n y1={y + rowH / 2}\n x2={LABEL_W + 14}\n y2={y + rowH / 2}\n stroke={CHART_GRID}\n strokeWidth={2}\n strokeDasharray=\"2 2\"\n />\n ) : (\n <>\n <rect\n x={LABEL_W}\n y={y}\n width={Math.max(2, barW)}\n height={rowH}\n rx={4}\n fill={color}\n className={styles.bar}\n />\n <text\n x={LABEL_W + Math.max(2, barW) + 6}\n y={y + rowH / 2}\n dy=\"0.32em\"\n className={styles.valueLabel}\n >\n {formatValue(d.value)}\n </text>\n </>\n )}\n <rect\n className={styles.hitArea}\n x={0}\n y={y - GAP / 2}\n width={svgW}\n height={rowH + GAP}\n tabIndex={0}\n role=\"img\"\n aria-label={`${d.label}: ${d.value === null ? 'no data' : formatValue(d.value)}`}\n onPointerEnter={() => setHover(i)}\n onPointerLeave={() => setHover((h) => (h === i ? null : h))}\n onFocus={() => setHover(i)}\n onBlur={() => setHover((h) => (h === i ? null : h))}\n />\n </g>\n );\n })}\n </svg>\n {hover !== null ? (\n <div\n className={styles.tooltip}\n style={{ left: LABEL_W + 8, top: GAP + hover * (rowH + GAP) - 4 }}\n >\n <span className={styles.tooltipValue}>\n {data[hover].value === null ? 'no data' : formatValue(data[hover].value as number)}\n </span>\n <span className={styles.tooltipLabel}>{data[hover].label}</span>\n </div>\n ) : null}\n </div>\n );\n }\n\n // Vertical orientation.\n const barSlot = data.length ? Math.max(BAR_MAX, 0) : BAR_MAX;\n const barW = Math.min(BAR_MAX, barSlot);\n const PAD_T = 20;\n const PAD_B = 30;\n const plotH = height;\n const svgH = plotH + PAD_T + PAD_B;\n const svgW = data.length * (barW + GAP) + GAP;\n const zeroY = PAD_T + plotH - ((0 - minVal) / range) * plotH;\n\n return (\n <div className={styles.wrap}>\n <svg\n className={styles.svg}\n width={svgW}\n height={svgH}\n viewBox={`0 0 ${svgW} ${svgH}`}\n role=\"img\"\n aria-label={ariaLabel}\n >\n <line x1={0} y1={zeroY} x2={svgW} y2={zeroY} className={styles.baseline} stroke={CHART_AXIS} />\n {data.map((d, i) => {\n const x = GAP + i * (barW + GAP);\n const barH = d.value !== null ? (Math.abs(d.value - minVal) / range) * plotH : 0;\n const top = d.value !== null && d.value >= 0 ? zeroY - barH : zeroY;\n return (\n <g key={d.label + i}>\n {d.value === null ? (\n <line\n x1={x + barW / 2 - 5}\n y1={zeroY}\n x2={x + barW / 2 + 5}\n y2={zeroY}\n stroke={CHART_GRID}\n strokeWidth={2}\n strokeDasharray=\"2 2\"\n />\n ) : (\n <>\n <rect\n x={x}\n y={top}\n width={barW}\n height={Math.max(2, barH)}\n rx={4}\n fill={color}\n className={styles.bar}\n />\n <text x={x + barW / 2} y={top - 4} textAnchor=\"middle\" className={styles.valueLabel}>\n {formatValue(d.value)}\n </text>\n </>\n )}\n <text\n x={x + barW / 2}\n y={svgH - 8}\n textAnchor=\"middle\"\n className={styles.axisLabel}\n >\n {d.label.length > 10 ? `${d.label.slice(0, 9)}…` : d.label}\n </text>\n <rect\n className={styles.hitArea}\n x={x - GAP / 2}\n y={0}\n width={barW + GAP}\n height={svgH}\n tabIndex={0}\n role=\"img\"\n aria-label={`${d.label}: ${d.value === null ? 'no data' : formatValue(d.value)}`}\n onPointerEnter={() => setHover(i)}\n onPointerLeave={() => setHover((h) => (h === i ? null : h))}\n onFocus={() => setHover(i)}\n onBlur={() => setHover((h) => (h === i ? null : h))}\n />\n </g>\n );\n })}\n </svg>\n {hover !== null ? (\n <div\n className={styles.tooltip}\n style={{ left: GAP + hover * (barW + GAP), top: 0 }}\n id={`${uid}-tooltip`}\n >\n <span className={styles.tooltipValue}>\n {data[hover].value === null ? 'no data' : formatValue(data[hover].value as number)}\n </span>\n <span className={styles.tooltipLabel}>{data[hover].label}</span>\n </div>\n ) : null}\n </div>\n );\n}\n","/**\n * components/charts/BurnDown.tsx — a quota window burning down to its reset:\n * remaining capacity over time (solid line + wash), the even-pace reference\n * from full at window start to empty at reset (thin dashed), a projection\n * from the recent slope (dashed), an optional reserve line (the headroom kept\n * for interactive use) and the reset marker.\n *\n * The verdict is written in words under the plot — \"At this pace: reserve\n * reached 14:20, 3h 40m before reset\" — so the chart's point never depends on\n * reading slopes. With fewer than two readings it says it cannot project,\n * rather than drawing a guess — and with no plausible reset (0 / NaN /\n * pre-2000) it draws neither pace nor projection and says the reset is\n * unknown, rather than projecting to an invented one.\n *\n * Polish (verse-visual-quality): the reserve is a BAND from empty up to the\n * reserve line (the region autonomy stays out of), the remaining line is a\n * monotone curve over a gradient wash, \"now\" is a labelled dashed rule, and\n * the plot is hoverable and a keyboard stop — the crosshair snaps to each\n * reading and the tooltip gives its local time, the exact remaining and,\n * with a known reset, where even pace would have it.\n */\nimport { useId, useRef, useState, type KeyboardEvent, type PointerEvent } from 'react';\nimport { CHART_SEQUENTIAL, gradientId, toneColor } from './colors.js';\nimport { ChartFrame, type ChartStatus } from './ChartFrame.js';\nimport { AreaGradient, ChartLegend, ChartTooltip, clampTooltipLeft, tooltipSide } from './ChartParts.js';\nimport { TableView, type TableColumn } from './TableView.js';\nimport {\n MIN_TIME_SPAN_MS,\n axisTicks,\n crisp,\n ensureSpan,\n isPlausibleTime,\n labelCharPx,\n layoutAxisLabels,\n linePath,\n linearScale,\n projectBurnDown,\n smoothAreaPath,\n smoothPath,\n splitRuns,\n tickGutter,\n type BurnPoint,\n} from './chart-math.js';\nimport { formatCompact, formatTooltipInstant, timeLabelLadder } from './format.js';\nimport { useChartMotion } from './motion.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport { useTextScale } from './useTextScale.js';\nimport plot from './plot.module.css';\n\nexport interface BurnDownProps {\n title: string;\n description?: string;\n caveat?: string;\n status?: ChartStatus;\n points: BurnPoint[];\n /** Full capacity of the window (e.g. 100 for percent). */\n capacity: number;\n /** Window start and reset, epoch ms. */\n start: number;\n resetAt: number;\n now: number;\n /** Capacity to keep in reserve (same units as `remaining`). */\n reserve?: { value: number; label: string };\n height?: number;\n width?: number;\n formatValue?: (v: number) => string;\n formatTime?: (ms: number) => string;\n ariaLabel?: string;\n}\n\nconst PAD_T = 16;\nconst PAD_B = 26;\nconst PAD_R = 14;\n\nfunction defaultFormatTime(ms: number): string {\n const d = new Date(ms);\n return Number.isNaN(d.getTime()) ? '' : d.toLocaleString('en-US', { weekday: 'short', hour: 'numeric', minute: '2-digit' });\n}\n\nexport function formatLead(ms: number): string {\n const m = Math.max(0, Math.round(ms / 60_000));\n if (m < 60) return `${m}m`;\n const h = Math.floor(m / 60);\n if (h < 48) return m % 60 ? `${h}h ${m % 60}m` : `${h}h`;\n return `${Math.round(h / 24)}d`;\n}\n\n/**\n * The verdict in words. `resetAt` null (or non-finite) is an UNKNOWN reset:\n * what the window has already crossed is still said, but nothing is\n * projected — \"about 40% left at reset\" needs a reset (V3.10.1 review: an\n * epoch-0 reset printed a green verdict for a seat burning 10%/h, and a NaN\n * one printed \"about NaN% left at reset\").\n */\nexport function burnVerdict(\n projection: ReturnType<typeof projectBurnDown>,\n resetAt: number | null,\n formatValue: (v: number) => string,\n formatTime: (ms: number) => string,\n reserveLabel?: string,\n): { text: string; severity: 'ok' | 'warn' | 'danger' | 'unknown' } {\n const reset = resetAt !== null && Number.isFinite(resetAt) ? resetAt : null;\n // Already past a line: say where it IS, not a \"projection\" to a moment\n // that has passed (a used-up seat is not \"running out at 3:02\").\n if (projection.from && projection.from.remaining <= 0) {\n return { text: reset === null ? 'Used up — reset time unknown.' : `Used up — resets ${formatTime(reset)}.`, severity: 'danger' };\n }\n if (projection.from && reserveLabel !== undefined && projection.reserveAt !== null && projection.reserveAt <= projection.from.t) {\n const until = reset === null ? 'until it resets (reset time unknown)' : `until ${formatTime(reset)}`;\n return { text: `Inside ${reserveLabel.toLowerCase()} — autonomy has stopped using this window ${until}.`, severity: 'warn' };\n }\n if (reset === null) return { text: 'Reset time unknown — not projecting this window.', severity: 'unknown' };\n if (projection.slopePerMs === null) return { text: 'Not enough readings to project this window yet.', severity: 'unknown' };\n if (projection.exhaustAt !== null) {\n return {\n text: `At this pace: runs out ${formatTime(projection.exhaustAt)}, ${formatLead(reset - projection.exhaustAt)} before reset.`,\n severity: 'danger',\n };\n }\n if (projection.reserveAt !== null) {\n return {\n text: `At this pace: ${reserveLabel ?? 'reserve'} reached ${formatTime(projection.reserveAt)}, ${formatLead(reset - projection.reserveAt)} before reset.`,\n severity: 'warn',\n };\n }\n return {\n text: `At this pace: about ${formatValue(projection.remainingAtReset ?? 0)} left at reset.`,\n severity: 'ok',\n };\n}\n\nexport function BurnDown({\n title,\n description,\n caveat,\n status,\n points,\n capacity,\n start,\n resetAt,\n now,\n reserve,\n height = 200,\n width: fixedWidth,\n formatValue: formatValueProp,\n formatTime: formatTimeProp,\n ariaLabel,\n}: BurnDownProps) {\n const formatValue = formatValueProp ?? formatCompact;\n const formatTime = formatTimeProp ?? defaultFormatTime;\n const wrapRef = useRef<HTMLDivElement>(null);\n const width = useChartWidth(wrapRef, fixedWidth);\n const textScale = useTextScale();\n const motion = useChartMotion();\n const gradKey = useId();\n const liveId = useId();\n const [active, setActive] = useState<number | null>(null);\n // A reading stamped 0 / NaN / pre-2000 is a null timestamp that leaked\n // through: it is not on this window's time axis, and it would drag both\n // the axis and the projection's slope back to 1970.\n const sorted = points.filter((p) => isPlausibleTime(p.t)).sort((a, b) => a.t - b.t);\n const anyKnown = sorted.some((p) => p.remaining !== null);\n const resolvedStatus: ChartStatus = status ?? (sorted.length === 0 ? { kind: 'empty', message: 'No readings in this window yet.' } : anyKnown ? { kind: 'ready' } : { kind: 'unknown' });\n\n // A reset of 0 / NaN / pre-2000 is a null that leaked through (an epoch-0\n // machine reset parses as a finite 0). It is UNKNOWN, not a moment: the\n // axis ends at the latest reading or now with no \"Resets\" on it, no even\n // pace or projection is drawn toward it, and the verdict says the reset is\n // unknown instead of inventing one (V3.10.1 review).\n const resetKnown = isPlausibleTime(resetAt);\n const reset = resetKnown ? resetAt : null;\n const projection = projectBurnDown(sorted, reset, { reserve: reserve?.value ?? null });\n const verdict = burnVerdict(projection, reset, formatValue, formatTime, reserve?.label);\n\n // Always 0 → capacity (100 for percent seats), so sibling cards share one\n // scale; widened only if a reading overshoots, never clipped.\n const known = sorted.flatMap((p) => (p.remaining !== null && Number.isFinite(p.remaining) ? [p.remaining] : []));\n const yAxis = axisTicks(0, Math.max(capacity, ...known, 1), {\n count: 4,\n integer: Number.isInteger(capacity) && known.every((v) => Number.isInteger(v)),\n format: formatValueProp,\n });\n const ticks = yAxis.ticks;\n const top = ticks[ticks.length - 1]!;\n const padL = tickGutter(yAxis.labels, 28, 56, textScale);\n const plotW = Math.max(40, width - padL - PAD_R);\n const plotH = height - PAD_T - PAD_B;\n // The window runs start → reset. An implausible bound (0 / NaN) falls back\n // to the readings; a degenerate one widens to MIN_TIME_SPAN_MS, keeping the\n // right edge where it is.\n const lastT = sorted.length ? sorted[sorted.length - 1]!.t : now;\n const rawEnd = reset ?? Math.max(now, lastT);\n const rawStart = isPlausibleTime(start) ? start : sorted[0]?.t ?? rawEnd;\n const [x0, xEnd] = ensureSpan(rawStart, rawEnd, MIN_TIME_SPAN_MS, 'end');\n const xs = linearScale(x0, xEnd, padL, padL + plotW);\n const ys = linearScale(0, top, PAD_T + plotH, PAD_T);\n const clampX = (t: number) => Math.min(xEnd, Math.max(x0, t));\n\n // x labels: the reset marker outranks the window start. Both walk the same\n // detail ladder (the caller's format → \"Fri 11:46 PM\" → \"Sep 18\"; clock\n // time only inside one day) until they fit side by side; if even the\n // shortest pair collides, the start is dropped rather than overprinted.\n // Widths are budgeted at the operator's Display size. With no known reset\n // the right edge is only the latest reading / now, and says just its time.\n const ladder = timeLabelLadder(x0, xEnd, formatTimeProp ?? defaultFormatTime, [x0, xEnd]);\n const xLabels = layoutAxisLabels(\n [\n { key: 'start', x: padL, anchor: 'start', priority: 2, variants: ladder.map((f) => f(x0)) },\n resetKnown\n ? { key: 'reset', x: padL + plotW, anchor: 'end', priority: 3, variants: ladder.map((f) => `Resets ${f(xEnd)}`) }\n : { key: 'end', x: padL + plotW, anchor: 'end', priority: 3, variants: ladder.map((f) => f(xEnd)) },\n ],\n { min: padL, max: padL + plotW, charPx: labelCharPx(textScale) },\n );\n\n const runs = splitRuns(sorted.map((p) => ({ x: clampX(p.t), y: p.remaining })))\n .map((run) => run.map((p) => ({ x: xs(p.x), y: ys(Math.max(0, p.y)) })));\n\n // Where even pace would have the window at `t`: full at the start, empty\n // at the reset — the same straight reference the dashed line draws.\n const paceAt = (t: number): number | null =>\n resetKnown && xEnd > x0 ? Math.max(0, Math.min(capacity, capacity * (1 - (t - x0) / (xEnd - x0)))) : null;\n\n function indexAt(clientX: number): number | null {\n const el = wrapRef.current;\n if (!el || sorted.length === 0) return null;\n const px = clientX - el.getBoundingClientRect().left;\n let best = 0;\n let bestD = Infinity;\n sorted.forEach((p, i) => {\n const d = Math.abs(xs(clampX(p.t)) - px);\n if (d < bestD) {\n bestD = d;\n best = i;\n }\n });\n return best;\n }\n\n function onKey(e: KeyboardEvent<HTMLDivElement>): void {\n if (sorted.length === 0) return;\n const cur = active ?? sorted.length - 1;\n const next = e.key === 'ArrowLeft' ? cur - 1 : e.key === 'ArrowRight' ? cur + 1 : e.key === 'Home' ? 0 : e.key === 'End' ? sorted.length - 1 : null;\n if (next === null) return;\n e.preventDefault();\n setActive(Math.max(0, Math.min(sorted.length - 1, next)));\n }\n\n const activePoint = active !== null ? sorted[active] : undefined;\n const activePace = activePoint ? paceAt(activePoint.t) : null;\n const nowX = now > x0 && now < xEnd ? xs(now) : null;\n // \"Now\" is labelled only where it cannot collide with the plot's edges.\n const nowLabel = nowX !== null && nowX - padL > 24 && padL + plotW - nowX > 24;\n\n let projectionPath = '';\n if (reset !== null && projection.from && projection.slopePerMs !== null) {\n const endT = projection.exhaustAt ?? reset;\n const endR = projection.exhaustAt !== null ? 0 : projection.remainingAtReset ?? projection.from.remaining;\n if (endT > projection.from.t) {\n projectionPath = linePath([\n { x: xs(clampX(projection.from.t)), y: ys(projection.from.remaining) },\n { x: xs(clampX(endT)), y: ys(Math.max(0, endR)) },\n ]);\n }\n }\n const projectionColor = verdict.severity === 'danger' ? toneColor('danger') : verdict.severity === 'warn' ? toneColor('warning') : 'var(--text-tertiary)';\n\n const summary = ariaLabel ?? `${title}: ${projection.from ? `${formatValue(projection.from.remaining)} of ${formatValue(capacity)} left at ${formatTime(projection.from.t)}` : 'no readings'}; ${reset === null ? 'reset time unknown' : `resets ${formatTime(reset)}`}. ${verdict.text}`;\n\n const columns: TableColumn<BurnPoint>[] = [\n { key: 't', label: 'When', render: (p) => formatTime(p.t) },\n { key: 'r', label: 'Remaining', numeric: true, render: (p) => (p.remaining === null ? '—' : formatValue(p.remaining)) },\n ];\n\n const legendItems = [\n { label: 'Remaining', color: CHART_SEQUENTIAL, kind: 'line' as const },\n // Even pace runs from full at the window's start to empty AT RESET: with\n // no reset there is no pace to draw.\n ...(resetKnown ? [{ label: 'Even pace', color: 'var(--text-tertiary)', kind: 'line' as const }] : []),\n ...(projectionPath ? [{ label: 'Projection', color: projectionColor, kind: 'line' as const }] : []),\n ];\n\n return (\n <ChartFrame\n title={title}\n description={description}\n caveat={caveat}\n status={resolvedStatus}\n skeleton=\"line\"\n skeletonHeight={height}\n table={<TableView caption={title} columns={columns} rows={sorted} rowKey={(p) => String(p.t)} />}\n footer={\n <>\n <p className={plot.note} data-severity={verdict.severity} role=\"status\">{verdict.text}</p>\n <ChartLegend items={legendItems} />\n </>\n }\n >\n <div\n ref={wrapRef}\n className={`${plot.plotWrap} ${plot.focusable}`}\n data-motion={motion}\n tabIndex={0}\n role=\"group\"\n aria-label={`${title}. Use the left and right arrow keys to read each reading.`}\n aria-describedby={liveId}\n onFocus={() => setActive((a) => a ?? (sorted.length ? sorted.length - 1 : null))}\n onBlur={() => setActive(null)}\n onKeyDown={onKey}\n >\n <svg\n className={plot.svg}\n width={width}\n height={height}\n viewBox={`0 0 ${width} ${height}`}\n role=\"img\"\n aria-label={summary}\n onPointerMove={(e: PointerEvent<SVGSVGElement>) => setActive(indexAt(e.clientX))}\n onPointerLeave={() => setActive(null)}\n >\n <defs>\n <AreaGradient id={gradientId(gradKey, 'remaining')} color={CHART_SEQUENTIAL} top={PAD_T} bottom={PAD_T + plotH} />\n </defs>\n {reserve && reserve.value > 0 ? (\n <rect\n data-role=\"reserve-band\"\n className={`${plot.reserveBand} ${plot.fadeIn}`}\n x={padL}\n y={ys(Math.min(top, reserve.value))}\n width={plotW}\n height={Math.max(0, ys(0) - ys(Math.min(top, reserve.value)))}\n />\n ) : null}\n {ticks.map((t, i) => (\n <g key={t}>\n <line className={plot.grid} x1={padL} x2={padL + plotW} y1={crisp(ys(t))} y2={crisp(ys(t))} />\n <text className={plot.tick} x={padL - 6} y={ys(t)} dy=\"0.32em\" textAnchor=\"end\">{yAxis.labels[i]}</text>\n </g>\n ))}\n <line className={plot.axis} x1={padL} x2={padL + plotW} y1={crisp(ys(0))} y2={crisp(ys(0))} />\n {xLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} className={plot.tick} x={l.x} y={height - 8} textAnchor={l.anchor}>{l.text}</text>\n ))}\n\n {resetKnown ? (\n <path data-role=\"pace\" className={plot.reference} d={linePath([{ x: xs(x0), y: ys(capacity) }, { x: xs(xEnd), y: ys(0) }])} />\n ) : null}\n {reserve ? (\n <g data-role=\"reserve\">\n <line className={plot.reference} x1={padL} x2={padL + plotW} y1={crisp(ys(reserve.value))} y2={crisp(ys(reserve.value))} />\n {/* Above-left of the line, over a surface halo (SPEC-310C §6): the\n window's start is the one place the remaining line is always\n high, and the projection only ever runs to the right, so the\n label never sits on the data. */}\n <text data-role=\"reserve-label\" className={`${plot.tick} ${plot.halo}`} x={padL + 4} y={ys(reserve.value) - 5} textAnchor=\"start\">\n {reserve.label} · {formatValue(reserve.value)}\n </text>\n </g>\n ) : null}\n {nowX !== null ? (\n <g data-role=\"now\">\n <line className={plot.now} x1={crisp(nowX)} x2={crisp(nowX)} y1={PAD_T} y2={PAD_T + plotH} />\n {nowLabel ? (\n <text data-role=\"now-label\" className={`${plot.tick} ${plot.halo}`} x={nowX} y={PAD_T - 4} textAnchor=\"middle\">Now</text>\n ) : null}\n </g>\n ) : null}\n {runs.map((run, i) => (\n <g key={i} data-role=\"remaining\">\n <path\n data-role=\"area\"\n className={`${plot.area} ${plot.fadeIn}`}\n fill={`url(#${gradientId(gradKey, 'remaining')})`}\n d={smoothAreaPath(run, run.map((p) => ({ x: p.x, y: ys(0) })))}\n />\n {run.length > 1 ? (\n <path data-role=\"line\" className={`${plot.line} ${plot.draw}`} pathLength={1} stroke={CHART_SEQUENTIAL} d={smoothPath(run)} />\n ) : null}\n </g>\n ))}\n {projectionPath ? (\n <path data-role=\"projection\" className={plot.projection} stroke={projectionColor} d={projectionPath} />\n ) : null}\n {projection.from ? (\n <circle className={plot.marker} cx={xs(clampX(projection.from.t))} cy={ys(projection.from.remaining)} r={4} fill={CHART_SEQUENTIAL} />\n ) : null}\n {activePoint ? (\n <g data-role=\"hover\">\n <line className={plot.crosshair} data-role=\"crosshair\" x1={crisp(xs(clampX(activePoint.t)))} x2={crisp(xs(clampX(activePoint.t)))} y1={PAD_T} y2={PAD_T + plotH} />\n {activePoint.remaining !== null ? (\n <circle className={plot.marker} cx={xs(clampX(activePoint.t))} cy={ys(Math.max(0, activePoint.remaining))} r={4} fill={CHART_SEQUENTIAL} />\n ) : null}\n </g>\n ) : null}\n </svg>\n <span id={liveId} className={plot.srOnly} aria-live=\"polite\">\n {activePoint\n ? `${formatTooltipInstant(activePoint.t)}: ${activePoint.remaining === null ? 'no reading' : `${formatValue(activePoint.remaining)} remaining`}` +\n (activePace !== null ? `; even pace ${formatValue(activePace)}` : '')\n : ''}\n </span>\n {activePoint ? (\n <ChartTooltip\n left={tooltipSide(xs(clampX(activePoint.t)), width) ? xs(clampX(activePoint.t)) : clampTooltipLeft(xs(clampX(activePoint.t)), width)}\n side={tooltipSide(xs(clampX(activePoint.t)), width)}\n top={PAD_T}\n title={formatTooltipInstant(activePoint.t)}\n rows={[\n { key: 'r', label: 'Remaining', value: activePoint.remaining === null ? null : formatValue(activePoint.remaining), color: CHART_SEQUENTIAL, kind: 'line' },\n ...(activePace !== null ? [{ key: 'p', label: 'Even pace', value: formatValue(activePace), color: 'var(--text-tertiary)', kind: 'line' as const }] : []),\n ]}\n />\n ) : null}\n </div>\n </ChartFrame>\n );\n}\n"],"mappings":"w6BC8BA,SAAgB,EAAe,CAC7B,QACA,cACA,SACA,WACA,QACA,QACA,eAAe,4BACO,CACtB,OACE,EAAA,EAAA,KAAA,CAAC,SAAD,CAAQ,UAAW,EAAO,OAA1B,SAAA,EACE,EAAA,EAAA,KAAA,CAAC,aAAD,CAAY,UAAW,EAAO,QAA9B,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,MAAQ,SAAA,CAAY,CAAA,EAC3C,GAAc,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,YAAc,SAAA,CAAkB,CAAA,EAAI,IACjE,IACX,GACC,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,OAAQ,KAAK,OAC/B,SAAA,CACA,CAAA,EACD,KACH,GACC,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAO,MAAQ,SAAA,CAAgB,CAAA,GAE7C,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,KAAO,UAAc,CAAA,EAE7C,GACC,EAAA,EAAA,KAAA,CAAC,UAAD,CAAS,UAAW,EAAO,gBAA3B,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,UAAD,CAAA,SAAS,eAAsB,CAAA,GAC/B,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,UAAW,EAAO,UAAY,SAAA,CAAW,CAAA,CACvC,CACP,CAAA,EAAA,IACE,GAEZ,oHEhDA,SAAgB,GAAO,CAAE,SAAkC,CAEzD,OADI,EAAM,OAAS,EAAU,MAE3B,EAAA,EAAA,IAAA,CAAC,KAAD,CAAI,UAAW,EAAO,OACnB,SAAA,EAAM,IAAK,IACV,EAAA,EAAA,KAAA,CAAC,KAAD,CAAmB,UAAW,EAAO,KAArC,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,UAAW,EAAG,OAAS,OAAS,EAAO,WAAa,EAAO,OAC3D,MAAO,CAAE,WAAY,EAAG,KAAM,EAC9B,cAAY,MACb,CAAA,EACA,EAAG,KACF,CAPK,EAAA,EAAG,KAOR,CACL,CACC,CAAA,CAER,yTE0BM,GAAa,IAEb,GAAQ,GACR,GAAQ,GACR,EAAQ,GACR,EAAQ,GACR,EAAU,EAcV,EAAe,IACf,GAAgB,EAMhB,GAAgB,IAEhB,EAAkB,GAOxB,SAAS,EAAU,EAAmC,CACpD,IAAM,EAAgB,CAAC,EACnB,EAAiB,CAAC,EACtB,IAAK,IAAM,KAAK,EAAQ,CACtB,GAAI,EAAE,IAAM,KAAM,CACZ,EAAQ,QAAQ,EAAK,KAAK,CAAO,EACrC,EAAU,CAAC,EACX,QACF,CACA,EAAQ,KAAK,CAAE,EAAG,EAAE,EAAG,EAAG,EAAE,CAAE,CAAC,CACjC,CAEA,OADI,EAAQ,QAAQ,EAAK,KAAK,CAAO,EAC9B,CACT,CAEA,SAAgB,EAAU,CACxB,OAAQ,EACR,SAAS,IACT,OAAO,GACP,QAAS,EACT,QAAS,GACT,cAAe,EACf,eAAgB,EAChB,YACA,MAAO,IAgBN,CACD,IAAM,IAAA,EAAS,EAAA,OAAA,CAAsB,IAAI,EACnC,IAAA,EAAU,EAAA,OAAA,CAAuB,IAAI,EACrC,EAAQ,GAAc,GAAS,GAAY,EAAU,EACrD,EAAY,GAAa,EACzB,GAAS,GAAe,EACxB,IAAA,EAAU,EAAA,MAAA,CAAM,EAChB,IAAA,EAAS,EAAA,MAAA,CAAM,EAEf,EAAc,GAAY,CAAS,EACnC,CAAC,EAAQ,IAAA,EAAa,EAAA,SAAA,CAAwB,IAAI,EAElD,EAAY,GAAqB,IAAe,GAIhD,EAAQ,EAAQ,EAAW,QAAS,GAAM,EAAE,OAAO,IAAK,GAAM,EAAE,CAAC,CAAC,CAAC,EACnE,EAAS,EAAW,IAAK,IAAO,CAAE,GAAG,EAAG,OAAQ,EAAE,OAAO,OAAQ,GAAM,EAAM,EAAE,CAAC,CAAC,CAAE,EAAE,EACrF,EAAO,EAAO,QAAS,GAAM,EAAE,OAAO,IAAK,GAAM,EAAE,CAAC,CAAC,EACrD,EAAS,EAAO,QAAS,GAAM,EAAE,OAAO,IAAK,GAAM,EAAE,CAAC,CAAC,CAAC,CAAC,OAAQ,GAAmB,IAAM,MAAQ,OAAO,SAAS,CAAC,CAAC,EAC1H,GAAI,EAAK,SAAW,EAClB,OACE,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,IAAK,GAAS,UAAW,EAAO,KACnC,UAAA,EAAA,EAAA,IAAA,CAAC,IAAD,CAAA,SAAG,UAAW,CAAA,CACX,CAAA,EAGT,IAAM,EAAU,KAAK,IAAI,GAAG,CAAI,EAC1B,GAAU,KAAK,IAAI,GAAG,CAAI,EAC1B,GAAW,GAAW,CAAI,EAE1B,GAAU,IAAgB,GAAW,GAAmB,GAAc,OAAO,CAAC,GAC9E,EAAa,GAAsB,IAAgB,GAAW,GAAqB,CAAI,EAAI,IAG3F,CAAC,GAAM,GAAQ,IAAY,GAAU,EAAU,EAAW,EAAS,GAAS,EAAgB,EAAI,CAAC,EAAS,EAAO,EACjH,EAAS,EAAO,IAAQ,EAIxB,EAAQ,EAAU,KAAK,IAAI,EAAG,GAAG,CAAM,EAAG,KAAK,IAAI,EAAG,GAAG,CAAM,EAAG,CACtE,MAAO,EACP,QAAS,EAAO,OAAS,GAAK,GAAY,CAAM,EAChD,OAAQ,EACV,CAAC,EACK,GAAS,EAAM,MACf,GAAO,GAAO,GAEd,GADO,GAAO,GAAO,OAAS,GACd,IAAQ,EACxB,EAAQ,EAAS,EAAQ,EACzB,EAAU,GAAc,EAAQ,GAAU,EAAI,IAAQ,GAAU,EAIhE,EAAO,KAAK,IAAI,GAAO,KAAK,KAAK,KAAK,IAAI,EAAG,GAAG,EAAM,OAAO,IAAK,GAAM,EAAE,MAAM,CAAC,EAAI,CAAW,EAAI,CAAC,EAOrG,EAAgB,EAAO,QAAU,GAAK,EAAO,QAAU,EACvD,EAAY,EACd,KAAK,IAAI,GAAG,EAAO,IAAK,GAAM,EAAE,MAAM,MAAM,CAAC,EAAI,EAAe,EAChE,EACE,GAAY,EAAO,QAAS,GAAM,CACtC,IAAK,IAAI,EAAI,EAAE,OAAO,OAAS,EAAG,GAAK,EAAG,IAAK,CAC7C,IAAM,EAAI,EAAE,OAAO,EAAE,CAAE,EACvB,GAAI,IAAM,MAAQ,OAAO,SAAS,CAAC,EAAG,MAAO,CAAC,CAAE,IAAK,EAAE,GAAI,EAAG,EAAO,CAAC,CAAE,CAAC,CAC3E,CACA,MAAO,CAAC,CACV,CAAC,EACK,GAAS,GAAiB,GAAa,GAAgB,EAAY,GAAW,EAAkB,EAAW,EAAO,EAAQ,CAAK,EAAI,KACnI,GAAgB,KAAW,MAAQ,GAAU,OAAS,EACtD,EAAO,IAAS,GAAgB,GAAgB,EAAY,GAC5D,GAAa,EAAO,QAAU,EAE9B,GAAQ,KAAK,IAAI,GAAI,EAAQ,EAAO,CAAI,EACxC,EAAU,GAAc,GAAS,EAAI,IAAQ,EAAU,GAIvD,EAAQ,MAAM,KAAK,IAAI,IAAI,CAAI,CAAC,CAAC,CAAC,MAAM,EAAG,IAAM,EAAI,CAAC,EAQtD,EAAU,EAAM,OAAS,EAAI,GAAY,EAAM,OAAQ,KAAK,IAAI,EAAG,KAAK,MAAM,GAAQ,EAAE,CAAC,CAAC,EAAI,CAAC,EAC/F,GAAS,GAAW,GAAgB,EAAS,GAAS,EAAa,EAAQ,IAAK,GAAM,EAAM,EAAG,CAAC,EAAI,CAAC,EAAO,EAC5G,GAAU,GACd,EAAQ,KAAK,EAAK,IAAM,CACtB,IAAM,EAAI,EAAM,GACV,EAAK,EAAO,CAAC,EACb,EAAU,IAAM,EAChB,EAAS,IAAM,EAAQ,OAAS,EAChC,EAAS,GAAW,GAAM,EAAO,GAAM,QAAmB,GAAU,GAAM,EAAQ,EAAO,GAAM,MAAiB,SACtH,MAAO,CACL,IAAK,EAAU,QAAU,EAAS,MAAQ,IAAI,IAC9C,EAAG,EACH,SACA,SAAU,EAAS,EAAI,EAAU,EAAI,EACrC,SAAU,GAAW,EACrB,SAAU,GAAO,IAAK,GAAM,EAAE,CAAC,CAAC,CAClC,CACF,CAAC,EACD,CAAE,IAAK,EAAM,IAAK,EAAQ,EAAM,OAAQ,CAAY,CACtD,EAEA,SAAS,GAAS,EAAgC,CAChD,IAAM,EAAM,GAAO,QACnB,GAAI,CAAC,EAAK,OAAO,KACjB,IAAM,EAAO,EAAI,sBAAsB,EAGjC,GAAS,EAAU,EAAK,OAAS,EAAK,OAAS,GAAU,EACzD,EAAQ,IAAS,EAAO,GAAQ,GAAS,EAC3C,EAAU,EAAM,GAChB,EAAO,IACX,IAAK,IAAM,KAAK,EAAO,CACrB,IAAM,EAAI,KAAK,IAAI,EAAI,CAAK,EACxB,EAAI,IACN,EAAO,EACP,EAAU,EAEd,CACA,OAAO,CACT,CAEA,SAAS,GAAW,EAAgC,CAClD,IAAM,EAAI,GAAS,EAAE,OAAO,EACxB,IAAM,MACV,EAAU,CAAC,CACb,CAEA,SAAS,GAAM,EAAwC,CACrD,GAAI,EAAM,SAAW,EAAG,OACxB,IAAM,EAAM,IAAW,KAAO,EAAM,OAAS,EAAI,KAAK,IAAI,EAAG,EAAM,QAAQ,CAAM,CAAC,EAC5E,EAAO,EAAE,MAAQ,YAAc,EAAM,EAAI,EAAE,MAAQ,aAAe,EAAM,EAAI,EAAE,MAAQ,OAAS,EAAI,EAAE,MAAQ,MAAQ,EAAM,OAAS,EAAI,KAC1I,IAAS,OACb,EAAE,eAAe,EACjB,EAAU,EAAM,KAAK,IAAI,EAAG,KAAK,IAAI,EAAM,OAAS,EAAG,CAAI,CAAC,EAAG,EACjE,CAEA,IAAM,GAAS,GAAQ,EAAO,QAAU,EAElC,GACJ,IAAW,KAKP,KAJA,EAAO,IAAK,IAAO,CACjB,OAAQ,EACR,MAAO,EAAE,OAAO,KAAM,GAAM,EAAE,IAAM,CAAM,GAAK,IACjD,EAAE,EAGR,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,IAAK,GACL,UAAW,GAAG,EAAO,KAAK,GAAG,EAAK,YAClC,cAAa,GACb,SAAU,EACV,KAAK,QACL,aAAY,GAAG,EAAU,qDACzB,mBAAkB,GAClB,YAAe,EAAW,GAAM,GAAK,EAAM,EAAM,OAAS,IAAM,IAAI,EACpE,WAAc,EAAU,IAAI,EAC5B,UAAW,GAVb,SAAA,EAYE,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,IAAK,GACL,UAAW,EAAO,IACX,QACC,SACR,QAAS,OAAO,EAAM,GAAG,IACzB,KAAK,MACL,aAAY,EACZ,cAAe,GACf,mBAAsB,EAAU,IAAI,EATtC,SAAA,CAWG,IACC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,SACG,EAAO,KAAK,EAAG,KACd,EAAA,EAAA,IAAA,CAAC,EAAD,CAAyB,GAAI,GAAW,GAAS,EAAE,EAAE,EAAG,MAAO,EAAY,CAAE,EAAG,IAAK,EAAO,OAAQ,EAAS,EAAO,KAAM,EAAO,OAAS,EAAI,IAAO,GAAO,EAAzI,EAAE,EAAuI,CAC7J,CACG,CAAA,EACJ,KACH,GAAO,KAAK,EAAG,KACd,EAAA,EAAA,KAAA,CAAC,IAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,GAAI,EACJ,GAAI,EAAQ,EACZ,GAAI,EAAM,EAAO,CAAC,CAAC,EACnB,GAAI,EAAM,EAAO,CAAC,CAAC,EACnB,UAAW,EAAO,SAClB,OAAQ,CACT,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAG,EAAO,EAAG,EAAG,EAAO,CAAC,EAAG,GAAG,SAAS,WAAW,MAAM,UAAW,EAAO,UAC7E,SAAA,EAAM,OAAO,EACV,CAAA,CACL,CAAA,EAZK,CAYL,CACJ,GACD,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,GAAI,EACJ,GAAI,EAAQ,EACZ,GAAI,EAAM,EAAS,CAAK,EACxB,GAAI,EAAM,EAAS,CAAK,EACxB,UAAW,EAAO,KAClB,OAAQ,CACT,CAAA,EACA,GAAQ,IAAK,IACZ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAkB,kBAAiB,EAAE,IAAK,EAAG,EAAE,EAAG,EAAG,EAAS,EAAG,WAAY,EAAE,OAAQ,UAAW,EAAO,UACtG,SAAA,EAAE,IACC,EAFK,EAAE,GAEP,CACP,EAEA,EAAO,KAAK,EAAG,IAAO,CACrB,IAAM,EAAQ,EAAY,CAAE,EACtB,EAAO,EAAU,EAAE,MAAM,EAC/B,OACE,EAAA,EAAA,KAAA,CAAC,IAAD,CAAA,SAAA,CACG,GACG,EAAK,KAAK,EAAK,IAAO,CACpB,IAAM,EAAM,EAAI,IAAK,IAAO,CAAE,EAAG,EAAO,EAAE,CAAC,EAAG,EAAG,EAAO,EAAE,CAAC,CAAE,EAAE,EACzD,EAAO,EAAI,IAAK,IAAO,CAAE,EAAG,EAAE,EAAG,EAAG,EAAO,KAAK,IAAI,GAAM,CAAC,CAAC,CAAE,EAAE,EACtE,OACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAEE,YAAU,OACV,EAAG,EAAe,EAAK,CAAI,EAC3B,KAAM,QAAQ,GAAW,GAAS,EAAE,EAAE,EAAE,GACxC,UAAW,GAAG,EAAO,KAAK,GAAG,EAAK,QACnC,EALM,CAKN,CAEL,CAAC,EACD,KACH,EAAK,KAAK,EAAK,IACd,EAAI,SAAW,GACb,EAAA,EAAA,IAAA,CAAC,SAAD,CAAiB,GAAI,EAAO,EAAI,EAAE,CAAC,CAAC,EAAG,GAAI,EAAO,EAAI,EAAE,CAAC,CAAC,EAAG,EAAG,EAAG,KAAM,CAAQ,EAApE,CAAoE,GAEjF,EAAA,EAAA,IAAA,CAAC,OAAD,CAEE,YAAU,OACV,EAAG,EAAW,EAAI,IAAK,IAAO,CAAE,EAAG,EAAO,EAAE,CAAC,EAAG,EAAG,EAAO,EAAE,CAAC,CAAE,EAAE,CAAC,EAClE,WAAY,EACZ,OAAQ,EACR,UAAW,GAAG,EAAO,KAAK,GAAG,EAAK,MACnC,EANM,CAMN,CAEL,EACC,IAAW,MAAQ,EAAK,QAAU,EAAK,EAAK,OAAS,EAAE,CAAC,OAAS,OAAW,CAE3E,IAAM,EAAU,EAAK,EAAK,OAAS,GAC7B,EAAO,EAAQ,EAAQ,OAAS,GACtC,OAAO,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,YAAU,UAAU,UAAW,GAAG,EAAK,OAAO,GAAG,EAAK,SAAU,GAAI,EAAO,EAAK,CAAC,EAAG,GAAI,EAAO,EAAK,CAAC,EAAG,EAAG,IAAK,KAAM,CAAQ,CAAA,CAC/I,EAAA,CAAG,EAAI,KACN,IAAiB,EAAK,YACd,CACL,IAAM,EAAU,EAAK,EAAK,OAAS,GAC7B,EAAO,EAAQ,EAAQ,OAAS,GACtC,OACE,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,iBAAgB,EAAE,GAClB,EAAG,EAAO,EAAK,CAAC,EAAI,GACpB,EAAG,IAAQ,IAAI,EAAE,EAAE,GAAK,EAAO,EAAK,CAAC,EACrC,GAAG,SACH,UAAW,EAAO,SAClB,KAAM,EAEL,SAAA,EAAE,KACC,CAAA,CAEV,EAAA,CAAG,EACD,IACH,CAAA,EAtDK,EAAE,EAsDP,CAEP,CAAC,EAEA,IAAW,KASR,MARF,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,YAAU,YACV,GAAI,EAAM,EAAO,CAAM,CAAC,EACxB,GAAI,EAAM,EAAO,CAAM,CAAC,EACxB,GAAI,EACJ,GAAI,EAAS,EACb,UAAW,EAAO,aACnB,CAAA,EAEF,IAAW,KAeR,KAdA,EAAO,KAAK,EAAG,IAAO,CACpB,IAAM,EAAI,EAAE,OAAO,KAAM,GAAO,EAAG,IAAM,CAAM,EAE/C,MADI,CAAC,GAAK,EAAE,IAAM,KAAa,MAE7B,EAAA,EAAA,IAAA,CAAC,SAAD,CAEE,GAAI,EAAO,EAAE,CAAC,EACd,GAAI,EAAO,EAAE,CAAC,EACd,EAAG,EACH,KAAM,EAAY,CAAE,EACpB,UAAW,EAAO,MACnB,EANM,EAAE,EAMR,CAEL,CAAC,GAGL,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,EAAG,EACH,EAAG,EACH,MAAO,GACP,OAAQ,EACR,UAAW,EAAO,OACnB,CAAA,CACE,KACL,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,GAAQ,UAAW,EAAK,OAAQ,YAAU,SACjD,SAAA,GACG,GAAG,EAAW,CAAgB,EAAE,IAAI,GAAY,KAAK,CAAE,OAAQ,EAAG,WAAY,GAAG,EAAE,MAAM,GAAG,GAAS,EAAM,IAAM,KAAO,EAAU,EAAM,CAAC,EAAI,WAAW,CAAC,CAAC,KAAK,IAAI,IACnK,EACA,CAAA,EACL,IAAe,IAAW,MACzB,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,KAAM,EAAY,EAAO,CAAM,EAAG,CAAK,EAAI,EAAO,CAAM,EAAI,EAAiB,EAAO,CAAM,EAAG,CAAK,EAClG,KAAM,EAAY,EAAO,CAAM,EAAG,CAAK,EACvC,IAAK,EACL,MAAO,EAAW,CAAM,EACxB,KAAM,GAAY,KAAK,CAAE,OAAQ,EAAG,SAAS,KAAO,CAClD,IAAK,EAAE,GACP,MAAO,EAAE,MACT,MAAO,GAAS,EAAM,IAAM,KAAO,EAAU,EAAM,CAAC,EAAI,KACxD,MAAO,EAAY,CAAC,EACpB,KAAM,MACR,EAAE,CACH,CAAA,EACC,KACH,IACC,EAAA,EAAA,IAAA,CAAC,GAAD,CAAQ,MAAO,EAAO,KAAK,EAAG,KAAO,CAAE,MAAO,EAAE,MAAO,MAAO,EAAY,CAAC,EAAG,KAAM,MAAO,EAAE,CAAI,CAAA,EAC/F,IACD,GAET,+WEvcM,EAAU,GACV,EAAM,GAEZ,SAAgB,EAAS,CACvB,OACA,SAAS,IACT,cAAc,WACd,QAAQ,EACR,cAAe,GAAc,OAAO,CAAC,EACrC,YACA,MAAO,GAUN,CACD,IAAM,GAAA,EAAM,EAAA,MAAA,CAAM,EACZ,IAAA,EAAU,EAAA,OAAA,CAAuB,IAAI,EAIrC,GAAY,GAAc,GAAS,EAAY,GAAG,EAClD,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAwB,IAAI,EAEhD,EAAQ,EAAK,IAAK,GAAM,EAAE,KAAK,CAAC,CAAC,OAAQ,GAAmB,IAAM,IAAI,EACtE,EAAS,KAAK,IAAI,EAAG,GAAG,EAAO,IAAM,EACrC,EAAS,KAAK,IAAI,EAAG,GAAG,CAAK,EAC7B,GAAQ,EAAS,GAAU,EAEjC,GAAI,IAAgB,aAAc,CAChC,IAEM,EAAO,KAAK,IAAI,EAAS,KAAK,IAAI,GAAI,KAAK,OAAO,EAAS,GAAO,EAAK,MAAM,EAAI,CAAG,CAAC,EACrF,EAAO,EAAK,QAAU,EAAO,GAAO,EACpC,EAAO,GACP,EAAQ,KAAK,IAAI,GAAI,EAAO,IAAU,EAAK,EAEjD,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,IAAK,GAAS,UAAW,EAAO,KAArC,SAAA,EACE,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAW,EAAO,IAClB,MAAO,EACP,OAAQ,EACR,QAAS,OAAO,EAAK,GAAG,IACxB,KAAK,MACL,aAAY,EANd,SAAA,EAQE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,IAAS,GAAI,EAAG,GAAI,IAAS,GAAI,EAAM,UAAW,EAAO,SAAU,OAAQ,CAAa,CAAA,EACjG,EAAK,KAAK,EAAG,IAAM,CAClB,IAAM,EAAI,EAAM,GAAK,EAAO,GACtB,EAAO,EAAE,QAAU,KAA8C,GAArC,EAAE,MAAQ,GAAU,GAAS,EAC/D,OACE,EAAA,EAAA,KAAA,CAAC,IAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,EAAG,IACH,EAAG,EAAI,EAAO,EACd,GAAG,SACH,WAAW,MACX,UAAW,EAAO,cAEjB,SAAA,EAAE,MAAM,OAAS,GAAK,GAAG,EAAE,MAAM,MAAM,EAAG,EAAE,EAAE,GAAK,EAAE,KAClD,CAAA,EACL,EAAE,QAAU,MACX,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,GAAI,IACJ,GAAI,EAAI,EAAO,EACf,GAAI,IACJ,GAAI,EAAI,EAAO,EACf,OAAQ,EACR,YAAa,EACb,gBAAgB,KACjB,CAAA,GAED,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,EAAG,IACA,IACH,MAAO,KAAK,IAAI,EAAG,CAAI,EACvB,OAAQ,EACR,GAAI,EACJ,KAAM,EACN,UAAW,EAAO,GACnB,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,EAAG,IAAU,KAAK,IAAI,EAAG,CAAI,EAAI,EACjC,EAAG,EAAI,EAAO,EACd,GAAG,SACH,UAAW,EAAO,WAEjB,SAAA,EAAY,EAAE,KAAK,CAChB,CAAA,CACN,CAAA,CAAA,GAEJ,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,UAAW,EAAO,QAClB,EAAG,EACH,EAAG,EAAI,EAAM,EACb,MAAO,EACP,OAAQ,EAAO,EACf,SAAU,EACV,KAAK,MACL,aAAY,GAAG,EAAE,MAAM,IAAI,EAAE,QAAU,KAAO,UAAY,EAAY,EAAE,KAAK,IAC7E,mBAAsB,EAAS,CAAC,EAChC,mBAAsB,EAAU,GAAO,IAAM,EAAI,KAAO,CAAE,EAC1D,YAAe,EAAS,CAAC,EACzB,WAAc,EAAU,GAAO,IAAM,EAAI,KAAO,CAAE,CACnD,CAAA,CACA,CAAA,EAvDK,EAAE,MAAQ,CAuDf,CAEP,CAAC,CACE,CACJ,CAAA,EAAA,IAAU,KAUP,MATF,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAW,EAAO,QAClB,MAAO,CAAE,KAAM,IAAa,IAAK,EAAM,GAAS,EAAO,GAAO,CAAE,EAFlE,SAAA,EAIE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,aACrB,SAAA,EAAK,EAAM,CAAC,QAAU,KAAO,UAAY,EAAY,EAAK,EAAM,CAAC,KAAe,CAC7E,CAAA,GACN,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,aAAe,SAAA,EAAK,EAAM,CAAC,KAAY,CAAA,CAC5D,CACH,CAAA,CACD,GAET,CAGA,IAAM,GAAU,EAAK,OAAS,KAAK,IAAI,EAAS,CAAC,EAAI,EAC/C,EAAO,KAAK,IAAI,EAAS,EAAO,EAGhC,EAAQ,EACR,EAAO,EAAQ,GAAQ,GACvB,GAAO,EAAK,QAAU,EAAO,GAAO,EACpC,EAAQ,GAAQ,GAAU,EAAI,GAAU,GAAS,EAEvD,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CAAK,UAAW,EAAO,KAAvB,SAAA,EACE,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAW,EAAO,IAClB,MAAO,GACP,OAAQ,EACR,QAAS,OAAO,GAAK,GAAG,IACxB,KAAK,MACL,aAAY,EANd,SAAA,EAQE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,EAAG,GAAI,EAAO,GAAI,GAAM,GAAI,EAAO,UAAW,EAAO,SAAU,OAAQ,CAAa,CAAA,EAC7F,EAAK,KAAK,EAAG,IAAM,CAClB,IAAM,EAAI,EAAM,GAAK,EAAO,GACtB,EAAO,EAAE,QAAU,KAAsD,EAA9C,KAAK,IAAI,EAAE,MAAQ,CAAM,EAAI,GAAS,EACjE,EAAM,EAAE,QAAU,MAAQ,EAAE,OAAS,EAAI,EAAQ,EAAO,EAC9D,OACE,EAAA,EAAA,KAAA,CAAC,IAAD,CAAA,SAAA,CACG,EAAE,QAAU,MACX,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,GAAI,EAAI,EAAO,EAAI,EACnB,GAAI,EACJ,GAAI,EAAI,EAAO,EAAI,EACnB,GAAI,EACJ,OAAQ,EACR,YAAa,EACb,gBAAgB,KACjB,CAAA,GAED,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CACK,IACH,EAAG,EACH,MAAO,EACP,OAAQ,KAAK,IAAI,EAAG,CAAI,EACxB,GAAI,EACJ,KAAM,EACN,UAAW,EAAO,GACnB,CAAA,GACD,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAG,EAAI,EAAO,EAAG,EAAG,EAAM,EAAG,WAAW,SAAS,UAAW,EAAO,WACtE,SAAA,EAAY,EAAE,KAAK,CAChB,CAAA,CACN,CAAA,CAAA,GAEJ,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,EAAG,EAAI,EAAO,EACd,EAAG,EAAO,EACV,WAAW,SACX,UAAW,EAAO,UAEjB,SAAA,EAAE,MAAM,OAAS,GAAK,GAAG,EAAE,MAAM,MAAM,EAAG,CAAC,EAAE,GAAK,EAAE,KACjD,CAAA,GACN,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,UAAW,EAAO,QAClB,EAAG,EAAI,EAAM,EACb,EAAG,EACH,MAAO,EAAO,EACd,OAAQ,EACR,SAAU,EACV,KAAK,MACL,aAAY,GAAG,EAAE,MAAM,IAAI,EAAE,QAAU,KAAO,UAAY,EAAY,EAAE,KAAK,IAC7E,mBAAsB,EAAS,CAAC,EAChC,mBAAsB,EAAU,GAAO,IAAM,EAAI,KAAO,CAAE,EAC1D,YAAe,EAAS,CAAC,EACzB,WAAc,EAAU,GAAO,IAAM,EAAI,KAAO,CAAE,CACnD,CAAA,CACA,CAAA,EAjDK,EAAE,MAAQ,CAiDf,CAEP,CAAC,CACE,CACJ,CAAA,EAAA,IAAU,KAWP,MAVF,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAW,EAAO,QAClB,MAAO,CAAE,KAAM,EAAM,GAAS,EAAO,GAAM,IAAK,CAAE,EAClD,GAAI,GAAG,EAAI,UAHb,SAAA,EAKE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,aACrB,SAAA,EAAK,EAAM,CAAC,QAAU,KAAO,UAAY,EAAY,EAAK,EAAM,CAAC,KAAe,CAC7E,CAAA,GACN,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,aAAe,SAAA,EAAK,EAAM,CAAC,KAAY,CAAA,CAC5D,CACH,CAAA,CACD,GAET,CC1KA,IAAM,EAAQ,GACR,GAAQ,GACR,GAAQ,GAEd,SAAS,GAAkB,EAAoB,CAC7C,IAAM,EAAI,IAAI,KAAK,CAAE,EACrB,OAAO,OAAO,MAAM,EAAE,QAAQ,CAAC,EAAI,GAAK,EAAE,eAAe,QAAS,CAAE,QAAS,QAAS,KAAM,UAAW,OAAQ,SAAU,CAAC,CAC5H,CAEA,SAAgB,EAAW,EAAoB,CAC7C,IAAM,EAAI,KAAK,IAAI,EAAG,KAAK,MAAM,EAAK,GAAM,CAAC,EAC7C,GAAI,EAAI,GAAI,MAAO,GAAG,EAAE,GACxB,IAAM,EAAI,KAAK,MAAM,EAAI,EAAE,EAE3B,OADI,EAAI,GAAW,EAAI,GAAK,GAAG,EAAE,IAAI,EAAI,GAAG,GAAK,GAAG,EAAE,GAC/C,GAAG,KAAK,MAAM,EAAI,EAAE,EAAE,EAC/B,CASA,SAAgB,GACd,EACA,EACA,EACA,EACA,EACkE,CAClE,IAAM,EAAQ,IAAY,MAAQ,OAAO,SAAS,CAAO,EAAI,EAAU,KAGvE,GAAI,EAAW,MAAQ,EAAW,KAAK,WAAa,EAClD,MAAO,CAAE,KAAM,IAAU,KAAO,gCAAkC,oBAAoB,EAAW,CAAK,EAAE,GAAI,SAAU,QAAS,EAEjI,GAAI,EAAW,MAAQ,IAAiB,IAAA,IAAa,EAAW,YAAc,MAAQ,EAAW,WAAa,EAAW,KAAK,EAAG,CAC/H,IAAM,EAAQ,IAAU,KAAO,uCAAyC,SAAS,EAAW,CAAK,IACjG,MAAO,CAAE,KAAM,UAAU,EAAa,YAAY,EAAE,4CAA4C,EAAM,GAAI,SAAU,MAAO,CAC7H,CAeA,OAdI,IAAU,KAAa,CAAE,KAAM,mDAAoD,SAAU,SAAU,EACvG,EAAW,aAAe,KAAa,CAAE,KAAM,kDAAmD,SAAU,SAAU,EACtH,EAAW,YAAc,KAMzB,EAAW,YAAc,KAMtB,CACL,KAAM,uBAAuB,EAAY,EAAW,kBAAoB,CAAC,EAAE,iBAC3E,SAAU,IACZ,EARS,CACL,KAAM,iBAAiB,GAAgB,UAAU,WAAW,EAAW,EAAW,SAAS,EAAE,IAAI,EAAW,EAAQ,EAAW,SAAS,EAAE,gBAC1I,SAAU,MACZ,EATO,CACL,KAAM,0BAA0B,EAAW,EAAW,SAAS,EAAE,IAAI,EAAW,EAAQ,EAAW,SAAS,EAAE,gBAC9G,SAAU,QACZ,CAYJ,CAEA,SAAgB,EAAS,CACvB,QACA,cACA,SACA,SACA,UACA,WACA,SACA,WACA,MACA,UACA,SAAS,IACT,MAAO,GACP,YAAa,GACb,WAAY,GACZ,aACgB,CAChB,IAAM,EAAc,IAAmB,GACjC,EAAa,IAAkB,GAC/B,IAAA,EAAU,EAAA,OAAA,CAAuB,IAAI,EACrC,EAAQ,GAAc,GAAS,EAAU,EACzC,GAAY,GAAa,EACzB,GAAS,GAAe,EACxB,IAAA,EAAU,EAAA,MAAA,CAAM,EAChB,GAAA,EAAS,EAAA,MAAA,CAAM,EACf,CAAC,EAAQ,IAAA,EAAa,EAAA,SAAA,CAAwB,IAAI,EAIlD,EAAS,GAAO,OAAQ,GAAM,EAAgB,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,EAAI,EAAE,CAAC,EAC5E,GAAW,EAAO,KAAM,GAAM,EAAE,YAAc,IAAI,EAClD,GAA8B,IAAW,EAAO,SAAW,EAAI,CAAE,KAAM,QAAS,QAAS,iCAAkC,EAAI,GAAW,CAAE,KAAM,OAAQ,EAAI,CAAE,KAAM,SAAU,GAOhL,EAAa,EAAgB,EAAO,EACpC,EAAQ,EAAa,GAAU,KAC/B,EAAa,EAAgB,EAAQ,EAAO,CAAE,QAAS,GAAS,OAAS,IAAK,CAAC,EAC/E,EAAU,GAAY,EAAY,EAAO,EAAa,EAAY,GAAS,KAAK,EAIhF,EAAQ,EAAO,QAAS,GAAO,EAAE,YAAc,MAAQ,OAAO,SAAS,EAAE,SAAS,EAAI,CAAC,EAAE,SAAS,EAAI,CAAC,CAAE,EACzG,EAAQ,EAAU,EAAG,KAAK,IAAI,EAAU,GAAG,EAAO,CAAC,EAAG,CAC1D,MAAO,EACP,QAAS,OAAO,UAAU,CAAQ,GAAK,EAAM,MAAO,GAAM,OAAO,UAAU,CAAC,CAAC,EAC7E,OAAQ,EACV,CAAC,EACK,EAAQ,EAAM,MACd,EAAM,EAAM,EAAM,OAAS,GAC3B,EAAO,EAAW,EAAM,OAAQ,GAAI,GAAI,EAAS,EACjD,EAAQ,KAAK,IAAI,GAAI,EAAQ,EAAO,EAAK,EACzC,EAAQ,EAAS,EAAQ,GAIzB,GAAQ,EAAO,OAAS,EAAO,EAAO,OAAS,EAAE,CAAE,EAAI,EACvD,GAAS,GAAS,KAAK,IAAI,EAAK,EAAK,EACrC,GAAW,EAAgB,EAAK,EAAI,GAAQ,EAAO,EAAE,EAAE,GAAK,GAC5D,CAAC,EAAI,GAAQ,EAAW,GAAU,GAAQ,GAAkB,KAAK,EACjE,EAAK,EAAY,EAAI,EAAM,EAAM,EAAO,CAAK,EAC7C,EAAK,EAAY,EAAG,EAAK,EAAQ,EAAO,CAAK,EAC7C,EAAU,GAAc,KAAK,IAAI,EAAM,KAAK,IAAI,EAAI,CAAC,CAAC,EAQtD,GAAS,GAAgB,EAAI,EAAM,IAAkB,GAAmB,CAAC,EAAI,CAAI,CAAC,EAClF,GAAU,GACd,CACE,CAAE,IAAK,QAAS,EAAG,EAAM,OAAQ,QAAS,SAAU,EAAG,SAAU,GAAO,IAAK,GAAM,EAAE,CAAE,CAAC,CAAE,EAC1F,EACI,CAAE,IAAK,QAAS,EAAG,EAAO,EAAO,OAAQ,MAAO,SAAU,EAAG,SAAU,GAAO,IAAK,GAAM,UAAU,EAAE,CAAI,GAAG,CAAE,EAC9G,CAAE,IAAK,MAAO,EAAG,EAAO,EAAO,OAAQ,MAAO,SAAU,EAAG,SAAU,GAAO,IAAK,GAAM,EAAE,CAAI,CAAC,CAAE,CACtG,EACA,CAAE,IAAK,EAAM,IAAK,EAAO,EAAO,OAAQ,GAAY,EAAS,CAAE,CACjE,EAEM,GAAO,GAAU,EAAO,IAAK,IAAO,CAAE,EAAG,EAAO,EAAE,CAAC,EAAG,EAAG,EAAE,SAAU,EAAE,CAAC,CAAC,CAC5E,IAAK,GAAQ,EAAI,IAAK,IAAO,CAAE,EAAG,EAAG,EAAE,CAAC,EAAG,EAAG,EAAG,KAAK,IAAI,EAAG,EAAE,CAAC,CAAC,CAAE,EAAE,CAAC,EAInE,EAAU,GACd,GAAc,EAAO,EAAK,KAAK,IAAI,EAAG,KAAK,IAAI,EAAU,GAAY,GAAK,EAAI,IAAO,EAAO,GAAI,CAAC,EAAI,KAEvG,SAAS,GAAQ,EAAgC,CAC/C,IAAM,EAAK,GAAQ,QACnB,GAAI,CAAC,GAAM,EAAO,SAAW,EAAG,OAAO,KACvC,IAAM,EAAK,EAAU,EAAG,sBAAsB,CAAC,CAAC,KAC5C,EAAO,EACP,EAAQ,IAQZ,OAPA,EAAO,SAAS,EAAG,IAAM,CACvB,IAAM,EAAI,KAAK,IAAI,EAAG,EAAO,EAAE,CAAC,CAAC,EAAI,CAAE,EACnC,EAAI,IACN,EAAQ,EACR,EAAO,EAEX,CAAC,EACM,CACT,CAEA,SAAS,GAAM,EAAwC,CACrD,GAAI,EAAO,SAAW,EAAG,OACzB,IAAM,EAAM,GAAU,EAAO,OAAS,EAChC,EAAO,EAAE,MAAQ,YAAc,EAAM,EAAI,EAAE,MAAQ,aAAe,EAAM,EAAI,EAAE,MAAQ,OAAS,EAAI,EAAE,MAAQ,MAAQ,EAAO,OAAS,EAAI,KAC3I,IAAS,OACb,EAAE,eAAe,EACjB,EAAU,KAAK,IAAI,EAAG,KAAK,IAAI,EAAO,OAAS,EAAG,CAAI,CAAC,CAAC,EAC1D,CAEA,IAAM,EAAc,IAAW,KAAwB,IAAA,GAAjB,EAAO,GACvC,EAAa,EAAc,EAAO,EAAY,CAAC,EAAI,KACnD,EAAO,EAAM,GAAM,EAAM,EAAO,EAAG,CAAG,EAAI,KAE1C,GAAW,IAAS,MAAQ,EAAO,EAAO,IAAM,EAAO,EAAQ,EAAO,GAExE,GAAiB,GACrB,GAAI,IAAU,MAAQ,EAAW,MAAQ,EAAW,aAAe,KAAM,CACvE,IAAM,EAAO,EAAW,WAAa,EAC/B,EAAO,EAAW,YAAc,KAAW,EAAW,kBAAoB,EAAW,KAAK,UAAnD,EACzC,EAAO,EAAW,KAAK,IACzB,GAAiB,EAAS,CACxB,CAAE,EAAG,EAAG,EAAO,EAAW,KAAK,CAAC,CAAC,EAAG,EAAG,EAAG,EAAW,KAAK,SAAS,CAAE,EACrE,CAAE,EAAG,EAAG,EAAO,CAAI,CAAC,EAAG,EAAG,EAAG,KAAK,IAAI,EAAG,CAAI,CAAC,CAAE,CAClD,CAAC,EAEL,CACA,IAAM,GAAkB,EAAQ,WAAa,SAAW,GAAU,QAAQ,EAAI,EAAQ,WAAa,OAAS,GAAU,SAAS,EAAI,uBAE7H,GAAU,GAAa,GAAG,EAAM,IAAI,EAAW,KAAO,GAAG,EAAY,EAAW,KAAK,SAAS,EAAE,MAAM,EAAY,CAAQ,EAAE,WAAW,EAAW,EAAW,KAAK,CAAC,IAAM,cAAc,IAAI,IAAU,KAAO,qBAAuB,UAAU,EAAW,CAAK,IAAI,IAAI,EAAQ,OAE7Q,GAAoC,CACxC,CAAE,IAAK,IAAK,MAAO,OAAQ,OAAS,GAAM,EAAW,EAAE,CAAC,CAAE,EAC1D,CAAE,IAAK,IAAK,MAAO,YAAa,QAAS,GAAM,OAAS,GAAO,EAAE,YAAc,KAAO,IAAM,EAAY,EAAE,SAAS,CAAG,CACxH,EAEM,GAAc,CAClB,CAAE,MAAO,YAAa,MAAO,EAAkB,KAAM,MAAgB,EAGrE,GAAI,EAAa,CAAC,CAAE,MAAO,YAAa,MAAO,uBAAwB,KAAM,MAAgB,CAAC,EAAI,CAAC,EACnG,GAAI,GAAiB,CAAC,CAAE,MAAO,aAAc,MAAO,GAAiB,KAAM,MAAgB,CAAC,EAAI,CAAC,CACnG,EAEA,OACE,EAAA,EAAA,IAAA,CAAC,GAAD,CACS,QACM,cACL,SACR,OAAQ,GACR,SAAS,OACT,eAAgB,EAChB,OAAO,EAAA,EAAA,IAAA,CAAC,GAAD,CAAW,QAAS,EAAgB,WAAS,KAAM,EAAQ,OAAS,GAAM,OAAO,EAAE,CAAC,CAAI,CAAA,EAC/F,QACE,EAAA,EAAA,KAAA,CAAA,EAAA,SAAA,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,IAAD,CAAG,UAAW,EAAK,KAAM,gBAAe,EAAQ,SAAU,KAAK,SAAU,SAAA,EAAQ,IAAQ,CAAA,GACzF,EAAA,EAAA,IAAA,CAAC,GAAD,CAAa,MAAO,EAAc,CAAA,CAClC,CAAA,CAAA,EAGJ,UAAA,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,IAAK,GACL,UAAW,GAAG,EAAK,SAAS,GAAG,EAAK,YACpC,cAAa,GACb,SAAU,EACV,KAAK,QACL,aAAY,GAAG,EAAM,2DACrB,mBAAkB,EAClB,YAAe,EAAW,GAAM,IAAM,EAAO,OAAS,EAAO,OAAS,EAAI,KAAK,EAC/E,WAAc,EAAU,IAAI,EAC5B,UAAW,GAVb,SAAA,EAYE,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,UAAW,EAAK,IACT,QACC,SACR,QAAS,OAAO,EAAM,GAAG,IACzB,KAAK,MACL,aAAY,GACZ,cAAgB,GAAmC,EAAU,GAAQ,EAAE,OAAO,CAAC,EAC/E,mBAAsB,EAAU,IAAI,EARtC,SAAA,EAUE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAA,UACE,EAAA,EAAA,IAAA,CAAC,EAAD,CAAc,GAAI,GAAW,GAAS,WAAW,EAAG,MAAO,EAAkB,IAAK,EAAO,OAAQ,EAAQ,CAAQ,CAAA,CAC7G,CAAA,EACL,GAAW,EAAQ,MAAQ,GAC1B,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,YAAU,eACV,UAAW,GAAG,EAAK,YAAY,GAAG,EAAK,SACvC,EAAG,EACH,EAAG,EAAG,KAAK,IAAI,EAAK,EAAQ,KAAK,CAAC,EAClC,MAAO,EACP,OAAQ,KAAK,IAAI,EAAG,EAAG,CAAC,EAAI,EAAG,KAAK,IAAI,EAAK,EAAQ,KAAK,CAAC,CAAC,CAC7D,CAAA,EACC,KACH,EAAM,KAAK,EAAG,KACb,EAAA,EAAA,KAAA,CAAC,IAAD,CAAA,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAK,KAAM,GAAI,EAAM,GAAI,EAAO,EAAO,GAAI,EAAM,EAAG,CAAC,CAAC,EAAG,GAAI,EAAM,EAAG,CAAC,CAAC,CAAI,CAAA,GAC7F,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAK,KAAM,EAAG,EAAO,EAAG,EAAG,EAAG,CAAC,EAAG,GAAG,SAAS,WAAW,MAAO,SAAA,EAAM,OAAO,EAAS,CAAA,CACtG,CAAA,EAHK,CAGL,CACJ,GACD,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAK,KAAM,GAAI,EAAM,GAAI,EAAO,EAAO,GAAI,EAAM,EAAG,CAAC,CAAC,EAAG,GAAI,EAAM,EAAG,CAAC,CAAC,CAAI,CAAA,EAC5F,GAAQ,IAAK,IACZ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAkB,kBAAiB,EAAE,IAAK,UAAW,EAAK,KAAM,EAAG,EAAE,EAAG,EAAG,EAAS,EAAG,WAAY,EAAE,OAAS,SAAA,EAAE,IAAW,EAAhH,EAAE,GAA8G,CAC5H,EAEA,GACC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,YAAU,OAAO,UAAW,EAAK,UAAW,EAAG,EAAS,CAAC,CAAE,EAAG,EAAG,CAAE,EAAG,EAAG,EAAG,CAAQ,CAAE,EAAG,CAAE,EAAG,EAAG,CAAI,EAAG,EAAG,EAAG,CAAC,CAAE,CAAC,CAAC,CAAI,CAAA,EAC3H,KACH,GACC,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,YAAU,UAAb,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAK,UAAW,GAAI,EAAM,GAAI,EAAO,EAAO,GAAI,EAAM,EAAG,EAAQ,KAAK,CAAC,EAAG,GAAI,EAAM,EAAG,EAAQ,KAAK,CAAC,CAAI,CAAA,GAK1H,EAAA,EAAA,KAAA,CAAC,OAAD,CAAM,YAAU,gBAAgB,UAAW,GAAG,EAAK,KAAK,GAAG,EAAK,OAAQ,EAAG,EAAO,EAAG,EAAG,EAAG,EAAQ,KAAK,EAAI,EAAG,WAAW,QAA1H,SAAA,CACG,EAAQ,MAAM,MAAI,EAAY,EAAQ,KAAK,CACxC,CACL,CAAA,CAAA,CACD,CAAA,EAAA,KACH,IAAS,KAON,MANF,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,YAAU,MAAb,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAK,IAAK,GAAI,EAAM,CAAI,EAAG,GAAI,EAAM,CAAI,EAAG,GAAI,EAAO,GAAI,EAAQ,CAAQ,CAAA,EAC3F,IACC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,YAAU,YAAY,UAAW,GAAG,EAAK,KAAK,GAAG,EAAK,OAAQ,EAAG,EAAM,EAAG,GAAW,WAAW,SAAS,SAAA,KAAS,CAAA,EACtH,IACH,CACD,CAAA,EACH,GAAK,KAAK,EAAK,KACd,EAAA,EAAA,KAAA,CAAC,IAAD,CAAW,YAAU,YAArB,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,YAAU,OACV,UAAW,GAAG,EAAK,KAAK,GAAG,EAAK,SAChC,KAAM,QAAQ,GAAW,GAAS,WAAW,EAAE,GAC/C,EAAG,EAAe,EAAK,EAAI,IAAK,IAAO,CAAE,EAAG,EAAE,EAAG,EAAG,EAAG,CAAC,CAAE,EAAE,CAAC,CAC9D,CAAA,EACA,EAAI,OAAS,GACZ,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,YAAU,OAAO,UAAW,GAAG,EAAK,KAAK,GAAG,EAAK,OAAQ,WAAY,EAAG,OAAQ,EAAkB,EAAG,EAAW,CAAG,CAAI,CAAA,EAC3H,IACH,CAVK,EAAA,CAUL,CACJ,EACA,IACC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,YAAU,aAAa,UAAW,EAAK,WAAY,OAAQ,GAAiB,EAAG,EAAiB,CAAA,EACpG,KACH,EAAW,MACV,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,UAAW,EAAK,OAAQ,GAAI,EAAG,EAAO,EAAW,KAAK,CAAC,CAAC,EAAG,GAAI,EAAG,EAAW,KAAK,SAAS,EAAG,EAAG,EAAG,KAAM,CAAmB,CAAA,EACnI,KACH,GACC,EAAA,EAAA,KAAA,CAAC,IAAD,CAAG,YAAU,QAAb,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAK,UAAW,YAAU,YAAY,GAAI,EAAM,EAAG,EAAO,EAAY,CAAC,CAAC,CAAC,EAAG,GAAI,EAAM,EAAG,EAAO,EAAY,CAAC,CAAC,CAAC,EAAG,GAAI,EAAO,GAAI,EAAQ,CAAQ,CAAA,EACjK,EAAY,YAAc,KAEvB,MADF,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,UAAW,EAAK,OAAQ,GAAI,EAAG,EAAO,EAAY,CAAC,CAAC,EAAG,GAAI,EAAG,KAAK,IAAI,EAAG,EAAY,SAAS,CAAC,EAAG,EAAG,EAAG,KAAM,CAAmB,CAAA,CAE3I,CACD,CAAA,EAAA,IACD,KACL,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,GAAI,EAAQ,UAAW,EAAK,OAAQ,YAAU,SACjD,SAAA,EACG,GAAG,GAAqB,EAAY,CAAC,EAAE,IAAI,EAAY,YAAc,KAAO,aAAe,GAAG,EAAY,EAAY,SAAS,EAAE,eAChI,IAAe,KAAkD,GAA3C,eAAe,EAAY,CAAU,KAC5D,EACA,CAAA,EACL,GACC,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,KAAM,EAAY,EAAG,EAAO,EAAY,CAAC,CAAC,EAAG,CAAK,EAAI,EAAG,EAAO,EAAY,CAAC,CAAC,EAAI,EAAiB,EAAG,EAAO,EAAY,CAAC,CAAC,EAAG,CAAK,EACnI,KAAM,EAAY,EAAG,EAAO,EAAY,CAAC,CAAC,EAAG,CAAK,EAClD,IAAK,EACL,MAAO,GAAqB,EAAY,CAAC,EACzC,KAAM,CACJ,CAAE,IAAK,IAAK,MAAO,YAAa,MAAO,EAAY,YAAc,KAAO,KAAO,EAAY,EAAY,SAAS,EAAG,MAAO,EAAkB,KAAM,MAAO,EACzJ,GAAI,IAAe,KAAkI,CAAC,EAA5H,CAAC,CAAE,IAAK,IAAK,MAAO,YAAa,MAAO,EAAY,CAAU,EAAG,MAAO,uBAAwB,KAAM,MAAgB,CAAC,CACnJ,CACD,CAAA,EACC,IACD,GACK,CAAA,CAEhB"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
._figure_1si9v_1{border:1px solid var(--border-subtle);border-radius:var(--radius-lg);background:var(--bg-surface);padding:var(--space-4);margin:0}._caption_1si9v_12{justify-content:space-between;align-items:baseline;gap:var(--space-3);margin-bottom:var(--space-3);display:flex}._title_1si9v_20{font-size:var(--text-sm-size);font-weight:var(--font-weight-semibold);color:var(--text-primary)}._description_1si9v_26{font-size:var(--text-xs-size);color:var(--text-tertiary)}._plot_1si9v_31{width:100%;overflow-x:auto}._tableDisclosure_1si9v_36{margin-top:var(--space-3);border-top:1px solid var(--border-subtle);padding-top:var(--space-2)}._tableDisclosure_1si9v_36>summary{cursor:pointer;font-size:var(--text-xs-size);color:var(--text-secondary);list-style:none}._tableDisclosure_1si9v_36>summary::-webkit-details-marker{display:none}._tableDisclosure_1si9v_36>summary:before{content:"▸ "}._tableDisclosure_1si9v_36[open]>summary:before{content:"▾ "}._tableBody_1si9v_61{margin-top:var(--space-2)}._caveat_1si9v_65{margin:0 0 var(--space-3);padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);background:var(--status-unknown-bg);color:var(--status-unknown-fg);font-size:var(--text-xs-size);line-height:var(--text-sm-line)}._empty_1si9v_75{color:var(--text-tertiary);font-size:var(--text-sm-size);padding:var(--space-6) 0;text-align:center}._legend_4pgvn_1{gap:var(--space-1) var(--space-4);margin:var(--space-2) 0 0;flex-wrap:wrap;padding:0;list-style:none;display:flex}._item_4pgvn_10{align-items:center;gap:var(--space-2);font-size:var(--text-xs-size);color:var(--text-secondary);display:inline-flex}._swatch_4pgvn_18{border-radius:var(--radius-full);flex:none;width:10px;height:10px}._swatchLine_4pgvn_25{border-radius:var(--radius-full);flex:none;width:14px;height:2px}._svg_2zwdg_5{font-variant-numeric:tabular-nums;max-width:100%;display:block}._gridline_2zwdg_12{stroke:var(--chart-grid);stroke-width:1px;shape-rendering:crispedges}._axis_2zwdg_18{stroke:var(--chart-axis);stroke-width:1px;shape-rendering:crispedges}._axisLabel_2zwdg_24{font-size:var(--text-xs-size);fill:var(--text-tertiary);font-family:var(--font-ui);font-variant-numeric:tabular-nums}._line_2zwdg_31{fill:none;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round}._area_2zwdg_40{stroke:none}._marker_2zwdg_44{stroke:var(--chart-surface);stroke-width:2px}._endLabel_2zwdg_49{font-size:var(--text-xs-size);font-family:var(--font-ui);font-weight:var(--font-weight-medium)}._crosshairLine_2zwdg_55{stroke:var(--chart-axis);stroke-width:1px;shape-rendering:crispedges;pointer-events:none}._overlay_2zwdg_62{fill:#0000;cursor:crosshair}._wrap_2zwdg_67{width:100%;min-width:0;position:relative}._svg_o4jfa_1{display:block;overflow:visible}._bar_o4jfa_6{transition:opacity var(--duration-fast) var(--ease-standard)}._bar_o4jfa_6:hover,._bar_o4jfa_6:focus-visible{opacity:.82}._baseline_o4jfa_15{stroke:var(--chart-axis);stroke-width:1px}._gridline_o4jfa_20{stroke:var(--chart-grid);stroke-width:1px}._axisLabel_o4jfa_25{fill:var(--text-tertiary);font-size:10px;font-family:var(--font-ui)}._valueLabel_o4jfa_31{fill:var(--text-secondary);font-size:10px;font-family:var(--font-ui);font-variant-numeric:tabular-nums}._categoryLabel_o4jfa_38{fill:var(--text-secondary);font-size:10px;font-family:var(--font-ui)}._hitArea_o4jfa_44{fill:#0000;cursor:pointer}._tooltip_o4jfa_49{pointer-events:none;background:var(--chart-tooltip-bg);border:1px solid var(--chart-tooltip-border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);padding:var(--space-1) var(--space-2);font-size:var(--text-xs-size);color:var(--text-primary);white-space:nowrap;z-index:var(--z-dropdown);position:absolute}._tooltipValue_o4jfa_63{font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums}._tooltipLabel_o4jfa_68{color:var(--text-tertiary);margin-left:var(--space-1)}._wrap_o4jfa_73{position:relative}
|
package/dist/core/web/public/next/assets/{cloud-model-CfRydq8N.js → cloud-model-BDivRMqv.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{o as e}from"./index-CyK31YRm.js";import{D as t}from"./VerseConsoleApp-DXDv1aOi.js";import{b as n,y as r}from"./format-BmH2yWL6.js";import{v as i}from"./context-model-Bb15chFt.js";import{a,i as o,n as s}from"./types-IYKrYLku.js";e(((e,t)=>{t.exports={}}))();var c=`[REDACTED]`;function ee(e){if(/^[0-9a-fA-F]{40}$/.test(e))return e;let t=e.replace(/^\+/,``).replace(/=+$/,``);return/^(.)\1{39,}$/.test(t)?e:c}var te=/\d{6,12}:[A-Za-z0-9_-]{33,35}(?![A-Za-z0-9_-])/g;function l(e,t,n){let r=e=>e<0||!/[A-Za-z0-9_]/.test(n[e]);return r(t-1)||n.slice(t-3,t)===`bot`&&r(t-4)?c:e}var u=/(https?:\/\/(?:hooks\.slack\.com\/(?:services|workflows|triggers)|(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks)\/)[A-Za-z0-9_/-]{8,}/gi,d=/(?<![A-Za-z0-9_-])xai-[A-Za-z0-9]{20,}/g,f=String.raw`\s*[=:]\s*["']?[^\s,;'"]{8,}["']?`,p=new RegExp(String.raw`(?<![A-Za-z0-9_$])([A-Z][A-Z0-9_]*_(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|CREDENTIALS?|AUTH|DSN))`+f,`g`),ne=new RegExp(String.raw`(?<![A-Za-z0-9_$])([a-z][a-z0-9_]*_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key))`+f,`g`),re=/_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key)\s*[=:]/,m=/(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?)\s*[=:]/,h=new RegExp(String.raw`(?<![A-Za-z0-9_$])([a-z][A-Za-z0-9]*(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?))`+f,`g`),g=/(\\?["'])([A-Za-z0-9_.-]*(?:api[_-]?key|token|secret|password|passwd|pwd|credentials?|private[_-]?key|access[_-]?key|secret[_-]?key|signing[_-]?key|auth|connection[_-]?string))\1(\s*:\s*)(\\?["'])([^"'\s\\]{8,})\4/gi;function _(e){let t=e.replace(/^["']|["']$/g,``);return/^[A-Za-z_$][\w$]*(?:\??\.[A-Za-z_$][\w$]*)+[)\]]*$/.test(t)||/^[A-Za-z_$][\w$.]*\(/.test(t)||/^(?:\$\{|\$[A-Za-z_]|`|<)/.test(t)}function v(e){let t=e.replace(/^["']|["']$/g,``);return!/\d/.test(t)&&/^[A-Za-z_$][A-Za-z_$.<>[\]|&?!()]*$/.test(t)}function y(e){return e.replace(/^["']|["']$/g,``)===c}function b(e,t,n,r){return y(n)||_(n)||r&&v(n)?t:`${e}=${c}`}function x(e,t){return e.slice(t.length).replace(/^\s*[=:]\s*/,``)}function S(e){try{let t=e.replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[\s\S]*?-----END[ A-Z]*PRIVATE KEY-----/g,c).replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[^\n]*/g,c).replace(te,l).replace(u,`$1[REDACTED]`).replace(d,c).replace(/\bsk-[A-Za-z0-9_-]{16,}/g,c).replace(/\bgh[poursa]_[A-Za-z0-9]{16,}/g,c).replace(/\bgithub_pat_[A-Za-z0-9_]{22,}/g,c).replace(/\b(Bearer|Token|Authorization)\s+[A-Za-z0-9\-._~+/]+=*/gi,`$1 [REDACTED]`).replace(/\b(api[_-]?key|api[_-]?token|secret|secret[_-]?key|token|password|passwd|pwd|auth|credential|client[_-]?secret|private[_-]?key|access[_-]?token|auth[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|connection[_-]?string|conn[_-]?str|_?auth[_-]?token|ASHLR_[A-Z_]+)\s*[=:]\s*["']?[^\s,;'"]{8,}["']?/gi,`$1=[REDACTED]`).replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}/gi,c).replace(/\bAKIA[0-9A-Z]{16}\b/g,c).replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,c).replace(/\b[0-9a-fA-F]{64,}\b/g,c).replace(/\bglpat-[A-Za-z0-9_-]{16,}/g,c).replace(/\bhf_[A-Za-z0-9]{16,}\b/g,c).replace(/\bnpm_[A-Za-z0-9]{16,}\b/g,c).replace(/\bAIza[0-9A-Za-z_-]{35}\b/g,c).replace(/(:\/\/[^:\s/@]*:)[^@\s]+(@)/g,`$1[REDACTED]$2`).replace(/(?<![/\w])[A-Za-z0-9+]{40,}={0,2}(?![/\w])/g,ee).replace(p,(e,t)=>b(t,e,x(e,t),!1));return re.test(t)&&(t=t.replace(ne,(e,t)=>b(t,e,x(e,t),!0))),m.test(t)&&(t=t.replace(h,(e,t)=>b(t,e,x(e,t),!0))),t.replace(g,(e,t,n,r,i,a)=>y(a)||_(a)?e:`${t}${n}${t}${r}${i}${c}${i}`)}catch{return e}}function C(e,t){return r(S(e),t)}var w=a.selfImprove.repo,T=/^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$/,E=/^[A-Za-z0-9._/+-]{1,200}$/;function D(e){return!E.test(e)||e.startsWith(`-`)||e.startsWith(`/`)||e.endsWith(`/`)||e.endsWith(`.`)||e.endsWith(`.lock`)?!1:!e.includes(`..`)&&!e.includes(`//`)}function O(e,t){if(typeof e!=`string`||e.length>2048)return null;try{let n=new URL(e);return n.protocol===`https:`&&n.hostname===t?n.toString():null}catch{return null}}function k(e){if(!Number.isFinite(e))return`—`;let t=Math.abs(e)<.005?0:e,n=Number.isInteger(t)?String(Math.abs(t)):Math.abs(t).toFixed(2);return`${t<0?`−`:``}$${n}`}function A(e){let n=e.creditsTotalUsd,r=e.estimatedRemainingUsd,i=e.budget.selfImprove.reserveUsd,a=n>0?n:null,o=a===null?null:(n-Math.max(0,r))/n*100,s=r<=0?`danger`:r<i?`warning`:`accent`,c=r<=0?`The estimate says the credits are spent. Check the real balance on claude.ai and adjust the budget.`:r<i?`Under the ${k(i)} reserve, so Verse stops launching self-improvement tasks.`:null;return{value:Math.max(0,r),max:a,text:`${k(Math.max(0,r))} of ${k(n)} · estimate`,usedText:o===null?`no credit total set`:`${t(o)} used`,tone:s,warning:c}}function j(e){let t=new Date(e);return t.setHours(24,0,0,0),t.getTime()}function M(e,t=Date.now()){let r=n(new Date(j(t)).toISOString(),t),i=e.running===1?`1 running`:`${e.running} running`;return`${e.sessionsToday} of ${e.budget.maxSessionsPerDay} sessions today · ${i}${r?` · resets ${r}`:``}`}function N(e){let t=e.budget.selfImprove;return t.enabled?`${e.selfImproveToday} of ${t.maxPerDay} self-improvement launches today, on ${t.repo}. Stops under a ${k(t.reserveUsd)} estimated balance.`:`Self-improvement is off. Verse launches cloud tasks only when you ask.`}function P(e,t){return e.ok?null:e.reason?C(e.reason):t}var F=`The Claude seat isn't set up on this Mac.`;function I(e){return e.ready?null:e.reason?C(e.reason):F}var ie=`Not set up`;function L(e){return`~$${Number.isFinite(e)?Math.max(0,Math.round(e)):0} credits`}function R(e){return`Cloud: not set up · ${L(e)}`}function z(e,t){return I(e)??P(t.canLaunch,`The cloud budget does not allow another launch right now.`)}var B={queued:`Queued`,launching:`Launching`,running:`Running`,"pr-open":`PR open`,merged:`Merged`,closed:`Closed`,failed:`Failed`,expired:`Expired`},V={queued:`info`,launching:`info`,running:`running`,"pr-open":`warning`,merged:`success`,closed:`neutral`,failed:`danger`,expired:`unknown`};function H(e){return e.state===`pr-open`&&!e.pr?`PR unverified`:e.state===`pr-open`&&e.pr?.draft?`Draft PR`:B[e.state]??e.state}function U(e){return o.includes(e)}function W(e){return e===`queued`||e===`launching`||e===`running`}var G=864e5;function K(e,t=Date.now()){let n=e=>{let n=Date.parse(e.updatedAt);return Number.isFinite(n)&&t-n<G},r=e.filter(e=>!U(e.state)||n(e)).sort((e,t)=>(Date.parse(t.createdAt)||0)-(Date.parse(e.createdAt)||0));return{shown:r.slice(0,6),hidden:Math.max(0,r.length-6)}}function q(e){return e.filter(e=>W(e.state)).length}function J(e,t=Date.now()){let n=e.state===`queued`||e.state===`launching`?e.createdAt:e.launchedAt??e.createdAt,r=i(n,t),a=e.state===`queued`?`queued`:e.state===`failed`?`tried`:`started`;return`${e.repo} from ${e.baseBranch}${r?` · ${a} ${r}`:``}`}function Y(e,t=Date.now()){return e.report?.summary&&(e.state===`pr-open`||e.state===`merged`)?`Cloud session reports (unverified): ${C(e.report.summary,t)}`:e.stateReason?C(e.stateReason,t):null}function ae(e){return e.state!==`merged`&&e.state!==`closed`}var X=new Intl.NumberFormat(`en-US`);function oe(e){let t={},n=e.repo.trim(),r=e.baseBranch.trim(),i=e.prompt.trim();return n?T.test(n)||(t.repo=`Use the GitHub owner/name form, like ashlrai/ashlr-hub.`):t.repo=`Enter the GitHub repository as owner/name.`,r&&!D(r)&&(t.baseBranch=`That isn't a branch name git accepts.`),i?i.length>2e4&&(t.prompt=`The task is ${X.format(i.length)} characters; the limit is ${X.format(s)}.`):t.prompt=`Describe the task for the cloud session.`,Object.keys(t).length>0?{ok:!1,errors:t}:{ok:!0,request:{repo:n,...r?{baseBranch:r}:{},prompt:i}}}var Z=[{field:`total`,label:`Credits on the account`,hint:`What claude.ai says you have.`,money:!0,integer:!1,min:0,max:1e5},{field:`spent`,label:`Already spent`,hint:`Spent before Verse tracked it, or a correction after checking.`,money:!0,integer:!1,min:-1e5,max:1e5},{field:`perSession`,label:`Estimate per session`,hint:`Flat cost Verse counts for each launch.`,money:!0,integer:!1,min:.01,max:1e3},{field:`maxPerDay`,label:`Sessions per day`,hint:`From every origin, counted per local day.`,money:!1,integer:!0,min:0,max:500},{field:`maxConcurrent`,label:`Running at once`,hint:`Launching or running together.`,money:!1,integer:!0,min:1,max:50},{field:`selfImproveMax`,label:`Self-improvement per day`,hint:`Launches Verse may make on its own.`,money:!1,integer:!0,min:0,max:100},{field:`selfImproveMaxOpen`,label:`Open self-improvement PRs`,hint:`Self-improvement waits while this many await review.`,money:!1,integer:!0,min:1,max:50},{field:`reserve`,label:`Reserve`,hint:`Self-improvement stops under this estimated balance.`,money:!0,integer:!1,min:0,max:1e5}];function Q(e){let t=e.selfImprove.maxOpenPrs;return typeof t==`number`&&Number.isFinite(t)?t:a.selfImprove.maxOpenPrs}function $(e){return String(Number.isInteger(e)?e:Math.round(e*100)/100)}function se(e){return{total:$(e.creditsTotalUsd),spent:$(e.creditsSpentAdjustmentUsd),perSession:$(e.estimatedCostPerSessionUsd),maxPerDay:$(e.maxSessionsPerDay),maxConcurrent:$(e.maxConcurrent),selfImprove:e.selfImprove.enabled,selfImproveMax:$(e.selfImprove.maxPerDay),selfImproveMaxOpen:$(Q(e)),reserve:$(e.selfImprove.reserveUsd)}}function ce(e,t){let n={},r={};for(let t of Z){let i=e[t.field].trim().replace(/^\$/,``),a=i===``?NaN:Number(i);Number.isFinite(a)?t.integer&&!Number.isInteger(a)?n[t.field]=`Enter a whole number.`:a<t.min||a>t.max?n[t.field]=t.money?`Between ${k(t.min)} and ${k(t.max)}.`:`Between ${X.format(t.min)} and ${X.format(t.max)}.`:r[t.field]=a:n[t.field]=`Enter a number.`}if(Object.keys(n).length>0)return{ok:!1,errors:n};let i={},a=(e,t)=>Math.abs(e-t)<.005;a(r.total,t.creditsTotalUsd)||(i.creditsTotalUsd=r.total),a(r.spent,t.creditsSpentAdjustmentUsd)||(i.creditsSpentAdjustmentUsd=r.spent),a(r.perSession,t.estimatedCostPerSessionUsd)||(i.estimatedCostPerSessionUsd=r.perSession),a(r.maxPerDay,t.maxSessionsPerDay)||(i.maxSessionsPerDay=r.maxPerDay),a(r.maxConcurrent,t.maxConcurrent)||(i.maxConcurrent=r.maxConcurrent);let o={};return e.selfImprove!==t.selfImprove.enabled&&(o.enabled=e.selfImprove),a(r.selfImproveMax,t.selfImprove.maxPerDay)||(o.maxPerDay=r.selfImproveMax),a(r.selfImproveMaxOpen,Q(t))||(o.maxOpenPrs=r.selfImproveMaxOpen),a(r.reserve,t.selfImprove.reserveUsd)||(o.reserveUsd=r.reserve),Object.keys(o).length>0&&(i.selfImprove=o),{ok:!0,update:i,changed:Object.keys(i).length>0}}function le(e){return e.overview?I(e.overview.seat)||(e.repo?P(e.overview.budget.canLaunch,`The cloud budget does not allow another launch right now.`)||(e.prompt.trim()?e.prompt.trim().length>2e4?`The message is over ${X.format(s)} characters — trim it to run it in the cloud.`:null:`Type the task in the message box first.`):e.rootsLoading?`Reading this chat's project…`:`This chat's project has no GitHub origin, so a cloud session has nothing to clone.`):e.overviewReason??`The cloud lane did not answer.`}export{J as C,Y as S,S as T,O as _,L as a,M as b,ae as c,k as d,P as f,le as g,R as h,V as i,K as l,z as m,w as n,se as o,q as p,ie as r,ce as s,Z as t,A as u,I as v,oe as w,H as x,N as y};
|
|
2
|
-
//# sourceMappingURL=cloud-model-
|
|
1
|
+
import{o as e}from"./index-DZ-UQ7v8.js";import{D as t}from"./VerseConsoleApp-CWU6R3By.js";import{b as n,y as r}from"./format-CH4g_sl1.js";import{v as i}from"./context-model-CokrgEUq.js";import{a,i as o,n as s}from"./types-IYKrYLku.js";e(((e,t)=>{t.exports={}}))();var c=`[REDACTED]`;function ee(e){if(/^[0-9a-fA-F]{40}$/.test(e))return e;let t=e.replace(/^\+/,``).replace(/=+$/,``);return/^(.)\1{39,}$/.test(t)?e:c}var te=/\d{6,12}:[A-Za-z0-9_-]{33,35}(?![A-Za-z0-9_-])/g;function l(e,t,n){let r=e=>e<0||!/[A-Za-z0-9_]/.test(n[e]);return r(t-1)||n.slice(t-3,t)===`bot`&&r(t-4)?c:e}var u=/(https?:\/\/(?:hooks\.slack\.com\/(?:services|workflows|triggers)|(?:ptb\.|canary\.)?discord(?:app)?\.com\/api\/webhooks)\/)[A-Za-z0-9_/-]{8,}/gi,d=/(?<![A-Za-z0-9_-])xai-[A-Za-z0-9]{20,}/g,f=String.raw`\s*[=:]\s*["']?[^\s,;'"]{8,}["']?`,p=new RegExp(String.raw`(?<![A-Za-z0-9_$])([A-Z][A-Z0-9_]*_(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|CREDENTIALS?|AUTH|DSN))`+f,`g`),ne=new RegExp(String.raw`(?<![A-Za-z0-9_$])([a-z][a-z0-9_]*_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key))`+f,`g`),re=/_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key)\s*[=:]/,m=/(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?)\s*[=:]/,h=new RegExp(String.raw`(?<![A-Za-z0-9_$])([a-z][A-Za-z0-9]*(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?))`+f,`g`),g=/(\\?["'])([A-Za-z0-9_.-]*(?:api[_-]?key|token|secret|password|passwd|pwd|credentials?|private[_-]?key|access[_-]?key|secret[_-]?key|signing[_-]?key|auth|connection[_-]?string))\1(\s*:\s*)(\\?["'])([^"'\s\\]{8,})\4/gi;function _(e){let t=e.replace(/^["']|["']$/g,``);return/^[A-Za-z_$][\w$]*(?:\??\.[A-Za-z_$][\w$]*)+[)\]]*$/.test(t)||/^[A-Za-z_$][\w$.]*\(/.test(t)||/^(?:\$\{|\$[A-Za-z_]|`|<)/.test(t)}function v(e){let t=e.replace(/^["']|["']$/g,``);return!/\d/.test(t)&&/^[A-Za-z_$][A-Za-z_$.<>[\]|&?!()]*$/.test(t)}function y(e){return e.replace(/^["']|["']$/g,``)===c}function b(e,t,n,r){return y(n)||_(n)||r&&v(n)?t:`${e}=${c}`}function x(e,t){return e.slice(t.length).replace(/^\s*[=:]\s*/,``)}function S(e){try{let t=e.replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[\s\S]*?-----END[ A-Z]*PRIVATE KEY-----/g,c).replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[^\n]*/g,c).replace(te,l).replace(u,`$1[REDACTED]`).replace(d,c).replace(/\bsk-[A-Za-z0-9_-]{16,}/g,c).replace(/\bgh[poursa]_[A-Za-z0-9]{16,}/g,c).replace(/\bgithub_pat_[A-Za-z0-9_]{22,}/g,c).replace(/\b(Bearer|Token|Authorization)\s+[A-Za-z0-9\-._~+/]+=*/gi,`$1 [REDACTED]`).replace(/\b(api[_-]?key|api[_-]?token|secret|secret[_-]?key|token|password|passwd|pwd|auth|credential|client[_-]?secret|private[_-]?key|access[_-]?token|auth[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|connection[_-]?string|conn[_-]?str|_?auth[_-]?token|ASHLR_[A-Z_]+)\s*[=:]\s*["']?[^\s,;'"]{8,}["']?/gi,`$1=[REDACTED]`).replace(/\bxox[baprs]-[A-Za-z0-9-]{10,}/gi,c).replace(/\bAKIA[0-9A-Z]{16}\b/g,c).replace(/\beyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g,c).replace(/\b[0-9a-fA-F]{64,}\b/g,c).replace(/\bglpat-[A-Za-z0-9_-]{16,}/g,c).replace(/\bhf_[A-Za-z0-9]{16,}\b/g,c).replace(/\bnpm_[A-Za-z0-9]{16,}\b/g,c).replace(/\bAIza[0-9A-Za-z_-]{35}\b/g,c).replace(/(:\/\/[^:\s/@]*:)[^@\s]+(@)/g,`$1[REDACTED]$2`).replace(/(?<![/\w])[A-Za-z0-9+]{40,}={0,2}(?![/\w])/g,ee).replace(p,(e,t)=>b(t,e,x(e,t),!1));return re.test(t)&&(t=t.replace(ne,(e,t)=>b(t,e,x(e,t),!0))),m.test(t)&&(t=t.replace(h,(e,t)=>b(t,e,x(e,t),!0))),t.replace(g,(e,t,n,r,i,a)=>y(a)||_(a)?e:`${t}${n}${t}${r}${i}${c}${i}`)}catch{return e}}function C(e,t){return r(S(e),t)}var w=a.selfImprove.repo,T=/^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$/,E=/^[A-Za-z0-9._/+-]{1,200}$/;function D(e){return!E.test(e)||e.startsWith(`-`)||e.startsWith(`/`)||e.endsWith(`/`)||e.endsWith(`.`)||e.endsWith(`.lock`)?!1:!e.includes(`..`)&&!e.includes(`//`)}function O(e,t){if(typeof e!=`string`||e.length>2048)return null;try{let n=new URL(e);return n.protocol===`https:`&&n.hostname===t?n.toString():null}catch{return null}}function k(e){if(!Number.isFinite(e))return`—`;let t=Math.abs(e)<.005?0:e,n=Number.isInteger(t)?String(Math.abs(t)):Math.abs(t).toFixed(2);return`${t<0?`−`:``}$${n}`}function A(e){let n=e.creditsTotalUsd,r=e.estimatedRemainingUsd,i=e.budget.selfImprove.reserveUsd,a=n>0?n:null,o=a===null?null:(n-Math.max(0,r))/n*100,s=r<=0?`danger`:r<i?`warning`:`accent`,c=r<=0?`The estimate says the credits are spent. Check the real balance on claude.ai and adjust the budget.`:r<i?`Under the ${k(i)} reserve, so Verse stops launching self-improvement tasks.`:null;return{value:Math.max(0,r),max:a,text:`${k(Math.max(0,r))} of ${k(n)} · estimate`,usedText:o===null?`no credit total set`:`${t(o)} used`,tone:s,warning:c}}function j(e){let t=new Date(e);return t.setHours(24,0,0,0),t.getTime()}function M(e,t=Date.now()){let r=n(new Date(j(t)).toISOString(),t),i=e.running===1?`1 running`:`${e.running} running`;return`${e.sessionsToday} of ${e.budget.maxSessionsPerDay} sessions today · ${i}${r?` · resets ${r}`:``}`}function N(e){let t=e.budget.selfImprove;return t.enabled?`${e.selfImproveToday} of ${t.maxPerDay} self-improvement launches today, on ${t.repo}. Stops under a ${k(t.reserveUsd)} estimated balance.`:`Self-improvement is off. Verse launches cloud tasks only when you ask.`}function P(e,t){return e.ok?null:e.reason?C(e.reason):t}var F=`The Claude seat isn't set up on this Mac.`;function I(e){return e.ready?null:e.reason?C(e.reason):F}var ie=`Not set up`;function L(e){return`~$${Number.isFinite(e)?Math.max(0,Math.round(e)):0} credits`}function R(e){return`Cloud: not set up · ${L(e)}`}function z(e,t){return I(e)??P(t.canLaunch,`The cloud budget does not allow another launch right now.`)}var B={queued:`Queued`,launching:`Launching`,running:`Running`,"pr-open":`PR open`,merged:`Merged`,closed:`Closed`,failed:`Failed`,expired:`Expired`},V={queued:`info`,launching:`info`,running:`running`,"pr-open":`warning`,merged:`success`,closed:`neutral`,failed:`danger`,expired:`unknown`};function H(e){return e.state===`pr-open`&&!e.pr?`PR unverified`:e.state===`pr-open`&&e.pr?.draft?`Draft PR`:B[e.state]??e.state}function U(e){return o.includes(e)}function W(e){return e===`queued`||e===`launching`||e===`running`}var G=864e5;function K(e,t=Date.now()){let n=e=>{let n=Date.parse(e.updatedAt);return Number.isFinite(n)&&t-n<G},r=e.filter(e=>!U(e.state)||n(e)).sort((e,t)=>(Date.parse(t.createdAt)||0)-(Date.parse(e.createdAt)||0));return{shown:r.slice(0,6),hidden:Math.max(0,r.length-6)}}function q(e){return e.filter(e=>W(e.state)).length}function J(e,t=Date.now()){let n=e.state===`queued`||e.state===`launching`?e.createdAt:e.launchedAt??e.createdAt,r=i(n,t),a=e.state===`queued`?`queued`:e.state===`failed`?`tried`:`started`;return`${e.repo} from ${e.baseBranch}${r?` · ${a} ${r}`:``}`}function Y(e,t=Date.now()){return e.report?.summary&&(e.state===`pr-open`||e.state===`merged`)?`Cloud session reports (unverified): ${C(e.report.summary,t)}`:e.stateReason?C(e.stateReason,t):null}function ae(e){return e.state!==`merged`&&e.state!==`closed`}var X=new Intl.NumberFormat(`en-US`);function oe(e){let t={},n=e.repo.trim(),r=e.baseBranch.trim(),i=e.prompt.trim();return n?T.test(n)||(t.repo=`Use the GitHub owner/name form, like ashlrai/ashlr-hub.`):t.repo=`Enter the GitHub repository as owner/name.`,r&&!D(r)&&(t.baseBranch=`That isn't a branch name git accepts.`),i?i.length>2e4&&(t.prompt=`The task is ${X.format(i.length)} characters; the limit is ${X.format(s)}.`):t.prompt=`Describe the task for the cloud session.`,Object.keys(t).length>0?{ok:!1,errors:t}:{ok:!0,request:{repo:n,...r?{baseBranch:r}:{},prompt:i}}}var Z=[{field:`total`,label:`Credits on the account`,hint:`What claude.ai says you have.`,money:!0,integer:!1,min:0,max:1e5},{field:`spent`,label:`Already spent`,hint:`Spent before Verse tracked it, or a correction after checking.`,money:!0,integer:!1,min:-1e5,max:1e5},{field:`perSession`,label:`Estimate per session`,hint:`Flat cost Verse counts for each launch.`,money:!0,integer:!1,min:.01,max:1e3},{field:`maxPerDay`,label:`Sessions per day`,hint:`From every origin, counted per local day.`,money:!1,integer:!0,min:0,max:500},{field:`maxConcurrent`,label:`Running at once`,hint:`Launching or running together.`,money:!1,integer:!0,min:1,max:50},{field:`selfImproveMax`,label:`Self-improvement per day`,hint:`Launches Verse may make on its own.`,money:!1,integer:!0,min:0,max:100},{field:`selfImproveMaxOpen`,label:`Open self-improvement PRs`,hint:`Self-improvement waits while this many await review.`,money:!1,integer:!0,min:1,max:50},{field:`reserve`,label:`Reserve`,hint:`Self-improvement stops under this estimated balance.`,money:!0,integer:!1,min:0,max:1e5}];function Q(e){let t=e.selfImprove.maxOpenPrs;return typeof t==`number`&&Number.isFinite(t)?t:a.selfImprove.maxOpenPrs}function $(e){return String(Number.isInteger(e)?e:Math.round(e*100)/100)}function se(e){return{total:$(e.creditsTotalUsd),spent:$(e.creditsSpentAdjustmentUsd),perSession:$(e.estimatedCostPerSessionUsd),maxPerDay:$(e.maxSessionsPerDay),maxConcurrent:$(e.maxConcurrent),selfImprove:e.selfImprove.enabled,selfImproveMax:$(e.selfImprove.maxPerDay),selfImproveMaxOpen:$(Q(e)),reserve:$(e.selfImprove.reserveUsd)}}function ce(e,t){let n={},r={};for(let t of Z){let i=e[t.field].trim().replace(/^\$/,``),a=i===``?NaN:Number(i);Number.isFinite(a)?t.integer&&!Number.isInteger(a)?n[t.field]=`Enter a whole number.`:a<t.min||a>t.max?n[t.field]=t.money?`Between ${k(t.min)} and ${k(t.max)}.`:`Between ${X.format(t.min)} and ${X.format(t.max)}.`:r[t.field]=a:n[t.field]=`Enter a number.`}if(Object.keys(n).length>0)return{ok:!1,errors:n};let i={},a=(e,t)=>Math.abs(e-t)<.005;a(r.total,t.creditsTotalUsd)||(i.creditsTotalUsd=r.total),a(r.spent,t.creditsSpentAdjustmentUsd)||(i.creditsSpentAdjustmentUsd=r.spent),a(r.perSession,t.estimatedCostPerSessionUsd)||(i.estimatedCostPerSessionUsd=r.perSession),a(r.maxPerDay,t.maxSessionsPerDay)||(i.maxSessionsPerDay=r.maxPerDay),a(r.maxConcurrent,t.maxConcurrent)||(i.maxConcurrent=r.maxConcurrent);let o={};return e.selfImprove!==t.selfImprove.enabled&&(o.enabled=e.selfImprove),a(r.selfImproveMax,t.selfImprove.maxPerDay)||(o.maxPerDay=r.selfImproveMax),a(r.selfImproveMaxOpen,Q(t))||(o.maxOpenPrs=r.selfImproveMaxOpen),a(r.reserve,t.selfImprove.reserveUsd)||(o.reserveUsd=r.reserve),Object.keys(o).length>0&&(i.selfImprove=o),{ok:!0,update:i,changed:Object.keys(i).length>0}}function le(e){return e.overview?I(e.overview.seat)||(e.repo?P(e.overview.budget.canLaunch,`The cloud budget does not allow another launch right now.`)||(e.prompt.trim()?e.prompt.trim().length>2e4?`The message is over ${X.format(s)} characters — trim it to run it in the cloud.`:null:`Type the task in the message box first.`):e.rootsLoading?`Reading this chat's project…`:`This chat's project has no GitHub origin, so a cloud session has nothing to clone.`):e.overviewReason??`The cloud lane did not answer.`}export{J as C,Y as S,S as T,O as _,L as a,M as b,ae as c,k as d,P as f,le as g,R as h,V as i,K as l,z as m,w as n,se as o,q as p,ie as r,ce as s,Z as t,A as u,I as v,oe as w,H as x,N as y};
|
|
2
|
+
//# sourceMappingURL=cloud-model-BDivRMqv.js.map
|
package/dist/core/web/public/next/assets/{cloud-model-CfRydq8N.js.map → cloud-model-BDivRMqv.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"cloud-model-CfRydq8N.js","names":[],"sources":["../../../../../../__vite-browser-external","../../../../../../src/core/util/scrub.ts","../../../../../../src/web-ui/routes/verse/cloud/cloud-model.ts"],"sourcesContent":["module.exports = {}","/**\n * src/core/util/scrub.ts — THE shared secret-scrub utility (single source of truth).\n *\n * Extracted from judge-trace.ts (stripSecrets) and extended to cover all\n * patterns previously missing from handlers.ts (scrubDiffSecrets). Since 3.10\n * the two historical duplicates delegate here instead of drifting:\n * - src/core/generative/invent.ts re-exports `scrubSecrets` verbatim.\n * - src/core/knowledge/index.ts runs this scrub FIRST, then its own\n * stricter corpus patterns (32-hex, `/`-bearing base64, Stripe) that\n * `ashlr verify-safety` pins by array length. Knowledge chunks are never\n * identity-checked, so the stricter pass is safe there and must not leak\n * into this default (see \"IDENTITY CALLERS\" below).\n *\n * Patterns covered by `scrubSecrets`:\n * 0. PEM/private-key blocks\n * 1. sk- API keys (Anthropic, OpenAI, etc.)\n * 2. GitHub tokens: ghp_, gho_, ghu_, ghs_, ghr_, gha_, github_pat_ (classic\n * and fine-grained `github_pat_<22>_<59>`)\n * 3. Bearer / Token / Authorization header values\n * 4. Generic key=value secrets: api_key, secret, token, password, passwd,\n * auth, credential, client_secret, private_key, refresh_token,\n * access_token, connection_string (including ASHLR_* env vars)\n * 5. Slack tokens: xox[baprs]-…\n * 6. AWS access key IDs: AKIA…\n * 7. JWTs: eyJ….<sig>\n * 8. Bare hex-64 (SHA-256 / API key hex form)\n * 9. GitLab/HuggingFace/npm/Google token prefixes\n * 10. URL authority passwords and long base64 blobs\n * 11. (3.10) Telegram bot tokens `<bot id>:<33–35 chars>` — bare, in\n * `api.telegram.org/bot<token>/…` URLs, and under any key name\n * 12. (3.10) xAI API keys `xai-…`\n * 13. (3.10) Suffix-named assignments the generic rule's `\\b` anchor misses:\n * SCREAMING env vars (`GROQ_API_KEY=…`, `DB_PASSWORD=…`), snake_case\n * (`bot_token: …`) and camelCase (`githubToken: …`) names\n * 14. (3.10) Quoted JSON/YAML keys (`\"password\": \"…\"`, `\\\"botToken\\\":\\\"…\\\"`),\n * which rule 4 never matched because the closing quote sits between the\n * name and the colon\n * 15. (3.10) Slack / Discord incoming-webhook URL paths\n *\n * `scrubPrivateText` layers two PRIVACY redactions on top for free text that\n * is persisted or exported (reasoning store, session export, logs):\n * - home-directory paths → `~` (on by default)\n * - email addresses → `[REDACTED]` (opt-in)\n *\n * IDENTITY CALLERS (why home paths/emails are NOT in `scrubSecrets`): many\n * ledgers validate values with `scrubSecrets(v) === v` (dispatch manifests,\n * worked/dispatch-production ledgers, best-of-n, generated-repair) and several\n * of those values are absolute repo paths or git author identities. Rewriting\n * `/Users/<me>/repo` → `~/repo` in the default scrub would make every such\n * record look \"secret-bearing\" and be rejected, and would corrupt functional\n * paths. Privacy redaction is therefore an explicit, separate call.\n *\n * IDEMPOTENCE is load-bearing: records persisted after scrubbing are later\n * re-validated with `scrubSecrets(v) === v`, and `canonicalizeProposalDiff`\n * iterates to a fixed point. Every rule's output is a fixed point of every\n * rule (pinned by test/scrub-310.test.ts).\n *\n * PURITY: no I/O, no side-effects. `scrubPrivateText` reads the home directory\n * from the environment (no filesystem access) unless `homes` is supplied.\n */\n\nimport { homedir } from 'node:os';\n\nconst REDACTED = '[REDACTED]';\n\nfunction scrubLongBase64Like(match: string): string {\n // Preserve ordinary Git SHA-1 commit ids for forensic audit trails. The\n // explicit hex-64 rule above still redacts longer raw-key shapes.\n if (/^[0-9a-fA-F]{40}$/.test(match)) return match;\n // Avoid erasing obvious low-entropy test/log filler such as xxxxx...; real\n // token-like blobs still have mixed character content and are redacted below.\n const repeatedCandidate = match.replace(/^\\+/, '').replace(/=+$/, '');\n if (/^(.)\\1{39,}$/.test(repeatedCandidate)) return match;\n return REDACTED;\n}\n\n// ---------------------------------------------------------------------------\n// 3.10 additions\n// ---------------------------------------------------------------------------\n\n/**\n * Telegram bot token: numeric bot id (8–10 digits today; 6–12 tolerated) +\n * ':' + a 33–35 char url-safe secret (35 for issued tokens; Telegram's own\n * documentation example is 34). The optional `bot` prefix covers the Bot API\n * URL form (`https://api.telegram.org/bot<id>:<secret>/sendMessage`), where a\n * plain `\\b` anchor fails because `t` and the first digit are both word chars.\n * The narrow secret length plus the non-word lookarounds keep\n * `<epoch-seconds>:<uuid|hex32|sha1>` style ids (36 / 32 / 40 chars) intact —\n * several ledgers identity-check such ids.\n */\nconst TELEGRAM_BOT_TOKEN = /\\d{6,12}:[A-Za-z0-9_-]{33,35}(?![A-Za-z0-9_-])/g;\n\n/**\n * Left-boundary check for a Telegram candidate, done in the replacer instead of\n * a leading lookbehind: a regex that starts with `\\d` lets V8 skip ahead to\n * digits, which measured ~3x cheaper on 1 MB of prose than testing a\n * lookbehind at every offset. Accept when the id starts the string, follows a\n * non-word char, or follows a `bot` that itself follows a non-word char.\n */\nfunction redactTelegram(match: string, offset: number, whole: string): string {\n const boundary = (i: number): boolean => i < 0 || !/[A-Za-z0-9_]/.test(whole[i]!);\n if (boundary(offset - 1)) return REDACTED;\n if (whole.slice(offset - 3, offset) === 'bot' && boundary(offset - 4)) return REDACTED;\n return match;\n}\n\n/**\n * Incoming-webhook URLs are bearer credentials in their path (anyone holding\n * the URL can post). Host + fixed path prefix are kept for forensics.\n */\nconst WEBHOOK_URL =\n /(https?:\\/\\/(?:hooks\\.slack\\.com\\/(?:services|workflows|triggers)|(?:ptb\\.|canary\\.)?discord(?:app)?\\.com\\/api\\/webhooks)\\/)[A-Za-z0-9_/-]{8,}/gi;\n\n/** xAI (Grok) API keys: `xai-` + ≥20 alphanumerics (80 in practice). */\nconst XAI_API_KEY = /(?<![A-Za-z0-9_-])xai-[A-Za-z0-9]{20,}/g;\n\n/**\n * Value shape shared by the suffix-name rules: optional quote, ≥8 chars that\n * are not whitespace/separators/quotes, optional closing quote. Mirrors rule 4.\n */\nconst ASSIGNED_VALUE = String.raw`\\s*[=:]\\s*[\"']?[^\\s,;'\"]{8,}[\"']?`;\n\n/**\n * SCREAMING_SNAKE env-var names ending in a secret noun. Rule 4's `\\b(token|…)`\n * never fires inside `GROQ_API_KEY` / `TELEGRAM_BOT_TOKEN` because `_` is a\n * word char, so the whole `.env` idiom slipped through. Case-SENSITIVE on\n * purpose: `sort_key=…` in prose/code must not match.\n */\nconst ENV_SECRET_ASSIGNMENT = new RegExp(\n String.raw`(?<![A-Za-z0-9_$])([A-Z][A-Z0-9_]*_(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|CREDENTIALS?|AUTH|DSN))` +\n ASSIGNED_VALUE,\n 'g',\n);\n\n/** snake_case names with a secret suffix (`bot_token`, `db_password`). */\nconst SNAKE_SECRET_ASSIGNMENT = new RegExp(\n String.raw`(?<![A-Za-z0-9_$])([a-z][a-z0-9_]*_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key))` +\n ASSIGNED_VALUE,\n 'g',\n);\n\n/**\n * Cheap literal-led prefilters for the snake/camel rules. Those two regexes\n * start at every lowercase word, which measured ~3–4.5 ms per MB; the\n * prefilters cost <1 ms and skip them on the common text that has no\n * `…Token =` / `…_password:` assignment at all.\n */\nconst SNAKE_PREFILTER = /_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key)\\s*[=:]/;\nconst CAMEL_PREFILTER = /(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?)\\s*[=:]/;\n\n/** camelCase names with a secret suffix (`githubToken`, `clientSecret`). */\nconst CAMEL_SECRET_ASSIGNMENT = new RegExp(\n String.raw`(?<![A-Za-z0-9_$])([a-z][A-Za-z0-9]*(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?))` +\n ASSIGNED_VALUE,\n 'g',\n);\n\n/**\n * Quoted keys (JSON, YAML, JS object literals), including JSON-escaped quotes\n * inside a serialized string (`\\\"password\\\":\\\"…\\\"`). The name must END in a\n * secret noun (`max_tokens`, `tokenizer`, `author` do not). Structure is kept —\n * only the value becomes `[REDACTED]` — so a scrubbed JSON line stays parseable.\n */\nconst QUOTED_SECRET_KEY =\n /(\\\\?[\"'])([A-Za-z0-9_.-]*(?:api[_-]?key|token|secret|password|passwd|pwd|credentials?|private[_-]?key|access[_-]?key|secret[_-]?key|signing[_-]?key|auth|connection[_-]?string))\\1(\\s*:\\s*)(\\\\?[\"'])([^\"'\\s\\\\]{8,})\\4/gi;\n\n/**\n * Values in CODE that merely reference a secret (a member chain, call, template\n * or env interpolation) rather than contain one. Scrubbed diffs are persisted\n * and applied as proposals, so turning `const GITHUB_TOKEN = process.env.GITHUB_TOKEN`\n * into `GITHUB_TOKEN=[REDACTED]` would corrupt a legitimate change. Applies to\n * the 3.10 suffix rules only — rule 4's historical behaviour is unchanged.\n */\nfunction isCodeReference(value: string): boolean {\n const v = value.replace(/^[\"']|[\"']$/g, '');\n return (\n /^[A-Za-z_$][\\w$]*(?:\\??\\.[A-Za-z_$][\\w$]*)+[)\\]]*$/.test(v) || // process.env.X, opts.apiToken\n /^[A-Za-z_$][\\w$.]*\\(/.test(v) || // getToken(), cfg.read(\n /^(?:\\$\\{|\\$[A-Za-z_]|`|<)/.test(v) // ${VAR}, $VAR, `template`, <placeholder>\n );\n}\n\n/**\n * Type annotations and identifier-only right-hand sides (`refreshToken: RefreshTokenRecord`,\n * `botToken: undefined`) carry no digits; real tokens essentially always do.\n * Only the camel/snake rules use this skip (they fire inside ordinary TS code);\n * the SCREAMING env rule still redacts a letters-only `.env` password.\n */\nfunction isIdentifierOnly(value: string): boolean {\n const v = value.replace(/^[\"']|[\"']$/g, '');\n return !/\\d/.test(v) && /^[A-Za-z_$][A-Za-z_$.<>[\\]|&?!()]*$/.test(v);\n}\n\n/** A value an earlier rule (or an earlier pass) already replaced. */\nfunction isAlreadyRedacted(value: string): boolean {\n return value.replace(/^[\"']|[\"']$/g, '') === REDACTED;\n}\n\nfunction redactAssignment(name: string, match: string, value: string, allowIdentifiers: boolean): string {\n // Idempotence: `NAME = \"[REDACTED]\"` must stay byte-identical on a re-scrub.\n if (isAlreadyRedacted(value)) return match;\n if (isCodeReference(value)) return match;\n if (allowIdentifiers && isIdentifierOnly(value)) return match;\n return `${name}=${REDACTED}`;\n}\n\nfunction valueOf(match: string, name: string): string {\n return match.slice(name.length).replace(/^\\s*[=:]\\s*/, '');\n}\n\n/**\n * Scrub recognised secret patterns from `text`.\n * Returns the scrubbed string with secrets replaced by `[REDACTED]`.\n * Never throws. Idempotent: `scrubSecrets(scrubSecrets(x)) === scrubSecrets(x)`.\n */\nexport function scrubSecrets(text: string): string {\n try {\n let out = text\n // 0. PEM/private-key blocks. Run before generic/base64 redaction so\n // BEGIN/END markers do not survive with only the body removed.\n .replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[\\s\\S]*?-----END[ A-Z]*PRIVATE KEY-----/g, REDACTED)\n .replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[^\\n]*/g, REDACTED)\n // 11. Telegram bot tokens — before rule 4 so a `botToken: <id>:<secret>`\n // value is removed whole even when its key name is not recognised.\n .replace(TELEGRAM_BOT_TOKEN, redactTelegram)\n // 15. Slack / Discord incoming-webhook URLs (credential in the path).\n .replace(WEBHOOK_URL, '$1[REDACTED]')\n // 12. xAI keys — before rule 10 so the `xai-` prefix does not survive\n // next to a base64-redacted tail.\n .replace(XAI_API_KEY, REDACTED)\n // 1. sk- API keys (Anthropic, OpenAI, etc.)\n .replace(/\\bsk-[A-Za-z0-9_-]{16,}/g, REDACTED)\n // 2. GitHub tokens (classic prefixes + fine-grained github_pat_<22>_<59>)\n .replace(/\\bgh[poursa]_[A-Za-z0-9]{16,}/g, REDACTED)\n .replace(/\\bgithub_pat_[A-Za-z0-9_]{22,}/g, REDACTED)\n // 3. Bearer / Token / Authorization header values\n .replace(/\\b(Bearer|Token|Authorization)\\s+[A-Za-z0-9\\-._~+/]+=*/gi, '$1 [REDACTED]')\n // 4. Generic key=value secret patterns. ASHLR_* env vars are only\n // redacted when they look like assignments, not plain audit metadata\n // such as \"keys=query\".\n .replace(\n /\\b(api[_-]?key|api[_-]?token|secret|secret[_-]?key|token|password|passwd|pwd|auth|credential|client[_-]?secret|private[_-]?key|access[_-]?token|auth[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|connection[_-]?string|conn[_-]?str|_?auth[_-]?token|ASHLR_[A-Z_]+)\\s*[=:]\\s*[\"']?[^\\s,;'\"]{8,}[\"']?/gi,\n '$1=[REDACTED]',\n )\n // 5. Slack tokens\n .replace(/\\bxox[baprs]-[A-Za-z0-9-]{10,}/gi, REDACTED)\n // 6. AWS access key IDs\n .replace(/\\bAKIA[0-9A-Z]{16}\\b/g, REDACTED)\n // 7. JWTs (eyJ header.payload.sig)\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, REDACTED)\n // 8. Bare hex-64 strings (SHA-256 / hex API keys)\n .replace(/\\b[0-9a-fA-F]{64,}\\b/g, REDACTED)\n // 9. Other common provider token prefixes.\n .replace(/\\bglpat-[A-Za-z0-9_-]{16,}/g, REDACTED)\n .replace(/\\bhf_[A-Za-z0-9]{16,}\\b/g, REDACTED)\n .replace(/\\bnpm_[A-Za-z0-9]{16,}\\b/g, REDACTED)\n .replace(/\\bAIza[0-9A-Za-z_-]{35}\\b/g, REDACTED)\n // 10. URL passwords and long base64-ish blobs.\n .replace(/(:\\/\\/[^:\\s/@]*:)[^@\\s]+(@)/g, '$1[REDACTED]$2')\n .replace(/(?<![/\\w])[A-Za-z0-9+]{40,}={0,2}(?![/\\w])/g, scrubLongBase64Like)\n // 13. Suffix-named assignments rule 4's `\\b` anchor cannot see. LAST, so\n // every token-shape rule above has already turned a JWT/AKIA/hex value\n // into [REDACTED]; that marker is left untouched below. Running these\n // earlier broke idempotence: a dotted JWT reads like a member chain\n // (skipped as a code reference), then pass 2 rewrote `NAME = \"[REDACTED]\"`.\n .replace(ENV_SECRET_ASSIGNMENT, (m: string, name: string) => redactAssignment(name, m, valueOf(m, name), false));\n if (SNAKE_PREFILTER.test(out)) {\n out = out.replace(SNAKE_SECRET_ASSIGNMENT, (m: string, name: string) => redactAssignment(name, m, valueOf(m, name), true));\n }\n if (CAMEL_PREFILTER.test(out)) {\n out = out.replace(CAMEL_SECRET_ASSIGNMENT, (m: string, name: string) => redactAssignment(name, m, valueOf(m, name), true));\n }\n // 14. Quoted keys: keep the JSON/YAML structure, replace the value only.\n return out.replace(\n QUOTED_SECRET_KEY,\n (m: string, q: string, name: string, sep: string, vq: string, value: string) =>\n isAlreadyRedacted(value) || isCodeReference(value) ? m : `${q}${name}${q}${sep}${vq}${REDACTED}${vq}`,\n );\n } catch {\n // Never throws — return original text on unexpected error.\n return text;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Privacy redaction for persisted / exported free text\n// ---------------------------------------------------------------------------\n\nexport interface PrivateScrubOptions {\n /** Rewrite home-directory paths to `~`. Default: true. */\n readonly homePaths?: boolean;\n /** Replace email addresses with `[REDACTED]`. Default: false (opt-in). */\n readonly emails?: boolean;\n /**\n * Home directories to collapse. Default: `os.homedir()`, `$HOME`,\n * `$USERPROFILE`. Supplied explicitly by callers that already resolved them\n * (and by tests).\n */\n readonly homes?: readonly string[];\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction defaultHomes(): string[] {\n const out: string[] = [];\n try {\n out.push(homedir());\n } catch {\n // homedir() can throw when no home is resolvable; env fallbacks below.\n }\n if (typeof process === 'undefined') return out;\n for (const key of ['HOME', 'USERPROFILE'] as const) {\n const v = process.env[key];\n if (v) out.push(v);\n }\n return out;\n}\n\n/**\n * Case-insensitive filesystems (macOS APFS default, Windows) name one home many\n * ways. A function, not a module-level constant: the Verse web UI imports\n * `scrubSecrets` from this module (routes/verse/cloud/cloud-model.ts), and a\n * top-level `process.platform` read throws `ReferenceError: process is not\n * defined` in the browser — which took down every lazy section that pulls the\n * cloud model in (Command, Fleet). Nothing here may touch `process` at load.\n */\nfunction caseInsensitiveFs(): boolean {\n if (typeof process === 'undefined') return false;\n return process.platform === 'darwin' || process.platform === 'win32';\n}\n\n/**\n * Other users' home roots (`/Users/<name>`, `/home/<name>`, `C:\\Users\\<name>`):\n * the username is the PII, so the whole root collapses to `~` too. macOS's\n * `/Users/Shared` is a system directory, not a person.\n */\nconst GENERIC_HOME_ROOT =\n /(?<![\\w.-])(?:\\/(?:Users|home)\\/(?!Shared(?![\\w.-]))[A-Za-z0-9._-]+|[A-Za-z]:\\\\Users\\\\[A-Za-z0-9._-]+)(?![\\w.-])/g;\n\n/**\n * Collapse home-directory paths to `~`. A home only matches as a whole path\n * prefix on segment boundaries: `/Users/me/x` → `~/x`; `/opt/Users/me` is left\n * alone, and `/Users/meagan` is never split into `~agan` (it is another\n * person's home, collapsed whole by the generic rule). Never throws.\n */\nexport function redactHomePaths(text: string, homes: readonly string[] = defaultHomes()): string {\n try {\n let out = text;\n const unique = Array.from(\n new Set(\n homes\n .map((h) => h.replace(/[\\\\/]+$/, ''))\n // A bare root (\"/\", \"C:\") would collapse every absolute path.\n .filter((h) => h.length > 1 && !/^[A-Za-z]:$/.test(h)),\n ),\n ).sort((a, b) => b.length - a.length);\n for (const home of unique) {\n const re = new RegExp(`(?<![\\\\w.-])${escapeRegExp(home)}(?![\\\\w.-])`, caseInsensitiveFs() ? 'gi' : 'g');\n out = out.replace(re, '~');\n }\n return out.replace(GENERIC_HOME_ROOT, '~');\n } catch {\n return text;\n }\n}\n\n/**\n * Email addresses in free text. `git@host:org/repo` SSH remotes are not\n * personal addresses and stay intact; `pkg@1.2.3` version pins never match\n * because the final label must be alphabetic.\n */\nconst EMAIL = /(?<![\\w.%+-])([A-Za-z0-9._%+-]+)@[A-Za-z0-9-]+(?:\\.[A-Za-z0-9-]+)*\\.[A-Za-z]{2,}(?![\\w-])/g;\n\n/** Replace email addresses with `[REDACTED]`. Never throws. */\nexport function redactEmails(text: string): string {\n try {\n return text.replace(EMAIL, (m: string, local: string) => (local === 'git' ? m : REDACTED));\n } catch {\n return text;\n }\n}\n\n/**\n * Secrets + privacy scrub for free text that is persisted or exported\n * (reasoning steps, session exports, crash logs). Runs `scrubSecrets`, then\n * collapses home paths (default on) and, when asked, emails. Home paths are\n * collapsed on both sides of the secret scrub so a secret rule can never split\n * a home prefix into an unrecognisable remainder (same idiom as\n * `sanitizePublicJson`). Never throws. Idempotent.\n */\nexport function scrubPrivateText(text: string, options: PrivateScrubOptions = {}): string {\n const homePaths = options.homePaths !== false;\n const homes = homePaths ? (options.homes ?? defaultHomes()) : [];\n let out = homePaths ? redactHomePaths(text, homes) : text;\n out = scrubSecrets(out);\n if (homePaths) out = redactHomePaths(out, homes);\n if (options.emails === true) out = redactEmails(out);\n return out;\n}\n\n/** Stable bytes for proposal persistence, hashing, and provenance signing. */\nexport function canonicalizeProposalDiff(text: string): string {\n let current = text;\n for (let pass = 0; pass < 8; pass += 1) {\n const next = scrubSecrets(current)\n .replace(/\\bsk_(?:live|test)_[A-Za-z0-9_]{16,}\\b/g, REDACTED)\n .replace(/\\b(?:AKIA|ASIA|AROA)[0-9A-Z]{16}\\b/g, REDACTED)\n .replace(/\\b[0-9a-fA-F]{32,}\\b/g, REDACTED);\n if (next === current) return current;\n current = next;\n }\n throw new Error('proposal diff canonicalization did not converge');\n}\n","/**\n * routes/verse/cloud/cloud-model.ts — the cloud lane's words and decisions as\n * pure functions (3.11 unit C3), so the card, the Usage panel, the Fleet chip\n * and the composer action say the same thing and the copy is tested as a\n * table. No React here.\n *\n * Copy rules (DESIGN §13.8, and the cloud contract's own):\n * - spend is ALWAYS an estimate and says so — Claude does not expose the\n * credit balance, so every dollar figure carries \"estimate\" beside it;\n * - server prose (gate reasons, state reasons, report summaries) is scrubbed\n * for secrets before `tidyProse` makes ISO instants readable in local time;\n * - times are local and relative (\"started 5m ago\"), never ISO;\n * - a state is always a WORD beside any colour.\n */\nimport {\n CLOUD_PROMPT_MAX_CHARS,\n CLOUD_TERMINAL_STATES,\n DEFAULT_CLOUD_BUDGET,\n type CloudBudgetUpdate,\n type CloudBudgetV1,\n type CloudBudgetView,\n type CloudSeatStatus,\n type CloudTaskState,\n type CloudTaskV1,\n} from '../../../../core/cloud/types.js';\nimport { describeResetAt } from '../../../../core/verse/seat-readiness.js';\nimport { scrubSecrets } from '../../../../core/util/scrub.js';\nimport type { Tone } from '../../../components/primitives/StatusBadge.js';\nimport type { MeterTone } from '../../../components/primitives/Meter.js';\nimport { tidyProse } from '../autonomy/format.js';\nimport { relativePhrase } from '../context/context-model.js';\nimport { usedPercentText } from '../percent-text.js';\n\n/** Cloud text can originate in a PR body; keep every card reason safe even outside the HTTP sanitizer. */\nfunction safeCloudProse(text: string, now?: number): string {\n return tidyProse(scrubSecrets(text), now);\n}\n\n/** The repo a new task targets unless the operator names another (the self-improvement default). */\nexport const CLOUD_DEFAULT_REPO = DEFAULT_CLOUD_BUDGET.selfImprove.repo;\n\n/** Same rule the service enforces (core/cloud/service.ts), checked here so the dialog can say so first. */\nexport const CLOUD_REPO_PATTERN = /^[A-Za-z0-9-]+\\/[A-Za-z0-9._-]+$/;\n\n/**\n * A branch name git would accept, conservatively: no spaces or control\n * characters, no `..`, no leading `-` or `/`, no trailing `/` or `.lock`.\n * The server re-checks it against origin; this only catches typing slips.\n */\nconst BRANCH_CHARS = /^[A-Za-z0-9._/+-]{1,200}$/;\nexport function isBranchName(value: string): boolean {\n if (!BRANCH_CHARS.test(value)) return false;\n if (value.startsWith('-') || value.startsWith('/') || value.endsWith('/') || value.endsWith('.') || value.endsWith('.lock')) return false;\n return !value.includes('..') && !value.includes('//');\n}\n\n/** Only these hosts become links: the ids came from a CLI's stdout and gh's JSON. */\nexport function safeHref(url: string | null | undefined, host: 'claude.ai' | 'github.com'): string | null {\n if (typeof url !== 'string' || url.length > 2_048) return null;\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'https:' && parsed.hostname === host ? parsed.toString() : null;\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Money and the credits meter\n// ---------------------------------------------------------------------------\n\n/** \"$250\", \"$12.50\" — whole dollars stay whole; never \"-$0\". */\nexport function formatDollars(value: number): string {\n if (!Number.isFinite(value)) return '—';\n const v = Math.abs(value) < 0.005 ? 0 : value;\n const text = Number.isInteger(v) ? String(Math.abs(v)) : Math.abs(v).toFixed(2);\n return `${v < 0 ? '−' : ''}$${text}`;\n}\n\nexport interface CreditsMeterView {\n /** Remaining, clamped at 0 for the bar (the text says when it went below). */\n value: number;\n max: number | null;\n /** \"$212 of $250 · estimate\" */\n text: string;\n /** \"15% used\" — the one percent rule. */\n usedText: string;\n tone: MeterTone;\n /** A plain sentence when the estimate is at or under the self-improvement reserve. */\n warning: string | null;\n}\n\nexport function creditsMeter(view: CloudBudgetView): CreditsMeterView {\n const total = view.creditsTotalUsd;\n const remaining = view.estimatedRemainingUsd;\n const reserve = view.budget.selfImprove.reserveUsd;\n const max = total > 0 ? total : null;\n const used = max === null ? null : ((total - Math.max(0, remaining)) / total) * 100;\n const tone: MeterTone = remaining <= 0 ? 'danger' : remaining < reserve ? 'warning' : 'accent';\n const warning = remaining <= 0\n ? 'The estimate says the credits are spent. Check the real balance on claude.ai and adjust the budget.'\n : remaining < reserve\n ? `Under the ${formatDollars(reserve)} reserve, so Verse stops launching self-improvement tasks.`\n : null;\n return {\n value: Math.max(0, remaining),\n max,\n text: `${formatDollars(Math.max(0, remaining))} of ${formatDollars(total)} · estimate`,\n usedText: used === null ? 'no credit total set' : `${usedPercentText(used)} used`,\n tone,\n warning,\n };\n}\n\n/** The next local midnight — when the per-day caps start counting again. */\nexport function nextLocalMidnight(now: number): number {\n const d = new Date(now);\n d.setHours(24, 0, 0, 0);\n return d.getTime();\n}\n\n/** \"3 of 20 sessions today · 1 running\" plus when the daily count resets. */\nexport function sessionsLine(view: CloudBudgetView, now: number = Date.now()): string {\n const reset = describeResetAt(new Date(nextLocalMidnight(now)).toISOString(), now);\n const running = view.running === 1 ? '1 running' : `${view.running} running`;\n return `${view.sessionsToday} of ${view.budget.maxSessionsPerDay} sessions today · ${running}${reset ? ` · resets ${reset}` : ''}`;\n}\n\nexport function selfImproveLine(view: CloudBudgetView): string {\n const si = view.budget.selfImprove;\n if (!si.enabled) return 'Self-improvement is off. Verse launches cloud tasks only when you ask.';\n return `${view.selfImproveToday} of ${si.maxPerDay} self-improvement launches today, on ${si.repo}. Stops under a ${formatDollars(si.reserveUsd)} estimated balance.`;\n}\n\n/** A gate's reason, fit to print (null when the gate is open). */\nexport function gateText(gate: { ok: boolean; reason: string | null }, fallback: string): string | null {\n if (gate.ok) return null;\n return gate.reason ? safeCloudProse(gate.reason) : fallback;\n}\n\nexport const SEAT_NOT_READY = \"The Claude seat isn't set up on this Mac.\";\n\nexport function seatText(seat: CloudSeatStatus): string | null {\n if (seat.ready) return null;\n return seat.reason ? safeCloudProse(seat.reason) : SEAT_NOT_READY;\n}\n\n// ---------------------------------------------------------------------------\n// Standing: what the credit figure MEANS while the lane cannot launch\n// ---------------------------------------------------------------------------\n//\n// The credit figure is always an estimate (a flat per-session cost counted\n// against the total the operator typed in; the real balance is not\n// readable). While the lane can launch, that estimate is headroom and a meter\n// is the honest picture. While the Claude seat is NOT set up nothing can\n// launch, so \"$250 of $250 left\" beside \"the seat isn't set up\" read as live\n// headroom the operator could not use. Then the setup blocker is the STATE,\n// and the credits a secondary, visibly approximate figure:\n//\n// Cloud: not set up · ~$250 credits\n//\n// Shared by Command's Cloud card, Usage's Cloud credits panel and the\n// Resources drawer's cloud card.\n\n/** The state word shown in place of the meter while the seat is missing. */\nexport const CLOUD_NOT_SET_UP_WORD = 'Not set up';\n\n/**\n * \"~$250 credits\" — whole dollars, because an estimate that cannot be spent\n * yet has no business showing cents. Never negative.\n */\nexport function approxCredits(remainingUsd: number): string {\n const v = Number.isFinite(remainingUsd) ? Math.max(0, Math.round(remainingUsd)) : 0;\n return `~$${v} credits`;\n}\n\n/** \"Cloud: not set up · ~$250 credits\" — the one-line summary of a lane that cannot launch. */\nexport function notSetUpLine(remainingUsd: number): string {\n return `Cloud: not set up · ${approxCredits(remainingUsd)}`;\n}\n\n/**\n * Why a launch button is disabled right now, or null when it may be pressed.\n * Seat first (nothing launches without it), then the budget gate.\n */\nexport function launchBlock(seat: CloudSeatStatus, budget: CloudBudgetView): string | null {\n return seatText(seat) ?? gateText(budget.canLaunch, 'The cloud budget does not allow another launch right now.');\n}\n\n// ---------------------------------------------------------------------------\n// Tasks\n// ---------------------------------------------------------------------------\n\nexport const STATE_WORD: Record<CloudTaskState, string> = {\n queued: 'Queued',\n launching: 'Launching',\n running: 'Running',\n 'pr-open': 'PR open',\n merged: 'Merged',\n closed: 'Closed',\n failed: 'Failed',\n expired: 'Expired',\n};\n\nexport const STATE_TONE: Record<CloudTaskState, Tone> = {\n queued: 'info',\n launching: 'info',\n running: 'running',\n 'pr-open': 'warning',\n merged: 'success',\n closed: 'neutral',\n failed: 'danger',\n expired: 'unknown',\n};\n\n/** A draft PR reads \"Draft PR\", not \"PR open\": the session may still be pushing. */\nexport function stateWord(task: Pick<CloudTaskV1, 'state' | 'pr'>): string {\n if (task.state === 'pr-open' && !task.pr) return 'PR unverified';\n if (task.state === 'pr-open' && task.pr?.draft) return 'Draft PR';\n return STATE_WORD[task.state] ?? task.state;\n}\n\nexport function isTerminal(state: CloudTaskState): boolean {\n return CLOUD_TERMINAL_STATES.includes(state);\n}\n\n/** In flight: counted by the Fleet chip and the \"running\" line. */\nexport function isInFlight(state: CloudTaskState): boolean {\n return state === 'queued' || state === 'launching' || state === 'running';\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n/** How many tasks the card lists before \"N more on GitHub\". */\nexport const CARD_TASK_LIMIT = 6;\n\n/**\n * What the card lists: everything still moving or waiting on review, then\n * anything that ended in the last 24 h (a failure you have not seen yet),\n * newest first. Older finished tasks live in `ashlr cloud list --all`.\n */\nexport function cardTasks(tasks: readonly CloudTaskV1[], now: number = Date.now()): { shown: CloudTaskV1[]; hidden: number } {\n const recent = (t: CloudTaskV1) => {\n const at = Date.parse(t.updatedAt);\n return Number.isFinite(at) && now - at < DAY_MS;\n };\n const listed = tasks\n .filter((t) => !isTerminal(t.state) || recent(t))\n .sort((a, b) => (Date.parse(b.createdAt) || 0) - (Date.parse(a.createdAt) || 0));\n return { shown: listed.slice(0, CARD_TASK_LIMIT), hidden: Math.max(0, listed.length - CARD_TASK_LIMIT) };\n}\n\nexport function inFlightCount(tasks: readonly CloudTaskV1[]): number {\n return tasks.filter((t) => isInFlight(t.state)).length;\n}\n\n/** \"ashlrai/ashlr-hub from master · started 5m ago\" */\nexport function taskMeta(task: CloudTaskV1, now: number = Date.now()): string {\n const when = task.state === 'queued' || task.state === 'launching' ? task.createdAt : task.launchedAt ?? task.createdAt;\n const phrase = relativePhrase(when, now);\n const verb = task.state === 'queued' ? 'queued' : task.state === 'failed' ? 'tried' : 'started';\n return `${task.repo} from ${task.baseBranch}${phrase ? ` · ${verb} ${phrase}` : ''}`;\n}\n\n/** The one line under a task's title: the report for a PR, else the state's reason. */\nexport function taskDetail(task: CloudTaskV1, now: number = Date.now()): string | null {\n if (task.report?.summary && (task.state === 'pr-open' || task.state === 'merged')) return `Cloud session reports (unverified): ${safeCloudProse(task.report.summary, now)}`;\n return task.stateReason ? safeCloudProse(task.stateReason, now) : null;\n}\n\n/** Dismiss is offered for anything Verse is still tracking; merged and closed tasks are already done. */\nexport function canDismiss(task: Pick<CloudTaskV1, 'state'>): boolean {\n return task.state !== 'merged' && task.state !== 'closed';\n}\n\n// ---------------------------------------------------------------------------\n// The launch form\n// ---------------------------------------------------------------------------\n\nexport interface LaunchDraft {\n repo: string;\n baseBranch: string;\n prompt: string;\n}\n\nexport type LaunchErrors = Partial<Record<keyof LaunchDraft, string>>;\n\nexport type LaunchValidation =\n | { ok: true; request: { repo: string; baseBranch?: string; prompt: string } }\n | { ok: false; errors: LaunchErrors };\n\nconst COUNT = new Intl.NumberFormat('en-US');\n\nexport function validateLaunch(draft: LaunchDraft): LaunchValidation {\n const errors: LaunchErrors = {};\n const repo = draft.repo.trim();\n const base = draft.baseBranch.trim();\n const prompt = draft.prompt.trim();\n if (!repo) errors.repo = 'Enter the GitHub repository as owner/name.';\n else if (!CLOUD_REPO_PATTERN.test(repo)) errors.repo = 'Use the GitHub owner/name form, like ashlrai/ashlr-hub.';\n if (base && !isBranchName(base)) errors.baseBranch = \"That isn't a branch name git accepts.\";\n if (!prompt) errors.prompt = 'Describe the task for the cloud session.';\n else if (prompt.length > CLOUD_PROMPT_MAX_CHARS) {\n errors.prompt = `The task is ${COUNT.format(prompt.length)} characters; the limit is ${COUNT.format(CLOUD_PROMPT_MAX_CHARS)}.`;\n }\n if (Object.keys(errors).length > 0) return { ok: false, errors };\n return { ok: true, request: { repo, ...(base ? { baseBranch: base } : {}), prompt } };\n}\n\n// ---------------------------------------------------------------------------\n// The budget form (Edit budget popover and the Usage panel share it)\n// ---------------------------------------------------------------------------\n\nexport interface BudgetForm {\n total: string;\n spent: string;\n perSession: string;\n maxPerDay: string;\n maxConcurrent: string;\n selfImprove: boolean;\n selfImproveMax: string;\n /** Self-improvement waits while this many of its PRs await review (3.13). */\n selfImproveMaxOpen: string;\n reserve: string;\n}\n\nexport type BudgetFormField = Exclude<keyof BudgetForm, 'selfImprove'>;\nexport type BudgetErrors = Partial<Record<BudgetFormField, string>>;\n\n/** Field → label and bounds. Bounds are the form's sanity check; the server clamps as well. */\nexport const BUDGET_FIELDS: ReadonlyArray<{\n field: BudgetFormField;\n label: string;\n hint: string;\n money: boolean;\n integer: boolean;\n min: number;\n max: number;\n}> = [\n { field: 'total', label: 'Credits on the account', hint: 'What claude.ai says you have.', money: true, integer: false, min: 0, max: 100_000 },\n { field: 'spent', label: 'Already spent', hint: 'Spent before Verse tracked it, or a correction after checking.', money: true, integer: false, min: -100_000, max: 100_000 },\n { field: 'perSession', label: 'Estimate per session', hint: 'Flat cost Verse counts for each launch.', money: true, integer: false, min: 0.01, max: 1_000 },\n { field: 'maxPerDay', label: 'Sessions per day', hint: 'From every origin, counted per local day.', money: false, integer: true, min: 0, max: 500 },\n { field: 'maxConcurrent', label: 'Running at once', hint: 'Launching or running together.', money: false, integer: true, min: 1, max: 50 },\n { field: 'selfImproveMax', label: 'Self-improvement per day', hint: 'Launches Verse may make on its own.', money: false, integer: true, min: 0, max: 100 },\n { field: 'selfImproveMaxOpen', label: 'Open self-improvement PRs', hint: 'Self-improvement waits while this many await review.', money: false, integer: true, min: 1, max: 50 },\n { field: 'reserve', label: 'Reserve', hint: 'Self-improvement stops under this estimated balance.', money: true, integer: false, min: 0, max: 100_000 },\n];\n\n/** A pre-3.13 server sends no maxOpenPrs: the form shows the default and never sends it unchanged. */\nfunction maxOpenPrsOf(b: CloudBudgetV1): number {\n const n = (b.selfImprove as Partial<CloudBudgetV1['selfImprove']>).maxOpenPrs;\n return typeof n === 'number' && Number.isFinite(n) ? n : DEFAULT_CLOUD_BUDGET.selfImprove.maxOpenPrs;\n}\n\nfunction numText(n: number): string {\n return Number.isInteger(n) ? String(n) : String(Math.round(n * 100) / 100);\n}\n\nexport function budgetFormFrom(b: CloudBudgetV1): BudgetForm {\n return {\n total: numText(b.creditsTotalUsd),\n spent: numText(b.creditsSpentAdjustmentUsd),\n perSession: numText(b.estimatedCostPerSessionUsd),\n maxPerDay: numText(b.maxSessionsPerDay),\n maxConcurrent: numText(b.maxConcurrent),\n selfImprove: b.selfImprove.enabled,\n selfImproveMax: numText(b.selfImprove.maxPerDay),\n selfImproveMaxOpen: numText(maxOpenPrsOf(b)),\n reserve: numText(b.selfImprove.reserveUsd),\n };\n}\n\nexport type BudgetPatch = { ok: true; update: CloudBudgetUpdate; changed: boolean } | { ok: false; errors: BudgetErrors };\n\n/**\n * The form as ONE update carrying only what changed — so two people editing\n * different fields never overwrite each other's numbers with stale ones.\n */\nexport function budgetPatch(form: BudgetForm, current: CloudBudgetV1): BudgetPatch {\n const errors: BudgetErrors = {};\n const values: Partial<Record<BudgetFormField, number>> = {};\n for (const spec of BUDGET_FIELDS) {\n const raw = form[spec.field].trim().replace(/^\\$/, '');\n const n = raw === '' ? Number.NaN : Number(raw);\n if (!Number.isFinite(n)) errors[spec.field] = 'Enter a number.';\n else if (spec.integer && !Number.isInteger(n)) errors[spec.field] = 'Enter a whole number.';\n else if (n < spec.min || n > spec.max) {\n errors[spec.field] = spec.money\n ? `Between ${formatDollars(spec.min)} and ${formatDollars(spec.max)}.`\n : `Between ${COUNT.format(spec.min)} and ${COUNT.format(spec.max)}.`;\n } else values[spec.field] = n;\n }\n if (Object.keys(errors).length > 0) return { ok: false, errors };\n const update: CloudBudgetUpdate = {};\n const same = (a: number, b: number) => Math.abs(a - b) < 0.005;\n if (!same(values.total!, current.creditsTotalUsd)) update.creditsTotalUsd = values.total!;\n if (!same(values.spent!, current.creditsSpentAdjustmentUsd)) update.creditsSpentAdjustmentUsd = values.spent!;\n if (!same(values.perSession!, current.estimatedCostPerSessionUsd)) update.estimatedCostPerSessionUsd = values.perSession!;\n if (!same(values.maxPerDay!, current.maxSessionsPerDay)) update.maxSessionsPerDay = values.maxPerDay!;\n if (!same(values.maxConcurrent!, current.maxConcurrent)) update.maxConcurrent = values.maxConcurrent!;\n const selfImprove: NonNullable<CloudBudgetUpdate['selfImprove']> = {};\n if (form.selfImprove !== current.selfImprove.enabled) selfImprove.enabled = form.selfImprove;\n if (!same(values.selfImproveMax!, current.selfImprove.maxPerDay)) selfImprove.maxPerDay = values.selfImproveMax!;\n if (!same(values.selfImproveMaxOpen!, maxOpenPrsOf(current))) selfImprove.maxOpenPrs = values.selfImproveMaxOpen!;\n if (!same(values.reserve!, current.selfImprove.reserveUsd)) selfImprove.reserveUsd = values.reserve!;\n if (Object.keys(selfImprove).length > 0) update.selfImprove = selfImprove;\n return { ok: true, update, changed: Object.keys(update).length > 0 };\n}\n\n// ---------------------------------------------------------------------------\n// The composer's \"Run in cloud\"\n// ---------------------------------------------------------------------------\n\nexport interface RunInCloudInputs {\n /** The cloud overview, or null when the route did not answer. */\n overview: { seat: CloudSeatStatus; budget: CloudBudgetView } | null;\n /** Why the overview is missing, when it is. */\n overviewReason: string | null;\n /** The chat project's GitHub `owner/name`, or null when it has none. */\n repo: string | null;\n /** True while the chat's roots have not been read yet. */\n rootsLoading: boolean;\n prompt: string;\n}\n\n/** Null when \"Run in cloud\" may be pressed; otherwise the tooltip saying why not. */\nexport function runInCloudBlock(inputs: RunInCloudInputs): string | null {\n if (!inputs.overview) return inputs.overviewReason ?? 'The cloud lane did not answer.';\n const seat = seatText(inputs.overview.seat);\n if (seat) return seat;\n if (!inputs.repo) {\n return inputs.rootsLoading\n ? \"Reading this chat's project…\"\n : \"This chat's project has no GitHub origin, so a cloud session has nothing to clone.\";\n }\n const gate = gateText(inputs.overview.budget.canLaunch, 'The cloud budget does not allow another launch right now.');\n if (gate) return gate;\n if (!inputs.prompt.trim()) return 'Type the task in the message box first.';\n if (inputs.prompt.trim().length > CLOUD_PROMPT_MAX_CHARS) {\n return `The message is over ${COUNT.format(CLOUD_PROMPT_MAX_CHARS)} characters — trim it to run it in the cloud.`;\n }\n return null;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"cloud-model-BDivRMqv.js","names":[],"sources":["../../../../../../__vite-browser-external","../../../../../../src/core/util/scrub.ts","../../../../../../src/web-ui/routes/verse/cloud/cloud-model.ts"],"sourcesContent":["module.exports = {}","/**\n * src/core/util/scrub.ts — THE shared secret-scrub utility (single source of truth).\n *\n * Extracted from judge-trace.ts (stripSecrets) and extended to cover all\n * patterns previously missing from handlers.ts (scrubDiffSecrets). Since 3.10\n * the two historical duplicates delegate here instead of drifting:\n * - src/core/generative/invent.ts re-exports `scrubSecrets` verbatim.\n * - src/core/knowledge/index.ts runs this scrub FIRST, then its own\n * stricter corpus patterns (32-hex, `/`-bearing base64, Stripe) that\n * `ashlr verify-safety` pins by array length. Knowledge chunks are never\n * identity-checked, so the stricter pass is safe there and must not leak\n * into this default (see \"IDENTITY CALLERS\" below).\n *\n * Patterns covered by `scrubSecrets`:\n * 0. PEM/private-key blocks\n * 1. sk- API keys (Anthropic, OpenAI, etc.)\n * 2. GitHub tokens: ghp_, gho_, ghu_, ghs_, ghr_, gha_, github_pat_ (classic\n * and fine-grained `github_pat_<22>_<59>`)\n * 3. Bearer / Token / Authorization header values\n * 4. Generic key=value secrets: api_key, secret, token, password, passwd,\n * auth, credential, client_secret, private_key, refresh_token,\n * access_token, connection_string (including ASHLR_* env vars)\n * 5. Slack tokens: xox[baprs]-…\n * 6. AWS access key IDs: AKIA…\n * 7. JWTs: eyJ….<sig>\n * 8. Bare hex-64 (SHA-256 / API key hex form)\n * 9. GitLab/HuggingFace/npm/Google token prefixes\n * 10. URL authority passwords and long base64 blobs\n * 11. (3.10) Telegram bot tokens `<bot id>:<33–35 chars>` — bare, in\n * `api.telegram.org/bot<token>/…` URLs, and under any key name\n * 12. (3.10) xAI API keys `xai-…`\n * 13. (3.10) Suffix-named assignments the generic rule's `\\b` anchor misses:\n * SCREAMING env vars (`GROQ_API_KEY=…`, `DB_PASSWORD=…`), snake_case\n * (`bot_token: …`) and camelCase (`githubToken: …`) names\n * 14. (3.10) Quoted JSON/YAML keys (`\"password\": \"…\"`, `\\\"botToken\\\":\\\"…\\\"`),\n * which rule 4 never matched because the closing quote sits between the\n * name and the colon\n * 15. (3.10) Slack / Discord incoming-webhook URL paths\n *\n * `scrubPrivateText` layers two PRIVACY redactions on top for free text that\n * is persisted or exported (reasoning store, session export, logs):\n * - home-directory paths → `~` (on by default)\n * - email addresses → `[REDACTED]` (opt-in)\n *\n * IDENTITY CALLERS (why home paths/emails are NOT in `scrubSecrets`): many\n * ledgers validate values with `scrubSecrets(v) === v` (dispatch manifests,\n * worked/dispatch-production ledgers, best-of-n, generated-repair) and several\n * of those values are absolute repo paths or git author identities. Rewriting\n * `/Users/<me>/repo` → `~/repo` in the default scrub would make every such\n * record look \"secret-bearing\" and be rejected, and would corrupt functional\n * paths. Privacy redaction is therefore an explicit, separate call.\n *\n * IDEMPOTENCE is load-bearing: records persisted after scrubbing are later\n * re-validated with `scrubSecrets(v) === v`, and `canonicalizeProposalDiff`\n * iterates to a fixed point. Every rule's output is a fixed point of every\n * rule (pinned by test/scrub-310.test.ts).\n *\n * PURITY: no I/O, no side-effects. `scrubPrivateText` reads the home directory\n * from the environment (no filesystem access) unless `homes` is supplied.\n */\n\nimport { homedir } from 'node:os';\n\nconst REDACTED = '[REDACTED]';\n\nfunction scrubLongBase64Like(match: string): string {\n // Preserve ordinary Git SHA-1 commit ids for forensic audit trails. The\n // explicit hex-64 rule above still redacts longer raw-key shapes.\n if (/^[0-9a-fA-F]{40}$/.test(match)) return match;\n // Avoid erasing obvious low-entropy test/log filler such as xxxxx...; real\n // token-like blobs still have mixed character content and are redacted below.\n const repeatedCandidate = match.replace(/^\\+/, '').replace(/=+$/, '');\n if (/^(.)\\1{39,}$/.test(repeatedCandidate)) return match;\n return REDACTED;\n}\n\n// ---------------------------------------------------------------------------\n// 3.10 additions\n// ---------------------------------------------------------------------------\n\n/**\n * Telegram bot token: numeric bot id (8–10 digits today; 6–12 tolerated) +\n * ':' + a 33–35 char url-safe secret (35 for issued tokens; Telegram's own\n * documentation example is 34). The optional `bot` prefix covers the Bot API\n * URL form (`https://api.telegram.org/bot<id>:<secret>/sendMessage`), where a\n * plain `\\b` anchor fails because `t` and the first digit are both word chars.\n * The narrow secret length plus the non-word lookarounds keep\n * `<epoch-seconds>:<uuid|hex32|sha1>` style ids (36 / 32 / 40 chars) intact —\n * several ledgers identity-check such ids.\n */\nconst TELEGRAM_BOT_TOKEN = /\\d{6,12}:[A-Za-z0-9_-]{33,35}(?![A-Za-z0-9_-])/g;\n\n/**\n * Left-boundary check for a Telegram candidate, done in the replacer instead of\n * a leading lookbehind: a regex that starts with `\\d` lets V8 skip ahead to\n * digits, which measured ~3x cheaper on 1 MB of prose than testing a\n * lookbehind at every offset. Accept when the id starts the string, follows a\n * non-word char, or follows a `bot` that itself follows a non-word char.\n */\nfunction redactTelegram(match: string, offset: number, whole: string): string {\n const boundary = (i: number): boolean => i < 0 || !/[A-Za-z0-9_]/.test(whole[i]!);\n if (boundary(offset - 1)) return REDACTED;\n if (whole.slice(offset - 3, offset) === 'bot' && boundary(offset - 4)) return REDACTED;\n return match;\n}\n\n/**\n * Incoming-webhook URLs are bearer credentials in their path (anyone holding\n * the URL can post). Host + fixed path prefix are kept for forensics.\n */\nconst WEBHOOK_URL =\n /(https?:\\/\\/(?:hooks\\.slack\\.com\\/(?:services|workflows|triggers)|(?:ptb\\.|canary\\.)?discord(?:app)?\\.com\\/api\\/webhooks)\\/)[A-Za-z0-9_/-]{8,}/gi;\n\n/** xAI (Grok) API keys: `xai-` + ≥20 alphanumerics (80 in practice). */\nconst XAI_API_KEY = /(?<![A-Za-z0-9_-])xai-[A-Za-z0-9]{20,}/g;\n\n/**\n * Value shape shared by the suffix-name rules: optional quote, ≥8 chars that\n * are not whitespace/separators/quotes, optional closing quote. Mirrors rule 4.\n */\nconst ASSIGNED_VALUE = String.raw`\\s*[=:]\\s*[\"']?[^\\s,;'\"]{8,}[\"']?`;\n\n/**\n * SCREAMING_SNAKE env-var names ending in a secret noun. Rule 4's `\\b(token|…)`\n * never fires inside `GROQ_API_KEY` / `TELEGRAM_BOT_TOKEN` because `_` is a\n * word char, so the whole `.env` idiom slipped through. Case-SENSITIVE on\n * purpose: `sort_key=…` in prose/code must not match.\n */\nconst ENV_SECRET_ASSIGNMENT = new RegExp(\n String.raw`(?<![A-Za-z0-9_$])([A-Z][A-Z0-9_]*_(?:KEY|TOKEN|SECRET|PASSWORD|PASSWD|PWD|CREDENTIALS?|AUTH|DSN))` +\n ASSIGNED_VALUE,\n 'g',\n);\n\n/** snake_case names with a secret suffix (`bot_token`, `db_password`). */\nconst SNAKE_SECRET_ASSIGNMENT = new RegExp(\n String.raw`(?<![A-Za-z0-9_$])([a-z][a-z0-9_]*_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key))` +\n ASSIGNED_VALUE,\n 'g',\n);\n\n/**\n * Cheap literal-led prefilters for the snake/camel rules. Those two regexes\n * start at every lowercase word, which measured ~3–4.5 ms per MB; the\n * prefilters cost <1 ms and skip them on the common text that has no\n * `…Token =` / `…_password:` assignment at all.\n */\nconst SNAKE_PREFILTER = /_(?:api_key|token|secret|password|passwd|pwd|credentials?|private_key|access_key|secret_key|signing_key)\\s*[=:]/;\nconst CAMEL_PREFILTER = /(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?)\\s*[=:]/;\n\n/** camelCase names with a secret suffix (`githubToken`, `clientSecret`). */\nconst CAMEL_SECRET_ASSIGNMENT = new RegExp(\n String.raw`(?<![A-Za-z0-9_$])([a-z][A-Za-z0-9]*(?:Token|Secret|Password|Passwd|ApiKey|PrivateKey|AccessKey|SecretKey|SigningKey|Credentials?))` +\n ASSIGNED_VALUE,\n 'g',\n);\n\n/**\n * Quoted keys (JSON, YAML, JS object literals), including JSON-escaped quotes\n * inside a serialized string (`\\\"password\\\":\\\"…\\\"`). The name must END in a\n * secret noun (`max_tokens`, `tokenizer`, `author` do not). Structure is kept —\n * only the value becomes `[REDACTED]` — so a scrubbed JSON line stays parseable.\n */\nconst QUOTED_SECRET_KEY =\n /(\\\\?[\"'])([A-Za-z0-9_.-]*(?:api[_-]?key|token|secret|password|passwd|pwd|credentials?|private[_-]?key|access[_-]?key|secret[_-]?key|signing[_-]?key|auth|connection[_-]?string))\\1(\\s*:\\s*)(\\\\?[\"'])([^\"'\\s\\\\]{8,})\\4/gi;\n\n/**\n * Values in CODE that merely reference a secret (a member chain, call, template\n * or env interpolation) rather than contain one. Scrubbed diffs are persisted\n * and applied as proposals, so turning `const GITHUB_TOKEN = process.env.GITHUB_TOKEN`\n * into `GITHUB_TOKEN=[REDACTED]` would corrupt a legitimate change. Applies to\n * the 3.10 suffix rules only — rule 4's historical behaviour is unchanged.\n */\nfunction isCodeReference(value: string): boolean {\n const v = value.replace(/^[\"']|[\"']$/g, '');\n return (\n /^[A-Za-z_$][\\w$]*(?:\\??\\.[A-Za-z_$][\\w$]*)+[)\\]]*$/.test(v) || // process.env.X, opts.apiToken\n /^[A-Za-z_$][\\w$.]*\\(/.test(v) || // getToken(), cfg.read(\n /^(?:\\$\\{|\\$[A-Za-z_]|`|<)/.test(v) // ${VAR}, $VAR, `template`, <placeholder>\n );\n}\n\n/**\n * Type annotations and identifier-only right-hand sides (`refreshToken: RefreshTokenRecord`,\n * `botToken: undefined`) carry no digits; real tokens essentially always do.\n * Only the camel/snake rules use this skip (they fire inside ordinary TS code);\n * the SCREAMING env rule still redacts a letters-only `.env` password.\n */\nfunction isIdentifierOnly(value: string): boolean {\n const v = value.replace(/^[\"']|[\"']$/g, '');\n return !/\\d/.test(v) && /^[A-Za-z_$][A-Za-z_$.<>[\\]|&?!()]*$/.test(v);\n}\n\n/** A value an earlier rule (or an earlier pass) already replaced. */\nfunction isAlreadyRedacted(value: string): boolean {\n return value.replace(/^[\"']|[\"']$/g, '') === REDACTED;\n}\n\nfunction redactAssignment(name: string, match: string, value: string, allowIdentifiers: boolean): string {\n // Idempotence: `NAME = \"[REDACTED]\"` must stay byte-identical on a re-scrub.\n if (isAlreadyRedacted(value)) return match;\n if (isCodeReference(value)) return match;\n if (allowIdentifiers && isIdentifierOnly(value)) return match;\n return `${name}=${REDACTED}`;\n}\n\nfunction valueOf(match: string, name: string): string {\n return match.slice(name.length).replace(/^\\s*[=:]\\s*/, '');\n}\n\n/**\n * Scrub recognised secret patterns from `text`.\n * Returns the scrubbed string with secrets replaced by `[REDACTED]`.\n * Never throws. Idempotent: `scrubSecrets(scrubSecrets(x)) === scrubSecrets(x)`.\n */\nexport function scrubSecrets(text: string): string {\n try {\n let out = text\n // 0. PEM/private-key blocks. Run before generic/base64 redaction so\n // BEGIN/END markers do not survive with only the body removed.\n .replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[\\s\\S]*?-----END[ A-Z]*PRIVATE KEY-----/g, REDACTED)\n .replace(/-----BEGIN[ A-Z]*PRIVATE KEY-----[^\\n]*/g, REDACTED)\n // 11. Telegram bot tokens — before rule 4 so a `botToken: <id>:<secret>`\n // value is removed whole even when its key name is not recognised.\n .replace(TELEGRAM_BOT_TOKEN, redactTelegram)\n // 15. Slack / Discord incoming-webhook URLs (credential in the path).\n .replace(WEBHOOK_URL, '$1[REDACTED]')\n // 12. xAI keys — before rule 10 so the `xai-` prefix does not survive\n // next to a base64-redacted tail.\n .replace(XAI_API_KEY, REDACTED)\n // 1. sk- API keys (Anthropic, OpenAI, etc.)\n .replace(/\\bsk-[A-Za-z0-9_-]{16,}/g, REDACTED)\n // 2. GitHub tokens (classic prefixes + fine-grained github_pat_<22>_<59>)\n .replace(/\\bgh[poursa]_[A-Za-z0-9]{16,}/g, REDACTED)\n .replace(/\\bgithub_pat_[A-Za-z0-9_]{22,}/g, REDACTED)\n // 3. Bearer / Token / Authorization header values\n .replace(/\\b(Bearer|Token|Authorization)\\s+[A-Za-z0-9\\-._~+/]+=*/gi, '$1 [REDACTED]')\n // 4. Generic key=value secret patterns. ASHLR_* env vars are only\n // redacted when they look like assignments, not plain audit metadata\n // such as \"keys=query\".\n .replace(\n /\\b(api[_-]?key|api[_-]?token|secret|secret[_-]?key|token|password|passwd|pwd|auth|credential|client[_-]?secret|private[_-]?key|access[_-]?token|auth[_-]?token|refresh[_-]?token|id[_-]?token|session[_-]?token|connection[_-]?string|conn[_-]?str|_?auth[_-]?token|ASHLR_[A-Z_]+)\\s*[=:]\\s*[\"']?[^\\s,;'\"]{8,}[\"']?/gi,\n '$1=[REDACTED]',\n )\n // 5. Slack tokens\n .replace(/\\bxox[baprs]-[A-Za-z0-9-]{10,}/gi, REDACTED)\n // 6. AWS access key IDs\n .replace(/\\bAKIA[0-9A-Z]{16}\\b/g, REDACTED)\n // 7. JWTs (eyJ header.payload.sig)\n .replace(/\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, REDACTED)\n // 8. Bare hex-64 strings (SHA-256 / hex API keys)\n .replace(/\\b[0-9a-fA-F]{64,}\\b/g, REDACTED)\n // 9. Other common provider token prefixes.\n .replace(/\\bglpat-[A-Za-z0-9_-]{16,}/g, REDACTED)\n .replace(/\\bhf_[A-Za-z0-9]{16,}\\b/g, REDACTED)\n .replace(/\\bnpm_[A-Za-z0-9]{16,}\\b/g, REDACTED)\n .replace(/\\bAIza[0-9A-Za-z_-]{35}\\b/g, REDACTED)\n // 10. URL passwords and long base64-ish blobs.\n .replace(/(:\\/\\/[^:\\s/@]*:)[^@\\s]+(@)/g, '$1[REDACTED]$2')\n .replace(/(?<![/\\w])[A-Za-z0-9+]{40,}={0,2}(?![/\\w])/g, scrubLongBase64Like)\n // 13. Suffix-named assignments rule 4's `\\b` anchor cannot see. LAST, so\n // every token-shape rule above has already turned a JWT/AKIA/hex value\n // into [REDACTED]; that marker is left untouched below. Running these\n // earlier broke idempotence: a dotted JWT reads like a member chain\n // (skipped as a code reference), then pass 2 rewrote `NAME = \"[REDACTED]\"`.\n .replace(ENV_SECRET_ASSIGNMENT, (m: string, name: string) => redactAssignment(name, m, valueOf(m, name), false));\n if (SNAKE_PREFILTER.test(out)) {\n out = out.replace(SNAKE_SECRET_ASSIGNMENT, (m: string, name: string) => redactAssignment(name, m, valueOf(m, name), true));\n }\n if (CAMEL_PREFILTER.test(out)) {\n out = out.replace(CAMEL_SECRET_ASSIGNMENT, (m: string, name: string) => redactAssignment(name, m, valueOf(m, name), true));\n }\n // 14. Quoted keys: keep the JSON/YAML structure, replace the value only.\n return out.replace(\n QUOTED_SECRET_KEY,\n (m: string, q: string, name: string, sep: string, vq: string, value: string) =>\n isAlreadyRedacted(value) || isCodeReference(value) ? m : `${q}${name}${q}${sep}${vq}${REDACTED}${vq}`,\n );\n } catch {\n // Never throws — return original text on unexpected error.\n return text;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Privacy redaction for persisted / exported free text\n// ---------------------------------------------------------------------------\n\nexport interface PrivateScrubOptions {\n /** Rewrite home-directory paths to `~`. Default: true. */\n readonly homePaths?: boolean;\n /** Replace email addresses with `[REDACTED]`. Default: false (opt-in). */\n readonly emails?: boolean;\n /**\n * Home directories to collapse. Default: `os.homedir()`, `$HOME`,\n * `$USERPROFILE`. Supplied explicitly by callers that already resolved them\n * (and by tests).\n */\n readonly homes?: readonly string[];\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\nfunction defaultHomes(): string[] {\n const out: string[] = [];\n try {\n out.push(homedir());\n } catch {\n // homedir() can throw when no home is resolvable; env fallbacks below.\n }\n if (typeof process === 'undefined') return out;\n for (const key of ['HOME', 'USERPROFILE'] as const) {\n const v = process.env[key];\n if (v) out.push(v);\n }\n return out;\n}\n\n/**\n * Case-insensitive filesystems (macOS APFS default, Windows) name one home many\n * ways. A function, not a module-level constant: the Verse web UI imports\n * `scrubSecrets` from this module (routes/verse/cloud/cloud-model.ts), and a\n * top-level `process.platform` read throws `ReferenceError: process is not\n * defined` in the browser — which took down every lazy section that pulls the\n * cloud model in (Command, Fleet). Nothing here may touch `process` at load.\n */\nfunction caseInsensitiveFs(): boolean {\n if (typeof process === 'undefined') return false;\n return process.platform === 'darwin' || process.platform === 'win32';\n}\n\n/**\n * Other users' home roots (`/Users/<name>`, `/home/<name>`, `C:\\Users\\<name>`):\n * the username is the PII, so the whole root collapses to `~` too. macOS's\n * `/Users/Shared` is a system directory, not a person.\n */\nconst GENERIC_HOME_ROOT =\n /(?<![\\w.-])(?:\\/(?:Users|home)\\/(?!Shared(?![\\w.-]))[A-Za-z0-9._-]+|[A-Za-z]:\\\\Users\\\\[A-Za-z0-9._-]+)(?![\\w.-])/g;\n\n/**\n * Collapse home-directory paths to `~`. A home only matches as a whole path\n * prefix on segment boundaries: `/Users/me/x` → `~/x`; `/opt/Users/me` is left\n * alone, and `/Users/meagan` is never split into `~agan` (it is another\n * person's home, collapsed whole by the generic rule). Never throws.\n */\nexport function redactHomePaths(text: string, homes: readonly string[] = defaultHomes()): string {\n try {\n let out = text;\n const unique = Array.from(\n new Set(\n homes\n .map((h) => h.replace(/[\\\\/]+$/, ''))\n // A bare root (\"/\", \"C:\") would collapse every absolute path.\n .filter((h) => h.length > 1 && !/^[A-Za-z]:$/.test(h)),\n ),\n ).sort((a, b) => b.length - a.length);\n for (const home of unique) {\n const re = new RegExp(`(?<![\\\\w.-])${escapeRegExp(home)}(?![\\\\w.-])`, caseInsensitiveFs() ? 'gi' : 'g');\n out = out.replace(re, '~');\n }\n return out.replace(GENERIC_HOME_ROOT, '~');\n } catch {\n return text;\n }\n}\n\n/**\n * Email addresses in free text. `git@host:org/repo` SSH remotes are not\n * personal addresses and stay intact; `pkg@1.2.3` version pins never match\n * because the final label must be alphabetic.\n */\nconst EMAIL = /(?<![\\w.%+-])([A-Za-z0-9._%+-]+)@[A-Za-z0-9-]+(?:\\.[A-Za-z0-9-]+)*\\.[A-Za-z]{2,}(?![\\w-])/g;\n\n/** Replace email addresses with `[REDACTED]`. Never throws. */\nexport function redactEmails(text: string): string {\n try {\n return text.replace(EMAIL, (m: string, local: string) => (local === 'git' ? m : REDACTED));\n } catch {\n return text;\n }\n}\n\n/**\n * Secrets + privacy scrub for free text that is persisted or exported\n * (reasoning steps, session exports, crash logs). Runs `scrubSecrets`, then\n * collapses home paths (default on) and, when asked, emails. Home paths are\n * collapsed on both sides of the secret scrub so a secret rule can never split\n * a home prefix into an unrecognisable remainder (same idiom as\n * `sanitizePublicJson`). Never throws. Idempotent.\n */\nexport function scrubPrivateText(text: string, options: PrivateScrubOptions = {}): string {\n const homePaths = options.homePaths !== false;\n const homes = homePaths ? (options.homes ?? defaultHomes()) : [];\n let out = homePaths ? redactHomePaths(text, homes) : text;\n out = scrubSecrets(out);\n if (homePaths) out = redactHomePaths(out, homes);\n if (options.emails === true) out = redactEmails(out);\n return out;\n}\n\n/** Stable bytes for proposal persistence, hashing, and provenance signing. */\nexport function canonicalizeProposalDiff(text: string): string {\n let current = text;\n for (let pass = 0; pass < 8; pass += 1) {\n const next = scrubSecrets(current)\n .replace(/\\bsk_(?:live|test)_[A-Za-z0-9_]{16,}\\b/g, REDACTED)\n .replace(/\\b(?:AKIA|ASIA|AROA)[0-9A-Z]{16}\\b/g, REDACTED)\n .replace(/\\b[0-9a-fA-F]{32,}\\b/g, REDACTED);\n if (next === current) return current;\n current = next;\n }\n throw new Error('proposal diff canonicalization did not converge');\n}\n","/**\n * routes/verse/cloud/cloud-model.ts — the cloud lane's words and decisions as\n * pure functions (3.11 unit C3), so the card, the Usage panel, the Fleet chip\n * and the composer action say the same thing and the copy is tested as a\n * table. No React here.\n *\n * Copy rules (DESIGN §13.8, and the cloud contract's own):\n * - spend is ALWAYS an estimate and says so — Claude does not expose the\n * credit balance, so every dollar figure carries \"estimate\" beside it;\n * - server prose (gate reasons, state reasons, report summaries) is scrubbed\n * for secrets before `tidyProse` makes ISO instants readable in local time;\n * - times are local and relative (\"started 5m ago\"), never ISO;\n * - a state is always a WORD beside any colour.\n */\nimport {\n CLOUD_PROMPT_MAX_CHARS,\n CLOUD_TERMINAL_STATES,\n DEFAULT_CLOUD_BUDGET,\n type CloudBudgetUpdate,\n type CloudBudgetV1,\n type CloudBudgetView,\n type CloudSeatStatus,\n type CloudTaskState,\n type CloudTaskV1,\n} from '../../../../core/cloud/types.js';\nimport { describeResetAt } from '../../../../core/verse/seat-readiness.js';\nimport { scrubSecrets } from '../../../../core/util/scrub.js';\nimport type { Tone } from '../../../components/primitives/StatusBadge.js';\nimport type { MeterTone } from '../../../components/primitives/Meter.js';\nimport { tidyProse } from '../autonomy/format.js';\nimport { relativePhrase } from '../context/context-model.js';\nimport { usedPercentText } from '../percent-text.js';\n\n/** Cloud text can originate in a PR body; keep every card reason safe even outside the HTTP sanitizer. */\nfunction safeCloudProse(text: string, now?: number): string {\n return tidyProse(scrubSecrets(text), now);\n}\n\n/** The repo a new task targets unless the operator names another (the self-improvement default). */\nexport const CLOUD_DEFAULT_REPO = DEFAULT_CLOUD_BUDGET.selfImprove.repo;\n\n/** Same rule the service enforces (core/cloud/service.ts), checked here so the dialog can say so first. */\nexport const CLOUD_REPO_PATTERN = /^[A-Za-z0-9-]+\\/[A-Za-z0-9._-]+$/;\n\n/**\n * A branch name git would accept, conservatively: no spaces or control\n * characters, no `..`, no leading `-` or `/`, no trailing `/` or `.lock`.\n * The server re-checks it against origin; this only catches typing slips.\n */\nconst BRANCH_CHARS = /^[A-Za-z0-9._/+-]{1,200}$/;\nexport function isBranchName(value: string): boolean {\n if (!BRANCH_CHARS.test(value)) return false;\n if (value.startsWith('-') || value.startsWith('/') || value.endsWith('/') || value.endsWith('.') || value.endsWith('.lock')) return false;\n return !value.includes('..') && !value.includes('//');\n}\n\n/** Only these hosts become links: the ids came from a CLI's stdout and gh's JSON. */\nexport function safeHref(url: string | null | undefined, host: 'claude.ai' | 'github.com'): string | null {\n if (typeof url !== 'string' || url.length > 2_048) return null;\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'https:' && parsed.hostname === host ? parsed.toString() : null;\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Money and the credits meter\n// ---------------------------------------------------------------------------\n\n/** \"$250\", \"$12.50\" — whole dollars stay whole; never \"-$0\". */\nexport function formatDollars(value: number): string {\n if (!Number.isFinite(value)) return '—';\n const v = Math.abs(value) < 0.005 ? 0 : value;\n const text = Number.isInteger(v) ? String(Math.abs(v)) : Math.abs(v).toFixed(2);\n return `${v < 0 ? '−' : ''}$${text}`;\n}\n\nexport interface CreditsMeterView {\n /** Remaining, clamped at 0 for the bar (the text says when it went below). */\n value: number;\n max: number | null;\n /** \"$212 of $250 · estimate\" */\n text: string;\n /** \"15% used\" — the one percent rule. */\n usedText: string;\n tone: MeterTone;\n /** A plain sentence when the estimate is at or under the self-improvement reserve. */\n warning: string | null;\n}\n\nexport function creditsMeter(view: CloudBudgetView): CreditsMeterView {\n const total = view.creditsTotalUsd;\n const remaining = view.estimatedRemainingUsd;\n const reserve = view.budget.selfImprove.reserveUsd;\n const max = total > 0 ? total : null;\n const used = max === null ? null : ((total - Math.max(0, remaining)) / total) * 100;\n const tone: MeterTone = remaining <= 0 ? 'danger' : remaining < reserve ? 'warning' : 'accent';\n const warning = remaining <= 0\n ? 'The estimate says the credits are spent. Check the real balance on claude.ai and adjust the budget.'\n : remaining < reserve\n ? `Under the ${formatDollars(reserve)} reserve, so Verse stops launching self-improvement tasks.`\n : null;\n return {\n value: Math.max(0, remaining),\n max,\n text: `${formatDollars(Math.max(0, remaining))} of ${formatDollars(total)} · estimate`,\n usedText: used === null ? 'no credit total set' : `${usedPercentText(used)} used`,\n tone,\n warning,\n };\n}\n\n/** The next local midnight — when the per-day caps start counting again. */\nexport function nextLocalMidnight(now: number): number {\n const d = new Date(now);\n d.setHours(24, 0, 0, 0);\n return d.getTime();\n}\n\n/** \"3 of 20 sessions today · 1 running\" plus when the daily count resets. */\nexport function sessionsLine(view: CloudBudgetView, now: number = Date.now()): string {\n const reset = describeResetAt(new Date(nextLocalMidnight(now)).toISOString(), now);\n const running = view.running === 1 ? '1 running' : `${view.running} running`;\n return `${view.sessionsToday} of ${view.budget.maxSessionsPerDay} sessions today · ${running}${reset ? ` · resets ${reset}` : ''}`;\n}\n\nexport function selfImproveLine(view: CloudBudgetView): string {\n const si = view.budget.selfImprove;\n if (!si.enabled) return 'Self-improvement is off. Verse launches cloud tasks only when you ask.';\n return `${view.selfImproveToday} of ${si.maxPerDay} self-improvement launches today, on ${si.repo}. Stops under a ${formatDollars(si.reserveUsd)} estimated balance.`;\n}\n\n/** A gate's reason, fit to print (null when the gate is open). */\nexport function gateText(gate: { ok: boolean; reason: string | null }, fallback: string): string | null {\n if (gate.ok) return null;\n return gate.reason ? safeCloudProse(gate.reason) : fallback;\n}\n\nexport const SEAT_NOT_READY = \"The Claude seat isn't set up on this Mac.\";\n\nexport function seatText(seat: CloudSeatStatus): string | null {\n if (seat.ready) return null;\n return seat.reason ? safeCloudProse(seat.reason) : SEAT_NOT_READY;\n}\n\n// ---------------------------------------------------------------------------\n// Standing: what the credit figure MEANS while the lane cannot launch\n// ---------------------------------------------------------------------------\n//\n// The credit figure is always an estimate (a flat per-session cost counted\n// against the total the operator typed in; the real balance is not\n// readable). While the lane can launch, that estimate is headroom and a meter\n// is the honest picture. While the Claude seat is NOT set up nothing can\n// launch, so \"$250 of $250 left\" beside \"the seat isn't set up\" read as live\n// headroom the operator could not use. Then the setup blocker is the STATE,\n// and the credits a secondary, visibly approximate figure:\n//\n// Cloud: not set up · ~$250 credits\n//\n// Shared by Command's Cloud card, Usage's Cloud credits panel and the\n// Resources drawer's cloud card.\n\n/** The state word shown in place of the meter while the seat is missing. */\nexport const CLOUD_NOT_SET_UP_WORD = 'Not set up';\n\n/**\n * \"~$250 credits\" — whole dollars, because an estimate that cannot be spent\n * yet has no business showing cents. Never negative.\n */\nexport function approxCredits(remainingUsd: number): string {\n const v = Number.isFinite(remainingUsd) ? Math.max(0, Math.round(remainingUsd)) : 0;\n return `~$${v} credits`;\n}\n\n/** \"Cloud: not set up · ~$250 credits\" — the one-line summary of a lane that cannot launch. */\nexport function notSetUpLine(remainingUsd: number): string {\n return `Cloud: not set up · ${approxCredits(remainingUsd)}`;\n}\n\n/**\n * Why a launch button is disabled right now, or null when it may be pressed.\n * Seat first (nothing launches without it), then the budget gate.\n */\nexport function launchBlock(seat: CloudSeatStatus, budget: CloudBudgetView): string | null {\n return seatText(seat) ?? gateText(budget.canLaunch, 'The cloud budget does not allow another launch right now.');\n}\n\n// ---------------------------------------------------------------------------\n// Tasks\n// ---------------------------------------------------------------------------\n\nexport const STATE_WORD: Record<CloudTaskState, string> = {\n queued: 'Queued',\n launching: 'Launching',\n running: 'Running',\n 'pr-open': 'PR open',\n merged: 'Merged',\n closed: 'Closed',\n failed: 'Failed',\n expired: 'Expired',\n};\n\nexport const STATE_TONE: Record<CloudTaskState, Tone> = {\n queued: 'info',\n launching: 'info',\n running: 'running',\n 'pr-open': 'warning',\n merged: 'success',\n closed: 'neutral',\n failed: 'danger',\n expired: 'unknown',\n};\n\n/** A draft PR reads \"Draft PR\", not \"PR open\": the session may still be pushing. */\nexport function stateWord(task: Pick<CloudTaskV1, 'state' | 'pr'>): string {\n if (task.state === 'pr-open' && !task.pr) return 'PR unverified';\n if (task.state === 'pr-open' && task.pr?.draft) return 'Draft PR';\n return STATE_WORD[task.state] ?? task.state;\n}\n\nexport function isTerminal(state: CloudTaskState): boolean {\n return CLOUD_TERMINAL_STATES.includes(state);\n}\n\n/** In flight: counted by the Fleet chip and the \"running\" line. */\nexport function isInFlight(state: CloudTaskState): boolean {\n return state === 'queued' || state === 'launching' || state === 'running';\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n/** How many tasks the card lists before \"N more on GitHub\". */\nexport const CARD_TASK_LIMIT = 6;\n\n/**\n * What the card lists: everything still moving or waiting on review, then\n * anything that ended in the last 24 h (a failure you have not seen yet),\n * newest first. Older finished tasks live in `ashlr cloud list --all`.\n */\nexport function cardTasks(tasks: readonly CloudTaskV1[], now: number = Date.now()): { shown: CloudTaskV1[]; hidden: number } {\n const recent = (t: CloudTaskV1) => {\n const at = Date.parse(t.updatedAt);\n return Number.isFinite(at) && now - at < DAY_MS;\n };\n const listed = tasks\n .filter((t) => !isTerminal(t.state) || recent(t))\n .sort((a, b) => (Date.parse(b.createdAt) || 0) - (Date.parse(a.createdAt) || 0));\n return { shown: listed.slice(0, CARD_TASK_LIMIT), hidden: Math.max(0, listed.length - CARD_TASK_LIMIT) };\n}\n\nexport function inFlightCount(tasks: readonly CloudTaskV1[]): number {\n return tasks.filter((t) => isInFlight(t.state)).length;\n}\n\n/** \"ashlrai/ashlr-hub from master · started 5m ago\" */\nexport function taskMeta(task: CloudTaskV1, now: number = Date.now()): string {\n const when = task.state === 'queued' || task.state === 'launching' ? task.createdAt : task.launchedAt ?? task.createdAt;\n const phrase = relativePhrase(when, now);\n const verb = task.state === 'queued' ? 'queued' : task.state === 'failed' ? 'tried' : 'started';\n return `${task.repo} from ${task.baseBranch}${phrase ? ` · ${verb} ${phrase}` : ''}`;\n}\n\n/** The one line under a task's title: the report for a PR, else the state's reason. */\nexport function taskDetail(task: CloudTaskV1, now: number = Date.now()): string | null {\n if (task.report?.summary && (task.state === 'pr-open' || task.state === 'merged')) return `Cloud session reports (unverified): ${safeCloudProse(task.report.summary, now)}`;\n return task.stateReason ? safeCloudProse(task.stateReason, now) : null;\n}\n\n/** Dismiss is offered for anything Verse is still tracking; merged and closed tasks are already done. */\nexport function canDismiss(task: Pick<CloudTaskV1, 'state'>): boolean {\n return task.state !== 'merged' && task.state !== 'closed';\n}\n\n// ---------------------------------------------------------------------------\n// The launch form\n// ---------------------------------------------------------------------------\n\nexport interface LaunchDraft {\n repo: string;\n baseBranch: string;\n prompt: string;\n}\n\nexport type LaunchErrors = Partial<Record<keyof LaunchDraft, string>>;\n\nexport type LaunchValidation =\n | { ok: true; request: { repo: string; baseBranch?: string; prompt: string } }\n | { ok: false; errors: LaunchErrors };\n\nconst COUNT = new Intl.NumberFormat('en-US');\n\nexport function validateLaunch(draft: LaunchDraft): LaunchValidation {\n const errors: LaunchErrors = {};\n const repo = draft.repo.trim();\n const base = draft.baseBranch.trim();\n const prompt = draft.prompt.trim();\n if (!repo) errors.repo = 'Enter the GitHub repository as owner/name.';\n else if (!CLOUD_REPO_PATTERN.test(repo)) errors.repo = 'Use the GitHub owner/name form, like ashlrai/ashlr-hub.';\n if (base && !isBranchName(base)) errors.baseBranch = \"That isn't a branch name git accepts.\";\n if (!prompt) errors.prompt = 'Describe the task for the cloud session.';\n else if (prompt.length > CLOUD_PROMPT_MAX_CHARS) {\n errors.prompt = `The task is ${COUNT.format(prompt.length)} characters; the limit is ${COUNT.format(CLOUD_PROMPT_MAX_CHARS)}.`;\n }\n if (Object.keys(errors).length > 0) return { ok: false, errors };\n return { ok: true, request: { repo, ...(base ? { baseBranch: base } : {}), prompt } };\n}\n\n// ---------------------------------------------------------------------------\n// The budget form (Edit budget popover and the Usage panel share it)\n// ---------------------------------------------------------------------------\n\nexport interface BudgetForm {\n total: string;\n spent: string;\n perSession: string;\n maxPerDay: string;\n maxConcurrent: string;\n selfImprove: boolean;\n selfImproveMax: string;\n /** Self-improvement waits while this many of its PRs await review (3.13). */\n selfImproveMaxOpen: string;\n reserve: string;\n}\n\nexport type BudgetFormField = Exclude<keyof BudgetForm, 'selfImprove'>;\nexport type BudgetErrors = Partial<Record<BudgetFormField, string>>;\n\n/** Field → label and bounds. Bounds are the form's sanity check; the server clamps as well. */\nexport const BUDGET_FIELDS: ReadonlyArray<{\n field: BudgetFormField;\n label: string;\n hint: string;\n money: boolean;\n integer: boolean;\n min: number;\n max: number;\n}> = [\n { field: 'total', label: 'Credits on the account', hint: 'What claude.ai says you have.', money: true, integer: false, min: 0, max: 100_000 },\n { field: 'spent', label: 'Already spent', hint: 'Spent before Verse tracked it, or a correction after checking.', money: true, integer: false, min: -100_000, max: 100_000 },\n { field: 'perSession', label: 'Estimate per session', hint: 'Flat cost Verse counts for each launch.', money: true, integer: false, min: 0.01, max: 1_000 },\n { field: 'maxPerDay', label: 'Sessions per day', hint: 'From every origin, counted per local day.', money: false, integer: true, min: 0, max: 500 },\n { field: 'maxConcurrent', label: 'Running at once', hint: 'Launching or running together.', money: false, integer: true, min: 1, max: 50 },\n { field: 'selfImproveMax', label: 'Self-improvement per day', hint: 'Launches Verse may make on its own.', money: false, integer: true, min: 0, max: 100 },\n { field: 'selfImproveMaxOpen', label: 'Open self-improvement PRs', hint: 'Self-improvement waits while this many await review.', money: false, integer: true, min: 1, max: 50 },\n { field: 'reserve', label: 'Reserve', hint: 'Self-improvement stops under this estimated balance.', money: true, integer: false, min: 0, max: 100_000 },\n];\n\n/** A pre-3.13 server sends no maxOpenPrs: the form shows the default and never sends it unchanged. */\nfunction maxOpenPrsOf(b: CloudBudgetV1): number {\n const n = (b.selfImprove as Partial<CloudBudgetV1['selfImprove']>).maxOpenPrs;\n return typeof n === 'number' && Number.isFinite(n) ? n : DEFAULT_CLOUD_BUDGET.selfImprove.maxOpenPrs;\n}\n\nfunction numText(n: number): string {\n return Number.isInteger(n) ? String(n) : String(Math.round(n * 100) / 100);\n}\n\nexport function budgetFormFrom(b: CloudBudgetV1): BudgetForm {\n return {\n total: numText(b.creditsTotalUsd),\n spent: numText(b.creditsSpentAdjustmentUsd),\n perSession: numText(b.estimatedCostPerSessionUsd),\n maxPerDay: numText(b.maxSessionsPerDay),\n maxConcurrent: numText(b.maxConcurrent),\n selfImprove: b.selfImprove.enabled,\n selfImproveMax: numText(b.selfImprove.maxPerDay),\n selfImproveMaxOpen: numText(maxOpenPrsOf(b)),\n reserve: numText(b.selfImprove.reserveUsd),\n };\n}\n\nexport type BudgetPatch = { ok: true; update: CloudBudgetUpdate; changed: boolean } | { ok: false; errors: BudgetErrors };\n\n/**\n * The form as ONE update carrying only what changed — so two people editing\n * different fields never overwrite each other's numbers with stale ones.\n */\nexport function budgetPatch(form: BudgetForm, current: CloudBudgetV1): BudgetPatch {\n const errors: BudgetErrors = {};\n const values: Partial<Record<BudgetFormField, number>> = {};\n for (const spec of BUDGET_FIELDS) {\n const raw = form[spec.field].trim().replace(/^\\$/, '');\n const n = raw === '' ? Number.NaN : Number(raw);\n if (!Number.isFinite(n)) errors[spec.field] = 'Enter a number.';\n else if (spec.integer && !Number.isInteger(n)) errors[spec.field] = 'Enter a whole number.';\n else if (n < spec.min || n > spec.max) {\n errors[spec.field] = spec.money\n ? `Between ${formatDollars(spec.min)} and ${formatDollars(spec.max)}.`\n : `Between ${COUNT.format(spec.min)} and ${COUNT.format(spec.max)}.`;\n } else values[spec.field] = n;\n }\n if (Object.keys(errors).length > 0) return { ok: false, errors };\n const update: CloudBudgetUpdate = {};\n const same = (a: number, b: number) => Math.abs(a - b) < 0.005;\n if (!same(values.total!, current.creditsTotalUsd)) update.creditsTotalUsd = values.total!;\n if (!same(values.spent!, current.creditsSpentAdjustmentUsd)) update.creditsSpentAdjustmentUsd = values.spent!;\n if (!same(values.perSession!, current.estimatedCostPerSessionUsd)) update.estimatedCostPerSessionUsd = values.perSession!;\n if (!same(values.maxPerDay!, current.maxSessionsPerDay)) update.maxSessionsPerDay = values.maxPerDay!;\n if (!same(values.maxConcurrent!, current.maxConcurrent)) update.maxConcurrent = values.maxConcurrent!;\n const selfImprove: NonNullable<CloudBudgetUpdate['selfImprove']> = {};\n if (form.selfImprove !== current.selfImprove.enabled) selfImprove.enabled = form.selfImprove;\n if (!same(values.selfImproveMax!, current.selfImprove.maxPerDay)) selfImprove.maxPerDay = values.selfImproveMax!;\n if (!same(values.selfImproveMaxOpen!, maxOpenPrsOf(current))) selfImprove.maxOpenPrs = values.selfImproveMaxOpen!;\n if (!same(values.reserve!, current.selfImprove.reserveUsd)) selfImprove.reserveUsd = values.reserve!;\n if (Object.keys(selfImprove).length > 0) update.selfImprove = selfImprove;\n return { ok: true, update, changed: Object.keys(update).length > 0 };\n}\n\n// ---------------------------------------------------------------------------\n// The composer's \"Run in cloud\"\n// ---------------------------------------------------------------------------\n\nexport interface RunInCloudInputs {\n /** The cloud overview, or null when the route did not answer. */\n overview: { seat: CloudSeatStatus; budget: CloudBudgetView } | null;\n /** Why the overview is missing, when it is. */\n overviewReason: string | null;\n /** The chat project's GitHub `owner/name`, or null when it has none. */\n repo: string | null;\n /** True while the chat's roots have not been read yet. */\n rootsLoading: boolean;\n prompt: string;\n}\n\n/** Null when \"Run in cloud\" may be pressed; otherwise the tooltip saying why not. */\nexport function runInCloudBlock(inputs: RunInCloudInputs): string | null {\n if (!inputs.overview) return inputs.overviewReason ?? 'The cloud lane did not answer.';\n const seat = seatText(inputs.overview.seat);\n if (seat) return seat;\n if (!inputs.repo) {\n return inputs.rootsLoading\n ? \"Reading this chat's project…\"\n : \"This chat's project has no GitHub origin, so a cloud session has nothing to clone.\";\n }\n const gate = gateText(inputs.overview.budget.canLaunch, 'The cloud budget does not allow another launch right now.');\n if (gate) return gate;\n if (!inputs.prompt.trim()) return 'Type the task in the message box first.';\n if (inputs.prompt.trim().length > CLOUD_PROMPT_MAX_CHARS) {\n return `The message is over ${COUNT.format(CLOUD_PROMPT_MAX_CHARS)} characters — trim it to run it in the cloud.`;\n }\n return null;\n}\n"],"mappings":"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"}
|
package/dist/core/web/public/next/assets/{cloud-queries-DmptbjS8.js → cloud-queries-BPQQ5_pJ.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{
|
|
2
|
-
//# sourceMappingURL=cloud-queries-
|
|
1
|
+
import{I as e,O as t,W as n,l as r,o as i,u as a}from"./global-CMNW_dqn.js";import{F as o}from"./VerseConsoleApp-CWU6R3By.js";import{c as s,d as c,l,o as u,r as d,s as f,u as p}from"./types-IYKrYLku.js";var m=`verse-cloud`,h=3e4,g=class extends Error{constructor(){super(`Unlock actions with the mutation token first.`),this.name=`CloudLockedError`}},_=class extends Error{failure;constructor(e,t){super(e),this.failure=t,this.name=`CloudLaunchRefusedError`}};function v(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function y(e){if(!v(e))return null;let{seat:t,budget:n,tasks:r,backlog:i}=e;if(!v(t)||typeof t.ready!=`boolean`||!v(n)||!v(n.budget)||!v(n.canLaunch)||!v(n.canSelfImprove))return null;for(let e of[`creditsTotalUsd`,`estimatedSpentUsd`,`estimatedRemainingUsd`,`sessionsToday`,`selfImproveToday`,`running`])if(typeof n[e]!=`number`||!Number.isFinite(n[e]))return null;return!Array.isArray(r)||!r.every(e=>v(e)&&typeof e.id==`string`&&typeof e.state==`string`)||!v(i)||!Array.isArray(i.items)?null:e}var b=`The cloud lane is not in this build yet.`;function x(e){return e instanceof i?e.status===404?b:e.status===503?`The cloud lane failed to load on the server.`:`The cloud lane answered HTTP ${e.status}.`:`The cloud lane could not be reached.`}var S={key:m,fetch:async e=>{try{let t=y(await r(l,e));return t===null?{value:null,available:!0,reason:`Unrecognized response — update Ashlr.`}:{value:t,available:!0,reason:null}}catch(e){if(e instanceof i&&e.status===401||e instanceof DOMException&&e.name===`AbortError`)throw e;return{value:null,available:!1,reason:x(e)}}}};async function C(n,r){let i=t();if(!i)throw new g;let o=await a(n,r,i);return e(),o}function w(){n(m),o()}async function T(e){try{let t=await C(s,e);if(!v(t)||t.ok!==!0||!v(t.task))throw new _(v(t)&&typeof t.error==`string`&&t.error?t.error:`The cloud session was not started, and the server sent no reason.`,v(t)&&typeof t.failure==`string`?t.failure:null);return t}finally{w()}}async function E(e){let t=await C(u,e);return n(m),t}async function D(e={count:1}){try{let t=await C(f,e);return{launched:v(t)&&Array.isArray(t.launched)?t.launched:[],skipped:v(t)&&Array.isArray(t.skipped)?t.skipped:[]}}finally{w()}}async function O(){try{return await C(p,{})}finally{w()}}async function k(e){if(!d.test(e))throw Error(`That task id is not one Verse issued, so nothing was sent.`);try{return await C(`${c}/${e}/dismiss`,{})}finally{w()}}export{T as a,E as c,k as i,h as n,O as o,S as r,D as s,b as t};
|
|
2
|
+
//# sourceMappingURL=cloud-queries-BPQQ5_pJ.js.map
|