@ashlr/hub 3.12.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 +157 -0
- package/README.md +29 -16
- package/dist/authority-surface.json +274 -148
- package/dist/build-identity.json +2 -2
- package/dist/cli/authority.d.ts +145 -33
- package/dist/cli/authority.js +1292 -315
- package/dist/cli/authority.js.map +1 -1
- package/dist/cli/cloud.js +12 -3
- package/dist/cli/cloud.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/protected-paths.js +11 -0
- package/dist/core/authority/protected-paths.js.map +1 -1
- package/dist/core/authority/resident.d.ts +101 -0
- package/dist/core/authority/resident.js +246 -0
- package/dist/core/authority/resident.js.map +1 -0
- 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/authority/types.d.ts +43 -0
- package/dist/core/authority/types.js +6 -0
- package/dist/core/authority/types.js.map +1 -1
- package/dist/core/cloud/budget.js +11 -1
- package/dist/core/cloud/budget.js.map +1 -1
- package/dist/core/cloud/cloud-api.d.ts +25 -2
- package/dist/core/cloud/cloud-api.js +139 -5
- package/dist/core/cloud/cloud-api.js.map +1 -1
- package/dist/core/cloud/pr-actions.d.ts +93 -0
- package/dist/core/cloud/pr-actions.js +436 -0
- package/dist/core/cloud/pr-actions.js.map +1 -0
- package/dist/core/cloud/pr-preview.d.ts +128 -0
- package/dist/core/cloud/pr-preview.js +228 -0
- package/dist/core/cloud/pr-preview.js.map +1 -0
- package/dist/core/cloud/store.d.ts +2 -0
- package/dist/core/cloud/store.js +28 -0
- package/dist/core/cloud/store.js.map +1 -1
- package/dist/core/cloud/timeline-api.d.ts +24 -0
- package/dist/core/cloud/timeline-api.js +46 -0
- package/dist/core/cloud/timeline-api.js.map +1 -0
- package/dist/core/cloud/timeline-types.d.ts +62 -0
- package/dist/core/cloud/timeline-types.js +36 -0
- package/dist/core/cloud/timeline-types.js.map +1 -0
- package/dist/core/cloud/timeline.d.ts +102 -0
- package/dist/core/cloud/timeline.js +925 -0
- package/dist/core/cloud/timeline.js.map +1 -0
- package/dist/core/cloud/tracker.js +67 -0
- package/dist/core/cloud/tracker.js.map +1 -1
- package/dist/core/cloud/types.d.ts +38 -0
- package/dist/core/cloud/types.js +1 -1
- package/dist/core/cloud/types.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/service-install-authority.d.ts +10 -2
- package/dist/core/daemon/service-install-authority.js +14 -5
- package/dist/core/daemon/service-install-authority.js.map +1 -1
- package/dist/core/daemon/service.d.ts +15 -0
- package/dist/core/daemon/service.js +26 -0
- package/dist/core/daemon/service.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/cloud-intake.d.ts +95 -0
- package/dist/core/fleet/cloud-intake.js +557 -0
- package/dist/core/fleet/cloud-intake.js.map +1 -0
- package/dist/core/fleet/dispatch-router.d.ts +13 -0
- package/dist/core/fleet/dispatch-router.js +32 -8
- package/dist/core/fleet/dispatch-router.js.map +1 -1
- package/dist/core/fleet/fleet-merge-state.d.ts +16 -0
- package/dist/core/fleet/fleet-merge-state.js.map +1 -1
- package/dist/core/fleet/host-merge.d.ts +14 -0
- package/dist/core/fleet/host-merge.js +24 -2
- package/dist/core/fleet/host-merge.js.map +1 -1
- package/dist/core/fleet/merge-gates.d.ts +21 -0
- package/dist/core/fleet/merge-gates.js +39 -5
- 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 +102 -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 +10 -1
- package/dist/core/fleet/tick-hooks-live.js +57 -8
- package/dist/core/fleet/tick-hooks-live.js.map +1 -1
- package/dist/core/fleet/verify-check-run.d.ts +90 -0
- package/dist/core/fleet/verify-check-run.js +274 -0
- package/dist/core/fleet/verify-check-run.js.map +1 -0
- 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 +18 -1
- package/dist/core/routing/budget-api.js +120 -10
- package/dist/core/routing/budget-api.js.map +1 -1
- package/dist/core/routing/budget-store.d.ts +22 -1
- package/dist/core/routing/budget-store.js +22 -8
- package/dist/core/routing/budget-store.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/account-health.js +9 -3
- package/dist/core/verse/account-health.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/activity-api.d.ts +5 -1
- package/dist/core/verse/activity-api.js +62 -14
- package/dist/core/verse/activity-api.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 +17 -3
- package/dist/core/verse/authority-api.js +122 -7
- 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/seat-readiness.d.ts +25 -0
- package/dist/core/verse/seat-readiness.js +43 -6
- package/dist/core/verse/seat-readiness.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.d.ts +3 -1
- package/dist/core/verse/verse-api.js +87 -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-B4-39f2S.js → ActionMenu-CIiX2X8w.js} +2 -2
- package/dist/core/web/public/next/assets/{ActionMenu-B4-39f2S.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-B-LqYXvd.js.map → Advanced-DHsysoIL.js.map} +1 -1
- package/dist/core/web/public/next/assets/App-CMeAocmW.js +7 -0
- package/dist/core/web/public/next/assets/{App-E2zCDRxm.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-8wXPPhZb.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-CEPSZToP.js +3 -0
- package/dist/core/web/public/next/assets/AutonomyOffState-CEPSZToP.js.map +1 -0
- package/dist/core/web/public/next/assets/AutonomyOffState-CmSSTHVe.css +1 -0
- package/dist/core/web/public/next/assets/AutonomySection-DWc3ciAD.js +2 -0
- package/dist/core/web/public/next/assets/{AutonomySection-B46igJKR.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-BRkrEQGs.js → BranchBar-BxhdiIpx.js} +2 -2
- package/dist/core/web/public/next/assets/{BranchBar-BRkrEQGs.js.map → BranchBar-BxhdiIpx.js.map} +1 -1
- package/dist/core/web/public/next/assets/BudgetControl-C-0KhjRS.js +2 -0
- package/dist/core/web/public/next/assets/BudgetControl-C-0KhjRS.js.map +1 -0
- package/dist/core/web/public/next/assets/{Button-BhO-WKPp.js → Button-D90dzI_o.js} +2 -2
- package/dist/core/web/public/next/assets/{Button-BhO-WKPp.js.map → Button-D90dzI_o.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CapacityStrip-CkFz5vq2.js → CapacityStrip-qKDBC65C.js} +2 -2
- package/dist/core/web/public/next/assets/{CapacityStrip-CkFz5vq2.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-DlT4QU6a.js.map +1 -0
- package/dist/core/web/public/next/assets/{CloudBudgetForm-Bd91iStN.js → CloudBudgetForm-BrNun_Yu.js} +2 -2
- package/dist/core/web/public/next/assets/{CloudBudgetForm-Bd91iStN.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-Bv4hdK2T.js → ConfirmDialog-BR4nZQ2D.js} +2 -2
- package/dist/core/web/public/next/assets/{ConfirmDialog-Bv4hdK2T.js.map → ConfirmDialog-BR4nZQ2D.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DeleteChatDialog-CH1Ix8Eh.js → DeleteChatDialog-BCfP12GH.js} +2 -2
- package/dist/core/web/public/next/assets/{DeleteChatDialog-CH1Ix8Eh.js.map → DeleteChatDialog-BCfP12GH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Dialog-BSsIFNqD.js → Dialog-D3msQlCj.js} +2 -2
- package/dist/core/web/public/next/assets/{Dialog-BSsIFNqD.js.map → Dialog-D3msQlCj.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffPane-BpNuJmth.js → DiffPane-Ix6hvXlY.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffPane-BpNuJmth.js.map → DiffPane-Ix6hvXlY.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffViewer-CJarUvs0.js → DiffViewer-C4WKsCIe.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffViewer-CJarUvs0.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-DW9q0NdR.js.map → DockHost-aWP7liri.js.map} +1 -1
- package/dist/core/web/public/next/assets/{EmptyState-DPrd2aak.js → EmptyState-D2IRy3Cg.js} +2 -2
- package/dist/core/web/public/next/assets/{EmptyState-DPrd2aak.js.map → EmptyState-D2IRy3Cg.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Epistemic-D7MxSmED.js → Epistemic-DMr18muX.js} +2 -2
- package/dist/core/web/public/next/assets/{Epistemic-D7MxSmED.js.map → Epistemic-DMr18muX.js.map} +1 -1
- package/dist/core/web/public/next/assets/EvidenceTimeline-DXmmz6Fi.js +2 -0
- package/dist/core/web/public/next/assets/EvidenceTimeline-DXmmz6Fi.js.map +1 -0
- package/dist/core/web/public/next/assets/EvidenceTimeline-PBDAiSuG.css +1 -0
- 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-CIPtzeIx.js → GearTray-Dt-ee32-.js} +2 -2
- package/dist/core/web/public/next/assets/{GearTray-CIPtzeIx.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-iiQg6wvK.js.map → GrowthSection-P9EUfGeA.js.map} +1 -1
- package/dist/core/web/public/next/assets/{HandoffDialog-DrQ6ofuy.js → HandoffDialog-CLJQLe7M.js} +2 -2
- package/dist/core/web/public/next/assets/{HandoffDialog-DrQ6ofuy.js.map → HandoffDialog-CLJQLe7M.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Input-C0MQxEM6.js → Input-D_KRJA9V.js} +2 -2
- package/dist/core/web/public/next/assets/{Input-C0MQxEM6.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-BRuCcTjT.js.map → McpSection-DGbRcyv8.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdown-bRvD5nSc.js → MessageMarkdown-DFvk06qG.js} +3 -3
- package/dist/core/web/public/next/assets/{MessageMarkdown-bRvD5nSc.js.map → MessageMarkdown-DFvk06qG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-FjjkPKA2.js → MessageMarkdownRenderer-BAv4oEUf.js} +2 -2
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-FjjkPKA2.js.map → MessageMarkdownRenderer-BAv4oEUf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Meter-CFNLpwA-.js → Meter-CMj-VafN.js} +2 -2
- package/dist/core/web/public/next/assets/{Meter-CFNLpwA-.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-T7gv3a9r.js → MutationTokenDialog-DbnO8aYi.js} +2 -2
- package/dist/core/web/public/next/assets/{MutationTokenDialog-T7gv3a9r.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-CCsijdWt.js +2 -0
- package/dist/core/web/public/next/assets/{NeedsYouList-BgH8ezqf.js.map → NeedsYouList-CCsijdWt.js.map} +1 -1
- package/dist/core/web/public/next/assets/NeedsYouList-CH6Mq-E_.css +1 -0
- package/dist/core/web/public/next/assets/NewChatDialog-BlCHtOIr.js +3 -0
- package/dist/core/web/public/next/assets/{NewChatDialog-Db5Xjrk8.js.map → NewChatDialog-BlCHtOIr.js.map} +1 -1
- package/dist/core/web/public/next/assets/OnboardingFlow-Cy9BA9eR.js +3 -0
- package/dist/core/web/public/next/assets/OnboardingFlow-Cy9BA9eR.js.map +1 -0
- package/dist/core/web/public/next/assets/OnboardingGate-BXpNFoLt.js +3 -0
- package/dist/core/web/public/next/assets/{OnboardingGate-C4VXn7BJ.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-BPBbcROb.js.map → PreviewPane-COid5A0f.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ProviderLogo-CT2cSfkg.js → ProviderLogo-Cq-CYIwT.js} +2 -2
- package/dist/core/web/public/next/assets/{ProviderLogo-CT2cSfkg.js.map → ProviderLogo-Cq-CYIwT.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RailStatus-Vgl0GYtd.js → RailStatus-Co5UB6We.js} +2 -2
- package/dist/core/web/public/next/assets/{RailStatus-Vgl0GYtd.js.map → RailStatus-Co5UB6We.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RefreshIndicator-CSyqpY_q.js → RefreshIndicator-DO9ibnSq.js} +2 -2
- package/dist/core/web/public/next/assets/{RefreshIndicator-CSyqpY_q.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-BX2nkdmZ.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-BaC7YVzR.js → RouteErrorBoundary-SkNhhUbt.js} +2 -2
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-BaC7YVzR.js.map → RouteErrorBoundary-SkNhhUbt.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RunInCloudAction-D5PDHJPE.js → RunInCloudAction-BXPlZwJQ.js} +2 -2
- package/dist/core/web/public/next/assets/{RunInCloudAction-D5PDHJPE.js.map → RunInCloudAction-BXPlZwJQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SeatSelector-Cg75LInq.js → SeatSelector-J5R3zDkB.js} +3 -3
- package/dist/core/web/public/next/assets/{SeatSelector-Cg75LInq.js.map → SeatSelector-J5R3zDkB.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Segmented-CametjLt.js → Segmented-CGh_-tBb.js} +2 -2
- package/dist/core/web/public/next/assets/{Segmented-CametjLt.js.map → Segmented-CGh_-tBb.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Select-De52fghU.js → Select-CWnmUzs3.js} +2 -2
- package/dist/core/web/public/next/assets/{Select-De52fghU.js.map → Select-CWnmUzs3.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionGate-CzlcNq3O.js → SessionGate-sp4KsnUo.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionGate-CzlcNq3O.js.map → SessionGate-sp4KsnUo.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionInsightChip-Bk_Owa7u.js → SessionInsightChip-DLFAzdbi.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionInsightChip-Bk_Owa7u.js.map → SessionInsightChip-DLFAzdbi.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionSearch-C6C8DHN8.js → SessionSearch-DbFjwR1h.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionSearch-C6C8DHN8.js.map → SessionSearch-DbFjwR1h.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SettingsSection-mI9wQYZg.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-Bd76MBAR.js +2 -0
- package/dist/core/web/public/next/assets/SetupChecklist-Bd76MBAR.js.map +1 -0
- package/dist/core/web/public/next/assets/SetupChecklist-BhZpFLsj.css +1 -0
- 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-CJhK9Dqv.js → Sheet-BZ2AG4Eo.js} +2 -2
- package/dist/core/web/public/next/assets/{Sheet-CJhK9Dqv.js.map → Sheet-BZ2AG4Eo.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-DDW-i9Fc.js → ShortcutsOverlay-C8n8y3zf.js} +2 -2
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-DDW-i9Fc.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-DN--cPYN.js.map +1 -0
- package/dist/core/web/public/next/assets/{Slider-Bwd9HfXl.js → Slider-KVoJLDD6.js} +2 -2
- package/dist/core/web/public/next/assets/{Slider-Bwd9HfXl.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-DHKRtttH.js → StatusBadge-CXsYqmdU.js} +2 -2
- package/dist/core/web/public/next/assets/{StatusBadge-DHKRtttH.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-D--LXgQm.js → Surface-BfDmQcKe.js} +2 -2
- package/dist/core/web/public/next/assets/{Surface-D--LXgQm.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-PMixU6b0.js → Switch-9NtO_6Lj.js} +2 -2
- package/dist/core/web/public/next/assets/{Switch-PMixU6b0.js.map → Switch-9NtO_6Lj.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Tag-fordBsrJ.js → Tag-DscCRFcN.js} +2 -2
- package/dist/core/web/public/next/assets/{Tag-fordBsrJ.js.map → Tag-DscCRFcN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{TerminalPane-BSnGdUuF.js → TerminalPane-B668-DJW.js} +5 -5
- package/dist/core/web/public/next/assets/{TerminalPane-BSnGdUuF.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-DtXFhAhw.js.map → UniverseConsoleApp-BUV_brY7.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseView-sWm3pnTW.js → UniverseView-DG70zH0W.js} +4 -4
- package/dist/core/web/public/next/assets/{UniverseView-sWm3pnTW.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-BQSZFSeO.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-Ci6I4C0l.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-DlwnfqwJ.js → apps-model-Du02KhAf.js} +2 -2
- package/dist/core/web/public/next/assets/{apps-model-DlwnfqwJ.js.map → apps-model-Du02KhAf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{authority-model-BFuPezSo.js → authority-model-79SeuKlJ.js} +2 -2
- package/dist/core/web/public/next/assets/{authority-model-BFuPezSo.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-DsAjH8ac.js.map → budget-queries-D8QV5XtH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{capacity-strip-model-Dn1cNOhz.js → capacity-strip-model-BwZ1ZbkU.js} +2 -2
- package/dist/core/web/public/next/assets/{capacity-strip-model-Dn1cNOhz.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-BDivRMqv.js +2 -0
- package/dist/core/web/public/next/assets/{cloud-model-CX407gPY.js.map → cloud-model-BDivRMqv.js.map} +1 -1
- package/dist/core/web/public/next/assets/{cloud-queries-QAhpExlz.js → cloud-queries-BPQQ5_pJ.js} +2 -2
- package/dist/core/web/public/next/assets/{cloud-queries-QAhpExlz.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-CF0cQQac.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-Co4wh3SM.js → context-model-Br8t9jgG.js} +2 -2
- package/dist/core/web/public/next/assets/{context-model-Co4wh3SM.js.map → context-model-Br8t9jgG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{context-model-DV1zCfAm.js → context-model-CokrgEUq.js} +3 -3
- package/dist/core/web/public/next/assets/{context-model-DV1zCfAm.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-CktFQqSS.js.map → context-queries-eL3caKVG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{control-queries-DAvlh_YM.js → control-queries-B9K-wmcB.js} +2 -2
- package/dist/core/web/public/next/assets/{control-queries-DAvlh_YM.js.map → control-queries-B9K-wmcB.js.map} +1 -1
- package/dist/core/web/public/next/assets/copy-setup-XMgCC5f8.js +2 -0
- package/dist/core/web/public/next/assets/copy-setup-XMgCC5f8.js.map +1 -0
- package/dist/core/web/public/next/assets/{dock-icons-BFuBbqJl.js → dock-icons-BJ6ZqB2t.js} +2 -2
- package/dist/core/web/public/next/assets/{dock-icons-BFuBbqJl.js.map → dock-icons-BJ6ZqB2t.js.map} +1 -1
- package/dist/core/web/public/next/assets/{fleet-model-Dfd5JyLR.js → fleet-model-BvDR3gjp.js} +2 -2
- package/dist/core/web/public/next/assets/{fleet-model-Dfd5JyLR.js.map → fleet-model-BvDR3gjp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{fleet-queries-RtMTd5rR.js → fleet-queries-W2UFVMZJ.js} +2 -2
- package/dist/core/web/public/next/assets/{fleet-queries-RtMTd5rR.js.map → fleet-queries-W2UFVMZJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{focus-trap-BdrbWfC4.js → focus-trap-CtI1SlMX.js} +2 -2
- package/dist/core/web/public/next/assets/{focus-trap-BdrbWfC4.js.map → focus-trap-CtI1SlMX.js.map} +1 -1
- package/dist/core/web/public/next/assets/format-CH4g_sl1.js +2 -0
- package/dist/core/web/public/next/assets/format-CH4g_sl1.js.map +1 -0
- 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-_BnI_Ogh.js → git-model-Dnkd1TnK.js} +2 -2
- package/dist/core/web/public/next/assets/{git-model-_BnI_Ogh.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-CNNGMril.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-DPh2d32e.js.map → guarded-runners-YeAc9wLQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{icons-0haWy6nh.js → icons-D1sYbCTQ.js} +2 -2
- package/dist/core/web/public/next/assets/{icons-0haWy6nh.js.map → icons-D1sYbCTQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{index-QesfXBsb.js → index-DZ-UQ7v8.js} +3 -3
- package/dist/core/web/public/next/assets/{index-QesfXBsb.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-De-q0ZFK.js → live-model-D_32RAOR.js} +2 -2
- package/dist/core/web/public/next/assets/live-model-D_32RAOR.js.map +1 -0
- package/dist/core/web/public/next/assets/{mind.module-BrK2nFOL.js → mind.module-7hA92hRg.js} +2 -2
- package/dist/core/web/public/next/assets/{mind.module-BrK2nFOL.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-DTCtKCn_.js.map → mutations-DQPbFdRJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{nav-KmGX0CVz.js → nav-0dOYe2rJ.js} +2 -2
- package/dist/core/web/public/next/assets/{nav-KmGX0CVz.js.map → nav-0dOYe2rJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{overnight-queries-mlO0xzsr.js → overnight-queries-C4wOnFtE.js} +2 -2
- package/dist/core/web/public/next/assets/{overnight-queries-mlO0xzsr.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-CyBE8nsW.js → queries-BTXWdZzU.js} +2 -2
- package/dist/core/web/public/next/assets/{queries-CyBE8nsW.js.map → queries-BTXWdZzU.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reasoning-pref-CaoA4_Vl.js → reasoning-pref-Ca6lN6x_.js} +2 -2
- package/dist/core/web/public/next/assets/{reasoning-pref-CaoA4_Vl.js.map → reasoning-pref-Ca6lN6x_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reveal-anchor-BP1VqnPU.js → reveal-anchor-DfNLgK_I.js} +2 -2
- package/dist/core/web/public/next/assets/{reveal-anchor-BP1VqnPU.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-C5Tvr0WQ.js.map → seat-subscription-C5uPHBsN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{sidebar-model-B5Qk95k_.js → sidebar-model-CLCdqwkR.js} +2 -2
- package/dist/core/web/public/next/assets/{sidebar-model-B5Qk95k_.js.map → sidebar-model-CLCdqwkR.js.map} +1 -1
- package/dist/core/web/public/next/assets/{slots-DHKQDoE6.js → slots-C-qBeu-8.js} +3 -3
- package/dist/core/web/public/next/assets/{slots-DHKQDoE6.js.map → slots-C-qBeu-8.js.map} +1 -1
- package/dist/core/web/public/next/assets/{surface-data-CchClvHo.js → surface-data-Dj71tdD-.js} +2 -2
- package/dist/core/web/public/next/assets/{surface-data-CchClvHo.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-D6WFVULI.js → tasks-model-O8yR5YXp.js} +2 -2
- package/dist/core/web/public/next/assets/{tasks-model-D6WFVULI.js.map → tasks-model-O8yR5YXp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{terminal-icons-BvCvuXk2.js → terminal-icons-CoRZq9iO.js} +2 -2
- package/dist/core/web/public/next/assets/{terminal-icons-BvCvuXk2.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/types-IYKrYLku.js +2 -0
- package/dist/core/web/public/next/assets/types-IYKrYLku.js.map +1 -0
- package/dist/core/web/public/next/assets/{usage-queries-D1SU1t7r.js → usage-queries-AdjEyEtn.js} +2 -2
- package/dist/core/web/public/next/assets/{usage-queries-D1SU1t7r.js.map → usage-queries-AdjEyEtn.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-guarded-action-BZmBv7CJ.js → use-guarded-action-CuuMHeDX.js} +2 -2
- package/dist/core/web/public/next/assets/{use-guarded-action-BZmBv7CJ.js.map → use-guarded-action-CuuMHeDX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-ticker-CkJ4-0wU.js → use-ticker-BBcp02SZ.js} +2 -2
- package/dist/core/web/public/next/assets/{use-ticker-CkJ4-0wU.js.map → use-ticker-BBcp02SZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-token-gate-CYcfk_GS.js → use-token-gate-CbXVYQYI.js} +2 -2
- package/dist/core/web/public/next/assets/{use-token-gate-CYcfk_GS.js.map → use-token-gate-CbXVYQYI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useOnboarding-CujRS6PK.js → useOnboarding-C_Fpe_sH.js} +2 -2
- package/dist/core/web/public/next/assets/{useOnboarding-CujRS6PK.js.map → useOnboarding-C_Fpe_sH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useSeatsRefresh-BEaQdkZs.js → useSeatsRefresh-Co1CnxLc.js} +2 -2
- package/dist/core/web/public/next/assets/{useSeatsRefresh-BEaQdkZs.js.map → useSeatsRefresh-Co1CnxLc.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useVerseTranscript-BQ0J6Xhx.js → useVerseTranscript-DgbigUlV.js} +2 -2
- package/dist/core/web/public/next/assets/{useVerseTranscript-BQ0J6Xhx.js.map → useVerseTranscript-DgbigUlV.js.map} +1 -1
- package/dist/core/web/public/next/assets/{verse-icons-DndgEgKS.js → verse-icons-S56hIiXS.js} +2 -2
- package/dist/core/web/public/next/assets/{verse-icons-DndgEgKS.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-MMySehjj.js.map → verse-model-DAVevkNe.js.map} +1 -1
- package/dist/core/web/public/next/assets/{warmup-CNEH_-be.js → warmup-B_RAtNZ_.js} +3 -3
- package/dist/core/web/public/next/assets/{warmup-CNEH_-be.js.map → warmup-B_RAtNZ_.js.map} +1 -1
- package/dist/core/web/public/next/assets/why-seat-model-M_r0wX3b.js +2 -0
- package/dist/core/web/public/next/assets/why-seat-model-M_r0wX3b.js.map +1 -0
- package/dist/core/web/public/next/assets/{workspace-model-Dukb2wwv.js → workspace-model-dji5-Al3.js} +2 -2
- package/dist/core/web/public/next/assets/{workspace-model-Dukb2wwv.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/docs/AUTONOMY-GAP.md +1 -1
- package/package.json +3 -2
- package/dist/core/web/public/next/assets/Advanced-B-LqYXvd.js +0 -2
- package/dist/core/web/public/next/assets/App-E2zCDRxm.js +0 -7
- package/dist/core/web/public/next/assets/AppsSection-8wXPPhZb.js +0 -2
- package/dist/core/web/public/next/assets/AreaTrend-BFimExYn.js +0 -2
- package/dist/core/web/public/next/assets/AreaTrend-BFimExYn.js.map +0 -1
- package/dist/core/web/public/next/assets/AutonomyOffState-B5eEkmiz.js +0 -2
- package/dist/core/web/public/next/assets/AutonomyOffState-B5eEkmiz.js.map +0 -1
- package/dist/core/web/public/next/assets/AutonomyOffState-DmbE71vI.css +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-B46igJKR.js +0 -2
- package/dist/core/web/public/next/assets/BudgetControl-T_RjPrw9.js +0 -2
- package/dist/core/web/public/next/assets/BudgetControl-T_RjPrw9.js.map +0 -1
- package/dist/core/web/public/next/assets/ChartFrame-BVuBe6RP.css +0 -1
- package/dist/core/web/public/next/assets/ChartFrame-SygZ7B3x.js +0 -2
- package/dist/core/web/public/next/assets/ChartFrame-SygZ7B3x.js.map +0 -1
- package/dist/core/web/public/next/assets/ChatSection-D6WybBpB.js +0 -3
- package/dist/core/web/public/next/assets/ChatSection-D6WybBpB.js.map +0 -1
- package/dist/core/web/public/next/assets/CommandPalette-B6SgDJH-.js +0 -2
- package/dist/core/web/public/next/assets/CommandPalette-B6SgDJH-.js.map +0 -1
- package/dist/core/web/public/next/assets/CommandSection-CvAVd1w4.css +0 -1
- package/dist/core/web/public/next/assets/CommandSection-DgMGoepd.js +0 -2
- package/dist/core/web/public/next/assets/CommandSection-DgMGoepd.js.map +0 -1
- package/dist/core/web/public/next/assets/DockHost-DW9q0NdR.js +0 -2
- package/dist/core/web/public/next/assets/FleetSection-BdZN6rGS.js +0 -3
- package/dist/core/web/public/next/assets/FleetSection-BdZN6rGS.js.map +0 -1
- package/dist/core/web/public/next/assets/Funnel-BeNQZWv2.js +0 -2
- package/dist/core/web/public/next/assets/Funnel-BeNQZWv2.js.map +0 -1
- package/dist/core/web/public/next/assets/GrowthSection-iiQg6wvK.js +0 -2
- package/dist/core/web/public/next/assets/LeaderCard-BRr3_yE-.js +0 -2
- package/dist/core/web/public/next/assets/LeaderCard-BRr3_yE-.js.map +0 -1
- package/dist/core/web/public/next/assets/MatrixHeatmap-DZvZeWXL.js +0 -2
- package/dist/core/web/public/next/assets/MatrixHeatmap-DZvZeWXL.js.map +0 -1
- package/dist/core/web/public/next/assets/McpSection-BRuCcTjT.js +0 -2
- package/dist/core/web/public/next/assets/MindSection-BTIiQS8P.js +0 -2
- package/dist/core/web/public/next/assets/MindSection-BTIiQS8P.js.map +0 -1
- package/dist/core/web/public/next/assets/NeedsYouDrawer-lYN4G_aM.js +0 -2
- package/dist/core/web/public/next/assets/NeedsYouDrawer-lYN4G_aM.js.map +0 -1
- package/dist/core/web/public/next/assets/NeedsYouList-BgH8ezqf.js +0 -2
- package/dist/core/web/public/next/assets/NeedsYouList-CruOt4JT.css +0 -1
- package/dist/core/web/public/next/assets/NewChatDialog-Db5Xjrk8.js +0 -3
- package/dist/core/web/public/next/assets/OnboardingFlow-LoY-zuSe.js +0 -2
- package/dist/core/web/public/next/assets/OnboardingFlow-LoY-zuSe.js.map +0 -1
- package/dist/core/web/public/next/assets/OnboardingGate-C4VXn7BJ.js +0 -3
- package/dist/core/web/public/next/assets/PreviewPane-BPBbcROb.js +0 -2
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-BX2nkdmZ.js +0 -7
- package/dist/core/web/public/next/assets/ResourcesChrome-B2U2lO1H.js +0 -3
- package/dist/core/web/public/next/assets/ResourcesChrome-B2U2lO1H.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcesDrawer-BCFJ2Uq8.css +0 -1
- package/dist/core/web/public/next/assets/ResourcesDrawer-DlUKOjl9.js +0 -2
- package/dist/core/web/public/next/assets/ResourcesDrawer-DlUKOjl9.js.map +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-mI9wQYZg.js.map +0 -1
- package/dist/core/web/public/next/assets/Sidebar-DT7ykaqS.js +0 -3
- package/dist/core/web/public/next/assets/Sidebar-DT7ykaqS.js.map +0 -1
- package/dist/core/web/public/next/assets/StatTile-BuLMsJMx.css +0 -1
- package/dist/core/web/public/next/assets/StatTile-DPZ5yyaU.js +0 -2
- package/dist/core/web/public/next/assets/StatTile-DPZ5yyaU.js.map +0 -1
- package/dist/core/web/public/next/assets/StepBand-DQykLkk_.js +0 -2
- package/dist/core/web/public/next/assets/StepBand-DQykLkk_.js.map +0 -1
- package/dist/core/web/public/next/assets/Swimlane-BzH6OCee.js +0 -2
- package/dist/core/web/public/next/assets/Swimlane-BzH6OCee.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-DtXFhAhw.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-CiD1DbuF.js +0 -3
- package/dist/core/web/public/next/assets/UsageSection-CiD1DbuF.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-BCY5uSok.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-BCY5uSok.js.map +0 -1
- package/dist/core/web/public/next/assets/Workspace-BQSZFSeO.js +0 -10
- package/dist/core/web/public/next/assets/actions-BmIf9avl.css +0 -1
- package/dist/core/web/public/next/assets/actions-Ci6I4C0l.js +0 -2
- package/dist/core/web/public/next/assets/budget-queries-DsAjH8ac.js +0 -2
- package/dist/core/web/public/next/assets/charts-C_xJbJiw.js +0 -2
- package/dist/core/web/public/next/assets/charts-C_xJbJiw.js.map +0 -1
- package/dist/core/web/public/next/assets/charts-DhKTrQLw.css +0 -1
- package/dist/core/web/public/next/assets/cloud-model-CX407gPY.js +0 -2
- package/dist/core/web/public/next/assets/command-catalog-CF0cQQac.js.map +0 -1
- package/dist/core/web/public/next/assets/context-queries-CktFQqSS.js +0 -2
- package/dist/core/web/public/next/assets/copy-setup-CqRSfELB.js +0 -2
- package/dist/core/web/public/next/assets/copy-setup-CqRSfELB.js.map +0 -1
- package/dist/core/web/public/next/assets/format-Dk4Fmxax.js +0 -2
- package/dist/core/web/public/next/assets/format-Dk4Fmxax.js.map +0 -1
- package/dist/core/web/public/next/assets/global-CNNGMril.js +0 -2
- package/dist/core/web/public/next/assets/guarded-runners-DPh2d32e.js +0 -2
- package/dist/core/web/public/next/assets/live-model-De-q0ZFK.js.map +0 -1
- package/dist/core/web/public/next/assets/mutations-DTCtKCn_.js +0 -2
- package/dist/core/web/public/next/assets/primitives-D0Fb3TtS.js +0 -1
- package/dist/core/web/public/next/assets/seat-subscription-C5Tvr0WQ.js +0 -2
- package/dist/core/web/public/next/assets/surface-prefetch-BWr0LBQn.js +0 -2
- package/dist/core/web/public/next/assets/surface-prefetch-BWr0LBQn.js.map +0 -1
- package/dist/core/web/public/next/assets/types-D5XOdyw8.js +0 -2
- package/dist/core/web/public/next/assets/types-D5XOdyw8.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-model-MMySehjj.js +0 -2
- package/dist/core/web/public/next/assets/why-seat-model-jlDTwYSc.js +0 -2
- package/dist/core/web/public/next/assets/why-seat-model-jlDTwYSc.js.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"GrowthSection-iiQg6wvK.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/fleet-history-view.ts","../../../../../../src/core/learn/harness-types.ts","../../../../../../src/web-ui/routes/verse/growth/growth-model.ts","../../../../../../src/web-ui/routes/verse/sections/GrowthSection.tsx"],"sourcesContent":["/**\n * components/charts/fleet-history-view.ts — maps the `GET /api/verse/fleet/history`\n * payload (core/verse/fleet-history-types.ts) onto the chart kit's props, so\n * every surface that charts fleet history (Command, Fleet, Growth) makes the\n * same honesty decisions:\n *\n * - the fleet is DARK → every chart shows \"Fleet dark since <date>\", not\n * empty axes;\n * - a source could not be read at all → \"unknown\", not zeros;\n * - a source was only partly read → a caveat naming why (lower bounds);\n * - claim-check → always the not-recorded state, never a fabricated series.\n *\n * Pure functions over the wire type; no fetching here.\n */\nimport type {\n FleetHistoryDay,\n FleetHistoryResponse,\n FleetHistorySource,\n} from '../../../core/verse/fleet-history-types.js';\nimport type { ChartStatus } from './ChartFrame.js';\nimport type { BarStackProps } from './BarStack.js';\nimport type { FunnelStage } from './Funnel.js';\nimport type { SwimlaneLane } from './Swimlane.js';\nimport type { CalendarDatum } from './CalendarHeatmap.js';\nimport type { AreaTrendSeries } from './AreaTrend.js';\nimport { toneColor } from './colors.js';\nimport { formatDayLabel } from './format.js';\n\nconst REASON_TEXT: Record<string, string> = {\n 'oversized-file': 'some records are over the size bound',\n 'invalid-file': 'some records are malformed',\n 'unsafe-file': 'some records were refused (symlink, shared or foreign-owned)',\n 'unsafe-directory': 'the store directory is not private',\n 'io-error': 'some records could not be read',\n 'file-limit': 'the store has more records than one read covers',\n 'invalid-row': 'some ledger rows are malformed',\n 'oversized-row': 'some ledger rows are over the size bound',\n 'duplicate-canonical-realized-merge-identity': 'two proposals claim the same merge, so merges are unknown',\n 'claim-integrity-verdicts-not-persisted': 'claim-check verdicts are not recorded per proposal yet',\n 'scorecard-trend-pending': 'the scorecard trend is still being collected',\n 'scorecard-worker-unavailable': 'the scorecard trend could not be read this time',\n};\n\nfunction reasonText(reason: string): string {\n return REASON_TEXT[reason] ?? reason.replace(/-/g, ' ');\n}\n\n/** A caveat sentence for a partly-read source, or undefined when it is complete. */\nexport function sourceCaveat(label: string, source: FleetHistorySource): string | undefined {\n if (source.complete || source.state === 'not-recorded') return undefined;\n if (source.reasons.length === 0) return undefined;\n const skipped = source.recordsSkipped > 0 ? ` (${source.recordsSkipped} skipped)` : '';\n return `${label} are lower bounds: ${source.reasons.map(reasonText).join('; ')}${skipped}.`;\n}\n\n/**\n * The shared status for a chart over one source. Order matters: unreadable\n * beats dark (we cannot claim darkness from a store we cannot read), and dark\n * beats an all-zero window (the designed \"since\" message is more useful).\n */\nexport function historyStatus(history: FleetHistoryResponse, source: FleetHistorySource): ChartStatus {\n if (source.state === 'not-recorded') return { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'not recorded')}.` };\n if (source.state === 'degraded' && source.recordsRead === 0) {\n return { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'io-error')}.` };\n }\n if (history.darkSince) return { kind: 'dark', since: history.darkSince };\n return { kind: 'ready' };\n}\n\n/** \"Sep 3\" for a day row (the wire's days are already in the caller's zone). */\nexport function dayLabel(day: FleetHistoryDay): string {\n return formatDayLabel(day.day);\n}\n\n/** Runs per day as done / failed / aborted / unfinished — status tones, legend-labelled. */\nexport function runsByDay(history: FleetHistoryResponse): Pick<BarStackProps, 'categories' | 'segments' | 'values' | 'status' | 'caveat'> {\n return {\n categories: history.days.map(dayLabel),\n segments: [\n { id: 'done', label: 'Done', color: toneColor('success') },\n { id: 'failed', label: 'Failed', color: toneColor('danger') },\n { id: 'aborted', label: 'Aborted', color: toneColor('neutral') },\n { id: 'unfinished', label: 'Unfinished', color: toneColor('running') },\n ],\n values: history.days.map((d) => [d.runs.done, d.runs.failed, d.runs.aborted, d.runs.unfinished]),\n status: historyStatus(history, history.sources.runs),\n caveat: sourceCaveat('Run counts', history.sources.runs),\n };\n}\n\n/** Judge verdicts per day (the considered ones, plus failed judge calls). */\nexport function verdictsByDay(history: FleetHistoryResponse): Pick<BarStackProps, 'categories' | 'segments' | 'values' | 'status' | 'caveat'> {\n return {\n categories: history.days.map(dayLabel),\n segments: [\n { id: 'ship', label: 'Ship', color: toneColor('success') },\n { id: 'review', label: 'Review', color: toneColor('warning') },\n { id: 'noise', label: 'Noise', color: toneColor('neutral') },\n { id: 'harmful', label: 'Harmful', color: toneColor('danger') },\n { id: 'failed', label: 'Judge failed', color: toneColor('unknown') },\n ],\n values: history.days.map((d) => [d.judged.ship, d.judged.review, d.judged.noise, d.judged.harmful, d.judged.failed]),\n status: historyStatus(history, history.sources.decisions),\n caveat: sourceCaveat('Verdict counts', history.sources.decisions),\n };\n}\n\n/** Proposal pipeline for the window (cumulative stages — see FleetHistoryFunnel). */\nexport function pipelineFunnel(history: FleetHistoryResponse): { stages: FunnelStage[]; status: ChartStatus; caveat?: string } {\n const f = history.funnel;\n const caveat = sourceCaveat('Pipeline counts', history.sources.proposals) ?? sourceCaveat('Pipeline counts', history.sources.decisions);\n return {\n stages: [\n { id: 'filed', label: 'Filed', value: f.filed },\n { id: 'verified', label: 'Verified', value: f.verified },\n { id: 'passed', label: 'Verification passed', value: f.verificationPassed },\n { id: 'ship', label: 'Judged ship', value: f.judgedShip },\n { id: 'merged', label: 'Merged', value: f.merged },\n ],\n status: historyStatus(history, history.sources.proposals),\n ...(caveat ? { caveat } : {}),\n };\n}\n\n/** Swimlane lanes straight from the projection (runs → bars, engine as detail). */\nexport function runLanes(history: FleetHistoryResponse): { lanes: SwimlaneLane[]; from: number; to: number; status: ChartStatus; caveat?: string } {\n const truncated = history.swimlanesTruncated ? 'Showing the newest runs only; the full list is longer.' : undefined;\n const caveat = [sourceCaveat('Runs', history.sources.runs), truncated].filter(Boolean).join(' ') || undefined;\n return {\n lanes: history.swimlanes.map((lane) => ({\n id: lane.id,\n label: lane.label,\n items: lane.items.map((item) => ({\n id: item.id,\n start: item.startMs,\n end: item.endMs,\n status: item.status,\n detail: item.engine,\n stale: item.stale,\n })),\n })),\n from: Date.parse(history.window.from),\n to: Date.parse(history.window.to),\n status: historyStatus(history, history.sources.runs),\n ...(caveat ? { caveat } : {}),\n };\n}\n\n/** One number per day for the calendar heatmap. */\nexport function dailyValues(history: FleetHistoryResponse, pick: (day: FleetHistoryDay) => number | null): CalendarDatum[] {\n return history.days.map((d) => ({ day: d.day, value: pick(d) }));\n}\n\n/** Scorecard trend (daily snapshots of the trailing window) as AreaTrend series. */\nexport function scorecardSeries(history: FleetHistoryResponse, window: '7d' | '30d' = '7d'): { series: AreaTrendSeries[]; status: ChartStatus; caveat?: string } {\n const points = window === '7d' ? history.scorecard.trend7d : history.scorecard.trend30d;\n const source = history.scorecard.source;\n const status: ChartStatus = points.length === 0\n ? source.state === 'degraded'\n ? { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'io-error')}.` }\n : { kind: 'empty', message: 'No scorecard snapshots yet — the first is taken today, then one a day.' }\n : { kind: 'ready' };\n const caveat = points.length > 0 ? sourceCaveat('Scorecard points', source) : undefined;\n return {\n series: [\n { id: 'merges', label: 'Merges', points: points.map((p) => ({ x: Date.parse(p.ts), y: p.merges.realized })) },\n { id: 'filed', label: 'Proposals filed', points: points.map((p) => ({ x: Date.parse(p.ts), y: p.proposalsFiled })) },\n ],\n status,\n ...(caveat ? { caveat } : {}),\n };\n}\n","/**\n * Harness registry + experiments — V3.10 Track B contract (unit B-U1, frozen day 0).\n *\n * A HARNESS is the config-only envelope around the fleet's models: prompt\n * overlays, effort, sampling, routing weights and enabled skills. The\n * self-improvement loop (unit U9) versions harnesses, A/B-tests a candidate\n * against the active version on free local slots (paired runs, 95% CI,\n * ≥ 8 pairs, held-out tasks), and adopts a winner only through the Leader's\n * class-B action, behind a 48 h canary with automatic rollback.\n *\n * WHY config-only: a harness can never carry code, so adopting one can never\n * change authority (SPEC-310B I2). Code self-improvement arrives as ordinary\n * fleet PRs that pass every merge gate and only run after Mason deploys them.\n *\n * Honesty rule: `null` = unknown / not measured, never zero.\n *\n * BROWSER-SAFE: the Growth surface imports this — type-only imports, plain consts.\n */\nimport type { RoutingDifficulty } from '../routing/types.js';\nimport type { FleetEngine } from '../fleet/fleet-types.js';\n\nexport const VERSE_LEARNING_PATH = '/api/verse/learning';\n\n// ---------------------------------------------------------------------------\n// Harness config (what a version pins)\n// ---------------------------------------------------------------------------\n\nexport type HarnessEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\n/** Roles a prompt overlay can target. */\nexport type HarnessRole = 'producer' | 'judge' | 'leader' | 'planner';\n\nexport interface HarnessSampling {\n /** null = the engine's own default. */\n temperature: number | null;\n topP: number | null;\n maxOutputTokens: number | null;\n}\n\n/**\n * The dispatch router's tunables. Precedence at dispatch (U5): a Leader\n * `router.tune` override (LeaderDirectivesV1) › the active harness › the\n * router's compiled defaults. All λ are ≥ 0.\n */\nexport interface HarnessRoutingWeights {\n lambdaCost: number;\n lambdaPressure: number;\n lambdaLatency: number;\n /** Best-of-N runs at and above this difficulty. */\n bonThreshold: RoutingDifficulty;\n}\n\nexport interface HarnessConfigV1 {\n v: 1;\n /** Text appended to a role's system prompt; absent role = no overlay. Scrubbed, ≤ 4 KB each. */\n prompts: Partial<Record<HarnessRole, string>>;\n /** Effort per fleet engine; absent = engine default. */\n effort: Partial<Record<FleetEngine, HarnessEffort>>;\n /** Sampling per fleet engine; absent = engine default. */\n sampling: Partial<Record<FleetEngine, HarnessSampling>>;\n routing: HarnessRoutingWeights;\n /** Enabled skill ids, sorted. */\n skills: string[];\n}\n\n/** A config change. Top-level fields present here REPLACE the base's field wholesale (no deep merge). */\nexport type HarnessConfigPatch = Partial<Omit<HarnessConfigV1, 'v'>>;\n\n// ---------------------------------------------------------------------------\n// Versions\n// ---------------------------------------------------------------------------\n\n/**\n * - `baseline` — version 0: the compiled defaults.\n * - `candidate` — under experiment.\n * - `canary` — adopted, inside its 48 h canary.\n * - `adopted` — canary passed; the active version.\n * - `rolled-back` — canary fell below baseline − 1 SE (or vetoed).\n * - `rejected` — failed the adoption gate.\n */\nexport type HarnessVersionStatus = 'baseline' | 'candidate' | 'canary' | 'adopted' | 'rolled-back' | 'rejected';\n\nexport interface HarnessVersion {\n v: 1;\n /** Stable id, e.g. `h-0007`. */\n id: string;\n /** Monotonic; baseline = 0. */\n seq: number;\n parentId: string | null;\n createdAt: string;\n status: HarnessVersionStatus;\n config: HarnessConfigV1;\n /** sha256 hex of the canonical config — what experiments and ledger rows bind to. */\n configDigest: string;\n source: { kind: 'baseline' | 'hypothesis' | 'manual'; hypothesisId: string | null };\n /** The experiment whose verdict justified adoption; null for baseline / manual. */\n experimentId: string | null;\n adoptedAt: string | null;\n /** End of the 48 h canary; null when not in canary. */\n canaryUntil: string | null;\n rolledBackAt: string | null;\n rollbackReason: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Hypotheses and experiments\n// ---------------------------------------------------------------------------\n\nexport type HarnessTarget = 'prompt' | 'effort' | 'sampling' | 'routing' | 'skill';\n\n/** A typed, testable claim about a config change (the Leader emits ≤ 3 per memo; A7 insights may too). */\nexport interface HarnessHypothesis {\n v: 1;\n id: string;\n source: { kind: 'leader' | 'insight' | 'manual'; ref: string | null };\n target: HarnessTarget;\n /** Config only — never code. */\n patch: HarnessConfigPatch;\n /** The claim in one sentence. Untrusted model text: scrubbed, rendered as text. */\n statement: string;\n /** Metric it should move, e.g. `local-eval.pass-rate`. */\n metric: string;\n /** Predicted change, in the metric's units. */\n predictedDelta: number;\n createdAt: string;\n}\n\nexport type ExperimentVerdict = 'adopt' | 'reject' | 'inconclusive';\n\nexport type ExperimentStatus = 'queued' | 'running' | 'done' | 'cancelled' | 'failed';\n\nexport interface ExperimentLift {\n /** Paired pass-rate lift of candidate over base, in percentage points. */\n mean: number;\n ciLow: number;\n ciHigh: number;\n level: 0.95;\n}\n\nexport interface ExperimentResultV1 {\n v: 1;\n id: string;\n hypothesisId: string | null;\n baseVersionId: string;\n candidateVersionId: string;\n /** The held-out task set the pairs were drawn from. */\n taskSet: { id: string; digest: string };\n status: ExperimentStatus;\n /** Complete pairs so far. */\n pairs: number;\n wins: number;\n losses: number;\n ties: number;\n /** null until pairs ≥ HARNESS_ADOPTION_GATE.minPairs. */\n lift: ExperimentLift | null;\n /** Any `refuse`-class task regressed (blocks adoption). null = not measured yet. */\n refuseRegression: boolean | null;\n /** candidate − base count of `claimed-change-none-made` failures; must be ≤ 0 to adopt. */\n claimedChangeNoneMadeDelta: number | null;\n /** Wall-time / cost change in percent; must be ≤ +20 to adopt. */\n costDeltaPct: number | null;\n /** null while running. */\n verdict: ExperimentVerdict | null;\n /** Specific sentences behind the verdict. */\n reasons: string[];\n startedAt: string | null;\n finishedAt: string | null;\n}\n\n/**\n * The adoption gate (SPEC-310B §5) — frozen numbers. Adoption is a Leader\n * class-B action and requires ALL of: pairs ≥ minPairs, lift.ciLow >\n * minLiftCiLow, no refuse regression, claimedChangeNoneMadeDelta ≤ 0, and\n * costDeltaPct ≤ maxCostIncreasePct.\n */\nexport const HARNESS_ADOPTION_GATE = Object.freeze({\n minPairs: 8,\n ciLevel: 0.95,\n minLiftCiLow: 0,\n maxCostIncreasePct: 20,\n canaryHours: 48,\n /** Roll back when the canary pass rate falls below baseline − this many standard errors. */\n rollbackStandardErrors: 1,\n /** local-eval/tasks-heldout.ts must hold at least this many tasks (20 of 22 current tasks are saturated). */\n minHeldOutTasks: 12,\n} as const);\n\n/** Ledger payload for harness:adopted / harness:rolled-back / harness:rejected. */\nexport interface HarnessTransition {\n versionId: string;\n /** The version active before; null when none. */\n fromVersionId: string | null;\n configDigest: string;\n experimentId: string | null;\n reason: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cross-unit request / result shapes (learn/{experiments,harness-registry}.ts)\n// ---------------------------------------------------------------------------\n\nexport type HarnessActor = 'mason' | 'leader' | 'daemon';\n\nexport interface StartExperimentRequest {\n hypothesis: HarnessHypothesis;\n requestedBy: HarnessActor;\n}\n\nexport type StartExperimentResult = { ok: true; experimentId: string } | { ok: false; reason: string };\n\nexport interface CancelExperimentRequest {\n experimentId: string;\n reason: string;\n actor: HarnessActor;\n}\n\n/** A finished experiment cannot be cancelled (ok: false). */\nexport type CancelExperimentResult = { ok: true } | { ok: false; reason: string };\n\nexport interface AdoptHarnessRequest {\n versionId: string;\n /** The experiment whose verdict passed the gate. */\n experimentId: string;\n actor: HarnessActor;\n}\n\nexport interface RollbackHarnessRequest {\n /** The version to make active again; null = back to the baseline defaults. */\n toVersionId: string | null;\n reason: string;\n actor: HarnessActor;\n}\n\n/** `before` is the version active before the call, so a veto can restore it exactly. */\nexport type HarnessChangeResult =\n | { ok: true; before: HarnessVersion | null; after: HarnessVersion | null }\n | { ok: false; reason: string };\n\n// ---------------------------------------------------------------------------\n// Learning API (U9) — GET /api/verse/learning\n// ---------------------------------------------------------------------------\n\nexport interface HarnessCanaryState {\n versionId: string;\n startedAt: string;\n until: string;\n baselinePassRate: number | null;\n baselineStandardError: number | null;\n currentPassRate: number | null;\n runs: number;\n}\n\nexport interface LearningStateV1 {\n v: 1;\n generatedAt: string;\n /** null = nothing adopted; the baseline defaults are in force. */\n active: HarnessVersion | null;\n canary: HarnessCanaryState | null;\n /** Oldest → newest (Growth step chart with CI band and rollback markers). */\n versions: HarnessVersion[];\n /** Newest first (ForestPlot). */\n experiments: ExperimentResultV1[];\n /** Open hypotheses not yet tested. */\n hypotheses: HarnessHypothesis[];\n}\n","/**\n * routes/verse/growth/growth-model.ts — \"is the output compounding?\" as pure\n * data (unit C7; SPEC-310B §6 Growth, SPEC-310C §5).\n *\n * weeklyBins rolling 7-day windows ENDING TODAY, so every point is a\n * complete week (a calendar week-to-date would dip every\n * Monday and read as a regression);\n * costPerMerge spend ÷ merges per window — undefined (null) for a week\n * with no merges, never $0 or ∞;\n * modelOutcomes what each model's dispatches became (ROI composition);\n * harnessSteps the active harness's level over time: each adoption\n * steps up by its experiment's lift, a rollback steps back\n * down with a ▼ marker; only real timestamps, never the\n * baseline's epoch stamp;\n * forestRows one row per experiment, newest first.\n *\n * Framework-free; tested directly.\n */\nimport type { FleetHistoryDay } from '../../../../core/verse/fleet-history-types.js';\nimport type { ExperimentResultV1, HarnessVersion, LearningStateV1 } from '../../../../core/learn/harness-types.js';\nimport { HARNESS_ADOPTION_GATE } from '../../../../core/learn/harness-types.js';\nimport type { ModelStats } from '../../../data/api-types.js';\nimport type { BarStackSegment } from '../../../components/charts/BarStack.js';\nimport { toneColor } from '../../../components/charts/colors.js';\nimport type { ForestRow } from '../../../components/charts/ForestPlot.js';\nimport type { StepMarker, StepPoint } from '../../../components/charts/StepBand.js';\nimport { calendarDayStart } from './calendar-day.js';\n\nexport interface WeekBin {\n /**\n * Epoch ms of the window's last day at the viewer's LOCAL midnight\n * (`calendarDayStart`), so every local time label names that day.\n */\n end: number;\n /** YYYY-MM-DD of the last day. */\n endDay: string;\n merges: number | null;\n costUsd: number | null;\n}\n\n/** Complete 7-day windows ending on the last day of `days`, oldest first. */\nexport function weeklyBins(days: readonly FleetHistoryDay[]): WeekBin[] {\n const bins: WeekBin[] = [];\n for (let end = days.length; end - 7 >= 0; end -= 7) {\n const week = days.slice(end - 7, end);\n const sum = (pick: (d: FleetHistoryDay) => number | null): number | null => {\n let total = 0;\n for (const d of week) {\n const v = pick(d);\n if (v === null || !Number.isFinite(v)) return null;\n total += v;\n }\n return total;\n };\n const lastDay = week[week.length - 1]!.day;\n bins.unshift({ end: calendarDayStart(lastDay), endDay: lastDay, merges: sum((d) => d.merges.realized), costUsd: sum((d) => d.estCostUsd) });\n }\n return bins;\n}\n\n/** Dollars per merge; null when either side is unknown or nothing merged. */\nexport function costPerMerge(bin: WeekBin): number | null {\n if (bin.merges === null || bin.costUsd === null || bin.merges === 0) return null;\n return bin.costUsd / bin.merges;\n}\n\n// ---------------------------------------------------------------------------\n// Model outcomes (ROI)\n// ---------------------------------------------------------------------------\n\nexport const OUTCOME_SEGMENTS: BarStackSegment[] = [\n { id: 'merged', label: 'Merged', color: toneColor('success') },\n { id: 'ship', label: 'Judged ship, not merged', color: toneColor('info') },\n { id: 'rejected', label: 'Judged not worth shipping', color: toneColor('warning') },\n { id: 'unjudged', label: 'Not judged', color: toneColor('neutral') },\n];\n\nexport interface ModelOutcomes {\n categories: string[];\n values: (number | null)[][];\n /** Per category, for the caption / table: dollars per merge. */\n costPerMerged: (number | null)[];\n models: ModelStats[];\n}\n\n/** The longest model name an axis category keeps before it is shortened. */\nexport const MODEL_LABEL_MAX = 18;\n\n/** A snapshot date at the end of a model id: `-20251001`, `-2025-10-01`, `@20251001`. */\nconst DATE_SUFFIX = /[-@](?:\\d{8}|\\d{4}-\\d{2}-\\d{2})$/;\n\n/**\n * `name` shortened to at most `max` characters by cutting at a word boundary\n * (a space, `-` or `:`) and closing with \"…\" — never mid-word\n * (`grok-4.7-fast-reasoning` → `grok-4.7-fast…`). A name with no boundary\n * early enough stays whole: a long label beats a broken word.\n */\nfunction cutAtBoundary(name: string, max = MODEL_LABEL_MAX): string {\n if (name.length <= max) return name;\n const head = name.slice(0, max);\n const at = Math.max(head.lastIndexOf(' '), head.lastIndexOf('-'), head.lastIndexOf(':'));\n return at > 0 ? `${name.slice(0, at)}…` : name;\n}\n\n/**\n * Each model's axis name, UNIQUE across the chart. A model reads as its id\n * without a vendor path or snapshot date (`claude-haiku-4-5`), shortened only\n * at a word boundary. Names that would read the same — two dated snapshots of\n * one model, two long ids sharing a prefix, one tag on two engines — step\n * down TOGETHER through the same fuller forms until they differ: the whole\n * name, the id with its date, the id with its vendor path, `engine:model`\n * (so `claude-haiku-4-5-20251001` and `claude-haiku-4-5` both keep plain\n * ids). An ordinal (\"#2\") is the last resort: two columns never share a label.\n */\nexport function modelLabels(models: readonly Pick<ModelStats, 'engine' | 'model'>[]): string[] {\n // One rung per form, the same rungs for every model (a form that adds\n // nothing for this model simply repeats), so a group steps in lockstep.\n const ladders = models.map((m) => {\n const id = m.model.includes('/') ? m.model.split('/').pop()! : m.model;\n const name = id.replace(DATE_SUFFIX, '') || id;\n return [cutAtBoundary(name), name, id, m.model, `${m.engine}:${m.model}`];\n });\n const level = models.map(() => 0);\n const current = () => ladders.map((l, i) => l[level[i]!]!);\n const rungs = ladders[0]?.length ?? 0;\n for (let rung = 1; rung < rungs; rung++) {\n const labels = current();\n const seen = new Map<string, number>();\n for (const l of labels) seen.set(l, (seen.get(l) ?? 0) + 1);\n const clashing = labels.map((l) => seen.get(l)! > 1);\n if (!clashing.includes(true)) break;\n clashing.forEach((clash, i) => {\n if (clash) level[i] = rung;\n });\n }\n const taken = new Set<string>();\n return current().map((l) => {\n let label = l;\n for (let n = 2; taken.has(label); n++) label = `${l} #${n}`;\n taken.add(label);\n return label;\n });\n}\n\n/** Top `limit` models by dispatches, each split into what its dispatches became. */\nexport function modelOutcomes(models: readonly ModelStats[], limit = 6): ModelOutcomes {\n const top = [...models].filter((m) => m.dispatches > 0).sort((a, b) => b.dispatches - a.dispatches).slice(0, limit);\n return {\n categories: modelLabels(top),\n values: top.map((m) => {\n const merged = Math.max(0, m.merged);\n const ship = Math.max(0, m.shipVerdicts - merged);\n const rejected = Math.max(0, m.judged - m.shipVerdicts);\n const unjudged = Math.max(0, m.dispatches - m.judged);\n return [merged, ship, rejected, unjudged];\n }),\n costPerMerged: top.map((m) => m.costPerMergedUsd),\n models: top,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Harness steps + experiments\n// ---------------------------------------------------------------------------\n\nexport interface HarnessSeries {\n steps: StepPoint[];\n markers: StepMarker[];\n}\n\n/**\n * Anything stamped before this is not a real harness event. The registry\n * stamps the compiled-defaults baseline `1970-01-01T00:00:00.000Z` (it has no\n * creation time — core/learn/harness-registry.ts `baselineVersion`), and a\n * step drawn there stretched the x-axis from \"Dec 31\" to today. No Ashlr\n * harness predates 2020, so the floor also catches any other zero-ish stamp.\n */\nexport const HARNESS_TIME_FLOOR_MS = Date.UTC(2020, 0, 1);\n\n/** With nothing but the compiled defaults on record, the chart shows this trailing window. */\nexport const HARNESS_BASELINE_WINDOW_MS = 90 * 86_400_000;\n\n/** Epoch ms of a real harness timestamp; null for missing, unparsable or pre-floor (epoch) stamps. */\nexport function harnessTime(iso: string | null | undefined): number | null {\n if (!iso) return null;\n const t = Date.parse(iso);\n return Number.isFinite(t) && t >= HARNESS_TIME_FLOOR_MS ? t : null;\n}\n\n/**\n * When the compiled-defaults step starts: the baseline's own time when it has\n * a real one, else the first real harness event (a candidate created, an\n * experiment started, an adoption, a rollback), else — nothing but the\n * defaults on record — `HARNESS_BASELINE_WINDOW_MS` before `now`.\n */\nfunction baselineStart(learning: LearningStateV1, baseline: HarnessVersion, now: number): number {\n const own = harnessTime(baseline.createdAt);\n if (own !== null) return own;\n const times = [\n ...learning.versions.filter((v) => v.id !== baseline.id).flatMap((v) => [v.createdAt, v.adoptedAt, v.rolledBackAt]),\n ...learning.experiments.flatMap((e) => [e.startedAt, e.finishedAt]),\n ]\n .map(harnessTime)\n .filter((t): t is number => t !== null);\n return times.length > 0 ? Math.min(...times) : now - HARNESS_BASELINE_WINDOW_MS;\n}\n\n/**\n * The level of the ACTIVE harness over time, in points of paired pass-rate\n * lift over the compiled defaults. Each adoption adds its own experiment's\n * lift to the level of the version it was measured against; its band is that\n * experiment's 95% interval (the step's own uncertainty, not a compounded\n * one — the caption says so). A rollback returns to the parent's level.\n *\n * Every step and marker carries a REAL timestamp (`harnessTime`): an event\n * without one is left out rather than drawn at the epoch. `now` (default: the\n * state's own `generatedAt`) only anchors the defaults-only window.\n */\nexport function harnessSteps(learning: LearningStateV1 | null, now?: number): HarnessSeries {\n if (!learning || learning.versions.length === 0) return { steps: [], markers: [] };\n const byId = new Map(learning.versions.map((v) => [v.id, v]));\n const exps = new Map(learning.experiments.map((e) => [e.id, e]));\n const level = new Map<string, number | null>();\n const events: { at: number; step?: StepPoint; marker?: StepMarker }[] = [];\n\n const baseline = [...learning.versions].sort((a, b) => a.seq - b.seq)[0]!;\n level.set(baseline.id, 0);\n const t0 = baselineStart(learning, baseline, now ?? harnessTime(learning.generatedAt) ?? Date.now());\n events.push({ at: t0, step: { id: `${baseline.id}@base`, at: t0, value: 0, low: 0, high: 0, label: baseline.status === 'baseline' ? 'Compiled defaults' : baseline.id, detail: 'baseline' } });\n\n const adopted = learning.versions\n .filter((v) => v.adoptedAt && v.id !== baseline.id)\n .sort((a, b) => Date.parse(a.adoptedAt!) - Date.parse(b.adoptedAt!));\n for (const v of adopted) {\n const exp: ExperimentResultV1 | undefined = v.experimentId ? exps.get(v.experimentId) : undefined;\n const baseId = exp?.baseVersionId ?? v.parentId ?? baseline.id;\n const baseLevel = level.get(baseId) ?? (byId.has(baseId) ? null : 0);\n const lift = exp?.lift ?? null;\n const value = lift && baseLevel !== null && baseLevel !== undefined ? baseLevel + lift.mean : null;\n level.set(v.id, value);\n const at = harnessTime(v.adoptedAt);\n if (at === null) continue;\n const detail = v.status === 'canary' ? 'canary' : v.status === 'rolled-back' ? 'adopted, later rolled back' : 'adopted';\n events.push({\n at,\n step: {\n id: `${v.id}@adopt`,\n at,\n value,\n low: value !== null && lift ? baseLevel! + lift.ciLow : null,\n high: value !== null && lift ? baseLevel! + lift.ciHigh : null,\n label: v.id,\n detail,\n },\n });\n if (v.rolledBackAt) {\n const back = harnessTime(v.rolledBackAt);\n if (back !== null) {\n const parentLevel = level.get(baseId) ?? null;\n const parent = byId.get(baseId);\n events.push({ at: back, marker: { id: `${v.id}@rb`, at: back, kind: 'rollback', label: `${v.id}: ${v.rollbackReason ?? 'rolled back'}` } });\n events.push({ at: back + 1, step: { id: `${v.id}@rb-step`, at: back + 1, value: parentLevel, low: null, high: null, label: parent?.id ?? baseId, detail: `restored after ${v.id} rolled back` } });\n }\n }\n }\n events.sort((a, b) => a.at - b.at);\n return {\n steps: events.flatMap((e) => (e.step ? [e.step] : [])),\n markers: events.flatMap((e) => (e.marker ? [e.marker] : [])),\n };\n}\n\nconst VERDICT_WORD: Record<string, string> = { adopt: 'passed the gate', reject: 'rejected', inconclusive: 'inconclusive' };\n\nexport function forestRows(learning: LearningStateV1 | null): ForestRow[] {\n if (!learning) return [];\n return learning.experiments.map((e) => ({\n id: e.id,\n label: `${e.candidateVersionId} vs ${e.baseVersionId}`,\n estimate: e.lift?.mean ?? null,\n low: e.lift?.ciLow ?? null,\n high: e.lift?.ciHigh ?? null,\n n: e.pairs,\n detail:\n e.status === 'running' || e.status === 'queued'\n ? `${e.status} · ${e.pairs}/${HARNESS_ADOPTION_GATE.minPairs} pairs`\n : e.verdict\n ? VERDICT_WORD[e.verdict] ?? e.verdict\n : e.status,\n }));\n}\n","/**\n * routes/verse/sections/GrowthSection.tsx — ⌘3 Growth: is the output\n * compounding? (SPEC-310B §6, SPEC-310C §5; unit C7)\n *\n * Merges / week (8) | Cost per merge (4)\n * Pipeline funnel (4) | Model outcomes (4) | Merges by day (4)\n * Harness level with 95% band + ▼ rollbacks (8) | Experiments forest plot (4)\n *\n * Sources: fleet history (A8), per-model economics (/api/models), learning\n * (B-U9). Each can be missing on its own; its cards say so. History and\n * learning change daily, so the surface refreshes every 5 minutes while\n * visible — never faster.\n *\n * Dormant fleet: when autonomy is off (or on but quiet) the shared\n * AutonomyOffState leads the grid. When history is also quiet (nothing\n * produced for 48 h), every history card would repeat the same \"since\" date,\n * so those five are left out, and the learning / model cards stay only if\n * they have something real to draw — one clear state instead of six\n * identical empty cards.\n */\nimport { useMemo } from 'react';\nimport { AreaTrend } from '../../../components/charts/AreaTrend.js';\nimport { BarStack } from '../../../components/charts/BarStack.js';\nimport { CalendarHeatmap } from '../../../components/charts/CalendarHeatmap.js';\nimport type { ChartStatus } from '../../../components/charts/ChartFrame.js';\nimport { CHART_SEQUENTIAL } from '../../../components/charts/colors.js';\nimport { ForestPlot } from '../../../components/charts/ForestPlot.js';\nimport { Funnel } from '../../../components/charts/Funnel.js';\nimport { StepBand } from '../../../components/charts/StepBand.js';\nimport { dailyValues, historyStatus, pipelineFunnel, sourceCaveat } from '../../../components/charts/fleet-history-view.js';\nimport { formatTimeLabel, formatUsd } from '../../../components/charts/format.js';\nimport { RefreshIndicator } from '../../../components/primitives/RefreshIndicator.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { AutonomyOffState, useAutonomyOff } from '../autonomy/AutonomyOffState.js';\nimport { modelsQuery } from '../../../data/queries.js';\nimport { useNow } from '../autonomy/use-ticker.js';\nimport { Cell, Surface } from '../command/Surface.js';\nimport { fleetHistoryQuery, learningQuery } from '../command/surface-data.js';\nimport { quietSinceStatus } from '../fleet/dark-since.js';\nimport { usePollWhileVisible } from '../shell/section-visibility.js';\nimport { OUTCOME_SEGMENTS, costPerMerge, forestRows, harnessSteps, modelOutcomes, weeklyBins } from '../growth/growth-model.js';\nimport { HARNESS_ADOPTION_GATE } from '../../../../core/learn/harness-types.js';\n\nexport const GROWTH_POLL_MS = 300_000;\n\nconst models30 = modelsQuery('30d');\n\nfunction unknownFrom(reason: string | null | undefined, fallback: string): ChartStatus {\n return { kind: 'unknown', reason: reason ?? fallback };\n}\n\nexport function GrowthSection() {\n const history = useQuery(fleetHistoryQuery, { freshMs: 60_000 });\n const learning = useQuery(learningQuery, { freshMs: 60_000 });\n const models = useQuery(models30, { freshMs: 60_000 });\n const refetchHistory = useRefetch(fleetHistoryQuery);\n const refetchLearning = useRefetch(learningQuery);\n const refetchModels = useRefetch(models30);\n usePollWhileVisible(() => {\n refetchHistory();\n refetchLearning();\n refetchModels();\n }, GROWTH_POLL_MS);\n const now = useNow(60_000);\n\n const hist = history.data?.value ?? null;\n const learn = learning.data?.value ?? null;\n\n const bins = useMemo(() => (hist ? weeklyBins(hist.days) : []), [hist]);\n const histStatus: ChartStatus = !history.data ? { kind: 'loading' } : !hist ? unknownFrom(history.data.reason, 'fleet history did not answer.') : quietSinceStatus(historyStatus(hist, hist.sources.runs));\n const weeklyStatus: ChartStatus = histStatus.kind !== 'ready' ? histStatus : bins.length === 0 ? { kind: 'empty', message: 'Less than a week of history.' } : { kind: 'ready' };\n const mergesCaveat = hist ? sourceCaveat('Merge counts', hist.sources.decisions) : undefined;\n const funnel = hist ? pipelineFunnel(hist) : null;\n\n const outcomes = useMemo(() => modelOutcomes(models.data?.models ?? []), [models.data]);\n const modelStatus: ChartStatus = models.status === 'loading'\n ? { kind: 'loading' }\n : models.status === 'error' || !models.data\n ? { kind: 'unknown', reason: 'per-model economics could not be read.' }\n : outcomes.categories.length === 0\n ? { kind: 'empty', message: 'No fleet dispatches in 30 days.' }\n : { kind: 'ready' };\n\n const harness = useMemo(() => harnessSteps(learn), [learn]);\n const forest = useMemo(() => forestRows(learn), [learn]);\n const learnStatus = (emptyMessage: string, hasData: boolean): ChartStatus =>\n !learning.data ? { kind: 'loading' } : !learn ? unknownFrom(learning.data.reason, 'self-improvement did not answer.') : hasData ? { kind: 'ready' } : { kind: 'empty', message: emptyMessage };\n\n // History's \"quiet since\" (48 h without a run or proposal). The shared\n // state decides what is off and why; undefined until its reads answer.\n const quietSince = hist?.darkSince ?? null;\n const off = useAutonomyOff(quietSince);\n // Collapse only once the state can explain it — never six blank cells.\n const dormant = quietSince !== null && off != null;\n // A defaults-only harness is a flat line at 0: nothing to show while dormant.\n const harnessMoved = harness.steps.length > 1 || harness.markers.length > 0;\n const keepModels = !dormant || modelStatus.kind === 'ready';\n const keepHarness = !dormant || harnessMoved;\n const keepExperiments = !dormant || forest.length > 0;\n // Nothing left to draw: the state is the whole surface, and says so first.\n const onlyState = dormant && modelStatus.kind !== 'ready' && !harnessMoved && forest.length === 0;\n\n // A week bin sits at its last day's LOCAL midnight (growth-model\n // `weeklyBins`), so this label and the chart's own fallback rung (the\n // local `formatTimeLabel`) name the same calendar day in every zone.\n const weekLabel = (ms: number) => `wk to ${formatTimeLabel(ms)}`;\n\n return (\n <Surface title=\"Growth\" actions={[history, learning].some((q) => q.status === 'refreshing') ? <RefreshIndicator /> : null}>\n {off ? (\n <Cell span={12}>\n <AutonomyOffState state={off} here=\"growth\" title={onlyState ? 'Growth starts with the first fleet run.' : undefined} />\n </Cell>\n ) : null}\n {dormant ? null : (\n <Cell span={8}>\n <AreaTrend\n title=\"Merges per week\"\n description=\"Rolling 7-day windows ending today\"\n caveat={mergesCaveat}\n status={weeklyStatus}\n series={[{ id: 'merges', label: 'Merges', color: CHART_SEQUENTIAL, points: bins.map((b) => ({ x: b.end, y: b.merges })) }]}\n formatX={weekLabel}\n />\n </Cell>\n )}\n {dormant ? null : (\n <Cell span={4}>\n <AreaTrend\n title=\"Cost per merge\"\n description=\"Estimated run spend ÷ merges, per week\"\n status={weeklyStatus}\n series={[{ id: 'cpm', label: 'Cost per merge', color: CHART_SEQUENTIAL, points: bins.map((b) => ({ x: b.end, y: costPerMerge(b) })) }]}\n formatX={weekLabel}\n formatY={formatUsd}\n height={200}\n />\n </Cell>\n )}\n {dormant ? null : (\n <Cell span={4}>\n <Funnel\n title=\"Pipeline · 90d\"\n description=\"Filed → verified → passed → judged ship → merged\"\n caveat={funnel?.caveat}\n status={!funnel ? histStatus : quietSinceStatus(funnel.status)}\n stages={funnel?.stages ?? []}\n />\n </Cell>\n )}\n {keepModels ? (\n <Cell span={4}>\n <BarStack\n title=\"Model outcomes · 30d\"\n description=\"What each model's dispatches became\"\n status={modelStatus}\n categories={outcomes.categories}\n segments={OUTCOME_SEGMENTS}\n values={outcomes.values}\n height={200}\n />\n </Cell>\n ) : null}\n {dormant ? null : (\n <Cell span={4}>\n <CalendarHeatmap\n title=\"Merges by day\"\n description=\"Last 90 days\"\n status={histStatus}\n days={hist ? dailyValues(hist, (d) => d.merges.realized) : []}\n unit=\"merges\"\n />\n </Cell>\n )}\n {keepHarness ? (\n <Cell span={8}>\n {/* The rules live in the tooltip; the card says what it plots. */}\n <div title={`Band = each step's own 95% interval. A new harness runs as a canary for ${HARNESS_ADOPTION_GATE.canaryHours} h first.`}>\n <StepBand\n title=\"Harness level\"\n description=\"Pass-rate lift vs defaults\"\n status={learnStatus('Compiled defaults in force.', harness.steps.length > 0)}\n steps={harness.steps}\n markers={harness.markers}\n now={now}\n baseline={{ value: 0, label: 'Compiled defaults' }}\n unit=\"pts\"\n />\n </div>\n </Cell>\n ) : null}\n {keepExperiments ? (\n <Cell span={4}>\n <div title={`Adopted only when the interval's low end is above ${HARNESS_ADOPTION_GATE.minLiftCiLow}, over at least ${HARNESS_ADOPTION_GATE.minPairs} pairs.`}>\n <ForestPlot\n title=\"Experiments\"\n description=\"Paired lift, 95% interval\"\n status={learnStatus('No experiments yet.', forest.length > 0)}\n rows={forest}\n unit=\"pts\"\n unknownText={`under ${HARNESS_ADOPTION_GATE.minPairs} pairs`}\n />\n </div>\n </Cell>\n ) : null}\n </Surface>\n );\n}\n"],"mappings":"8vBA4BM,EAAsC,CAC1C,iBAAkB,uCAClB,eAAgB,6BAChB,cAAe,+DACf,mBAAoB,qCACpB,WAAY,iCACZ,aAAc,kDACd,cAAe,iCACf,gBAAiB,2CACjB,8CAA+C,4DAC/C,yCAA0C,yDAC1C,0BAA2B,+CAC3B,+BAAgC,iDAClC,EAEA,SAAS,EAAW,EAAwB,CAC1C,OAAO,EAAY,IAAW,EAAO,QAAQ,KAAM,GAAG,CACxD,CAGA,SAAgB,EAAa,EAAe,EAAgD,CAE1F,GADI,EAAO,UAAY,EAAO,QAAU,gBACpC,EAAO,QAAQ,SAAW,EAAG,OACjC,IAAM,EAAU,EAAO,eAAiB,EAAI,KAAK,EAAO,eAAe,WAAa,GACpF,MAAO,GAAG,EAAM,qBAAqB,EAAO,QAAQ,IAAI,CAAU,CAAC,CAAC,KAAK,IAAI,IAAI,EAAQ,EAC3F,CAOA,SAAgB,EAAc,EAA+B,EAAyC,CAMpG,OALI,EAAO,QAAU,eAAuB,CAAE,KAAM,UAAW,OAAQ,GAAG,EAAW,EAAO,QAAQ,IAAM,cAAc,EAAE,EAAG,EACzH,EAAO,QAAU,YAAc,EAAO,cAAgB,EACjD,CAAE,KAAM,UAAW,OAAQ,GAAG,EAAW,EAAO,QAAQ,IAAM,UAAU,EAAE,EAAG,EAElF,EAAQ,UAAkB,CAAE,KAAM,OAAQ,MAAO,EAAQ,SAAU,EAChE,CAAE,KAAM,OAAQ,CACzB,CAyCA,SAAgB,EAAe,EAAgG,CAC7H,IAAM,EAAI,EAAQ,OACZ,EAAS,EAAa,kBAAmB,EAAQ,QAAQ,SAAS,GAAK,EAAa,kBAAmB,EAAQ,QAAQ,SAAS,EACtI,MAAO,CACL,OAAQ,CACN,CAAE,GAAI,QAAS,MAAO,QAAS,MAAO,EAAE,KAAM,EAC9C,CAAE,GAAI,WAAY,MAAO,WAAY,MAAO,EAAE,QAAS,EACvD,CAAE,GAAI,SAAU,MAAO,sBAAuB,MAAO,EAAE,kBAAmB,EAC1E,CAAE,GAAI,OAAQ,MAAO,cAAe,MAAO,EAAE,UAAW,EACxD,CAAE,GAAI,SAAU,MAAO,SAAU,MAAO,EAAE,MAAO,CACnD,EACA,OAAQ,EAAc,EAAS,EAAQ,QAAQ,SAAS,EACxD,GAAI,EAAS,CAAE,QAAO,EAAI,CAAC,CAC7B,CACF,CA2BA,SAAgB,EAAY,EAA+B,EAAgE,CACzH,OAAO,EAAQ,KAAK,IAAK,IAAO,CAAE,IAAK,EAAE,IAAK,MAAO,EAAK,CAAC,CAAE,EAAE,CACjE,CCwBA,IAAa,EAAwB,OAAO,OAAO,CACjD,SAAU,EACV,QAAS,IACT,aAAc,EACd,mBAAoB,GACpB,YAAa,GAEb,uBAAwB,EAExB,gBAAiB,EACnB,CAAU,EChJV,SAAgB,EAAW,EAA6C,CACtE,IAAM,EAAkB,CAAC,EACzB,IAAK,IAAI,EAAM,EAAK,OAAQ,EAAM,GAAK,EAAG,GAAO,EAAG,CAClD,IAAM,EAAO,EAAK,MAAM,EAAM,EAAG,CAAG,EAC9B,EAAO,GAA+D,CAC1E,IAAI,EAAQ,EACZ,IAAK,IAAM,KAAK,EAAM,CACpB,IAAM,EAAI,EAAK,CAAC,EAChB,GAAI,IAAM,MAAQ,CAAC,OAAO,SAAS,CAAC,EAAG,OAAO,KAC9C,GAAS,CACX,CACA,OAAO,CACT,EACM,EAAU,EAAK,EAAK,OAAS,EAAE,CAAE,IACvC,EAAK,QAAQ,CAAE,IAAK,EAAiB,CAAO,EAAG,OAAQ,EAAS,OAAQ,EAAK,GAAM,EAAE,OAAO,QAAQ,EAAG,QAAS,EAAK,GAAM,EAAE,UAAU,CAAE,CAAC,CAC5I,CACA,OAAO,CACT,CAGA,SAAgB,EAAa,EAA6B,CAExD,OADI,EAAI,SAAW,MAAQ,EAAI,UAAY,MAAQ,EAAI,SAAW,EAAU,KACrE,EAAI,QAAU,EAAI,MAC3B,CAMA,IAAa,GAAsC,CACjD,CAAE,GAAI,SAAU,MAAO,SAAU,MAAO,EAAU,SAAS,CAAE,EAC7D,CAAE,GAAI,OAAQ,MAAO,0BAA2B,MAAO,EAAU,MAAM,CAAE,EACzE,CAAE,GAAI,WAAY,MAAO,4BAA6B,MAAO,EAAU,SAAS,CAAE,EAClF,CAAE,GAAI,WAAY,MAAO,aAAc,MAAO,EAAU,SAAS,CAAE,CACrE,EAcM,EAAc,mCAQpB,SAAS,EAAc,EAAc,EAAA,GAA+B,CAClE,GAAI,EAAK,QAAU,EAAK,OAAO,EAC/B,IAAM,EAAO,EAAK,MAAM,EAAG,CAAG,EACxB,EAAK,KAAK,IAAI,EAAK,YAAY,GAAG,EAAG,EAAK,YAAY,GAAG,EAAG,EAAK,YAAY,GAAG,CAAC,EACvF,OAAO,EAAK,EAAI,GAAG,EAAK,MAAM,EAAG,CAAE,EAAE,GAAK,CAC5C,CAYA,SAAgB,EAAY,EAAmE,CAG7F,IAAM,EAAU,EAAO,IAAK,GAAM,CAChC,IAAM,EAAK,EAAE,MAAM,SAAS,GAAG,EAAI,EAAE,MAAM,MAAM,GAAG,CAAC,CAAC,IAAI,EAAK,EAAE,MAC3D,EAAO,EAAG,QAAQ,EAAa,EAAE,GAAK,EAC5C,MAAO,CAAC,EAAc,CAAI,EAAG,EAAM,EAAI,EAAE,MAAO,GAAG,EAAE,OAAO,GAAG,EAAE,OAAO,CAC1E,CAAC,EACK,EAAQ,EAAO,QAAU,CAAC,EAC1B,MAAgB,EAAQ,KAAK,EAAG,IAAM,EAAE,EAAM,GAAK,EACnD,EAAQ,EAAQ,EAAE,EAAE,QAAU,EACpC,IAAK,IAAI,EAAO,EAAG,EAAO,EAAO,IAAQ,CACvC,IAAM,EAAS,EAAQ,EACjB,EAAO,IAAI,IACjB,IAAK,IAAM,KAAK,EAAQ,EAAK,IAAI,GAAI,EAAK,IAAI,CAAC,GAAK,GAAK,CAAC,EAC1D,IAAM,EAAW,EAAO,IAAK,GAAM,EAAK,IAAI,CAAC,EAAK,CAAC,EACnD,GAAI,CAAC,EAAS,SAAS,EAAI,EAAG,MAC9B,EAAS,SAAS,EAAO,IAAM,CACzB,IAAO,EAAM,GAAK,EACxB,CAAC,CACH,CACA,IAAM,EAAQ,IAAI,IAClB,OAAO,EAAQ,CAAC,CAAC,IAAK,GAAM,CAC1B,IAAI,EAAQ,EACZ,IAAK,IAAI,EAAI,EAAG,EAAM,IAAI,CAAK,EAAG,IAAK,EAAQ,GAAG,EAAE,IAAI,IAExD,OADA,EAAM,IAAI,CAAK,EACR,CACT,CAAC,CACH,CAGA,SAAgB,GAAc,EAA+B,EAAQ,EAAkB,CACrF,IAAM,EAAM,CAAC,GAAG,CAAM,CAAC,CAAC,OAAQ,GAAM,EAAE,WAAa,CAAC,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,WAAa,EAAE,UAAU,CAAC,CAAC,MAAM,EAAG,CAAK,EAClH,MAAO,CACL,WAAY,EAAY,CAAG,EAC3B,OAAQ,EAAI,IAAK,GAAM,CACrB,IAAM,EAAS,KAAK,IAAI,EAAG,EAAE,MAAM,EAInC,MAAO,CAAC,EAHK,KAAK,IAAI,EAAG,EAAE,aAAe,CAG1B,EAFC,KAAK,IAAI,EAAG,EAAE,OAAS,EAAE,YAEpB,EADL,KAAK,IAAI,EAAG,EAAE,WAAa,EAAE,MACd,CAAQ,CAC1C,CAAC,EACD,cAAe,EAAI,IAAK,GAAM,EAAE,gBAAgB,EAChD,OAAQ,CACV,CACF,CAkBA,IAAa,EAAwB,KAAK,IAAI,KAAM,EAAG,CAAC,EAG3C,EAA6B,OAG1C,SAAgB,EAAY,EAA+C,CACzE,GAAI,CAAC,EAAK,OAAO,KACjB,IAAM,EAAI,KAAK,MAAM,CAAG,EACxB,OAAO,OAAO,SAAS,CAAC,GAAK,GAAK,EAAwB,EAAI,IAChE,CAQA,SAAS,EAAc,EAA2B,EAA0B,EAAqB,CAC/F,IAAM,EAAM,EAAY,EAAS,SAAS,EAC1C,GAAI,IAAQ,KAAM,OAAO,EACzB,IAAM,EAAQ,CACZ,GAAG,EAAS,SAAS,OAAQ,GAAM,EAAE,KAAO,EAAS,EAAE,CAAC,CAAC,QAAS,GAAM,CAAC,EAAE,UAAW,EAAE,UAAW,EAAE,YAAY,CAAC,EAClH,GAAG,EAAS,YAAY,QAAS,GAAM,CAAC,EAAE,UAAW,EAAE,UAAU,CAAC,CACpE,CAAC,CACE,IAAI,CAAW,CAAC,CAChB,OAAQ,GAAmB,IAAM,IAAI,EACxC,OAAO,EAAM,OAAS,EAAI,KAAK,IAAI,GAAG,CAAK,EAAI,EAAM,CACvD,CAaA,SAAgB,EAAa,EAAkC,EAA6B,CAC1F,GAAI,CAAC,GAAY,EAAS,SAAS,SAAW,EAAG,MAAO,CAAE,MAAO,CAAC,EAAG,QAAS,CAAC,CAAE,EACjF,IAAM,EAAO,IAAI,IAAI,EAAS,SAAS,IAAK,GAAM,CAAC,EAAE,GAAI,CAAC,CAAC,CAAC,EACtD,EAAO,IAAI,IAAI,EAAS,YAAY,IAAK,GAAM,CAAC,EAAE,GAAI,CAAC,CAAC,CAAC,EACzD,EAAQ,IAAI,IACZ,EAAkE,CAAC,EAEnE,EAAW,CAAC,GAAG,EAAS,QAAQ,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,IAAM,EAAE,GAAG,CAAC,CAAC,GACtE,EAAM,IAAI,EAAS,GAAI,CAAC,EACxB,IAAM,EAAK,EAAc,EAAU,EAAU,GAAO,EAAY,EAAS,WAAW,GAAK,KAAK,IAAI,CAAC,EACnG,EAAO,KAAK,CAAE,GAAI,EAAI,KAAM,CAAE,GAAI,GAAG,EAAS,GAAG,OAAQ,GAAI,EAAI,MAAO,EAAG,IAAK,EAAG,KAAM,EAAG,MAAO,EAAS,SAAW,WAAa,oBAAsB,EAAS,GAAI,OAAQ,UAAW,CAAE,CAAC,EAE7L,IAAM,EAAU,EAAS,SACtB,OAAQ,GAAM,EAAE,WAAa,EAAE,KAAO,EAAS,EAAE,CAAC,CAClD,MAAM,EAAG,IAAM,KAAK,MAAM,EAAE,SAAU,EAAI,KAAK,MAAM,EAAE,SAAU,CAAC,EACrE,IAAK,IAAM,KAAK,EAAS,CACvB,IAAM,EAAsC,EAAE,aAAe,EAAK,IAAI,EAAE,YAAY,EAAI,IAAA,GAClF,EAAS,GAAK,eAAiB,EAAE,UAAY,EAAS,GACtD,EAAY,EAAM,IAAI,CAAM,IAAM,EAAK,IAAI,CAAM,EAAI,KAAO,GAC5D,EAAO,GAAK,MAAQ,KACpB,EAAQ,GAAQ,GAAc,KAAkC,EAAY,EAAK,KAAO,KAC9F,EAAM,IAAI,EAAE,GAAI,CAAK,EACrB,IAAM,EAAK,EAAY,EAAE,SAAS,EAClC,GAAI,IAAO,KAAM,SACjB,IAAM,EAAS,EAAE,SAAW,SAAW,SAAW,EAAE,SAAW,cAAgB,6BAA+B,UAa9G,GAZA,EAAO,KAAK,CACV,KACA,KAAM,CACJ,GAAI,GAAG,EAAE,GAAG,QACZ,KACA,QACA,IAAK,IAAU,MAAQ,EAAO,EAAa,EAAK,MAAQ,KACxD,KAAM,IAAU,MAAQ,EAAO,EAAa,EAAK,OAAS,KAC1D,MAAO,EAAE,GACT,QACF,CACF,CAAC,EACG,EAAE,aAAc,CAClB,IAAM,EAAO,EAAY,EAAE,YAAY,EACvC,GAAI,IAAS,KAAM,CACjB,IAAM,EAAc,EAAM,IAAI,CAAM,GAAK,KACnC,EAAS,EAAK,IAAI,CAAM,EAC9B,EAAO,KAAK,CAAE,GAAI,EAAM,OAAQ,CAAE,GAAI,GAAG,EAAE,GAAG,KAAM,GAAI,EAAM,KAAM,WAAY,MAAO,GAAG,EAAE,GAAG,IAAI,EAAE,gBAAkB,eAAgB,CAAE,CAAC,EAC1I,EAAO,KAAK,CAAE,GAAI,EAAO,EAAG,KAAM,CAAE,GAAI,GAAG,EAAE,GAAG,UAAW,GAAI,EAAO,EAAG,MAAO,EAAa,IAAK,KAAM,KAAM,KAAM,MAAO,GAAQ,IAAM,EAAQ,OAAQ,kBAAkB,EAAE,GAAG,aAAc,CAAE,CAAC,CACnM,CACF,CACF,CAEA,OADA,EAAO,MAAM,EAAG,IAAM,EAAE,GAAK,EAAE,EAAE,EAC1B,CACL,MAAO,EAAO,QAAS,GAAO,EAAE,KAAO,CAAC,EAAE,IAAI,EAAI,CAAC,CAAE,EACrD,QAAS,EAAO,QAAS,GAAO,EAAE,OAAS,CAAC,EAAE,MAAM,EAAI,CAAC,CAAE,CAC7D,CACF,CAEA,IAAM,EAAuC,CAAE,MAAO,kBAAmB,OAAQ,WAAY,aAAc,cAAe,EAE1H,SAAgB,EAAW,EAA+C,CAExE,OADK,EACE,EAAS,YAAY,IAAK,IAAO,CACtC,GAAI,EAAE,GACN,MAAO,GAAG,EAAE,mBAAmB,MAAM,EAAE,gBACvC,SAAU,EAAE,MAAM,MAAQ,KAC1B,IAAK,EAAE,MAAM,OAAS,KACtB,KAAM,EAAE,MAAM,QAAU,KACxB,EAAG,EAAE,MACL,OACE,EAAE,SAAW,WAAa,EAAE,SAAW,SACnC,GAAG,EAAE,OAAO,KAAK,EAAE,MAAM,GAAG,EAAsB,SAAS,QAC3D,EAAE,QACA,EAAa,EAAE,UAAY,EAAE,QAC7B,EAAE,MACZ,EAAE,EAdoB,CAAC,CAezB,WCvPa,EAAiB,IAExB,EAAW,EAAY,KAAK,EAElC,SAAS,EAAY,EAAmC,EAA+B,CACrF,MAAO,CAAE,KAAM,UAAW,OAAQ,GAAU,CAAS,CACvD,CAEA,SAAgB,GAAgB,CAC9B,IAAM,EAAU,EAAS,EAAmB,CAAE,QAAS,GAAO,CAAC,EACzD,EAAW,EAAS,EAAe,CAAE,QAAS,GAAO,CAAC,EACtD,EAAS,EAAS,EAAU,CAAE,QAAS,GAAO,CAAC,EAC/C,EAAiB,EAAW,CAAiB,EAC7C,EAAkB,EAAW,CAAa,EAC1C,EAAgB,EAAW,CAAQ,EACzC,OAA0B,CACxB,EAAe,EACf,EAAgB,EAChB,EAAc,CAChB,EAAG,CAAc,EACjB,IAAM,EAAM,GAAO,GAAM,EAEnB,EAAO,EAAQ,MAAM,OAAS,KAC9B,EAAQ,EAAS,MAAM,OAAS,KAEhC,GAAA,EAAO,EAAA,QAAA,KAAe,EAAO,EAAW,EAAK,IAAI,EAAI,CAAC,EAAI,CAAC,CAAI,CAAC,EAChE,EAA2B,EAAQ,KAA8B,EAA2E,EAAiB,EAAc,EAAM,EAAK,QAAQ,IAAI,CAAC,EAA3H,EAAY,EAAQ,KAAK,OAAQ,+BAA+B,EAA9F,CAAE,KAAM,SAAU,EAC5D,EAA4B,EAAW,OAAS,QAAuB,EAAK,SAAW,EAAI,CAAE,KAAM,QAAS,QAAS,8BAA+B,EAAI,CAAE,KAAM,OAAQ,EAA9G,EAC1D,EAAe,EAAO,EAAa,eAAgB,EAAK,QAAQ,SAAS,EAAI,IAAA,GAC7E,EAAS,EAAO,EAAe,CAAI,EAAI,KAEvC,GAAA,EAAW,EAAA,QAAA,KAAc,GAAc,EAAO,MAAM,QAAU,CAAC,CAAC,EAAG,CAAC,EAAO,IAAI,CAAC,EAChF,EAA2B,EAAO,SAAW,UAC/C,CAAE,KAAM,SAAU,EAClB,EAAO,SAAW,SAAW,CAAC,EAAO,KACnC,CAAE,KAAM,UAAW,OAAQ,wCAAyC,EACpE,EAAS,WAAW,SAAW,EAC7B,CAAE,KAAM,QAAS,QAAS,iCAAkC,EAC5D,CAAE,KAAM,OAAQ,EAElB,GAAA,EAAU,EAAA,QAAA,KAAc,EAAa,CAAK,EAAG,CAAC,CAAK,CAAC,EACpD,GAAA,EAAS,EAAA,QAAA,KAAc,EAAW,CAAK,EAAG,CAAC,CAAK,CAAC,EACjD,GAAe,EAAsB,IACxC,EAAS,KAA8B,EAAgF,EAAU,CAAE,KAAM,OAAQ,EAAI,CAAE,KAAM,QAAS,QAAS,CAAa,EAA7I,EAAY,EAAS,KAAK,OAAQ,kCAAkC,EAAnG,CAAE,KAAM,SAAU,EAI/B,EAAa,GAAM,WAAa,KAChC,EAAM,EAAe,CAAU,EAE/B,EAAU,IAAe,MAAQ,GAAO,KAExC,EAAe,EAAQ,MAAM,OAAS,GAAK,EAAQ,QAAQ,OAAS,EACpE,GAAa,CAAC,GAAW,EAAY,OAAS,QAC9C,GAAc,CAAC,GAAW,EAC1B,GAAkB,CAAC,GAAW,EAAO,OAAS,EAE9C,EAAY,GAAW,EAAY,OAAS,SAAW,CAAC,GAAgB,EAAO,SAAW,EAK1F,EAAa,GAAe,SAAS,EAAgB,CAAE,IAE7D,OACE,EAAA,EAAA,KAAA,CAAC,GAAD,CAAS,MAAM,SAAS,QAAS,CAAC,EAAS,CAAQ,CAAC,CAAC,KAAM,GAAM,EAAE,SAAW,YAAY,GAAI,EAAA,EAAA,IAAA,CAAC,EAAD,CAAmB,CAAA,EAAI,KAArH,SAAA,CACG,GACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,KAAM,GACV,UAAA,EAAA,EAAA,IAAA,CAAC,GAAD,CAAkB,MAAO,EAAK,KAAK,SAAS,MAAO,EAAY,0CAA4C,IAAA,EAAY,CAAA,CACnH,CAAA,EACJ,KACH,EAAU,MACT,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,KAAM,EACV,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAM,kBACN,YAAY,qCACZ,OAAQ,EACR,OAAQ,EACR,OAAQ,CAAC,CAAE,GAAI,SAAU,MAAO,SAAU,MAAO,EAAkB,OAAQ,EAAK,IAAK,IAAO,CAAE,EAAG,EAAE,IAAK,EAAG,EAAE,MAAO,EAAE,CAAE,CAAC,EACzH,QAAS,CACV,CAAA,CACG,CAAA,EAEP,EAAU,MACT,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,KAAM,EACV,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAM,iBACN,YAAY,yCACZ,OAAQ,EACR,OAAQ,CAAC,CAAE,GAAI,MAAO,MAAO,iBAAkB,MAAO,EAAkB,OAAQ,EAAK,IAAK,IAAO,CAAE,EAAG,EAAE,IAAK,EAAG,EAAa,CAAC,CAAE,EAAE,CAAE,CAAC,EACrI,QAAS,EACT,QAAS,EACT,OAAQ,GACT,CAAA,CACG,CAAA,EAEP,EAAU,MACT,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,KAAM,EACV,UAAA,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,MAAM,iBACN,YAAY,mDACZ,OAAQ,GAAQ,OAChB,OAAS,EAAsB,EAAiB,EAAO,MAAM,EAA3C,EAClB,OAAQ,GAAQ,QAAU,CAAC,CAC5B,CAAA,CACG,CAAA,EAEP,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,KAAM,EACV,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAM,uBACN,YAAY,sCACZ,OAAQ,EACR,WAAY,EAAS,WACrB,SAAU,GACV,OAAQ,EAAS,OACjB,OAAQ,GACT,CAAA,CACG,CAAA,EACJ,KACH,EAAU,MACT,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,KAAM,EACV,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAM,gBACN,YAAY,eACZ,OAAQ,EACR,KAAM,EAAO,EAAY,EAAO,GAAM,EAAE,OAAO,QAAQ,EAAI,CAAC,EAC5D,KAAK,QACN,CAAA,CACG,CAAA,EAEP,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,KAAM,EAEV,UAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,MAAO,2EAA2E,EAAsB,YAAY,WACvH,UAAA,EAAA,EAAA,IAAA,CAAC,EAAD,CACE,MAAM,gBACN,YAAY,6BACZ,OAAQ,EAAY,8BAA+B,EAAQ,MAAM,OAAS,CAAC,EAC3E,MAAO,EAAQ,MACf,QAAS,EAAQ,QACZ,MACL,SAAU,CAAE,MAAO,EAAG,MAAO,mBAAoB,EACjD,KAAK,KACN,CAAA,CACE,CAAA,CACD,CAAA,EACJ,KACH,IACC,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,KAAM,EACV,UAAA,EAAA,EAAA,IAAA,CAAC,MAAD,CAAK,MAAO,qDAAqD,EAAsB,aAAa,kBAAkB,EAAsB,SAAS,SACnJ,UAAA,EAAA,EAAA,IAAA,CAAC,GAAD,CACE,MAAM,cACN,YAAY,4BACZ,OAAQ,EAAY,sBAAuB,EAAO,OAAS,CAAC,EAC5D,KAAM,EACN,KAAK,MACL,YAAa,SAAS,EAAsB,SAAS,OACtD,CAAA,CACE,CAAA,CACD,CAAA,EACJ,IACG,GAEb"}
|
|
1
|
+
{"version":3,"file":"GrowthSection-P9EUfGeA.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/fleet-history-view.ts","../../../../../../src/core/learn/harness-types.ts","../../../../../../src/web-ui/routes/verse/growth/growth-model.ts","../../../../../../src/web-ui/routes/verse/sections/GrowthSection.tsx"],"sourcesContent":["/**\n * components/charts/fleet-history-view.ts — maps the `GET /api/verse/fleet/history`\n * payload (core/verse/fleet-history-types.ts) onto the chart kit's props, so\n * every surface that charts fleet history (Command, Fleet, Growth) makes the\n * same honesty decisions:\n *\n * - the fleet is DARK → every chart shows \"Fleet dark since <date>\", not\n * empty axes;\n * - a source could not be read at all → \"unknown\", not zeros;\n * - a source was only partly read → a caveat naming why (lower bounds);\n * - claim-check → always the not-recorded state, never a fabricated series.\n *\n * Pure functions over the wire type; no fetching here.\n */\nimport type {\n FleetHistoryDay,\n FleetHistoryResponse,\n FleetHistorySource,\n} from '../../../core/verse/fleet-history-types.js';\nimport type { ChartStatus } from './ChartFrame.js';\nimport type { BarStackProps } from './BarStack.js';\nimport type { FunnelStage } from './Funnel.js';\nimport type { SwimlaneLane } from './Swimlane.js';\nimport type { CalendarDatum } from './CalendarHeatmap.js';\nimport type { AreaTrendSeries } from './AreaTrend.js';\nimport { toneColor } from './colors.js';\nimport { formatDayLabel } from './format.js';\n\nconst REASON_TEXT: Record<string, string> = {\n 'oversized-file': 'some records are over the size bound',\n 'invalid-file': 'some records are malformed',\n 'unsafe-file': 'some records were refused (symlink, shared or foreign-owned)',\n 'unsafe-directory': 'the store directory is not private',\n 'io-error': 'some records could not be read',\n 'file-limit': 'the store has more records than one read covers',\n 'invalid-row': 'some ledger rows are malformed',\n 'oversized-row': 'some ledger rows are over the size bound',\n 'duplicate-canonical-realized-merge-identity': 'two proposals claim the same merge, so merges are unknown',\n 'claim-integrity-verdicts-not-persisted': 'claim-check verdicts are not recorded per proposal yet',\n 'scorecard-trend-pending': 'the scorecard trend is still being collected',\n 'scorecard-worker-unavailable': 'the scorecard trend could not be read this time',\n};\n\nfunction reasonText(reason: string): string {\n return REASON_TEXT[reason] ?? reason.replace(/-/g, ' ');\n}\n\n/** A caveat sentence for a partly-read source, or undefined when it is complete. */\nexport function sourceCaveat(label: string, source: FleetHistorySource): string | undefined {\n if (source.complete || source.state === 'not-recorded') return undefined;\n if (source.reasons.length === 0) return undefined;\n const skipped = source.recordsSkipped > 0 ? ` (${source.recordsSkipped} skipped)` : '';\n return `${label} are lower bounds: ${source.reasons.map(reasonText).join('; ')}${skipped}.`;\n}\n\n/**\n * The shared status for a chart over one source. Order matters: unreadable\n * beats dark (we cannot claim darkness from a store we cannot read), and dark\n * beats an all-zero window (the designed \"since\" message is more useful).\n */\nexport function historyStatus(history: FleetHistoryResponse, source: FleetHistorySource): ChartStatus {\n if (source.state === 'not-recorded') return { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'not recorded')}.` };\n if (source.state === 'degraded' && source.recordsRead === 0) {\n return { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'io-error')}.` };\n }\n if (history.darkSince) return { kind: 'dark', since: history.darkSince };\n return { kind: 'ready' };\n}\n\n/** \"Sep 3\" for a day row (the wire's days are already in the caller's zone). */\nexport function dayLabel(day: FleetHistoryDay): string {\n return formatDayLabel(day.day);\n}\n\n/** Runs per day as done / failed / aborted / unfinished — status tones, legend-labelled. */\nexport function runsByDay(history: FleetHistoryResponse): Pick<BarStackProps, 'categories' | 'segments' | 'values' | 'status' | 'caveat'> {\n return {\n categories: history.days.map(dayLabel),\n segments: [\n { id: 'done', label: 'Done', color: toneColor('success') },\n { id: 'failed', label: 'Failed', color: toneColor('danger') },\n { id: 'aborted', label: 'Aborted', color: toneColor('neutral') },\n { id: 'unfinished', label: 'Unfinished', color: toneColor('running') },\n ],\n values: history.days.map((d) => [d.runs.done, d.runs.failed, d.runs.aborted, d.runs.unfinished]),\n status: historyStatus(history, history.sources.runs),\n caveat: sourceCaveat('Run counts', history.sources.runs),\n };\n}\n\n/** Judge verdicts per day (the considered ones, plus failed judge calls). */\nexport function verdictsByDay(history: FleetHistoryResponse): Pick<BarStackProps, 'categories' | 'segments' | 'values' | 'status' | 'caveat'> {\n return {\n categories: history.days.map(dayLabel),\n segments: [\n { id: 'ship', label: 'Ship', color: toneColor('success') },\n { id: 'review', label: 'Review', color: toneColor('warning') },\n { id: 'noise', label: 'Noise', color: toneColor('neutral') },\n { id: 'harmful', label: 'Harmful', color: toneColor('danger') },\n { id: 'failed', label: 'Judge failed', color: toneColor('unknown') },\n ],\n values: history.days.map((d) => [d.judged.ship, d.judged.review, d.judged.noise, d.judged.harmful, d.judged.failed]),\n status: historyStatus(history, history.sources.decisions),\n caveat: sourceCaveat('Verdict counts', history.sources.decisions),\n };\n}\n\n/** Proposal pipeline for the window (cumulative stages — see FleetHistoryFunnel). */\nexport function pipelineFunnel(history: FleetHistoryResponse): { stages: FunnelStage[]; status: ChartStatus; caveat?: string } {\n const f = history.funnel;\n const caveat = sourceCaveat('Pipeline counts', history.sources.proposals) ?? sourceCaveat('Pipeline counts', history.sources.decisions);\n return {\n stages: [\n { id: 'filed', label: 'Filed', value: f.filed },\n { id: 'verified', label: 'Verified', value: f.verified },\n { id: 'passed', label: 'Verification passed', value: f.verificationPassed },\n { id: 'ship', label: 'Judged ship', value: f.judgedShip },\n { id: 'merged', label: 'Merged', value: f.merged },\n ],\n status: historyStatus(history, history.sources.proposals),\n ...(caveat ? { caveat } : {}),\n };\n}\n\n/** Swimlane lanes straight from the projection (runs → bars, engine as detail). */\nexport function runLanes(history: FleetHistoryResponse): { lanes: SwimlaneLane[]; from: number; to: number; status: ChartStatus; caveat?: string } {\n const truncated = history.swimlanesTruncated ? 'Showing the newest runs only; the full list is longer.' : undefined;\n const caveat = [sourceCaveat('Runs', history.sources.runs), truncated].filter(Boolean).join(' ') || undefined;\n return {\n lanes: history.swimlanes.map((lane) => ({\n id: lane.id,\n label: lane.label,\n items: lane.items.map((item) => ({\n id: item.id,\n start: item.startMs,\n end: item.endMs,\n status: item.status,\n detail: item.engine,\n stale: item.stale,\n })),\n })),\n from: Date.parse(history.window.from),\n to: Date.parse(history.window.to),\n status: historyStatus(history, history.sources.runs),\n ...(caveat ? { caveat } : {}),\n };\n}\n\n/** One number per day for the calendar heatmap. */\nexport function dailyValues(history: FleetHistoryResponse, pick: (day: FleetHistoryDay) => number | null): CalendarDatum[] {\n return history.days.map((d) => ({ day: d.day, value: pick(d) }));\n}\n\n/** Scorecard trend (daily snapshots of the trailing window) as AreaTrend series. */\nexport function scorecardSeries(history: FleetHistoryResponse, window: '7d' | '30d' = '7d'): { series: AreaTrendSeries[]; status: ChartStatus; caveat?: string } {\n const points = window === '7d' ? history.scorecard.trend7d : history.scorecard.trend30d;\n const source = history.scorecard.source;\n const status: ChartStatus = points.length === 0\n ? source.state === 'degraded'\n ? { kind: 'unknown', reason: `${reasonText(source.reasons[0] ?? 'io-error')}.` }\n : { kind: 'empty', message: 'No scorecard snapshots yet — the first is taken today, then one a day.' }\n : { kind: 'ready' };\n const caveat = points.length > 0 ? sourceCaveat('Scorecard points', source) : undefined;\n return {\n series: [\n { id: 'merges', label: 'Merges', points: points.map((p) => ({ x: Date.parse(p.ts), y: p.merges.realized })) },\n { id: 'filed', label: 'Proposals filed', points: points.map((p) => ({ x: Date.parse(p.ts), y: p.proposalsFiled })) },\n ],\n status,\n ...(caveat ? { caveat } : {}),\n };\n}\n","/**\n * Harness registry + experiments — V3.10 Track B contract (unit B-U1, frozen day 0).\n *\n * A HARNESS is the config-only envelope around the fleet's models: prompt\n * overlays, effort, sampling, routing weights and enabled skills. The\n * self-improvement loop (unit U9) versions harnesses, A/B-tests a candidate\n * against the active version on free local slots (paired runs, 95% CI,\n * ≥ 8 pairs, held-out tasks), and adopts a winner only through the Leader's\n * class-B action, behind a 48 h canary with automatic rollback.\n *\n * WHY config-only: a harness can never carry code, so adopting one can never\n * change authority (SPEC-310B I2). Code self-improvement arrives as ordinary\n * fleet PRs that pass every merge gate and only run after Mason deploys them.\n *\n * Honesty rule: `null` = unknown / not measured, never zero.\n *\n * BROWSER-SAFE: the Growth surface imports this — type-only imports, plain consts.\n */\nimport type { RoutingDifficulty } from '../routing/types.js';\nimport type { FleetEngine } from '../fleet/fleet-types.js';\n\nexport const VERSE_LEARNING_PATH = '/api/verse/learning';\n\n// ---------------------------------------------------------------------------\n// Harness config (what a version pins)\n// ---------------------------------------------------------------------------\n\nexport type HarnessEffort = 'low' | 'medium' | 'high' | 'xhigh' | 'max';\n\n/** Roles a prompt overlay can target. */\nexport type HarnessRole = 'producer' | 'judge' | 'leader' | 'planner';\n\nexport interface HarnessSampling {\n /** null = the engine's own default. */\n temperature: number | null;\n topP: number | null;\n maxOutputTokens: number | null;\n}\n\n/**\n * The dispatch router's tunables. Precedence at dispatch (U5): a Leader\n * `router.tune` override (LeaderDirectivesV1) › the active harness › the\n * router's compiled defaults. All λ are ≥ 0.\n */\nexport interface HarnessRoutingWeights {\n lambdaCost: number;\n lambdaPressure: number;\n lambdaLatency: number;\n /** Best-of-N runs at and above this difficulty. */\n bonThreshold: RoutingDifficulty;\n}\n\nexport interface HarnessConfigV1 {\n v: 1;\n /** Text appended to a role's system prompt; absent role = no overlay. Scrubbed, ≤ 4 KB each. */\n prompts: Partial<Record<HarnessRole, string>>;\n /** Effort per fleet engine; absent = engine default. */\n effort: Partial<Record<FleetEngine, HarnessEffort>>;\n /** Sampling per fleet engine; absent = engine default. */\n sampling: Partial<Record<FleetEngine, HarnessSampling>>;\n routing: HarnessRoutingWeights;\n /** Enabled skill ids, sorted. */\n skills: string[];\n}\n\n/** A config change. Top-level fields present here REPLACE the base's field wholesale (no deep merge). */\nexport type HarnessConfigPatch = Partial<Omit<HarnessConfigV1, 'v'>>;\n\n// ---------------------------------------------------------------------------\n// Versions\n// ---------------------------------------------------------------------------\n\n/**\n * - `baseline` — version 0: the compiled defaults.\n * - `candidate` — under experiment.\n * - `canary` — adopted, inside its 48 h canary.\n * - `adopted` — canary passed; the active version.\n * - `rolled-back` — canary fell below baseline − 1 SE (or vetoed).\n * - `rejected` — failed the adoption gate.\n */\nexport type HarnessVersionStatus = 'baseline' | 'candidate' | 'canary' | 'adopted' | 'rolled-back' | 'rejected';\n\nexport interface HarnessVersion {\n v: 1;\n /** Stable id, e.g. `h-0007`. */\n id: string;\n /** Monotonic; baseline = 0. */\n seq: number;\n parentId: string | null;\n createdAt: string;\n status: HarnessVersionStatus;\n config: HarnessConfigV1;\n /** sha256 hex of the canonical config — what experiments and ledger rows bind to. */\n configDigest: string;\n source: { kind: 'baseline' | 'hypothesis' | 'manual'; hypothesisId: string | null };\n /** The experiment whose verdict justified adoption; null for baseline / manual. */\n experimentId: string | null;\n adoptedAt: string | null;\n /** End of the 48 h canary; null when not in canary. */\n canaryUntil: string | null;\n rolledBackAt: string | null;\n rollbackReason: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Hypotheses and experiments\n// ---------------------------------------------------------------------------\n\nexport type HarnessTarget = 'prompt' | 'effort' | 'sampling' | 'routing' | 'skill';\n\n/** A typed, testable claim about a config change (the Leader emits ≤ 3 per memo; A7 insights may too). */\nexport interface HarnessHypothesis {\n v: 1;\n id: string;\n source: { kind: 'leader' | 'insight' | 'manual'; ref: string | null };\n target: HarnessTarget;\n /** Config only — never code. */\n patch: HarnessConfigPatch;\n /** The claim in one sentence. Untrusted model text: scrubbed, rendered as text. */\n statement: string;\n /** Metric it should move, e.g. `local-eval.pass-rate`. */\n metric: string;\n /** Predicted change, in the metric's units. */\n predictedDelta: number;\n createdAt: string;\n}\n\nexport type ExperimentVerdict = 'adopt' | 'reject' | 'inconclusive';\n\nexport type ExperimentStatus = 'queued' | 'running' | 'done' | 'cancelled' | 'failed';\n\nexport interface ExperimentLift {\n /** Paired pass-rate lift of candidate over base, in percentage points. */\n mean: number;\n ciLow: number;\n ciHigh: number;\n level: 0.95;\n}\n\nexport interface ExperimentResultV1 {\n v: 1;\n id: string;\n hypothesisId: string | null;\n baseVersionId: string;\n candidateVersionId: string;\n /** The held-out task set the pairs were drawn from. */\n taskSet: { id: string; digest: string };\n status: ExperimentStatus;\n /** Complete pairs so far. */\n pairs: number;\n wins: number;\n losses: number;\n ties: number;\n /** null until pairs ≥ HARNESS_ADOPTION_GATE.minPairs. */\n lift: ExperimentLift | null;\n /** Any `refuse`-class task regressed (blocks adoption). null = not measured yet. */\n refuseRegression: boolean | null;\n /** candidate − base count of `claimed-change-none-made` failures; must be ≤ 0 to adopt. */\n claimedChangeNoneMadeDelta: number | null;\n /** Wall-time / cost change in percent; must be ≤ +20 to adopt. */\n costDeltaPct: number | null;\n /** null while running. */\n verdict: ExperimentVerdict | null;\n /** Specific sentences behind the verdict. */\n reasons: string[];\n startedAt: string | null;\n finishedAt: string | null;\n}\n\n/**\n * The adoption gate (SPEC-310B §5) — frozen numbers. Adoption is a Leader\n * class-B action and requires ALL of: pairs ≥ minPairs, lift.ciLow >\n * minLiftCiLow, no refuse regression, claimedChangeNoneMadeDelta ≤ 0, and\n * costDeltaPct ≤ maxCostIncreasePct.\n */\nexport const HARNESS_ADOPTION_GATE = Object.freeze({\n minPairs: 8,\n ciLevel: 0.95,\n minLiftCiLow: 0,\n maxCostIncreasePct: 20,\n canaryHours: 48,\n /** Roll back when the canary pass rate falls below baseline − this many standard errors. */\n rollbackStandardErrors: 1,\n /** local-eval/tasks-heldout.ts must hold at least this many tasks (20 of 22 current tasks are saturated). */\n minHeldOutTasks: 12,\n} as const);\n\n/** Ledger payload for harness:adopted / harness:rolled-back / harness:rejected. */\nexport interface HarnessTransition {\n versionId: string;\n /** The version active before; null when none. */\n fromVersionId: string | null;\n configDigest: string;\n experimentId: string | null;\n reason: string;\n}\n\n// ---------------------------------------------------------------------------\n// Cross-unit request / result shapes (learn/{experiments,harness-registry}.ts)\n// ---------------------------------------------------------------------------\n\nexport type HarnessActor = 'mason' | 'leader' | 'daemon';\n\nexport interface StartExperimentRequest {\n hypothesis: HarnessHypothesis;\n requestedBy: HarnessActor;\n}\n\nexport type StartExperimentResult = { ok: true; experimentId: string } | { ok: false; reason: string };\n\nexport interface CancelExperimentRequest {\n experimentId: string;\n reason: string;\n actor: HarnessActor;\n}\n\n/** A finished experiment cannot be cancelled (ok: false). */\nexport type CancelExperimentResult = { ok: true } | { ok: false; reason: string };\n\nexport interface AdoptHarnessRequest {\n versionId: string;\n /** The experiment whose verdict passed the gate. */\n experimentId: string;\n actor: HarnessActor;\n}\n\nexport interface RollbackHarnessRequest {\n /** The version to make active again; null = back to the baseline defaults. */\n toVersionId: string | null;\n reason: string;\n actor: HarnessActor;\n}\n\n/** `before` is the version active before the call, so a veto can restore it exactly. */\nexport type HarnessChangeResult =\n | { ok: true; before: HarnessVersion | null; after: HarnessVersion | null }\n | { ok: false; reason: string };\n\n// ---------------------------------------------------------------------------\n// Learning API (U9) — GET /api/verse/learning\n// ---------------------------------------------------------------------------\n\nexport interface HarnessCanaryState {\n versionId: string;\n startedAt: string;\n until: string;\n baselinePassRate: number | null;\n baselineStandardError: number | null;\n currentPassRate: number | null;\n runs: number;\n}\n\nexport interface LearningStateV1 {\n v: 1;\n generatedAt: string;\n /** null = nothing adopted; the baseline defaults are in force. */\n active: HarnessVersion | null;\n canary: HarnessCanaryState | null;\n /** Oldest → newest (Growth step chart with CI band and rollback markers). */\n versions: HarnessVersion[];\n /** Newest first (ForestPlot). */\n experiments: ExperimentResultV1[];\n /** Open hypotheses not yet tested. */\n hypotheses: HarnessHypothesis[];\n}\n","/**\n * routes/verse/growth/growth-model.ts — \"is the output compounding?\" as pure\n * data (unit C7; SPEC-310B §6 Growth, SPEC-310C §5).\n *\n * weeklyBins rolling 7-day windows ENDING TODAY, so every point is a\n * complete week (a calendar week-to-date would dip every\n * Monday and read as a regression);\n * costPerMerge spend ÷ merges per window — undefined (null) for a week\n * with no merges, never $0 or ∞;\n * modelOutcomes what each model's dispatches became (ROI composition);\n * harnessSteps the active harness's level over time: each adoption\n * steps up by its experiment's lift, a rollback steps back\n * down with a ▼ marker; only real timestamps, never the\n * baseline's epoch stamp;\n * forestRows one row per experiment, newest first.\n *\n * Framework-free; tested directly.\n */\nimport type { FleetHistoryDay } from '../../../../core/verse/fleet-history-types.js';\nimport type { ExperimentResultV1, HarnessVersion, LearningStateV1 } from '../../../../core/learn/harness-types.js';\nimport { HARNESS_ADOPTION_GATE } from '../../../../core/learn/harness-types.js';\nimport type { ModelStats } from '../../../data/api-types.js';\nimport type { BarStackSegment } from '../../../components/charts/BarStack.js';\nimport { toneColor } from '../../../components/charts/colors.js';\nimport type { ForestRow } from '../../../components/charts/ForestPlot.js';\nimport type { StepMarker, StepPoint } from '../../../components/charts/StepBand.js';\nimport { calendarDayStart } from './calendar-day.js';\n\nexport interface WeekBin {\n /**\n * Epoch ms of the window's last day at the viewer's LOCAL midnight\n * (`calendarDayStart`), so every local time label names that day.\n */\n end: number;\n /** YYYY-MM-DD of the last day. */\n endDay: string;\n merges: number | null;\n costUsd: number | null;\n}\n\n/** Complete 7-day windows ending on the last day of `days`, oldest first. */\nexport function weeklyBins(days: readonly FleetHistoryDay[]): WeekBin[] {\n const bins: WeekBin[] = [];\n for (let end = days.length; end - 7 >= 0; end -= 7) {\n const week = days.slice(end - 7, end);\n const sum = (pick: (d: FleetHistoryDay) => number | null): number | null => {\n let total = 0;\n for (const d of week) {\n const v = pick(d);\n if (v === null || !Number.isFinite(v)) return null;\n total += v;\n }\n return total;\n };\n const lastDay = week[week.length - 1]!.day;\n bins.unshift({ end: calendarDayStart(lastDay), endDay: lastDay, merges: sum((d) => d.merges.realized), costUsd: sum((d) => d.estCostUsd) });\n }\n return bins;\n}\n\n/** Dollars per merge; null when either side is unknown or nothing merged. */\nexport function costPerMerge(bin: WeekBin): number | null {\n if (bin.merges === null || bin.costUsd === null || bin.merges === 0) return null;\n return bin.costUsd / bin.merges;\n}\n\n// ---------------------------------------------------------------------------\n// Model outcomes (ROI)\n// ---------------------------------------------------------------------------\n\nexport const OUTCOME_SEGMENTS: BarStackSegment[] = [\n { id: 'merged', label: 'Merged', color: toneColor('success') },\n { id: 'ship', label: 'Judged ship, not merged', color: toneColor('info') },\n { id: 'rejected', label: 'Judged not worth shipping', color: toneColor('warning') },\n { id: 'unjudged', label: 'Not judged', color: toneColor('neutral') },\n];\n\nexport interface ModelOutcomes {\n categories: string[];\n values: (number | null)[][];\n /** Per category, for the caption / table: dollars per merge. */\n costPerMerged: (number | null)[];\n models: ModelStats[];\n}\n\n/** The longest model name an axis category keeps before it is shortened. */\nexport const MODEL_LABEL_MAX = 18;\n\n/** A snapshot date at the end of a model id: `-20251001`, `-2025-10-01`, `@20251001`. */\nconst DATE_SUFFIX = /[-@](?:\\d{8}|\\d{4}-\\d{2}-\\d{2})$/;\n\n/**\n * `name` shortened to at most `max` characters by cutting at a word boundary\n * (a space, `-` or `:`) and closing with \"…\" — never mid-word\n * (`grok-4.7-fast-reasoning` → `grok-4.7-fast…`). A name with no boundary\n * early enough stays whole: a long label beats a broken word.\n */\nfunction cutAtBoundary(name: string, max = MODEL_LABEL_MAX): string {\n if (name.length <= max) return name;\n const head = name.slice(0, max);\n const at = Math.max(head.lastIndexOf(' '), head.lastIndexOf('-'), head.lastIndexOf(':'));\n return at > 0 ? `${name.slice(0, at)}…` : name;\n}\n\n/**\n * Each model's axis name, UNIQUE across the chart. A model reads as its id\n * without a vendor path or snapshot date (`claude-haiku-4-5`), shortened only\n * at a word boundary. Names that would read the same — two dated snapshots of\n * one model, two long ids sharing a prefix, one tag on two engines — step\n * down TOGETHER through the same fuller forms until they differ: the whole\n * name, the id with its date, the id with its vendor path, `engine:model`\n * (so `claude-haiku-4-5-20251001` and `claude-haiku-4-5` both keep plain\n * ids). An ordinal (\"#2\") is the last resort: two columns never share a label.\n */\nexport function modelLabels(models: readonly Pick<ModelStats, 'engine' | 'model'>[]): string[] {\n // One rung per form, the same rungs for every model (a form that adds\n // nothing for this model simply repeats), so a group steps in lockstep.\n const ladders = models.map((m) => {\n const id = m.model.includes('/') ? m.model.split('/').pop()! : m.model;\n const name = id.replace(DATE_SUFFIX, '') || id;\n return [cutAtBoundary(name), name, id, m.model, `${m.engine}:${m.model}`];\n });\n const level = models.map(() => 0);\n const current = () => ladders.map((l, i) => l[level[i]!]!);\n const rungs = ladders[0]?.length ?? 0;\n for (let rung = 1; rung < rungs; rung++) {\n const labels = current();\n const seen = new Map<string, number>();\n for (const l of labels) seen.set(l, (seen.get(l) ?? 0) + 1);\n const clashing = labels.map((l) => seen.get(l)! > 1);\n if (!clashing.includes(true)) break;\n clashing.forEach((clash, i) => {\n if (clash) level[i] = rung;\n });\n }\n const taken = new Set<string>();\n return current().map((l) => {\n let label = l;\n for (let n = 2; taken.has(label); n++) label = `${l} #${n}`;\n taken.add(label);\n return label;\n });\n}\n\n/** Top `limit` models by dispatches, each split into what its dispatches became. */\nexport function modelOutcomes(models: readonly ModelStats[], limit = 6): ModelOutcomes {\n const top = [...models].filter((m) => m.dispatches > 0).sort((a, b) => b.dispatches - a.dispatches).slice(0, limit);\n return {\n categories: modelLabels(top),\n values: top.map((m) => {\n const merged = Math.max(0, m.merged);\n const ship = Math.max(0, m.shipVerdicts - merged);\n const rejected = Math.max(0, m.judged - m.shipVerdicts);\n const unjudged = Math.max(0, m.dispatches - m.judged);\n return [merged, ship, rejected, unjudged];\n }),\n costPerMerged: top.map((m) => m.costPerMergedUsd),\n models: top,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Harness steps + experiments\n// ---------------------------------------------------------------------------\n\nexport interface HarnessSeries {\n steps: StepPoint[];\n markers: StepMarker[];\n}\n\n/**\n * Anything stamped before this is not a real harness event. The registry\n * stamps the compiled-defaults baseline `1970-01-01T00:00:00.000Z` (it has no\n * creation time — core/learn/harness-registry.ts `baselineVersion`), and a\n * step drawn there stretched the x-axis from \"Dec 31\" to today. No Ashlr\n * harness predates 2020, so the floor also catches any other zero-ish stamp.\n */\nexport const HARNESS_TIME_FLOOR_MS = Date.UTC(2020, 0, 1);\n\n/** With nothing but the compiled defaults on record, the chart shows this trailing window. */\nexport const HARNESS_BASELINE_WINDOW_MS = 90 * 86_400_000;\n\n/** Epoch ms of a real harness timestamp; null for missing, unparsable or pre-floor (epoch) stamps. */\nexport function harnessTime(iso: string | null | undefined): number | null {\n if (!iso) return null;\n const t = Date.parse(iso);\n return Number.isFinite(t) && t >= HARNESS_TIME_FLOOR_MS ? t : null;\n}\n\n/**\n * When the compiled-defaults step starts: the baseline's own time when it has\n * a real one, else the first real harness event (a candidate created, an\n * experiment started, an adoption, a rollback), else — nothing but the\n * defaults on record — `HARNESS_BASELINE_WINDOW_MS` before `now`.\n */\nfunction baselineStart(learning: LearningStateV1, baseline: HarnessVersion, now: number): number {\n const own = harnessTime(baseline.createdAt);\n if (own !== null) return own;\n const times = [\n ...learning.versions.filter((v) => v.id !== baseline.id).flatMap((v) => [v.createdAt, v.adoptedAt, v.rolledBackAt]),\n ...learning.experiments.flatMap((e) => [e.startedAt, e.finishedAt]),\n ]\n .map(harnessTime)\n .filter((t): t is number => t !== null);\n return times.length > 0 ? Math.min(...times) : now - HARNESS_BASELINE_WINDOW_MS;\n}\n\n/**\n * The level of the ACTIVE harness over time, in points of paired pass-rate\n * lift over the compiled defaults. Each adoption adds its own experiment's\n * lift to the level of the version it was measured against; its band is that\n * experiment's 95% interval (the step's own uncertainty, not a compounded\n * one — the caption says so). A rollback returns to the parent's level.\n *\n * Every step and marker carries a REAL timestamp (`harnessTime`): an event\n * without one is left out rather than drawn at the epoch. `now` (default: the\n * state's own `generatedAt`) only anchors the defaults-only window.\n */\nexport function harnessSteps(learning: LearningStateV1 | null, now?: number): HarnessSeries {\n if (!learning || learning.versions.length === 0) return { steps: [], markers: [] };\n const byId = new Map(learning.versions.map((v) => [v.id, v]));\n const exps = new Map(learning.experiments.map((e) => [e.id, e]));\n const level = new Map<string, number | null>();\n const events: { at: number; step?: StepPoint; marker?: StepMarker }[] = [];\n\n const baseline = [...learning.versions].sort((a, b) => a.seq - b.seq)[0]!;\n level.set(baseline.id, 0);\n const t0 = baselineStart(learning, baseline, now ?? harnessTime(learning.generatedAt) ?? Date.now());\n events.push({ at: t0, step: { id: `${baseline.id}@base`, at: t0, value: 0, low: 0, high: 0, label: baseline.status === 'baseline' ? 'Compiled defaults' : baseline.id, detail: 'baseline' } });\n\n const adopted = learning.versions\n .filter((v) => v.adoptedAt && v.id !== baseline.id)\n .sort((a, b) => Date.parse(a.adoptedAt!) - Date.parse(b.adoptedAt!));\n for (const v of adopted) {\n const exp: ExperimentResultV1 | undefined = v.experimentId ? exps.get(v.experimentId) : undefined;\n const baseId = exp?.baseVersionId ?? v.parentId ?? baseline.id;\n const baseLevel = level.get(baseId) ?? (byId.has(baseId) ? null : 0);\n const lift = exp?.lift ?? null;\n const value = lift && baseLevel !== null && baseLevel !== undefined ? baseLevel + lift.mean : null;\n level.set(v.id, value);\n const at = harnessTime(v.adoptedAt);\n if (at === null) continue;\n const detail = v.status === 'canary' ? 'canary' : v.status === 'rolled-back' ? 'adopted, later rolled back' : 'adopted';\n events.push({\n at,\n step: {\n id: `${v.id}@adopt`,\n at,\n value,\n low: value !== null && lift ? baseLevel! + lift.ciLow : null,\n high: value !== null && lift ? baseLevel! + lift.ciHigh : null,\n label: v.id,\n detail,\n },\n });\n if (v.rolledBackAt) {\n const back = harnessTime(v.rolledBackAt);\n if (back !== null) {\n const parentLevel = level.get(baseId) ?? null;\n const parent = byId.get(baseId);\n events.push({ at: back, marker: { id: `${v.id}@rb`, at: back, kind: 'rollback', label: `${v.id}: ${v.rollbackReason ?? 'rolled back'}` } });\n events.push({ at: back + 1, step: { id: `${v.id}@rb-step`, at: back + 1, value: parentLevel, low: null, high: null, label: parent?.id ?? baseId, detail: `restored after ${v.id} rolled back` } });\n }\n }\n }\n events.sort((a, b) => a.at - b.at);\n return {\n steps: events.flatMap((e) => (e.step ? [e.step] : [])),\n markers: events.flatMap((e) => (e.marker ? [e.marker] : [])),\n };\n}\n\nconst VERDICT_WORD: Record<string, string> = { adopt: 'passed the gate', reject: 'rejected', inconclusive: 'inconclusive' };\n\nexport function forestRows(learning: LearningStateV1 | null): ForestRow[] {\n if (!learning) return [];\n return learning.experiments.map((e) => ({\n id: e.id,\n label: `${e.candidateVersionId} vs ${e.baseVersionId}`,\n estimate: e.lift?.mean ?? null,\n low: e.lift?.ciLow ?? null,\n high: e.lift?.ciHigh ?? null,\n n: e.pairs,\n detail:\n e.status === 'running' || e.status === 'queued'\n ? `${e.status} · ${e.pairs}/${HARNESS_ADOPTION_GATE.minPairs} pairs`\n : e.verdict\n ? VERDICT_WORD[e.verdict] ?? e.verdict\n : e.status,\n }));\n}\n","/**\n * routes/verse/sections/GrowthSection.tsx — ⌘3 Growth: is the output\n * compounding? (SPEC-310B §6, SPEC-310C §5; unit C7)\n *\n * Merges / week (8) | Cost per merge (4)\n * Pipeline funnel (4) | Model outcomes (4) | Merges by day (4)\n * Harness level with 95% band + ▼ rollbacks (8) | Experiments forest plot (4)\n *\n * Sources: fleet history (A8), per-model economics (/api/models), learning\n * (B-U9). Each can be missing on its own; its cards say so. History and\n * learning change daily, so the surface refreshes every 5 minutes while\n * visible — never faster.\n *\n * Dormant fleet: when autonomy is off (or on but quiet) the shared\n * AutonomyOffState leads the grid. When history is also quiet (nothing\n * produced for 48 h), every history card would repeat the same \"since\" date,\n * so those five are left out, and the learning / model cards stay only if\n * they have something real to draw — one clear state instead of six\n * identical empty cards.\n */\nimport { useMemo } from 'react';\nimport { AreaTrend } from '../../../components/charts/AreaTrend.js';\nimport { BarStack } from '../../../components/charts/BarStack.js';\nimport { CalendarHeatmap } from '../../../components/charts/CalendarHeatmap.js';\nimport type { ChartStatus } from '../../../components/charts/ChartFrame.js';\nimport { CHART_SEQUENTIAL } from '../../../components/charts/colors.js';\nimport { ForestPlot } from '../../../components/charts/ForestPlot.js';\nimport { Funnel } from '../../../components/charts/Funnel.js';\nimport { StepBand } from '../../../components/charts/StepBand.js';\nimport { dailyValues, historyStatus, pipelineFunnel, sourceCaveat } from '../../../components/charts/fleet-history-view.js';\nimport { formatTimeLabel, formatUsd } from '../../../components/charts/format.js';\nimport { RefreshIndicator } from '../../../components/primitives/RefreshIndicator.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { AutonomyOffState, useAutonomyOff } from '../autonomy/AutonomyOffState.js';\nimport { modelsQuery } from '../../../data/queries.js';\nimport { useNow } from '../autonomy/use-ticker.js';\nimport { Cell, Surface } from '../command/Surface.js';\nimport { fleetHistoryQuery, learningQuery } from '../command/surface-data.js';\nimport { quietSinceStatus } from '../fleet/dark-since.js';\nimport { usePollWhileVisible } from '../shell/section-visibility.js';\nimport { OUTCOME_SEGMENTS, costPerMerge, forestRows, harnessSteps, modelOutcomes, weeklyBins } from '../growth/growth-model.js';\nimport { HARNESS_ADOPTION_GATE } from '../../../../core/learn/harness-types.js';\n\nexport const GROWTH_POLL_MS = 300_000;\n\nconst models30 = modelsQuery('30d');\n\n/** One series of weekly merge counts: the quantity ink, no legend needed. */\nconst MERGE_SEGMENTS = [{ id: 'merges', label: 'Merges', color: CHART_SEQUENTIAL }];\n\nfunction unknownFrom(reason: string | null | undefined, fallback: string): ChartStatus {\n return { kind: 'unknown', reason: reason ?? fallback };\n}\n\nexport function GrowthSection() {\n const history = useQuery(fleetHistoryQuery, { freshMs: 60_000 });\n const learning = useQuery(learningQuery, { freshMs: 60_000 });\n const models = useQuery(models30, { freshMs: 60_000 });\n const refetchHistory = useRefetch(fleetHistoryQuery);\n const refetchLearning = useRefetch(learningQuery);\n const refetchModels = useRefetch(models30);\n usePollWhileVisible(() => {\n refetchHistory();\n refetchLearning();\n refetchModels();\n }, GROWTH_POLL_MS);\n const now = useNow(60_000);\n\n const hist = history.data?.value ?? null;\n const learn = learning.data?.value ?? null;\n\n const bins = useMemo(() => (hist ? weeklyBins(hist.days) : []), [hist]);\n const histStatus: ChartStatus = !history.data ? { kind: 'loading' } : !hist ? unknownFrom(history.data.reason, 'fleet history did not answer.') : quietSinceStatus(historyStatus(hist, hist.sources.runs));\n const weeklyStatus: ChartStatus = histStatus.kind !== 'ready' ? histStatus : bins.length === 0 ? { kind: 'empty', message: 'Less than a week of history.' } : { kind: 'ready' };\n const mergesCaveat = hist ? sourceCaveat('Merge counts', hist.sources.decisions) : undefined;\n const funnel = hist ? pipelineFunnel(hist) : null;\n\n const outcomes = useMemo(() => modelOutcomes(models.data?.models ?? []), [models.data]);\n const modelStatus: ChartStatus = models.status === 'loading'\n ? { kind: 'loading' }\n : models.status === 'error' || !models.data\n ? { kind: 'unknown', reason: 'per-model economics could not be read.' }\n : outcomes.categories.length === 0\n ? { kind: 'empty', message: 'No fleet dispatches in 30 days.' }\n : { kind: 'ready' };\n\n const harness = useMemo(() => harnessSteps(learn), [learn]);\n const forest = useMemo(() => forestRows(learn), [learn]);\n const learnStatus = (emptyMessage: string, hasData: boolean): ChartStatus =>\n !learning.data ? { kind: 'loading' } : !learn ? unknownFrom(learning.data.reason, 'self-improvement did not answer.') : hasData ? { kind: 'ready' } : { kind: 'empty', message: emptyMessage };\n\n // History's \"quiet since\" (48 h without a run or proposal). The shared\n // state decides what is off and why; undefined until its reads answer.\n const quietSince = hist?.darkSince ?? null;\n const off = useAutonomyOff(quietSince);\n // Collapse only once the state can explain it — never six blank cells.\n const dormant = quietSince !== null && off != null;\n // A defaults-only harness is a flat line at 0: nothing to show while dormant.\n const harnessMoved = harness.steps.length > 1 || harness.markers.length > 0;\n const keepModels = !dormant || modelStatus.kind === 'ready';\n const keepHarness = !dormant || harnessMoved;\n const keepExperiments = !dormant || forest.length > 0;\n // Nothing left to draw: the state is the whole surface, and says so first.\n const onlyState = dormant && modelStatus.kind !== 'ready' && !harnessMoved && forest.length === 0;\n\n // A week bin sits at its last day's LOCAL midnight (growth-model\n // `weeklyBins`), so this label and the chart's own fallback rung (the\n // local `formatTimeLabel`) name the same calendar day in every zone.\n const weekLabel = (ms: number) => `wk to ${formatTimeLabel(ms)}`;\n\n return (\n <Surface title=\"Growth\" actions={[history, learning].some((q) => q.status === 'refreshing') ? <RefreshIndicator /> : null}>\n {off ? (\n <Cell span={12}>\n <AutonomyOffState state={off} here=\"growth\" title={onlyState ? 'Growth starts with the first fleet run.' : undefined} />\n </Cell>\n ) : null}\n {dormant ? null : (\n <Cell span={8}>\n {/* Columns, not an area: each week is a separate count, and a\n line between two weekly totals would draw merges that happened\n on no particular day. An unknown week is the kit's hatch. */}\n <BarStack\n title=\"Merges per week\"\n description=\"Rolling 7-day windows ending today\"\n caveat={mergesCaveat}\n status={weeklyStatus}\n categories={bins.map((b) => weekLabel(b.end))}\n segments={MERGE_SEGMENTS}\n values={bins.map((b) => [b.merges])}\n height={200}\n />\n </Cell>\n )}\n {dormant ? null : (\n <Cell span={4}>\n <AreaTrend\n title=\"Cost per merge\"\n description=\"Estimated run spend ÷ merges, per week\"\n status={weeklyStatus}\n series={[{ id: 'cpm', label: 'Cost per merge', color: CHART_SEQUENTIAL, points: bins.map((b) => ({ x: b.end, y: costPerMerge(b) })) }]}\n formatX={weekLabel}\n formatY={formatUsd}\n height={200}\n />\n </Cell>\n )}\n {dormant ? null : (\n <Cell span={4}>\n <Funnel\n title=\"Pipeline · 90d\"\n description=\"Filed → verified → passed → judged ship → merged\"\n caveat={funnel?.caveat}\n status={!funnel ? histStatus : quietSinceStatus(funnel.status)}\n stages={funnel?.stages ?? []}\n />\n </Cell>\n )}\n {keepModels ? (\n <Cell span={4}>\n <BarStack\n title=\"Model outcomes · 30d\"\n description=\"What each model's dispatches became\"\n status={modelStatus}\n categories={outcomes.categories}\n segments={OUTCOME_SEGMENTS}\n values={outcomes.values}\n height={200}\n />\n </Cell>\n ) : null}\n {dormant ? null : (\n <Cell span={4}>\n <CalendarHeatmap\n title=\"Merges by day\"\n description=\"Last 90 days\"\n status={histStatus}\n days={hist ? dailyValues(hist, (d) => d.merges.realized) : []}\n unit=\"merges\"\n />\n </Cell>\n )}\n {keepHarness ? (\n <Cell span={8}>\n {/* The rules live in the tooltip; the card says what it plots. */}\n <div title={`Band = each step's own 95% interval. A new harness runs as a canary for ${HARNESS_ADOPTION_GATE.canaryHours} h first.`}>\n <StepBand\n title=\"Harness level\"\n description=\"Pass-rate lift vs defaults\"\n status={learnStatus('Compiled defaults in force.', harness.steps.length > 0)}\n steps={harness.steps}\n markers={harness.markers}\n now={now}\n baseline={{ value: 0, label: 'Compiled defaults' }}\n unit=\"pts\"\n />\n </div>\n </Cell>\n ) : null}\n {keepExperiments ? (\n <Cell span={4}>\n <div title={`Adopted only when the interval's low end is above ${HARNESS_ADOPTION_GATE.minLiftCiLow}, over at least ${HARNESS_ADOPTION_GATE.minPairs} pairs.`}>\n <ForestPlot\n title=\"Experiments\"\n description=\"Paired lift, 95% interval\"\n status={learnStatus('No experiments yet.', forest.length > 0)}\n rows={forest}\n unit=\"pts\"\n unknownText={`under ${HARNESS_ADOPTION_GATE.minPairs} pairs`}\n />\n </div>\n </Cell>\n ) : null}\n </Surface>\n );\n}\n"],"mappings":"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"}
|
package/dist/core/web/public/next/assets/{HandoffDialog-DrQ6ofuy.js → HandoffDialog-CLJQLe7M.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,c as t,n}from"./index-QesfXBsb.js";import{O as r,p as i}from"./global-CNNGMril.js";import{t as a}from"./Dialog-BSsIFNqD.js";import{t as ee}from"./MutationTokenDialog-T7gv3a9r.js";import{a as te,h as ne,it as re,u as ie}from"./VerseConsoleApp-BCY5uSok.js";import{n as ae,v as o}from"./verse-model-MMySehjj.js";import{t as oe}from"./Segmented-CametjLt.js";import{a as s,l as c,p as se,s as ce,u as l}from"./verse-store-DNVRuiJL.js";import{t as le,y as ue}from"./format-Dk4Fmxax.js";import{l as de,r as fe,t as pe}from"./context-queries-CktFQqSS.js";import{o as me,s as he}from"./context-model-Co4wh3SM.js";import{t as ge}from"./SeatSelector-Cg75LInq.js";import{C as _e,D as ve,E as u,S as ye,c as d,d as be,f as xe,g as Se,h as Ce,m as we,o as f,s as Te,w as Ee,y as p}from"./context-model-DV1zCfAm.js";import{o as De}from"./workspace-model-Dukb2wwv.js";import{n as Oe,t as m}from"./use-token-gate-CYcfk_GS.js";import{t as h}from"./context.module-BijAfoJw.js";var g=t(e(),1),_=n();function v(e,t,n){if(!n)return d(e,t);if(e.length===0)return null;let r=e.find(e=>e.id===n.seatId);if(!r)return d(e,t);let i=Ce(r,n.model);if(i)return{seatId:r.id,model:i.id};let a=r.models.find(e=>!e.unavailableReason);return{seatId:r.id,model:a?a.id:n.model}}var ke=4e3,Ae="Building the handoff reads this chat’s log and runs `git diff --stat` on its folders. It spends nothing.",je=`Asking for a summary sends one turn to this chat’s seat.`,Me=`Stopping the summary turn.`,Ne=`Creating the chat records a new session on this machine. Nothing is sent to a model until you press Send in it.`;function Pe(e,t){let n=null,r=!1;for(let i of e)if(`turnId`in i&&i.turnId===t){if(i.type===`error`)n=i.message;else if(i.type===`assistant-message`||i.type===`text-delta`&&i.text.trim().length>0)r=!0;else if(i.type===`cancelled`)return{kind:`cancelled`};else if(i.type===`turn-done`)return i.ok?r?{kind:`ok`}:{kind:`empty`}:{kind:`failed`,message:n}}return null}function y(e){return e.open?(0,_.jsx)(b,{...e}):null}function b({session:e,seats:t,onClose:n,onCreated:d,initialTarget:y}){let b=(0,g.useId)(),x=(0,g.useId)(),S=(0,g.useId)(),C=(0,g.useId)(),Fe=(0,g.useId)(),w=(0,g.useId)(),T=(0,g.useId)(),E=(0,g.useRef)(null),D=Oe(),Ie=i(de),[O,Le]=(0,g.useState)(null),[k,A]=(0,g.useState)(`idle`),[j,Re]=(0,g.useState)(null),[M,ze]=(0,g.useState)(``),[N,Be]=(0,g.useState)(``),[Ve,He]=(0,g.useState)(!1),P=(0,g.useRef)(0),F=(0,g.useRef)(!0);(0,g.useEffect)(()=>(F.current=!0,()=>{F.current=!1}),[]);let Ue=(0,g.useRef)(null);Ue.current=O;let We=D.run,I=(0,g.useCallback)(async t=>{let n=P.current+=1;A(`loading`),Re(null);try{let r=await We(Ae,()=>fe(e.id,t));if(!F.current||n!==P.current)return;if(r===null){A(Ue.current?`ready`:`locked`);return}Le(r),ze(r.text),A(`ready`)}catch(e){if(!F.current||n!==P.current)return;Re(m(e)),A(`error`)}},[We,e.id]);(0,g.useEffect)(()=>{r()?I({includeLastAssistant:!1,focus:``}):A(`locked`)},[]);let L=O!==null&&M!==O.text,Ge=(0,g.useMemo)(()=>Ee(M)>65536||we({text:M})>65536,[M]),Ke=M.length>u,[R,qe]=(0,g.useState)(()=>v(t,e,y));(0,g.useEffect)(()=>{R===null&&t.length>0&&qe(v(t,e,y))},[R,t,e,y]);let z=R?o(t,R.seatId)??null:null,B=R?Ce(z,R.model):null,[V,Je]=(0,g.useState)(null),Ye=Te({option:B,target:R,source:e,preferences:Ie.data}),H=V!==null&&p(B,V)!==void 0?V:Ye,Xe=Se(B),U=ye(z,B),W=be(M.length,B,H,z?.engine??null),Ze=[he(B),me(z?.engine)].filter(Boolean).join(` `),Qe=1+(e.extraRoots?.filter(t=>t&&t!==e.projectPath).length??0),$e=De(z?.engine??null,Qe);function et(e){qe({seatId:e.seatId,model:e.model}),Je(null)}let[tt,nt]=(0,g.useState)(()=>xe(e.title)),[G,K]=(0,g.useState)({phase:`idle`}),q=o(t,e.seatId)?.label??ae[e.engine],J=G.phase===`sending`||G.phase===`waiting`||G.phase===`cancelling`,Y=e.status===`running`?`A turn is running in this chat. Wait for it to finish first.`:e.turnCount===0?`This chat has no turns yet, so there is nothing to summarize.`:null;async function rt(){K({phase:`sending`});try{let t=await D.run(je,async()=>{l(e.id,`running`);try{let t=await ne(e.id,ve);return c(e.id,t.session,t.turnId),t.turnId}catch(t){throw l(e.id,`idle`),t}});if(!F.current)return;K(t===null?{phase:`idle`}:{phase:`waiting`,turnId:t})}catch(e){F.current&&K({phase:`failed`,message:m(e)})}}async function it(){if(G.phase!==`waiting`)return;let t=G.turnId;K({phase:`cancelling`,turnId:t});try{await D.run(Me,()=>te(e.id))===null&&F.current&&K({phase:`waiting`,turnId:t})}catch(e){F.current&&K({phase:`failed`,message:m(e)})}}let at=(0,g.useRef)(N);at.current=N,(0,g.useEffect)(()=>{if(G.phase!==`waiting`&&G.phase!==`cancelling`)return;let t=G.turnId,n=!1,r=()=>{if(n)return;let r=Pe(s(e.id).events,t);if(r!==null)switch(n=!0,r.kind){case`ok`:K({phase:`done`}),He(!0),I({includeLastAssistant:!0,focus:at.current});break;case`cancelled`:K({phase:`failed`,message:`Summary stopped. The automatic preview is unchanged.`});break;case`empty`:K({phase:`failed`,message:`${q} finished without writing a summary. The automatic preview is unchanged.`});break;default:K({phase:`failed`,message:`The summary turn failed${r.message?`: ${le(ue(r.message))}`:``}. The automatic preview is unchanged.`})}};r();let i=se(r),a=setInterval(()=>{let t=s(e.id).stream;t!==`open`&&t!==`connecting`&&t!==`reconnecting`&&ie(e.id).then(t=>ce(e.id,t.session,t.events)).catch(()=>{})},ke);return()=>{n=!0,i(),clearInterval(a)}},[G,e.id]);let[X,ot]=(0,g.useState)(!1),[Z,st]=(0,g.useState)(null),ct=M.trim().length>0,Q=U??(O?null:`Build the handoff first.`)??(ct?null:`The handoff is empty — rebuild it or write one.`)??(Ge?`The handoff is over the 64 KB limit for one message. Trim it first.`:null)??(J?`Wait for the summary to finish, or stop it.`:null);async function lt(){if(!R||Q!==null||X)return;ot(!0),st(null);let t=M;try{let r=await D.run(Ne,()=>pe({source:e,seatId:R.seatId,model:R.model,contextMode:p(B,H),title:tt.trim()||void 0}));if(r===null)return;c(r.id,r),re(r.projectPath,{seatId:r.seatId,model:r.model}),d(r,t),n()}catch(e){F.current&&st(m(e))}finally{F.current&&ot(!1)}}let ut=()=>{D.dialog.open||n()},dt=Math.ceil(M.length/4),$=()=>void I({includeLastAssistant:Ve,focus:N});return(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(a,{open:!0,onClose:ut,titleId:b,title:`Continue in a fresh chat`,initialFocusRef:E,widthClassName:h.dialogWidth,description:(0,_.jsxs)(_.Fragment,{children:[`Start a new chat from a written handoff of “`,e.title||`Untitled chat`,`” instead of its full history.`]}),children:(0,_.jsxs)(`form`,{className:h.form,noValidate:!0,onSubmit:e=>{e.preventDefault(),lt()},children:[(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsxs)(`label`,{className:h.label,htmlFor:x,children:[`Focus for the next chat `,(0,_.jsx)(`span`,{className:h.optional,children:`optional`})]}),(0,_.jsxs)(`div`,{className:h.row,children:[(0,_.jsx)(`input`,{id:x,ref:E,className:h.input,value:N,maxLength:500,placeholder:`e.g. finish the migration, then run the full test suite`,autoComplete:`off`,onChange:e=>Be(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),k!==`loading`&&$())}}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:$,disabled:k===`loading`||J,children:L?`Rebuild (replaces your edits)`:`Rebuild`})]})]}),(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(`label`,{className:h.label,htmlFor:S,children:`Handoff — becomes the new chat’s first message`}),k===`locked`&&!O?(0,_.jsxs)(`div`,{className:h.locked,role:`status`,children:[(0,_.jsxs)(`p`,{children:[`Building the handoff needs the mutation token: it reads this chat’s log and runs `,(0,_.jsx)(`code`,{children:`git diff --stat`}),`. It spends nothing.`]}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:$,children:`Unlock and build the handoff`})]}):(0,_.jsx)(`textarea`,{id:S,className:h.textarea,value:M,rows:12,spellCheck:!1,"aria-describedby":C,"aria-busy":k===`loading`||void 0,disabled:!O,placeholder:k===`loading`?`Building the handoff from this chat’s log…`:``,onChange:e=>ze(e.target.value)}),(0,_.jsx)(`p`,{id:C,className:h.hint,"aria-live":`polite`,children:k===`loading`?O?`Rebuilding…`:`Reading this chat’s log…`:O?(0,_.jsxs)(_.Fragment,{children:[M.length.toLocaleString(),` chars · ~`,dt.toLocaleString(),` tokens`,` · `,O.stats.turnsCovered,` `,O.stats.turnsCovered===1?`turn`:`turns`,` · `,O.stats.filesTouched,` `,O.stats.filesTouched===1?`file`:`files`,` touched`,L?` · edited`:``,Ve?` · includes ${q}’s own summary`:``]}):null}),O&&O.stats.truncated.length>0?(0,_.jsxs)(`p`,{className:h.hint,children:[`To stay under `,u.toLocaleString(),` characters these sections were left out: `,O.stats.truncated.join(`, `),`.`]}):null,Ge?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:`Over the 64 KB limit for one message (counted as it is sent, line breaks and quotes encoded) — the new chat could not send it. Trim it first.`}):Ke?(0,_.jsxs)(`p`,{className:h.warn,children:[`Longer than the `,u.toLocaleString(),`-character handoff budget. It can still be sent; the new chat just starts bigger.`]}):null,k===`error`&&j?(0,_.jsxs)(`p`,{className:h.error,role:`alert`,children:[`Could not build the handoff: `,j,` `,(0,_.jsx)(`button`,{type:`button`,className:h.link,onClick:$,children:`Try again`})]}):null]}),(0,_.jsxs)(`section`,{className:h.aside,"aria-labelledby":`${b}-summary`,children:[(0,_.jsxs)(`h3`,{id:`${b}-summary`,className:h.label,children:[`Better summary `,(0,_.jsx)(`span`,{className:h.optional,children:`optional, spends`})]}),(0,_.jsxs)(`p`,{className:h.hint,children:[`The handoff above is assembled from this chat’s log. For one in the agent’s own words, ask `,q,` to write it first — its reply is added to the handoff. `,_e(e.engine,q)]}),G.phase===`waiting`||G.phase===`cancelling`?(0,_.jsxs)(`div`,{className:h.row,role:`status`,children:[(0,_.jsx)(`span`,{className:h.pending,"aria-hidden":`true`}),(0,_.jsx)(`span`,{className:h.hint,children:G.phase===`cancelling`?`Stopping the summary…`:`Waiting for ${q} to finish its summary…`}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:()=>void it(),disabled:G.phase===`cancelling`,children:`Stop the summary`})]}):(0,_.jsxs)(`div`,{className:h.row,children:[(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:()=>void rt(),disabled:Y!==null||G.phase===`sending`,children:G.phase===`sending`?`Sending…`:G.phase===`done`?`Ask ${q} again`:`Ask ${q} to summarize first`}),G.phase===`done`?(0,_.jsx)(`span`,{className:h.hint,role:`status`,children:`Summary added.`}):null]}),Y!==null&&!J?(0,_.jsx)(`p`,{className:h.hint,children:Y}):null,Y===null&&G.phase===`idle`&&L?(0,_.jsx)(`p`,{className:h.hint,children:`The handoff is rebuilt with the summary, which replaces your edits above.`}):null,G.phase===`failed`?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:G.message}):null]}),(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(ge,{id:Fe,seats:t,value:R,onChange:et,label:`Continue on`,modeFor:(e,t)=>R&&e.id===R.seatId&&t.id===R.model?H:`standard`}),U?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:U}):null,$e?(0,_.jsx)(`p`,{className:h.hint,children:$e}):null]}),B&&!U?(0,_.jsxs)(`div`,{className:h.field,children:[Xe?(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(`span`,{id:T,className:h.label,children:`Context mode`}),(0,_.jsx)(oe,{"aria-labelledby":T,size:`sm`,value:H,onChange:e=>Je(e),options:[{value:`standard`,label:`Standard`},{value:`expansive`,label:`Expansive`}]}),(0,_.jsxs)(`p`,{className:h.hint,children:[f(B,H),`.`,` `,H===`expansive`?`Expansive keeps far more of the conversation before compacting, but every turn re-sends all of it — each turn costs more usage.${Ze?` ${Ze}`:``}`:`Standard compacts sooner and keeps each turn cheaper. Expansive is one click away if the work needs it.`]})]}):f(B,`standard`)?(0,_.jsxs)(`p`,{className:h.hint,children:[f(B,`standard`),`.`]}):null,(0,_.jsx)(`p`,{className:`${h.fit} ${h[`fit-${W.tone}`]??``}`,"data-verdict":W.verdict??`unknown`,children:W.text})]}):null,(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(`label`,{className:h.label,htmlFor:w,children:`Title`}),(0,_.jsx)(`input`,{id:w,className:h.input,value:tt,maxLength:120,autoComplete:`off`,onChange:e=>nt(e.target.value)})]}),Z?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:Z}):null,(0,_.jsx)(`p`,{className:h.cost,children:`Creating the chat is free — nothing is sent to a model. The handoff goes into the new chat’s composer; read it, then press Send. That first turn is the first thing spent.`}),(0,_.jsxs)(`div`,{className:h.actions,children:[Q&&O?(0,_.jsx)(`span`,{className:h.blocked,children:Q}):null,(0,_.jsx)(`button`,{type:`button`,className:h.cancel,onClick:n,children:`Cancel`}),(0,_.jsx)(`button`,{type:`submit`,className:h.primary,disabled:Q!==null||X,children:X?`Creating…`:`Create chat`})]})]})}),(0,_.jsx)(ee,{open:D.dialog.open,reason:D.dialog.reason,tokenLabel:`Mutation token`,tokenHelp:`the mutation token ashlr verse printed`,onClose:D.dialog.onClose,onUnlocked:D.dialog.onUnlocked})]})}export{y as HandoffDialog};
|
|
2
|
-
//# sourceMappingURL=HandoffDialog-
|
|
1
|
+
import{a as e,c as t,n}from"./index-DZ-UQ7v8.js";import{A as r,h as i}from"./global-CMNW_dqn.js";import{t as a}from"./Dialog-D3msQlCj.js";import{t as ee}from"./MutationTokenDialog-DbnO8aYi.js";import{a as te,h as ne,it as re,u as ie}from"./VerseConsoleApp-CWU6R3By.js";import{n as ae,y as o}from"./verse-model-DAVevkNe.js";import{t as oe}from"./Segmented-CGh_-tBb.js";import{a as s,l as c,p as se,s as ce,u as l}from"./verse-store-DNVRuiJL.js";import{t as le,y as ue}from"./format-CH4g_sl1.js";import{l as de,r as fe,t as pe}from"./context-queries-eL3caKVG.js";import{o as me,s as he}from"./context-model-Br8t9jgG.js";import{t as ge}from"./SeatSelector-J5R3zDkB.js";import{C as _e,D as ve,E as u,S as ye,c as d,d as be,f as xe,g as Se,h as Ce,m as we,o as f,s as Te,w as Ee,y as p}from"./context-model-CokrgEUq.js";import{o as De}from"./workspace-model-dji5-Al3.js";import{n as Oe,t as m}from"./use-token-gate-CbXVYQYI.js";import{t as h}from"./context.module-BijAfoJw.js";var g=t(e(),1),_=n();function v(e,t,n){if(!n)return d(e,t);if(e.length===0)return null;let r=e.find(e=>e.id===n.seatId);if(!r)return d(e,t);let i=Ce(r,n.model);if(i)return{seatId:r.id,model:i.id};let a=r.models.find(e=>!e.unavailableReason);return{seatId:r.id,model:a?a.id:n.model}}var ke=4e3,Ae="Building the handoff reads this chat’s log and runs `git diff --stat` on its folders. It spends nothing.",je=`Asking for a summary sends one turn to this chat’s seat.`,Me=`Stopping the summary turn.`,Ne=`Creating the chat records a new session on this machine. Nothing is sent to a model until you press Send in it.`;function Pe(e,t){let n=null,r=!1;for(let i of e)if(`turnId`in i&&i.turnId===t){if(i.type===`error`)n=i.message;else if(i.type===`assistant-message`||i.type===`text-delta`&&i.text.trim().length>0)r=!0;else if(i.type===`cancelled`)return{kind:`cancelled`};else if(i.type===`turn-done`)return i.ok?r?{kind:`ok`}:{kind:`empty`}:{kind:`failed`,message:n}}return null}function y(e){return e.open?(0,_.jsx)(b,{...e}):null}function b({session:e,seats:t,onClose:n,onCreated:d,initialTarget:y}){let b=(0,g.useId)(),x=(0,g.useId)(),S=(0,g.useId)(),C=(0,g.useId)(),Fe=(0,g.useId)(),w=(0,g.useId)(),T=(0,g.useId)(),E=(0,g.useRef)(null),D=Oe(),Ie=i(de),[O,Le]=(0,g.useState)(null),[k,A]=(0,g.useState)(`idle`),[j,Re]=(0,g.useState)(null),[M,ze]=(0,g.useState)(``),[N,Be]=(0,g.useState)(``),[Ve,He]=(0,g.useState)(!1),P=(0,g.useRef)(0),F=(0,g.useRef)(!0);(0,g.useEffect)(()=>(F.current=!0,()=>{F.current=!1}),[]);let Ue=(0,g.useRef)(null);Ue.current=O;let We=D.run,I=(0,g.useCallback)(async t=>{let n=P.current+=1;A(`loading`),Re(null);try{let r=await We(Ae,()=>fe(e.id,t));if(!F.current||n!==P.current)return;if(r===null){A(Ue.current?`ready`:`locked`);return}Le(r),ze(r.text),A(`ready`)}catch(e){if(!F.current||n!==P.current)return;Re(m(e)),A(`error`)}},[We,e.id]);(0,g.useEffect)(()=>{r()?I({includeLastAssistant:!1,focus:``}):A(`locked`)},[]);let L=O!==null&&M!==O.text,Ge=(0,g.useMemo)(()=>Ee(M)>65536||we({text:M})>65536,[M]),Ke=M.length>u,[R,qe]=(0,g.useState)(()=>v(t,e,y));(0,g.useEffect)(()=>{R===null&&t.length>0&&qe(v(t,e,y))},[R,t,e,y]);let z=R?o(t,R.seatId)??null:null,B=R?Ce(z,R.model):null,[V,Je]=(0,g.useState)(null),Ye=Te({option:B,target:R,source:e,preferences:Ie.data}),H=V!==null&&p(B,V)!==void 0?V:Ye,Xe=Se(B),U=ye(z,B),W=be(M.length,B,H,z?.engine??null),Ze=[he(B),me(z?.engine)].filter(Boolean).join(` `),Qe=1+(e.extraRoots?.filter(t=>t&&t!==e.projectPath).length??0),$e=De(z?.engine??null,Qe);function et(e){qe({seatId:e.seatId,model:e.model}),Je(null)}let[tt,nt]=(0,g.useState)(()=>xe(e.title)),[G,K]=(0,g.useState)({phase:`idle`}),q=o(t,e.seatId)?.label??ae[e.engine],J=G.phase===`sending`||G.phase===`waiting`||G.phase===`cancelling`,Y=e.status===`running`?`A turn is running in this chat. Wait for it to finish first.`:e.turnCount===0?`This chat has no turns yet, so there is nothing to summarize.`:null;async function rt(){K({phase:`sending`});try{let t=await D.run(je,async()=>{l(e.id,`running`);try{let t=await ne(e.id,ve);return c(e.id,t.session,t.turnId),t.turnId}catch(t){throw l(e.id,`idle`),t}});if(!F.current)return;K(t===null?{phase:`idle`}:{phase:`waiting`,turnId:t})}catch(e){F.current&&K({phase:`failed`,message:m(e)})}}async function it(){if(G.phase!==`waiting`)return;let t=G.turnId;K({phase:`cancelling`,turnId:t});try{await D.run(Me,()=>te(e.id))===null&&F.current&&K({phase:`waiting`,turnId:t})}catch(e){F.current&&K({phase:`failed`,message:m(e)})}}let at=(0,g.useRef)(N);at.current=N,(0,g.useEffect)(()=>{if(G.phase!==`waiting`&&G.phase!==`cancelling`)return;let t=G.turnId,n=!1,r=()=>{if(n)return;let r=Pe(s(e.id).events,t);if(r!==null)switch(n=!0,r.kind){case`ok`:K({phase:`done`}),He(!0),I({includeLastAssistant:!0,focus:at.current});break;case`cancelled`:K({phase:`failed`,message:`Summary stopped. The automatic preview is unchanged.`});break;case`empty`:K({phase:`failed`,message:`${q} finished without writing a summary. The automatic preview is unchanged.`});break;default:K({phase:`failed`,message:`The summary turn failed${r.message?`: ${le(ue(r.message))}`:``}. The automatic preview is unchanged.`})}};r();let i=se(r),a=setInterval(()=>{let t=s(e.id).stream;t!==`open`&&t!==`connecting`&&t!==`reconnecting`&&ie(e.id).then(t=>ce(e.id,t.session,t.events)).catch(()=>{})},ke);return()=>{n=!0,i(),clearInterval(a)}},[G,e.id]);let[X,ot]=(0,g.useState)(!1),[Z,st]=(0,g.useState)(null),ct=M.trim().length>0,Q=U??(O?null:`Build the handoff first.`)??(ct?null:`The handoff is empty — rebuild it or write one.`)??(Ge?`The handoff is over the 64 KB limit for one message. Trim it first.`:null)??(J?`Wait for the summary to finish, or stop it.`:null);async function lt(){if(!R||Q!==null||X)return;ot(!0),st(null);let t=M;try{let r=await D.run(Ne,()=>pe({source:e,seatId:R.seatId,model:R.model,contextMode:p(B,H),title:tt.trim()||void 0}));if(r===null)return;c(r.id,r),re(r.projectPath,{seatId:r.seatId,model:r.model}),d(r,t),n()}catch(e){F.current&&st(m(e))}finally{F.current&&ot(!1)}}let ut=()=>{D.dialog.open||n()},dt=Math.ceil(M.length/4),$=()=>void I({includeLastAssistant:Ve,focus:N});return(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(a,{open:!0,onClose:ut,titleId:b,title:`Continue in a fresh chat`,initialFocusRef:E,widthClassName:h.dialogWidth,description:(0,_.jsxs)(_.Fragment,{children:[`Start a new chat from a written handoff of “`,e.title||`Untitled chat`,`” instead of its full history.`]}),children:(0,_.jsxs)(`form`,{className:h.form,noValidate:!0,onSubmit:e=>{e.preventDefault(),lt()},children:[(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsxs)(`label`,{className:h.label,htmlFor:x,children:[`Focus for the next chat `,(0,_.jsx)(`span`,{className:h.optional,children:`optional`})]}),(0,_.jsxs)(`div`,{className:h.row,children:[(0,_.jsx)(`input`,{id:x,ref:E,className:h.input,value:N,maxLength:500,placeholder:`e.g. finish the migration, then run the full test suite`,autoComplete:`off`,onChange:e=>Be(e.target.value),onKeyDown:e=>{e.key===`Enter`&&(e.preventDefault(),k!==`loading`&&$())}}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:$,disabled:k===`loading`||J,children:L?`Rebuild (replaces your edits)`:`Rebuild`})]})]}),(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(`label`,{className:h.label,htmlFor:S,children:`Handoff — becomes the new chat’s first message`}),k===`locked`&&!O?(0,_.jsxs)(`div`,{className:h.locked,role:`status`,children:[(0,_.jsxs)(`p`,{children:[`Building the handoff needs the mutation token: it reads this chat’s log and runs `,(0,_.jsx)(`code`,{children:`git diff --stat`}),`. It spends nothing.`]}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:$,children:`Unlock and build the handoff`})]}):(0,_.jsx)(`textarea`,{id:S,className:h.textarea,value:M,rows:12,spellCheck:!1,"aria-describedby":C,"aria-busy":k===`loading`||void 0,disabled:!O,placeholder:k===`loading`?`Building the handoff from this chat’s log…`:``,onChange:e=>ze(e.target.value)}),(0,_.jsx)(`p`,{id:C,className:h.hint,"aria-live":`polite`,children:k===`loading`?O?`Rebuilding…`:`Reading this chat’s log…`:O?(0,_.jsxs)(_.Fragment,{children:[M.length.toLocaleString(),` chars · ~`,dt.toLocaleString(),` tokens`,` · `,O.stats.turnsCovered,` `,O.stats.turnsCovered===1?`turn`:`turns`,` · `,O.stats.filesTouched,` `,O.stats.filesTouched===1?`file`:`files`,` touched`,L?` · edited`:``,Ve?` · includes ${q}’s own summary`:``]}):null}),O&&O.stats.truncated.length>0?(0,_.jsxs)(`p`,{className:h.hint,children:[`To stay under `,u.toLocaleString(),` characters these sections were left out: `,O.stats.truncated.join(`, `),`.`]}):null,Ge?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:`Over the 64 KB limit for one message (counted as it is sent, line breaks and quotes encoded) — the new chat could not send it. Trim it first.`}):Ke?(0,_.jsxs)(`p`,{className:h.warn,children:[`Longer than the `,u.toLocaleString(),`-character handoff budget. It can still be sent; the new chat just starts bigger.`]}):null,k===`error`&&j?(0,_.jsxs)(`p`,{className:h.error,role:`alert`,children:[`Could not build the handoff: `,j,` `,(0,_.jsx)(`button`,{type:`button`,className:h.link,onClick:$,children:`Try again`})]}):null]}),(0,_.jsxs)(`section`,{className:h.aside,"aria-labelledby":`${b}-summary`,children:[(0,_.jsxs)(`h3`,{id:`${b}-summary`,className:h.label,children:[`Better summary `,(0,_.jsx)(`span`,{className:h.optional,children:`optional, spends`})]}),(0,_.jsxs)(`p`,{className:h.hint,children:[`The handoff above is assembled from this chat’s log. For one in the agent’s own words, ask `,q,` to write it first — its reply is added to the handoff. `,_e(e.engine,q)]}),G.phase===`waiting`||G.phase===`cancelling`?(0,_.jsxs)(`div`,{className:h.row,role:`status`,children:[(0,_.jsx)(`span`,{className:h.pending,"aria-hidden":`true`}),(0,_.jsx)(`span`,{className:h.hint,children:G.phase===`cancelling`?`Stopping the summary…`:`Waiting for ${q} to finish its summary…`}),(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:()=>void it(),disabled:G.phase===`cancelling`,children:`Stop the summary`})]}):(0,_.jsxs)(`div`,{className:h.row,children:[(0,_.jsx)(`button`,{type:`button`,className:h.secondary,onClick:()=>void rt(),disabled:Y!==null||G.phase===`sending`,children:G.phase===`sending`?`Sending…`:G.phase===`done`?`Ask ${q} again`:`Ask ${q} to summarize first`}),G.phase===`done`?(0,_.jsx)(`span`,{className:h.hint,role:`status`,children:`Summary added.`}):null]}),Y!==null&&!J?(0,_.jsx)(`p`,{className:h.hint,children:Y}):null,Y===null&&G.phase===`idle`&&L?(0,_.jsx)(`p`,{className:h.hint,children:`The handoff is rebuilt with the summary, which replaces your edits above.`}):null,G.phase===`failed`?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:G.message}):null]}),(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(ge,{id:Fe,seats:t,value:R,onChange:et,label:`Continue on`,modeFor:(e,t)=>R&&e.id===R.seatId&&t.id===R.model?H:`standard`}),U?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:U}):null,$e?(0,_.jsx)(`p`,{className:h.hint,children:$e}):null]}),B&&!U?(0,_.jsxs)(`div`,{className:h.field,children:[Xe?(0,_.jsxs)(_.Fragment,{children:[(0,_.jsx)(`span`,{id:T,className:h.label,children:`Context mode`}),(0,_.jsx)(oe,{"aria-labelledby":T,size:`sm`,value:H,onChange:e=>Je(e),options:[{value:`standard`,label:`Standard`},{value:`expansive`,label:`Expansive`}]}),(0,_.jsxs)(`p`,{className:h.hint,children:[f(B,H),`.`,` `,H===`expansive`?`Expansive keeps far more of the conversation before compacting, but every turn re-sends all of it — each turn costs more usage.${Ze?` ${Ze}`:``}`:`Standard compacts sooner and keeps each turn cheaper. Expansive is one click away if the work needs it.`]})]}):f(B,`standard`)?(0,_.jsxs)(`p`,{className:h.hint,children:[f(B,`standard`),`.`]}):null,(0,_.jsx)(`p`,{className:`${h.fit} ${h[`fit-${W.tone}`]??``}`,"data-verdict":W.verdict??`unknown`,children:W.text})]}):null,(0,_.jsxs)(`div`,{className:h.field,children:[(0,_.jsx)(`label`,{className:h.label,htmlFor:w,children:`Title`}),(0,_.jsx)(`input`,{id:w,className:h.input,value:tt,maxLength:120,autoComplete:`off`,onChange:e=>nt(e.target.value)})]}),Z?(0,_.jsx)(`p`,{className:h.error,role:`alert`,children:Z}):null,(0,_.jsx)(`p`,{className:h.cost,children:`Creating the chat is free — nothing is sent to a model. The handoff goes into the new chat’s composer; read it, then press Send. That first turn is the first thing spent.`}),(0,_.jsxs)(`div`,{className:h.actions,children:[Q&&O?(0,_.jsx)(`span`,{className:h.blocked,children:Q}):null,(0,_.jsx)(`button`,{type:`button`,className:h.cancel,onClick:n,children:`Cancel`}),(0,_.jsx)(`button`,{type:`submit`,className:h.primary,disabled:Q!==null||X,children:X?`Creating…`:`Create chat`})]})]})}),(0,_.jsx)(ee,{open:D.dialog.open,reason:D.dialog.reason,tokenLabel:`Mutation token`,tokenHelp:`the mutation token ashlr verse printed`,onClose:D.dialog.onClose,onUnlocked:D.dialog.onUnlocked})]})}export{y as HandoffDialog};
|
|
2
|
+
//# sourceMappingURL=HandoffDialog-CLJQLe7M.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"HandoffDialog-DrQ6ofuy.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/context/HandoffDialog.tsx"],"sourcesContent":["/**\n * routes/verse/context/HandoffDialog.tsx — \"Continue in a fresh chat\".\n *\n * A long session gets expensive (every turn re-sends the whole prefix) and\n * forgetful (after a couple of compactions its early turns survive only as\n * summaries). The fix is a NEW session that starts from a written note\n * instead of the full history. This dialog builds that note, lets the\n * operator read and edit it, picks where it continues, and creates the\n * session — and then STOPS. The note is handed back through `onCreated` so\n * the caller can drop it into the new chat's composer; the operator presses\n * Send. That keeps the spending rule simple enough to say in one sentence:\n *\n * Building the preview and creating the chat spend nothing. The first\n * thing spent is the turn the operator sends, having read it.\n *\n * The one optional spend is \"Ask this seat to summarize first\": an ordinary\n * turn on the CURRENT session (through `sendVerseTurn`, so it passes the\n * engine's spend chokepoint and the local-only policy like any other turn),\n * after which the preview is rebuilt with `includeLastAssistant` so the\n * seat's own summary is carried over verbatim. It is a button, never a\n * default, and its cost is stated beside it in the seat's own name.\n *\n * Mounted only while open (the exported wrapper returns null otherwise), so\n * every open starts from a clean state and nothing is fetched for a dialog\n * nobody opened.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { VerseEvent, VerseSeat, VerseSession } from '../../../data/api-types.js';\nimport {\n VERSE_HANDOFF_MAX_CHARS,\n VERSE_HANDOFF_SUMMARY_REQUEST,\n VERSE_MAX_TURN_TEXT_BYTES,\n type VerseContextMode,\n type VerseHandoffPreview,\n} from '../../../../core/verse/types.js';\nimport { MutationTokenDialog } from '../../../components/auth/MutationTokenDialog.js';\nimport { Dialog } from '../../../components/primitives/Dialog.js';\nimport { Segmented } from '../../../components/primitives/Segmented.js';\nimport { hasMutationHold } from '../../../data/auth-store.js';\nimport { useQuery } from '../../../data/hooks.js';\nimport { SeatSelector, type SeatChoice } from '../SeatSelector.js';\nimport { ENGINE_LABEL, seatById } from '../verse-model.js';\nimport { cancelVerseTurn, fetchVerseSessionDetail, sendVerseTurn } from '../verse-queries.js';\nimport {\n getVerseSessionState,\n seedVerseSession,\n setVerseSession,\n setVerseSessionStatus,\n subscribeVerseStore,\n} from '../verse-store.js';\nimport { expansiveMeteringNote, expansiveRatioSentence } from '../usage/context-model.js';\nimport { rememberVerseSeat } from '../verse-ui-store.js';\nimport { extraRootsCaveat } from '../workspace-model.js';\nimport { asClause, tidyProse } from '../autonomy/format.js';\nimport {\n budgetLine,\n defaultHandoffMode,\n defaultHandoffTarget,\n handoffFit,\n handoffTitle,\n modelOption,\n offersExpansive,\n requestMode,\n targetUnavailableReason,\n TITLE_MAX_CHARS,\n turnCostSentence,\n utf8Bytes,\n API_BODY_MAX_BYTES,\n jsonBodyBytes,\n type HandoffTarget,\n} from './context-model.js';\nimport {\n createHandoffSession,\n fetchHandoffPreview,\n HANDOFF_FOCUS_MAX_CHARS,\n versePreferencesQuery,\n} from './context-queries.js';\nimport { describeContextError, useTokenGate } from './use-token-gate.js';\nimport styles from './context.module.css';\n\nexport interface HandoffDialogProps {\n /** The session being handed off (the live record — its status gates \"summarize\"). */\n session: VerseSession;\n seats: readonly VerseSeat[];\n open: boolean;\n onClose: () => void;\n /**\n * The new session exists. `text` is the handoff exactly as the operator left\n * it in the editor — pre-fill it into the new chat's composer; do NOT send it.\n */\n onCreated: (session: VerseSession, text: string) => void;\n /**\n * The seat + model to open on, when the operator already named one — the\n * composer's \"Continue on ‹seat›\" (Workspace). Absent = the usual default\n * (same seat and model, \"same agent, fresh context\"). See\n * `initialHandoffTarget` for how a stale choice is resolved.\n */\n initialTarget?: SeatChoice;\n}\n\n/**\n * Where the dialog opens. An explicit `initial` choice wins over the default\n * because the operator just picked it; the dialog must not silently swap it\n * for \"same seat\" and make them pick again.\n *\n * - The seat is in the roster → that seat, on the named model (matched\n * exactly, then by canonical id). If the model is gone, the seat's first\n * runnable model: the seat was the choice; the model id may be an alias the\n * roster has since renamed. If nothing on it runs, the named model stays\n * selected so `targetUnavailableReason` says WHY, rather than a different\n * seat appearing unasked.\n * - The roster is still empty (cold bootstrap) → null; the fill-once effect\n * retries with the same choice when seats arrive.\n * - The seat is not in a loaded roster (removed since) → the ordinary default.\n */\nexport function initialHandoffTarget(\n seats: readonly VerseSeat[],\n source: Pick<VerseSession, 'seatId' | 'model'>,\n initial: SeatChoice | undefined,\n): HandoffTarget | null {\n if (!initial) return defaultHandoffTarget(seats, source);\n if (seats.length === 0) return null;\n const seat = seats.find((s) => s.id === initial.seatId);\n if (!seat) return defaultHandoffTarget(seats, source);\n const named = modelOption(seat, initial.model);\n if (named) return { seatId: seat.id, model: named.id };\n const runnable = seat.models.find((m) => !m.unavailableReason);\n return { seatId: seat.id, model: runnable ? runnable.id : initial.model };\n}\n\n/** How often to re-read a session's log while waiting on a summary, when no live stream feeds the store. */\nexport const SUMMARY_POLL_MS = 4_000;\n\nconst PREVIEW_REASON = 'Building the handoff reads this chat’s log and runs `git diff --stat` on its folders. It spends nothing.';\nconst SUMMARY_REASON = 'Asking for a summary sends one turn to this chat’s seat.';\nconst CANCEL_REASON = 'Stopping the summary turn.';\nconst CREATE_REASON = 'Creating the chat records a new session on this machine. Nothing is sent to a model until you press Send in it.';\n\ntype PreviewStatus = 'idle' | 'locked' | 'loading' | 'ready' | 'error';\n\ntype SummaryState =\n | { phase: 'idle' }\n | { phase: 'sending' }\n | { phase: 'waiting'; turnId: string }\n | { phase: 'cancelling'; turnId: string }\n | { phase: 'done' }\n | { phase: 'failed'; message: string };\n\ntype TurnOutcome = { kind: 'ok' } | { kind: 'cancelled' } | { kind: 'failed'; message: string | null } | { kind: 'empty' };\n\n/**\n * How a turn ended, read from the session's event log; null while it runs.\n * Every terminal path in the engine emits `turn-done` (a stopped turn emits\n * `cancelled` first), so waiting for one of those two is sufficient.\n */\nexport function turnOutcome(events: readonly VerseEvent[], turnId: string): TurnOutcome | null {\n let lastError: string | null = null;\n let wroteReply = false;\n for (const e of events) {\n if (!('turnId' in e) || e.turnId !== turnId) continue;\n if (e.type === 'error') lastError = e.message;\n else if (e.type === 'assistant-message' || (e.type === 'text-delta' && e.text.trim().length > 0)) wroteReply = true;\n else if (e.type === 'cancelled') return { kind: 'cancelled' };\n else if (e.type === 'turn-done') {\n if (!e.ok) return { kind: 'failed', message: lastError };\n return wroteReply ? { kind: 'ok' } : { kind: 'empty' };\n }\n }\n return null;\n}\n\nexport function HandoffDialog(props: HandoffDialogProps) {\n if (!props.open) return null;\n return <HandoffDialogBody {...props} />;\n}\n\nfunction HandoffDialogBody({ session, seats, onClose, onCreated, initialTarget }: HandoffDialogProps) {\n const titleId = useId();\n const focusId = useId();\n const textId = useId();\n const statsId = useId();\n const seatId = useId();\n const nameId = useId();\n const modeLabelId = useId();\n const focusRef = useRef<HTMLInputElement>(null);\n const gate = useTokenGate();\n const prefs = useQuery(versePreferencesQuery);\n\n // ---- preview -----------------------------------------------------------\n const [preview, setPreview] = useState<VerseHandoffPreview | null>(null);\n const [previewStatus, setPreviewStatus] = useState<PreviewStatus>('idle');\n const [previewError, setPreviewError] = useState<string | null>(null);\n const [text, setText] = useState('');\n const [focus, setFocus] = useState('');\n const [includeLastAssistant, setIncludeLastAssistant] = useState(false);\n /** Only the newest preview request may land (a rebuild can race the first read). */\n const requestSeq = useRef(0);\n const mounted = useRef(true);\n useEffect(() => {\n mounted.current = true;\n return () => { mounted.current = false; };\n }, []);\n\n // Read through a ref by the async paths below, which outlive the render\n // that started them (a summary turn can take minutes).\n const previewRef = useRef<VerseHandoffPreview | null>(null);\n previewRef.current = preview;\n const runGated = gate.run;\n\n const requestPreview = useCallback(async (opts: { includeLastAssistant: boolean; focus: string }) => {\n const seq = (requestSeq.current += 1);\n setPreviewStatus('loading');\n setPreviewError(null);\n try {\n const result = await runGated(PREVIEW_REASON, () => fetchHandoffPreview(session.id, opts));\n if (!mounted.current || seq !== requestSeq.current) return;\n if (result === null) {\n // Token prompt dismissed: keep whatever preview is already on screen.\n setPreviewStatus(previewRef.current ? 'ready' : 'locked');\n return;\n }\n setPreview(result);\n setText(result.text);\n setPreviewStatus('ready');\n } catch (err) {\n if (!mounted.current || seq !== requestSeq.current) return;\n setPreviewError(describeContextError(err));\n setPreviewStatus('error');\n }\n }, [runGated, session.id]);\n\n // First build on open. With no token held it waits for an explicit unlock\n // rather than stacking a second dialog on top of this one uninvited.\n useEffect(() => {\n if (hasMutationHold()) void requestPreview({ includeLastAssistant: false, focus: '' });\n else setPreviewStatus('locked');\n // eslint-disable-next-line react-hooks/exhaustive-deps -- once per open; the body is mounted per open.\n }, []);\n\n const edited = preview !== null && text !== preview.text;\n // The new chat sends this as its first turn: it must fit the turn cap AND\n // the API's request-body cap once JSON-escaped, or the Send would be refused.\n const overTurnLimit = useMemo(\n () => utf8Bytes(text) > VERSE_MAX_TURN_TEXT_BYTES || jsonBodyBytes({ text }) > API_BODY_MAX_BYTES,\n [text],\n );\n const overBudget = text.length > VERSE_HANDOFF_MAX_CHARS;\n\n // ---- target ------------------------------------------------------------\n // The body mounts per open, so `initialTarget` is read once per open: a\n // later pick inside the dialog is never overwritten by the prop.\n const [target, setTarget] = useState<HandoffTarget | null>(() => initialHandoffTarget(seats, session, initialTarget));\n // Seats that arrive after the dialog opened (cold bootstrap) fill an empty target once.\n useEffect(() => {\n if (target === null && seats.length > 0) setTarget(initialHandoffTarget(seats, session, initialTarget));\n }, [target, seats, session, initialTarget]);\n const targetSeat = target ? seatById(seats, target.seatId) ?? null : null;\n const option = target ? modelOption(targetSeat, target.model) : null;\n const [modeChoice, setModeChoice] = useState<VerseContextMode | null>(null);\n const defaultMode = defaultHandoffMode({ option, target, source: session, preferences: prefs.data });\n const mode: VerseContextMode = modeChoice !== null && requestMode(option, modeChoice) !== undefined ? modeChoice : defaultMode;\n const expansiveOffered = offersExpansive(option);\n const unavailable = targetUnavailableReason(targetSeat, option);\n // The TARGET seat's engine: the new chat carries that CLI's fixed prompt, not the source's.\n const fit = handoffFit(text.length, option, mode, targetSeat?.engine ?? null);\n // Expansive's cost in the shared wording: the re-send ratio, then (codex\n // only) the reported >272k metering that multiplies it.\n const expansiveCost = [expansiveRatioSentence(option), expansiveMeteringNote(targetSeat?.engine)].filter(Boolean).join(' ');\n const rootCount = 1 + (session.extraRoots?.filter((r) => r && r !== session.projectPath).length ?? 0);\n const reachCaveat = extraRootsCaveat(targetSeat?.engine ?? null, rootCount);\n\n function chooseTarget(choice: SeatChoice) {\n setTarget({ seatId: choice.seatId, model: choice.model });\n // A new model re-derives its own default mode; a choice made for the old\n // model may not even exist on the new one.\n setModeChoice(null);\n }\n\n const [title, setTitle] = useState(() => handoffTitle(session.title));\n\n // ---- summarize first ---------------------------------------------------\n const [summary, setSummary] = useState<SummaryState>({ phase: 'idle' });\n const sourceSeat = seatById(seats, session.seatId);\n const sourceSeatLabel = sourceSeat?.label ?? ENGINE_LABEL[session.engine];\n const summarizing = summary.phase === 'sending' || summary.phase === 'waiting' || summary.phase === 'cancelling';\n const summarizeBlocked = session.status === 'running'\n ? 'A turn is running in this chat. Wait for it to finish first.'\n : session.turnCount === 0\n ? 'This chat has no turns yet, so there is nothing to summarize.'\n : null;\n\n async function summarize() {\n setSummary({ phase: 'sending' });\n try {\n const turnId = await gate.run(SUMMARY_REASON, async () => {\n setVerseSessionStatus(session.id, 'running');\n try {\n // The SHARED constant, verbatim: the handoff builder recognises this\n // exact text and keeps it out of the new chat's \"latest requests\".\n const response = await sendVerseTurn(session.id, VERSE_HANDOFF_SUMMARY_REQUEST);\n // Same reconciliation ChatSection's send uses: the turn may already\n // have settled by the time the 202 is applied.\n setVerseSession(session.id, response.session, response.turnId);\n return response.turnId;\n } catch (err) {\n setVerseSessionStatus(session.id, 'idle');\n throw err;\n }\n });\n if (!mounted.current) return;\n setSummary(turnId === null ? { phase: 'idle' } : { phase: 'waiting', turnId });\n } catch (err) {\n if (mounted.current) setSummary({ phase: 'failed', message: describeContextError(err) });\n }\n }\n\n async function stopSummary() {\n if (summary.phase !== 'waiting') return;\n const turnId = summary.turnId;\n setSummary({ phase: 'cancelling', turnId });\n try {\n const done = await gate.run(CANCEL_REASON, () => cancelVerseTurn(session.id));\n if (done === null && mounted.current) setSummary({ phase: 'waiting', turnId });\n // Otherwise the `cancelled` event settles it through the store watcher.\n } catch (err) {\n if (mounted.current) setSummary({ phase: 'failed', message: describeContextError(err) });\n }\n }\n\n // Watch the session's event log for the summary turn to finish. The open\n // chat's SSE stream feeds verse-store already; when nothing is streaming\n // this session (the dialog was opened for a chat that is not selected), a\n // slow poll of its detail feeds the SAME store path instead.\n const focusRefValue = useRef(focus);\n focusRefValue.current = focus;\n useEffect(() => {\n if (summary.phase !== 'waiting' && summary.phase !== 'cancelling') return undefined;\n const turnId = summary.turnId;\n let settled = false;\n const check = () => {\n if (settled) return;\n const outcome = turnOutcome(getVerseSessionState(session.id).events, turnId);\n if (outcome === null) return;\n settled = true;\n switch (outcome.kind) {\n case 'ok':\n setSummary({ phase: 'done' });\n setIncludeLastAssistant(true);\n void requestPreview({ includeLastAssistant: true, focus: focusRefValue.current });\n break;\n case 'cancelled':\n setSummary({ phase: 'failed', message: 'Summary stopped. The automatic preview is unchanged.' });\n break;\n case 'empty':\n setSummary({ phase: 'failed', message: `${sourceSeatLabel} finished without writing a summary. The automatic preview is unchanged.` });\n break;\n default:\n setSummary({\n phase: 'failed',\n // The engine's error is a sentence of its own: embedded as a\n // clause so it cannot close with \"..\", instants read as local time.\n message: `The summary turn failed${outcome.message ? `: ${asClause(tidyProse(outcome.message))}` : ''}. The automatic preview is unchanged.`,\n });\n }\n };\n check();\n const unsubscribe = subscribeVerseStore(check);\n const timer = setInterval(() => {\n const stream = getVerseSessionState(session.id).stream;\n if (stream === 'open' || stream === 'connecting' || stream === 'reconnecting') return;\n fetchVerseSessionDetail(session.id)\n .then((detail) => seedVerseSession(session.id, detail.session, detail.events))\n .catch(() => { /* the next tick retries; the operator can also stop waiting */ });\n }, SUMMARY_POLL_MS);\n return () => {\n settled = true;\n unsubscribe();\n clearInterval(timer);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- keyed on the turn being waited for, not on every render's callbacks.\n }, [summary, session.id]);\n\n // ---- create ------------------------------------------------------------\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n const hasText = text.trim().length > 0;\n const createBlocked = unavailable\n ?? (!preview ? 'Build the handoff first.' : null)\n ?? (!hasText ? 'The handoff is empty — rebuild it or write one.' : null)\n ?? (overTurnLimit ? 'The handoff is over the 64 KB limit for one message. Trim it first.' : null)\n ?? (summarizing ? 'Wait for the summary to finish, or stop it.' : null);\n\n async function create() {\n if (!target || createBlocked !== null || creating) return;\n setCreating(true);\n setCreateError(null);\n const handoffText = text;\n try {\n const created = await gate.run(CREATE_REASON, () => createHandoffSession({\n source: session,\n seatId: target.seatId,\n model: target.model,\n contextMode: requestMode(option, mode),\n title: title.trim() || undefined,\n }));\n if (created === null) return;\n // Same bookkeeping ChatSection does for any new chat: the store knows\n // the record before its detail fetch lands, and the project remembers\n // the seat it was last started on.\n setVerseSession(created.id, created);\n rememberVerseSeat(created.projectPath, { seatId: created.seatId, model: created.model });\n onCreated(created, handoffText);\n onClose();\n } catch (err) {\n if (mounted.current) setCreateError(describeContextError(err));\n } finally {\n if (mounted.current) setCreating(false);\n }\n }\n\n // Escape on the token prompt must close only the prompt — both dialogs\n // listen on the document, so this one stands down while the prompt is up.\n const closeUnlessPrompting = () => {\n if (!gate.dialog.open) onClose();\n };\n\n const liveTokens = Math.ceil(text.length / 4);\n const rebuild = () => void requestPreview({ includeLastAssistant, focus });\n\n return (\n <>\n <Dialog open onClose={closeUnlessPrompting} titleId={titleId} title=\"Continue in a fresh chat\" initialFocusRef={focusRef}\n widthClassName={styles.dialogWidth}\n description={<>Start a new chat from a written handoff of “{session.title || 'Untitled chat'}” instead of its full history.</>}>\n <form className={styles.form} noValidate onSubmit={(event) => { event.preventDefault(); void create(); }}>\n {/* ---- the note ---- */}\n <div className={styles.field}>\n <label className={styles.label} htmlFor={focusId}>\n Focus for the next chat <span className={styles.optional}>optional</span>\n </label>\n <div className={styles.row}>\n <input id={focusId} ref={focusRef} className={styles.input} value={focus} maxLength={HANDOFF_FOCUS_MAX_CHARS}\n placeholder=\"e.g. finish the migration, then run the full test suite\" autoComplete=\"off\"\n onChange={(event) => setFocus(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n if (previewStatus !== 'loading') rebuild();\n }\n }} />\n <button type=\"button\" className={styles.secondary} onClick={rebuild}\n disabled={previewStatus === 'loading' || summarizing}>\n {edited ? 'Rebuild (replaces your edits)' : 'Rebuild'}\n </button>\n </div>\n </div>\n\n <div className={styles.field}>\n <label className={styles.label} htmlFor={textId}>Handoff — becomes the new chat’s first message</label>\n {previewStatus === 'locked' && !preview ? (\n <div className={styles.locked} role=\"status\">\n <p>Building the handoff needs the mutation token: it reads this chat’s log and runs <code>git diff --stat</code>. It spends nothing.</p>\n <button type=\"button\" className={styles.secondary} onClick={rebuild}>Unlock and build the handoff</button>\n </div>\n ) : (\n <textarea id={textId} className={styles.textarea} value={text} rows={12} spellCheck={false}\n aria-describedby={statsId} aria-busy={previewStatus === 'loading' ? true : undefined}\n disabled={!preview}\n placeholder={previewStatus === 'loading' ? 'Building the handoff from this chat’s log…' : ''}\n onChange={(event) => setText(event.target.value)} />\n )}\n <p id={statsId} className={styles.hint} aria-live=\"polite\">\n {previewStatus === 'loading'\n ? preview ? 'Rebuilding…' : 'Reading this chat’s log…'\n : preview ? (\n <>\n {text.length.toLocaleString()} chars · ~{liveTokens.toLocaleString()} tokens\n {' · '}{preview.stats.turnsCovered} {preview.stats.turnsCovered === 1 ? 'turn' : 'turns'}\n {' · '}{preview.stats.filesTouched} {preview.stats.filesTouched === 1 ? 'file' : 'files'} touched\n {edited ? ' · edited' : ''}\n {includeLastAssistant ? ` · includes ${sourceSeatLabel}’s own summary` : ''}\n </>\n ) : null}\n </p>\n {preview && preview.stats.truncated.length > 0 ? (\n <p className={styles.hint}>\n To stay under {VERSE_HANDOFF_MAX_CHARS.toLocaleString()} characters these sections were left out: {preview.stats.truncated.join(', ')}.\n </p>\n ) : null}\n {overTurnLimit ? (\n <p className={styles.error} role=\"alert\">\n Over the 64 KB limit for one message (counted as it is sent, line breaks and quotes encoded) — the new chat could\n not send it. Trim it first.\n </p>\n ) : overBudget ? (\n <p className={styles.warn}>\n Longer than the {VERSE_HANDOFF_MAX_CHARS.toLocaleString()}-character handoff budget. It can still be sent; the new chat just starts bigger.\n </p>\n ) : null}\n {previewStatus === 'error' && previewError ? (\n <p className={styles.error} role=\"alert\">\n Could not build the handoff: {previewError}{' '}\n <button type=\"button\" className={styles.link} onClick={rebuild}>Try again</button>\n </p>\n ) : null}\n </div>\n\n {/* ---- optional: the seat's own summary ---- */}\n <section className={styles.aside} aria-labelledby={`${titleId}-summary`}>\n <h3 id={`${titleId}-summary`} className={styles.label}>Better summary <span className={styles.optional}>optional, spends</span></h3>\n <p className={styles.hint}>\n The handoff above is assembled from this chat’s log. For one in the agent’s own words, ask {sourceSeatLabel} to\n write it first — its reply is added to the handoff. {turnCostSentence(session.engine, sourceSeatLabel)}\n </p>\n {summary.phase === 'waiting' || summary.phase === 'cancelling' ? (\n <div className={styles.row} role=\"status\">\n <span className={styles.pending} aria-hidden=\"true\" />\n <span className={styles.hint}>\n {summary.phase === 'cancelling' ? 'Stopping the summary…' : `Waiting for ${sourceSeatLabel} to finish its summary…`}\n </span>\n <button type=\"button\" className={styles.secondary} onClick={() => void stopSummary()}\n disabled={summary.phase === 'cancelling'}>Stop the summary</button>\n </div>\n ) : (\n <div className={styles.row}>\n <button type=\"button\" className={styles.secondary} onClick={() => void summarize()}\n disabled={summarizeBlocked !== null || summary.phase === 'sending'}>\n {summary.phase === 'sending' ? 'Sending…' : summary.phase === 'done' ? `Ask ${sourceSeatLabel} again` : `Ask ${sourceSeatLabel} to summarize first`}\n </button>\n {summary.phase === 'done' ? <span className={styles.hint} role=\"status\">Summary added.</span> : null}\n </div>\n )}\n {summarizeBlocked !== null && !summarizing ? <p className={styles.hint}>{summarizeBlocked}</p> : null}\n {summarizeBlocked === null && summary.phase === 'idle' && edited ? (\n <p className={styles.hint}>The handoff is rebuilt with the summary, which replaces your edits above.</p>\n ) : null}\n {summary.phase === 'failed' ? <p className={styles.error} role=\"alert\">{summary.message}</p> : null}\n </section>\n\n {/* ---- where it continues ---- */}\n <div className={styles.field}>\n <SeatSelector id={seatId} seats={seats} value={target} onChange={chooseTarget} label=\"Continue on\"\n modeFor={(seat, model) => (target && seat.id === target.seatId && model.id === target.model ? mode : 'standard')} />\n {unavailable ? <p className={styles.error} role=\"alert\">{unavailable}</p> : null}\n {reachCaveat ? <p className={styles.hint}>{reachCaveat}</p> : null}\n </div>\n\n {option && !unavailable ? (\n <div className={styles.field}>\n {expansiveOffered ? (\n <>\n <span id={modeLabelId} className={styles.label}>Context mode</span>\n <Segmented<VerseContextMode> aria-labelledby={modeLabelId} size=\"sm\" value={mode}\n onChange={(next) => setModeChoice(next)}\n options={[\n { value: 'standard', label: 'Standard' },\n { value: 'expansive', label: 'Expansive' },\n ]} />\n <p className={styles.hint}>\n {budgetLine(option, mode)}.{' '}\n {mode === 'expansive'\n ? `Expansive keeps far more of the conversation before compacting, but every turn re-sends all of it — each turn costs more usage.${expansiveCost ? ` ${expansiveCost}` : ''}`\n : 'Standard compacts sooner and keeps each turn cheaper. Expansive is one click away if the work needs it.'}\n </p>\n </>\n ) : budgetLine(option, 'standard') ? (\n <p className={styles.hint}>{budgetLine(option, 'standard')}.</p>\n ) : null}\n <p className={`${styles.fit} ${styles[`fit-${fit.tone}`] ?? ''}`} data-verdict={fit.verdict ?? 'unknown'}>\n {fit.text}\n </p>\n </div>\n ) : null}\n\n <div className={styles.field}>\n <label className={styles.label} htmlFor={nameId}>Title</label>\n <input id={nameId} className={styles.input} value={title} maxLength={TITLE_MAX_CHARS} autoComplete=\"off\"\n onChange={(event) => setTitle(event.target.value)} />\n </div>\n\n {createError ? <p className={styles.error} role=\"alert\">{createError}</p> : null}\n\n <p className={styles.cost}>\n Creating the chat is free — nothing is sent to a model. The handoff goes into the new chat’s composer; read it,\n then press Send. That first turn is the first thing spent.\n </p>\n <div className={styles.actions}>\n {createBlocked && preview ? <span className={styles.blocked}>{createBlocked}</span> : null}\n <button type=\"button\" className={styles.cancel} onClick={onClose}>Cancel</button>\n <button type=\"submit\" className={styles.primary} disabled={createBlocked !== null || creating}>\n {creating ? 'Creating…' : 'Create chat'}\n </button>\n </div>\n </form>\n </Dialog>\n <MutationTokenDialog open={gate.dialog.open} reason={gate.dialog.reason} tokenLabel=\"Mutation token\"\n tokenHelp=\"the mutation token ashlr verse printed\" onClose={gate.dialog.onClose} onUnlocked={gate.dialog.onUnlocked} />\n </>\n );\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"HandoffDialog-CLJQLe7M.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/context/HandoffDialog.tsx"],"sourcesContent":["/**\n * routes/verse/context/HandoffDialog.tsx — \"Continue in a fresh chat\".\n *\n * A long session gets expensive (every turn re-sends the whole prefix) and\n * forgetful (after a couple of compactions its early turns survive only as\n * summaries). The fix is a NEW session that starts from a written note\n * instead of the full history. This dialog builds that note, lets the\n * operator read and edit it, picks where it continues, and creates the\n * session — and then STOPS. The note is handed back through `onCreated` so\n * the caller can drop it into the new chat's composer; the operator presses\n * Send. That keeps the spending rule simple enough to say in one sentence:\n *\n * Building the preview and creating the chat spend nothing. The first\n * thing spent is the turn the operator sends, having read it.\n *\n * The one optional spend is \"Ask this seat to summarize first\": an ordinary\n * turn on the CURRENT session (through `sendVerseTurn`, so it passes the\n * engine's spend chokepoint and the local-only policy like any other turn),\n * after which the preview is rebuilt with `includeLastAssistant` so the\n * seat's own summary is carried over verbatim. It is a button, never a\n * default, and its cost is stated beside it in the seat's own name.\n *\n * Mounted only while open (the exported wrapper returns null otherwise), so\n * every open starts from a clean state and nothing is fetched for a dialog\n * nobody opened.\n */\nimport { useCallback, useEffect, useId, useMemo, useRef, useState } from 'react';\nimport type { VerseEvent, VerseSeat, VerseSession } from '../../../data/api-types.js';\nimport {\n VERSE_HANDOFF_MAX_CHARS,\n VERSE_HANDOFF_SUMMARY_REQUEST,\n VERSE_MAX_TURN_TEXT_BYTES,\n type VerseContextMode,\n type VerseHandoffPreview,\n} from '../../../../core/verse/types.js';\nimport { MutationTokenDialog } from '../../../components/auth/MutationTokenDialog.js';\nimport { Dialog } from '../../../components/primitives/Dialog.js';\nimport { Segmented } from '../../../components/primitives/Segmented.js';\nimport { hasMutationHold } from '../../../data/auth-store.js';\nimport { useQuery } from '../../../data/hooks.js';\nimport { SeatSelector, type SeatChoice } from '../SeatSelector.js';\nimport { ENGINE_LABEL, seatById } from '../verse-model.js';\nimport { cancelVerseTurn, fetchVerseSessionDetail, sendVerseTurn } from '../verse-queries.js';\nimport {\n getVerseSessionState,\n seedVerseSession,\n setVerseSession,\n setVerseSessionStatus,\n subscribeVerseStore,\n} from '../verse-store.js';\nimport { expansiveMeteringNote, expansiveRatioSentence } from '../usage/context-model.js';\nimport { rememberVerseSeat } from '../verse-ui-store.js';\nimport { extraRootsCaveat } from '../workspace-model.js';\nimport { asClause, tidyProse } from '../autonomy/format.js';\nimport {\n budgetLine,\n defaultHandoffMode,\n defaultHandoffTarget,\n handoffFit,\n handoffTitle,\n modelOption,\n offersExpansive,\n requestMode,\n targetUnavailableReason,\n TITLE_MAX_CHARS,\n turnCostSentence,\n utf8Bytes,\n API_BODY_MAX_BYTES,\n jsonBodyBytes,\n type HandoffTarget,\n} from './context-model.js';\nimport {\n createHandoffSession,\n fetchHandoffPreview,\n HANDOFF_FOCUS_MAX_CHARS,\n versePreferencesQuery,\n} from './context-queries.js';\nimport { describeContextError, useTokenGate } from './use-token-gate.js';\nimport styles from './context.module.css';\n\nexport interface HandoffDialogProps {\n /** The session being handed off (the live record — its status gates \"summarize\"). */\n session: VerseSession;\n seats: readonly VerseSeat[];\n open: boolean;\n onClose: () => void;\n /**\n * The new session exists. `text` is the handoff exactly as the operator left\n * it in the editor — pre-fill it into the new chat's composer; do NOT send it.\n */\n onCreated: (session: VerseSession, text: string) => void;\n /**\n * The seat + model to open on, when the operator already named one — the\n * composer's \"Continue on ‹seat›\" (Workspace). Absent = the usual default\n * (same seat and model, \"same agent, fresh context\"). See\n * `initialHandoffTarget` for how a stale choice is resolved.\n */\n initialTarget?: SeatChoice;\n}\n\n/**\n * Where the dialog opens. An explicit `initial` choice wins over the default\n * because the operator just picked it; the dialog must not silently swap it\n * for \"same seat\" and make them pick again.\n *\n * - The seat is in the roster → that seat, on the named model (matched\n * exactly, then by canonical id). If the model is gone, the seat's first\n * runnable model: the seat was the choice; the model id may be an alias the\n * roster has since renamed. If nothing on it runs, the named model stays\n * selected so `targetUnavailableReason` says WHY, rather than a different\n * seat appearing unasked.\n * - The roster is still empty (cold bootstrap) → null; the fill-once effect\n * retries with the same choice when seats arrive.\n * - The seat is not in a loaded roster (removed since) → the ordinary default.\n */\nexport function initialHandoffTarget(\n seats: readonly VerseSeat[],\n source: Pick<VerseSession, 'seatId' | 'model'>,\n initial: SeatChoice | undefined,\n): HandoffTarget | null {\n if (!initial) return defaultHandoffTarget(seats, source);\n if (seats.length === 0) return null;\n const seat = seats.find((s) => s.id === initial.seatId);\n if (!seat) return defaultHandoffTarget(seats, source);\n const named = modelOption(seat, initial.model);\n if (named) return { seatId: seat.id, model: named.id };\n const runnable = seat.models.find((m) => !m.unavailableReason);\n return { seatId: seat.id, model: runnable ? runnable.id : initial.model };\n}\n\n/** How often to re-read a session's log while waiting on a summary, when no live stream feeds the store. */\nexport const SUMMARY_POLL_MS = 4_000;\n\nconst PREVIEW_REASON = 'Building the handoff reads this chat’s log and runs `git diff --stat` on its folders. It spends nothing.';\nconst SUMMARY_REASON = 'Asking for a summary sends one turn to this chat’s seat.';\nconst CANCEL_REASON = 'Stopping the summary turn.';\nconst CREATE_REASON = 'Creating the chat records a new session on this machine. Nothing is sent to a model until you press Send in it.';\n\ntype PreviewStatus = 'idle' | 'locked' | 'loading' | 'ready' | 'error';\n\ntype SummaryState =\n | { phase: 'idle' }\n | { phase: 'sending' }\n | { phase: 'waiting'; turnId: string }\n | { phase: 'cancelling'; turnId: string }\n | { phase: 'done' }\n | { phase: 'failed'; message: string };\n\ntype TurnOutcome = { kind: 'ok' } | { kind: 'cancelled' } | { kind: 'failed'; message: string | null } | { kind: 'empty' };\n\n/**\n * How a turn ended, read from the session's event log; null while it runs.\n * Every terminal path in the engine emits `turn-done` (a stopped turn emits\n * `cancelled` first), so waiting for one of those two is sufficient.\n */\nexport function turnOutcome(events: readonly VerseEvent[], turnId: string): TurnOutcome | null {\n let lastError: string | null = null;\n let wroteReply = false;\n for (const e of events) {\n if (!('turnId' in e) || e.turnId !== turnId) continue;\n if (e.type === 'error') lastError = e.message;\n else if (e.type === 'assistant-message' || (e.type === 'text-delta' && e.text.trim().length > 0)) wroteReply = true;\n else if (e.type === 'cancelled') return { kind: 'cancelled' };\n else if (e.type === 'turn-done') {\n if (!e.ok) return { kind: 'failed', message: lastError };\n return wroteReply ? { kind: 'ok' } : { kind: 'empty' };\n }\n }\n return null;\n}\n\nexport function HandoffDialog(props: HandoffDialogProps) {\n if (!props.open) return null;\n return <HandoffDialogBody {...props} />;\n}\n\nfunction HandoffDialogBody({ session, seats, onClose, onCreated, initialTarget }: HandoffDialogProps) {\n const titleId = useId();\n const focusId = useId();\n const textId = useId();\n const statsId = useId();\n const seatId = useId();\n const nameId = useId();\n const modeLabelId = useId();\n const focusRef = useRef<HTMLInputElement>(null);\n const gate = useTokenGate();\n const prefs = useQuery(versePreferencesQuery);\n\n // ---- preview -----------------------------------------------------------\n const [preview, setPreview] = useState<VerseHandoffPreview | null>(null);\n const [previewStatus, setPreviewStatus] = useState<PreviewStatus>('idle');\n const [previewError, setPreviewError] = useState<string | null>(null);\n const [text, setText] = useState('');\n const [focus, setFocus] = useState('');\n const [includeLastAssistant, setIncludeLastAssistant] = useState(false);\n /** Only the newest preview request may land (a rebuild can race the first read). */\n const requestSeq = useRef(0);\n const mounted = useRef(true);\n useEffect(() => {\n mounted.current = true;\n return () => { mounted.current = false; };\n }, []);\n\n // Read through a ref by the async paths below, which outlive the render\n // that started them (a summary turn can take minutes).\n const previewRef = useRef<VerseHandoffPreview | null>(null);\n previewRef.current = preview;\n const runGated = gate.run;\n\n const requestPreview = useCallback(async (opts: { includeLastAssistant: boolean; focus: string }) => {\n const seq = (requestSeq.current += 1);\n setPreviewStatus('loading');\n setPreviewError(null);\n try {\n const result = await runGated(PREVIEW_REASON, () => fetchHandoffPreview(session.id, opts));\n if (!mounted.current || seq !== requestSeq.current) return;\n if (result === null) {\n // Token prompt dismissed: keep whatever preview is already on screen.\n setPreviewStatus(previewRef.current ? 'ready' : 'locked');\n return;\n }\n setPreview(result);\n setText(result.text);\n setPreviewStatus('ready');\n } catch (err) {\n if (!mounted.current || seq !== requestSeq.current) return;\n setPreviewError(describeContextError(err));\n setPreviewStatus('error');\n }\n }, [runGated, session.id]);\n\n // First build on open. With no token held it waits for an explicit unlock\n // rather than stacking a second dialog on top of this one uninvited.\n useEffect(() => {\n if (hasMutationHold()) void requestPreview({ includeLastAssistant: false, focus: '' });\n else setPreviewStatus('locked');\n // eslint-disable-next-line react-hooks/exhaustive-deps -- once per open; the body is mounted per open.\n }, []);\n\n const edited = preview !== null && text !== preview.text;\n // The new chat sends this as its first turn: it must fit the turn cap AND\n // the API's request-body cap once JSON-escaped, or the Send would be refused.\n const overTurnLimit = useMemo(\n () => utf8Bytes(text) > VERSE_MAX_TURN_TEXT_BYTES || jsonBodyBytes({ text }) > API_BODY_MAX_BYTES,\n [text],\n );\n const overBudget = text.length > VERSE_HANDOFF_MAX_CHARS;\n\n // ---- target ------------------------------------------------------------\n // The body mounts per open, so `initialTarget` is read once per open: a\n // later pick inside the dialog is never overwritten by the prop.\n const [target, setTarget] = useState<HandoffTarget | null>(() => initialHandoffTarget(seats, session, initialTarget));\n // Seats that arrive after the dialog opened (cold bootstrap) fill an empty target once.\n useEffect(() => {\n if (target === null && seats.length > 0) setTarget(initialHandoffTarget(seats, session, initialTarget));\n }, [target, seats, session, initialTarget]);\n const targetSeat = target ? seatById(seats, target.seatId) ?? null : null;\n const option = target ? modelOption(targetSeat, target.model) : null;\n const [modeChoice, setModeChoice] = useState<VerseContextMode | null>(null);\n const defaultMode = defaultHandoffMode({ option, target, source: session, preferences: prefs.data });\n const mode: VerseContextMode = modeChoice !== null && requestMode(option, modeChoice) !== undefined ? modeChoice : defaultMode;\n const expansiveOffered = offersExpansive(option);\n const unavailable = targetUnavailableReason(targetSeat, option);\n // The TARGET seat's engine: the new chat carries that CLI's fixed prompt, not the source's.\n const fit = handoffFit(text.length, option, mode, targetSeat?.engine ?? null);\n // Expansive's cost in the shared wording: the re-send ratio, then (codex\n // only) the reported >272k metering that multiplies it.\n const expansiveCost = [expansiveRatioSentence(option), expansiveMeteringNote(targetSeat?.engine)].filter(Boolean).join(' ');\n const rootCount = 1 + (session.extraRoots?.filter((r) => r && r !== session.projectPath).length ?? 0);\n const reachCaveat = extraRootsCaveat(targetSeat?.engine ?? null, rootCount);\n\n function chooseTarget(choice: SeatChoice) {\n setTarget({ seatId: choice.seatId, model: choice.model });\n // A new model re-derives its own default mode; a choice made for the old\n // model may not even exist on the new one.\n setModeChoice(null);\n }\n\n const [title, setTitle] = useState(() => handoffTitle(session.title));\n\n // ---- summarize first ---------------------------------------------------\n const [summary, setSummary] = useState<SummaryState>({ phase: 'idle' });\n const sourceSeat = seatById(seats, session.seatId);\n const sourceSeatLabel = sourceSeat?.label ?? ENGINE_LABEL[session.engine];\n const summarizing = summary.phase === 'sending' || summary.phase === 'waiting' || summary.phase === 'cancelling';\n const summarizeBlocked = session.status === 'running'\n ? 'A turn is running in this chat. Wait for it to finish first.'\n : session.turnCount === 0\n ? 'This chat has no turns yet, so there is nothing to summarize.'\n : null;\n\n async function summarize() {\n setSummary({ phase: 'sending' });\n try {\n const turnId = await gate.run(SUMMARY_REASON, async () => {\n setVerseSessionStatus(session.id, 'running');\n try {\n // The SHARED constant, verbatim: the handoff builder recognises this\n // exact text and keeps it out of the new chat's \"latest requests\".\n const response = await sendVerseTurn(session.id, VERSE_HANDOFF_SUMMARY_REQUEST);\n // Same reconciliation ChatSection's send uses: the turn may already\n // have settled by the time the 202 is applied.\n setVerseSession(session.id, response.session, response.turnId);\n return response.turnId;\n } catch (err) {\n setVerseSessionStatus(session.id, 'idle');\n throw err;\n }\n });\n if (!mounted.current) return;\n setSummary(turnId === null ? { phase: 'idle' } : { phase: 'waiting', turnId });\n } catch (err) {\n if (mounted.current) setSummary({ phase: 'failed', message: describeContextError(err) });\n }\n }\n\n async function stopSummary() {\n if (summary.phase !== 'waiting') return;\n const turnId = summary.turnId;\n setSummary({ phase: 'cancelling', turnId });\n try {\n const done = await gate.run(CANCEL_REASON, () => cancelVerseTurn(session.id));\n if (done === null && mounted.current) setSummary({ phase: 'waiting', turnId });\n // Otherwise the `cancelled` event settles it through the store watcher.\n } catch (err) {\n if (mounted.current) setSummary({ phase: 'failed', message: describeContextError(err) });\n }\n }\n\n // Watch the session's event log for the summary turn to finish. The open\n // chat's SSE stream feeds verse-store already; when nothing is streaming\n // this session (the dialog was opened for a chat that is not selected), a\n // slow poll of its detail feeds the SAME store path instead.\n const focusRefValue = useRef(focus);\n focusRefValue.current = focus;\n useEffect(() => {\n if (summary.phase !== 'waiting' && summary.phase !== 'cancelling') return undefined;\n const turnId = summary.turnId;\n let settled = false;\n const check = () => {\n if (settled) return;\n const outcome = turnOutcome(getVerseSessionState(session.id).events, turnId);\n if (outcome === null) return;\n settled = true;\n switch (outcome.kind) {\n case 'ok':\n setSummary({ phase: 'done' });\n setIncludeLastAssistant(true);\n void requestPreview({ includeLastAssistant: true, focus: focusRefValue.current });\n break;\n case 'cancelled':\n setSummary({ phase: 'failed', message: 'Summary stopped. The automatic preview is unchanged.' });\n break;\n case 'empty':\n setSummary({ phase: 'failed', message: `${sourceSeatLabel} finished without writing a summary. The automatic preview is unchanged.` });\n break;\n default:\n setSummary({\n phase: 'failed',\n // The engine's error is a sentence of its own: embedded as a\n // clause so it cannot close with \"..\", instants read as local time.\n message: `The summary turn failed${outcome.message ? `: ${asClause(tidyProse(outcome.message))}` : ''}. The automatic preview is unchanged.`,\n });\n }\n };\n check();\n const unsubscribe = subscribeVerseStore(check);\n const timer = setInterval(() => {\n const stream = getVerseSessionState(session.id).stream;\n if (stream === 'open' || stream === 'connecting' || stream === 'reconnecting') return;\n fetchVerseSessionDetail(session.id)\n .then((detail) => seedVerseSession(session.id, detail.session, detail.events))\n .catch(() => { /* the next tick retries; the operator can also stop waiting */ });\n }, SUMMARY_POLL_MS);\n return () => {\n settled = true;\n unsubscribe();\n clearInterval(timer);\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- keyed on the turn being waited for, not on every render's callbacks.\n }, [summary, session.id]);\n\n // ---- create ------------------------------------------------------------\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n const hasText = text.trim().length > 0;\n const createBlocked = unavailable\n ?? (!preview ? 'Build the handoff first.' : null)\n ?? (!hasText ? 'The handoff is empty — rebuild it or write one.' : null)\n ?? (overTurnLimit ? 'The handoff is over the 64 KB limit for one message. Trim it first.' : null)\n ?? (summarizing ? 'Wait for the summary to finish, or stop it.' : null);\n\n async function create() {\n if (!target || createBlocked !== null || creating) return;\n setCreating(true);\n setCreateError(null);\n const handoffText = text;\n try {\n const created = await gate.run(CREATE_REASON, () => createHandoffSession({\n source: session,\n seatId: target.seatId,\n model: target.model,\n contextMode: requestMode(option, mode),\n title: title.trim() || undefined,\n }));\n if (created === null) return;\n // Same bookkeeping ChatSection does for any new chat: the store knows\n // the record before its detail fetch lands, and the project remembers\n // the seat it was last started on.\n setVerseSession(created.id, created);\n rememberVerseSeat(created.projectPath, { seatId: created.seatId, model: created.model });\n onCreated(created, handoffText);\n onClose();\n } catch (err) {\n if (mounted.current) setCreateError(describeContextError(err));\n } finally {\n if (mounted.current) setCreating(false);\n }\n }\n\n // Escape on the token prompt must close only the prompt — both dialogs\n // listen on the document, so this one stands down while the prompt is up.\n const closeUnlessPrompting = () => {\n if (!gate.dialog.open) onClose();\n };\n\n const liveTokens = Math.ceil(text.length / 4);\n const rebuild = () => void requestPreview({ includeLastAssistant, focus });\n\n return (\n <>\n <Dialog open onClose={closeUnlessPrompting} titleId={titleId} title=\"Continue in a fresh chat\" initialFocusRef={focusRef}\n widthClassName={styles.dialogWidth}\n description={<>Start a new chat from a written handoff of “{session.title || 'Untitled chat'}” instead of its full history.</>}>\n <form className={styles.form} noValidate onSubmit={(event) => { event.preventDefault(); void create(); }}>\n {/* ---- the note ---- */}\n <div className={styles.field}>\n <label className={styles.label} htmlFor={focusId}>\n Focus for the next chat <span className={styles.optional}>optional</span>\n </label>\n <div className={styles.row}>\n <input id={focusId} ref={focusRef} className={styles.input} value={focus} maxLength={HANDOFF_FOCUS_MAX_CHARS}\n placeholder=\"e.g. finish the migration, then run the full test suite\" autoComplete=\"off\"\n onChange={(event) => setFocus(event.target.value)}\n onKeyDown={(event) => {\n if (event.key === 'Enter') {\n event.preventDefault();\n if (previewStatus !== 'loading') rebuild();\n }\n }} />\n <button type=\"button\" className={styles.secondary} onClick={rebuild}\n disabled={previewStatus === 'loading' || summarizing}>\n {edited ? 'Rebuild (replaces your edits)' : 'Rebuild'}\n </button>\n </div>\n </div>\n\n <div className={styles.field}>\n <label className={styles.label} htmlFor={textId}>Handoff — becomes the new chat’s first message</label>\n {previewStatus === 'locked' && !preview ? (\n <div className={styles.locked} role=\"status\">\n <p>Building the handoff needs the mutation token: it reads this chat’s log and runs <code>git diff --stat</code>. It spends nothing.</p>\n <button type=\"button\" className={styles.secondary} onClick={rebuild}>Unlock and build the handoff</button>\n </div>\n ) : (\n <textarea id={textId} className={styles.textarea} value={text} rows={12} spellCheck={false}\n aria-describedby={statsId} aria-busy={previewStatus === 'loading' ? true : undefined}\n disabled={!preview}\n placeholder={previewStatus === 'loading' ? 'Building the handoff from this chat’s log…' : ''}\n onChange={(event) => setText(event.target.value)} />\n )}\n <p id={statsId} className={styles.hint} aria-live=\"polite\">\n {previewStatus === 'loading'\n ? preview ? 'Rebuilding…' : 'Reading this chat’s log…'\n : preview ? (\n <>\n {text.length.toLocaleString()} chars · ~{liveTokens.toLocaleString()} tokens\n {' · '}{preview.stats.turnsCovered} {preview.stats.turnsCovered === 1 ? 'turn' : 'turns'}\n {' · '}{preview.stats.filesTouched} {preview.stats.filesTouched === 1 ? 'file' : 'files'} touched\n {edited ? ' · edited' : ''}\n {includeLastAssistant ? ` · includes ${sourceSeatLabel}’s own summary` : ''}\n </>\n ) : null}\n </p>\n {preview && preview.stats.truncated.length > 0 ? (\n <p className={styles.hint}>\n To stay under {VERSE_HANDOFF_MAX_CHARS.toLocaleString()} characters these sections were left out: {preview.stats.truncated.join(', ')}.\n </p>\n ) : null}\n {overTurnLimit ? (\n <p className={styles.error} role=\"alert\">\n Over the 64 KB limit for one message (counted as it is sent, line breaks and quotes encoded) — the new chat could\n not send it. Trim it first.\n </p>\n ) : overBudget ? (\n <p className={styles.warn}>\n Longer than the {VERSE_HANDOFF_MAX_CHARS.toLocaleString()}-character handoff budget. It can still be sent; the new chat just starts bigger.\n </p>\n ) : null}\n {previewStatus === 'error' && previewError ? (\n <p className={styles.error} role=\"alert\">\n Could not build the handoff: {previewError}{' '}\n <button type=\"button\" className={styles.link} onClick={rebuild}>Try again</button>\n </p>\n ) : null}\n </div>\n\n {/* ---- optional: the seat's own summary ---- */}\n <section className={styles.aside} aria-labelledby={`${titleId}-summary`}>\n <h3 id={`${titleId}-summary`} className={styles.label}>Better summary <span className={styles.optional}>optional, spends</span></h3>\n <p className={styles.hint}>\n The handoff above is assembled from this chat’s log. For one in the agent’s own words, ask {sourceSeatLabel} to\n write it first — its reply is added to the handoff. {turnCostSentence(session.engine, sourceSeatLabel)}\n </p>\n {summary.phase === 'waiting' || summary.phase === 'cancelling' ? (\n <div className={styles.row} role=\"status\">\n <span className={styles.pending} aria-hidden=\"true\" />\n <span className={styles.hint}>\n {summary.phase === 'cancelling' ? 'Stopping the summary…' : `Waiting for ${sourceSeatLabel} to finish its summary…`}\n </span>\n <button type=\"button\" className={styles.secondary} onClick={() => void stopSummary()}\n disabled={summary.phase === 'cancelling'}>Stop the summary</button>\n </div>\n ) : (\n <div className={styles.row}>\n <button type=\"button\" className={styles.secondary} onClick={() => void summarize()}\n disabled={summarizeBlocked !== null || summary.phase === 'sending'}>\n {summary.phase === 'sending' ? 'Sending…' : summary.phase === 'done' ? `Ask ${sourceSeatLabel} again` : `Ask ${sourceSeatLabel} to summarize first`}\n </button>\n {summary.phase === 'done' ? <span className={styles.hint} role=\"status\">Summary added.</span> : null}\n </div>\n )}\n {summarizeBlocked !== null && !summarizing ? <p className={styles.hint}>{summarizeBlocked}</p> : null}\n {summarizeBlocked === null && summary.phase === 'idle' && edited ? (\n <p className={styles.hint}>The handoff is rebuilt with the summary, which replaces your edits above.</p>\n ) : null}\n {summary.phase === 'failed' ? <p className={styles.error} role=\"alert\">{summary.message}</p> : null}\n </section>\n\n {/* ---- where it continues ---- */}\n <div className={styles.field}>\n <SeatSelector id={seatId} seats={seats} value={target} onChange={chooseTarget} label=\"Continue on\"\n modeFor={(seat, model) => (target && seat.id === target.seatId && model.id === target.model ? mode : 'standard')} />\n {unavailable ? <p className={styles.error} role=\"alert\">{unavailable}</p> : null}\n {reachCaveat ? <p className={styles.hint}>{reachCaveat}</p> : null}\n </div>\n\n {option && !unavailable ? (\n <div className={styles.field}>\n {expansiveOffered ? (\n <>\n <span id={modeLabelId} className={styles.label}>Context mode</span>\n <Segmented<VerseContextMode> aria-labelledby={modeLabelId} size=\"sm\" value={mode}\n onChange={(next) => setModeChoice(next)}\n options={[\n { value: 'standard', label: 'Standard' },\n { value: 'expansive', label: 'Expansive' },\n ]} />\n <p className={styles.hint}>\n {budgetLine(option, mode)}.{' '}\n {mode === 'expansive'\n ? `Expansive keeps far more of the conversation before compacting, but every turn re-sends all of it — each turn costs more usage.${expansiveCost ? ` ${expansiveCost}` : ''}`\n : 'Standard compacts sooner and keeps each turn cheaper. Expansive is one click away if the work needs it.'}\n </p>\n </>\n ) : budgetLine(option, 'standard') ? (\n <p className={styles.hint}>{budgetLine(option, 'standard')}.</p>\n ) : null}\n <p className={`${styles.fit} ${styles[`fit-${fit.tone}`] ?? ''}`} data-verdict={fit.verdict ?? 'unknown'}>\n {fit.text}\n </p>\n </div>\n ) : null}\n\n <div className={styles.field}>\n <label className={styles.label} htmlFor={nameId}>Title</label>\n <input id={nameId} className={styles.input} value={title} maxLength={TITLE_MAX_CHARS} autoComplete=\"off\"\n onChange={(event) => setTitle(event.target.value)} />\n </div>\n\n {createError ? <p className={styles.error} role=\"alert\">{createError}</p> : null}\n\n <p className={styles.cost}>\n Creating the chat is free — nothing is sent to a model. The handoff goes into the new chat’s composer; read it,\n then press Send. That first turn is the first thing spent.\n </p>\n <div className={styles.actions}>\n {createBlocked && preview ? <span className={styles.blocked}>{createBlocked}</span> : null}\n <button type=\"button\" className={styles.cancel} onClick={onClose}>Cancel</button>\n <button type=\"submit\" className={styles.primary} disabled={createBlocked !== null || creating}>\n {creating ? 'Creating…' : 'Create chat'}\n </button>\n </div>\n </form>\n </Dialog>\n <MutationTokenDialog open={gate.dialog.open} reason={gate.dialog.reason} tokenLabel=\"Mutation token\"\n tokenHelp=\"the mutation token ashlr verse printed\" onClose={gate.dialog.onClose} onUnlocked={gate.dialog.onUnlocked} />\n </>\n );\n}\n"],"mappings":"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"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,c as t,n}from"./index-
|
|
2
|
-
//# sourceMappingURL=Input-
|
|
1
|
+
import{a as e,c as t,n}from"./index-DZ-UQ7v8.js";var r=t(e(),1),i={field:`_field_ki2n9_1`,label:`_label_ki2n9_8`,shell:`_shell_ki2n9_15`,sm:`_sm_ki2n9_29`,input:`_input_ki2n9_33`,invalid:`_invalid_ki2n9_50`,mono:`_mono_ki2n9_80`,prefix:`_prefix_ki2n9_85`,hint:`_hint_ki2n9_91`,error:`_error_ki2n9_97`},a=n();function o({label:e,hint:t,error:n,size:o=`md`,mono:s=!1,prefix:c,className:l,id:u,...d}){let f=(0,r.useId)(),p=u??f,m=`${p}-hint`,h=`${p}-error`,g=[d[`aria-describedby`],t?m:null,n?h:null].filter(Boolean).join(` `);return(0,a.jsxs)(`div`,{className:`${i.field} ${l??``}`,children:[e?(0,a.jsx)(`label`,{className:i.label,htmlFor:p,children:e}):null,(0,a.jsxs)(`div`,{className:`${i.shell} ${i[o]} ${n?i.invalid:``}`,children:[c?(0,a.jsx)(`span`,{className:i.prefix,children:c}):null,(0,a.jsx)(`input`,{...d,id:p,className:`${i.input} ${s?i.mono:``}`,"aria-invalid":n?!0:d[`aria-invalid`],"aria-describedby":g||void 0})]}),t?(0,a.jsx)(`p`,{id:m,className:i.hint,children:t}):null,n?(0,a.jsx)(`p`,{id:h,className:i.error,role:`alert`,children:n}):null]})}export{o as t};
|
|
2
|
+
//# sourceMappingURL=Input-D_KRJA9V.js.map
|