@ashlr/hub 3.13.0 → 3.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +74 -0
- package/dist/authority-surface.json +204 -124
- package/dist/build-identity.json +2 -2
- package/dist/cli/authority.js +112 -18
- package/dist/cli/authority.js.map +1 -1
- package/dist/cli/comms.d.ts +33 -19
- package/dist/cli/comms.js +128 -151
- package/dist/cli/comms.js.map +1 -1
- package/dist/cli/completions.js +1 -1
- package/dist/cli/completions.js.map +1 -1
- package/dist/cli/daemon.js +29 -0
- package/dist/cli/daemon.js.map +1 -1
- package/dist/cli/director.d.ts +8 -12
- package/dist/cli/director.js +17 -52
- package/dist/cli/director.js.map +1 -1
- package/dist/cli/fleet.js +4 -1
- package/dist/cli/fleet.js.map +1 -1
- package/dist/cli/help.js +1 -0
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/leader.d.ts +27 -3
- package/dist/cli/leader.js +253 -4
- package/dist/cli/leader.js.map +1 -1
- package/dist/core/authority/server-enforcement.d.ts +110 -0
- package/dist/core/authority/server-enforcement.js +260 -0
- package/dist/core/authority/server-enforcement.js.map +1 -0
- package/dist/core/authority/standing-grant.d.ts +24 -4
- package/dist/core/authority/standing-grant.js +19 -3
- package/dist/core/authority/standing-grant.js.map +1 -1
- package/dist/core/cloud/timeline.js +13 -7
- package/dist/core/cloud/timeline.js.map +1 -1
- package/dist/core/comms/change-digest.d.ts +130 -0
- package/dist/core/comms/change-digest.js +451 -0
- package/dist/core/comms/change-digest.js.map +1 -0
- package/dist/core/comms/director-prompt.d.ts +4 -5
- package/dist/core/comms/director-prompt.js +4 -71
- package/dist/core/comms/director-prompt.js.map +1 -1
- package/dist/core/comms/director.d.ts +24 -61
- package/dist/core/comms/director.js +29 -382
- package/dist/core/comms/director.js.map +1 -1
- package/dist/core/comms/dispatch.d.ts +37 -12
- package/dist/core/comms/dispatch.js +244 -177
- package/dist/core/comms/dispatch.js.map +1 -1
- package/dist/core/comms/elon-dialogue.d.ts +23 -15
- package/dist/core/comms/elon-dialogue.js +36 -307
- package/dist/core/comms/elon-dialogue.js.map +1 -1
- package/dist/core/comms/fleet-pulse.js +4 -7
- package/dist/core/comms/fleet-pulse.js.map +1 -1
- package/dist/core/comms/handlers.d.ts +10 -6
- package/dist/core/comms/handlers.js +14 -48
- package/dist/core/comms/handlers.js.map +1 -1
- package/dist/core/comms/migrations.d.ts +47 -0
- package/dist/core/comms/migrations.js +125 -0
- package/dist/core/comms/migrations.js.map +1 -0
- package/dist/core/comms/requests.d.ts +32 -5
- package/dist/core/comms/requests.js +101 -5
- package/dist/core/comms/requests.js.map +1 -1
- package/dist/core/comms/telegram-channel.d.ts +104 -0
- package/dist/core/comms/telegram-channel.js +622 -0
- package/dist/core/comms/telegram-channel.js.map +1 -0
- package/dist/core/comms/telegram-thread-map.d.ts +56 -0
- package/dist/core/comms/telegram-thread-map.js +144 -0
- package/dist/core/comms/telegram-thread-map.js.map +1 -0
- package/dist/core/daemon/capacity-publisher.d.ts +8 -1
- package/dist/core/daemon/capacity-publisher.js +40 -2
- package/dist/core/daemon/capacity-publisher.js.map +1 -1
- package/dist/core/daemon/loop.js +18 -4
- package/dist/core/daemon/loop.js.map +1 -1
- package/dist/core/daemon/tick-deadline.d.ts +44 -0
- package/dist/core/daemon/tick-deadline.js +83 -0
- package/dist/core/daemon/tick-deadline.js.map +1 -0
- package/dist/core/daemon/tick-hooks.d.ts +7 -0
- package/dist/core/daemon/tick-hooks.js.map +1 -1
- package/dist/core/daemon/tick-progress.d.ts +39 -0
- package/dist/core/daemon/tick-progress.js +194 -0
- package/dist/core/daemon/tick-progress.js.map +1 -0
- package/dist/core/dashboard.js +3 -1
- package/dist/core/dashboard.js.map +1 -1
- package/dist/core/fleet/fleet-merge-state.d.ts +6 -0
- package/dist/core/fleet/fleet-merge-state.js.map +1 -1
- package/dist/core/fleet/host-merge.d.ts +9 -0
- package/dist/core/fleet/host-merge.js +13 -2
- package/dist/core/fleet/host-merge.js.map +1 -1
- package/dist/core/fleet/merge-gates.d.ts +13 -0
- package/dist/core/fleet/merge-gates.js +14 -0
- package/dist/core/fleet/merge-gates.js.map +1 -1
- package/dist/core/fleet/mirrors.d.ts +162 -6
- package/dist/core/fleet/mirrors.js +1051 -49
- package/dist/core/fleet/mirrors.js.map +1 -1
- package/dist/core/fleet/standing-merge-pass.d.ts +8 -0
- package/dist/core/fleet/standing-merge-pass.js +72 -1
- package/dist/core/fleet/standing-merge-pass.js.map +1 -1
- package/dist/core/fleet/status.d.ts +17 -0
- package/dist/core/fleet/status.js +22 -0
- package/dist/core/fleet/status.js.map +1 -1
- package/dist/core/fleet/tick-hooks-live.d.ts +1 -1
- package/dist/core/fleet/tick-hooks-live.js +13 -3
- package/dist/core/fleet/tick-hooks-live.js.map +1 -1
- package/dist/core/git.d.ts +17 -0
- package/dist/core/git.js +124 -25
- package/dist/core/git.js.map +1 -1
- package/dist/core/goals/open-goals.d.ts +47 -0
- package/dist/core/goals/open-goals.js +33 -0
- package/dist/core/goals/open-goals.js.map +1 -0
- package/dist/core/inbox/merge.d.ts +5 -0
- package/dist/core/inbox/merge.js +58 -2
- package/dist/core/inbox/merge.js.map +1 -1
- package/dist/core/integrations/locus.d.ts +28 -0
- package/dist/core/integrations/locus.js +155 -30
- package/dist/core/integrations/locus.js.map +1 -1
- package/dist/core/integrations/telegram-format.d.ts +40 -0
- package/dist/core/integrations/telegram-format.js +123 -0
- package/dist/core/integrations/telegram-format.js.map +1 -0
- package/dist/core/integrations/telegram.d.ts +60 -4
- package/dist/core/integrations/telegram.js +161 -28
- package/dist/core/integrations/telegram.js.map +1 -1
- package/dist/core/mcp-registry.d.ts +12 -0
- package/dist/core/mcp-registry.js +70 -0
- package/dist/core/mcp-registry.js.map +1 -1
- package/dist/core/observability/rollup.d.ts +12 -10
- package/dist/core/observability/rollup.js +44 -17
- package/dist/core/observability/rollup.js.map +1 -1
- package/dist/core/resources/connection-monitor.d.ts +9 -0
- package/dist/core/resources/connection-monitor.js +19 -9
- package/dist/core/resources/connection-monitor.js.map +1 -1
- package/dist/core/resources/quota-refresh-lease.d.ts +17 -0
- package/dist/core/resources/quota-refresh-lease.js +34 -1
- package/dist/core/resources/quota-refresh-lease.js.map +1 -1
- package/dist/core/routing/budget-api.d.ts +7 -1
- package/dist/core/routing/budget-api.js +56 -2
- package/dist/core/routing/budget-api.js.map +1 -1
- package/dist/core/routing/readiness-types.d.ts +82 -0
- package/dist/core/routing/readiness-types.js +23 -0
- package/dist/core/routing/readiness-types.js.map +1 -0
- package/dist/core/routing/readiness.d.ts +103 -0
- package/dist/core/routing/readiness.js +480 -0
- package/dist/core/routing/readiness.js.map +1 -0
- package/dist/core/sandbox/confine.js +22 -1
- package/dist/core/sandbox/confine.js.map +1 -1
- package/dist/core/sandbox/policy.d.ts +23 -0
- package/dist/core/sandbox/policy.js +100 -0
- package/dist/core/sandbox/policy.js.map +1 -1
- package/dist/core/types.d.ts +13 -0
- package/dist/core/types.js.map +1 -1
- package/dist/core/universe/builtins/preparation/manifest.json +1 -1
- package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +1204 -939
- package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +1319 -1054
- package/dist/core/usage/frontier-usage.d.ts +20 -2
- package/dist/core/usage/frontier-usage.js +75 -17
- package/dist/core/usage/frontier-usage.js.map +1 -1
- package/dist/core/verse/accounts.d.ts +45 -0
- package/dist/core/verse/accounts.js +246 -17
- package/dist/core/verse/accounts.js.map +1 -1
- package/dist/core/verse/apps-api.js +23 -11
- package/dist/core/verse/apps-api.js.map +1 -1
- package/dist/core/verse/apps.d.ts +11 -9
- package/dist/core/verse/apps.js +2 -2
- package/dist/core/verse/apps.js.map +1 -1
- package/dist/core/verse/authority-api.d.ts +8 -2
- package/dist/core/verse/authority-api.js +40 -5
- package/dist/core/verse/authority-api.js.map +1 -1
- package/dist/core/verse/autonomy-ladder.d.ts +172 -0
- package/dist/core/verse/autonomy-ladder.js +251 -0
- package/dist/core/verse/autonomy-ladder.js.map +1 -0
- package/dist/core/verse/context-fit.js +7 -5
- package/dist/core/verse/context-fit.js.map +1 -1
- package/dist/core/verse/control-api.d.ts +23 -1
- package/dist/core/verse/control-api.js +117 -10
- package/dist/core/verse/control-api.js.map +1 -1
- package/dist/core/verse/fleet-live-api.js +13 -5
- package/dist/core/verse/fleet-live-api.js.map +1 -1
- package/dist/core/verse/folder-io.d.ts +50 -0
- package/dist/core/verse/folder-io.js +142 -0
- package/dist/core/verse/folder-io.js.map +1 -0
- package/dist/core/verse/git-api.js +5 -4
- package/dist/core/verse/git-api.js.map +1 -1
- package/dist/core/verse/git-ops.d.ts +10 -1
- package/dist/core/verse/git-ops.js +18 -2
- package/dist/core/verse/git-ops.js.map +1 -1
- package/dist/core/verse/github-api.d.ts +1 -1
- package/dist/core/verse/github-api.js +5 -4
- package/dist/core/verse/github-api.js.map +1 -1
- package/dist/core/verse/github-repo.js +118 -14
- package/dist/core/verse/github-repo.js.map +1 -1
- package/dist/core/verse/leader-api.d.ts +5 -4
- package/dist/core/verse/leader-api.js +237 -10
- package/dist/core/verse/leader-api.js.map +1 -1
- package/dist/core/verse/local-models.d.ts +10 -0
- package/dist/core/verse/local-models.js +10 -1
- package/dist/core/verse/local-models.js.map +1 -1
- package/dist/core/verse/login-path.d.ts +73 -0
- package/dist/core/verse/login-path.js +123 -14
- package/dist/core/verse/login-path.js.map +1 -1
- package/dist/core/verse/mcp-control-api.js +4 -4
- package/dist/core/verse/mcp-control-api.js.map +1 -1
- package/dist/core/verse/mcp-scope.d.ts +22 -0
- package/dist/core/verse/mcp-scope.js +41 -1
- package/dist/core/verse/mcp-scope.js.map +1 -1
- package/dist/core/verse/mcp-seat-view.d.ts +10 -0
- package/dist/core/verse/mcp-seat-view.js +30 -4
- package/dist/core/verse/mcp-seat-view.js.map +1 -1
- package/dist/core/verse/overnight-api.js +20 -2
- package/dist/core/verse/overnight-api.js.map +1 -1
- package/dist/core/verse/path-guard.d.ts +24 -0
- package/dist/core/verse/path-guard.js +91 -22
- package/dist/core/verse/path-guard.js.map +1 -1
- package/dist/core/verse/preview-api.js +22 -0
- package/dist/core/verse/preview-api.js.map +1 -1
- package/dist/core/verse/projects.d.ts +21 -0
- package/dist/core/verse/projects.js +82 -0
- package/dist/core/verse/projects.js.map +1 -1
- package/dist/core/verse/session-controls-api.js +5 -3
- package/dist/core/verse/session-controls-api.js.map +1 -1
- package/dist/core/verse/session-handoff.d.ts +26 -0
- package/dist/core/verse/session-handoff.js +90 -12
- package/dist/core/verse/session-handoff.js.map +1 -1
- package/dist/core/verse/terminal-api.js +7 -4
- package/dist/core/verse/terminal-api.js.map +1 -1
- package/dist/core/verse/terminal.js +9 -5
- package/dist/core/verse/terminal.js.map +1 -1
- package/dist/core/verse/verse-api.js +81 -27
- package/dist/core/verse/verse-api.js.map +1 -1
- package/dist/core/verse/workspaces.d.ts +51 -0
- package/dist/core/verse/workspaces.js +177 -47
- package/dist/core/verse/workspaces.js.map +1 -1
- package/dist/core/vision/leader-apply.d.ts +40 -0
- package/dist/core/vision/leader-apply.js +101 -30
- package/dist/core/vision/leader-apply.js.map +1 -1
- package/dist/core/vision/leader-cadence.d.ts +114 -0
- package/dist/core/vision/leader-cadence.js +127 -0
- package/dist/core/vision/leader-cadence.js.map +1 -0
- package/dist/core/vision/leader-goal-evidence.d.ts +25 -0
- package/dist/core/vision/leader-goal-evidence.js +36 -0
- package/dist/core/vision/leader-goal-evidence.js.map +1 -0
- package/dist/core/vision/leader-health.d.ts +53 -0
- package/dist/core/vision/leader-health.js +92 -0
- package/dist/core/vision/leader-health.js.map +1 -0
- package/dist/core/vision/leader-operator.d.ts +176 -0
- package/dist/core/vision/leader-operator.js +355 -0
- package/dist/core/vision/leader-operator.js.map +1 -0
- package/dist/core/vision/leader-run-chain.d.ts +41 -0
- package/dist/core/vision/leader-run-chain.js +54 -0
- package/dist/core/vision/leader-run-chain.js.map +1 -0
- package/dist/core/vision/leader-seat-plan.d.ts +68 -0
- package/dist/core/vision/leader-seat-plan.js +93 -0
- package/dist/core/vision/leader-seat-plan.js.map +1 -0
- package/dist/core/vision/leader-seat.d.ts +71 -5
- package/dist/core/vision/leader-seat.js +235 -33
- package/dist/core/vision/leader-seat.js.map +1 -1
- package/dist/core/vision/leader-thread-types.d.ts +104 -0
- package/dist/core/vision/leader-thread-types.js +9 -0
- package/dist/core/vision/leader-thread-types.js.map +1 -0
- package/dist/core/vision/leader-thread.d.ts +138 -0
- package/dist/core/vision/leader-thread.js +926 -0
- package/dist/core/vision/leader-thread.js.map +1 -0
- package/dist/core/vision/leader-types.d.ts +75 -1
- package/dist/core/vision/leader.d.ts +88 -18
- package/dist/core/vision/leader.js +269 -69
- package/dist/core/vision/leader.js.map +1 -1
- package/dist/core/web/public/next/assets/{ActionMenu-Dwjk6rUQ.js → ActionMenu-CIiX2X8w.js} +2 -2
- package/dist/core/web/public/next/assets/{ActionMenu-Dwjk6rUQ.js.map → ActionMenu-CIiX2X8w.js.map} +1 -1
- package/dist/core/web/public/next/assets/Advanced-DHsysoIL.js +2 -0
- package/dist/core/web/public/next/assets/{Advanced-cVYTAsfB.js.map → Advanced-DHsysoIL.js.map} +1 -1
- package/dist/core/web/public/next/assets/{App-IsaWDsdF.js → App-CMeAocmW.js} +5 -5
- package/dist/core/web/public/next/assets/{App-IsaWDsdF.js.map → App-CMeAocmW.js.map} +1 -1
- package/dist/core/web/public/next/assets/AppsSection-DISYnMnc.js +2 -0
- package/dist/core/web/public/next/assets/{AppsSection-DDqeSrty.js.map → AppsSection-DISYnMnc.js.map} +1 -1
- package/dist/core/web/public/next/assets/AreaTrend-DK2Y2TbZ.js +2 -0
- package/dist/core/web/public/next/assets/AreaTrend-DK2Y2TbZ.js.map +1 -0
- package/dist/core/web/public/next/assets/{AutonomyOffState-CpFYS3tQ.js → AutonomyOffState-CEPSZToP.js} +3 -3
- package/dist/core/web/public/next/assets/{AutonomyOffState-CpFYS3tQ.js.map → AutonomyOffState-CEPSZToP.js.map} +1 -1
- package/dist/core/web/public/next/assets/AutonomySection-DWc3ciAD.js +2 -0
- package/dist/core/web/public/next/assets/{AutonomySection-Dwn8UtOy.js.map → AutonomySection-DWc3ciAD.js.map} +1 -1
- package/dist/core/web/public/next/assets/AutonomyStatus-CYaHjJ9U.js +2 -0
- package/dist/core/web/public/next/assets/AutonomyStatus-CYaHjJ9U.js.map +1 -0
- package/dist/core/web/public/next/assets/{BranchBar-ISZ7xUCj.js → BranchBar-BxhdiIpx.js} +2 -2
- package/dist/core/web/public/next/assets/{BranchBar-ISZ7xUCj.js.map → BranchBar-BxhdiIpx.js.map} +1 -1
- package/dist/core/web/public/next/assets/{BudgetControl-BARVp-En.js → BudgetControl-C-0KhjRS.js} +2 -2
- package/dist/core/web/public/next/assets/{BudgetControl-BARVp-En.js.map → BudgetControl-C-0KhjRS.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Button-DtE0rlWD.js → Button-D90dzI_o.js} +2 -2
- package/dist/core/web/public/next/assets/{Button-DtE0rlWD.js.map → Button-D90dzI_o.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CapacityStrip-DKbKA_Aa.js → CapacityStrip-qKDBC65C.js} +2 -2
- package/dist/core/web/public/next/assets/{CapacityStrip-DKbKA_Aa.js.map → CapacityStrip-qKDBC65C.js.map} +1 -1
- package/dist/core/web/public/next/assets/ChartFrame-DY-GVUb3.js +2 -0
- package/dist/core/web/public/next/assets/ChartFrame-DY-GVUb3.js.map +1 -0
- package/dist/core/web/public/next/assets/ChartFrame-DyjmyV8N.css +1 -0
- package/dist/core/web/public/next/assets/ChatSection-DlT4QU6a.js +3 -0
- package/dist/core/web/public/next/assets/{ChatSection-C9myY4ei.js.map → ChatSection-DlT4QU6a.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CloudBudgetForm-CvjK4Oh6.js → CloudBudgetForm-BrNun_Yu.js} +2 -2
- package/dist/core/web/public/next/assets/{CloudBudgetForm-CvjK4Oh6.js.map → CloudBudgetForm-BrNun_Yu.js.map} +1 -1
- package/dist/core/web/public/next/assets/CommandPalette-C5lDDKN0.js +2 -0
- package/dist/core/web/public/next/assets/CommandPalette-C5lDDKN0.js.map +1 -0
- package/dist/core/web/public/next/assets/CommandSection-B0xuU-yZ.css +1 -0
- package/dist/core/web/public/next/assets/CommandSection-DXFvPgKp.js +3 -0
- package/dist/core/web/public/next/assets/CommandSection-DXFvPgKp.js.map +1 -0
- package/dist/core/web/public/next/assets/{ConfirmDialog-CLUhzaBj.js → ConfirmDialog-BR4nZQ2D.js} +2 -2
- package/dist/core/web/public/next/assets/{ConfirmDialog-CLUhzaBj.js.map → ConfirmDialog-BR4nZQ2D.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DeleteChatDialog-C_eDhV8b.js → DeleteChatDialog-BCfP12GH.js} +2 -2
- package/dist/core/web/public/next/assets/{DeleteChatDialog-C_eDhV8b.js.map → DeleteChatDialog-BCfP12GH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Dialog-BRd_B9OE.js → Dialog-D3msQlCj.js} +2 -2
- package/dist/core/web/public/next/assets/{Dialog-BRd_B9OE.js.map → Dialog-D3msQlCj.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffPane-Cpr9soB2.js → DiffPane-Ix6hvXlY.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffPane-Cpr9soB2.js.map → DiffPane-Ix6hvXlY.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffViewer-CNwd0W3Q.js → DiffViewer-C4WKsCIe.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffViewer-CNwd0W3Q.js.map → DiffViewer-C4WKsCIe.js.map} +1 -1
- package/dist/core/web/public/next/assets/DockHost-aWP7liri.js +2 -0
- package/dist/core/web/public/next/assets/{DockHost-BcEq2qaS.js.map → DockHost-aWP7liri.js.map} +1 -1
- package/dist/core/web/public/next/assets/{EmptyState-DsN1H6MC.js → EmptyState-D2IRy3Cg.js} +2 -2
- package/dist/core/web/public/next/assets/{EmptyState-DsN1H6MC.js.map → EmptyState-D2IRy3Cg.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Epistemic-fycQTBRO.js → Epistemic-DMr18muX.js} +2 -2
- package/dist/core/web/public/next/assets/{Epistemic-fycQTBRO.js.map → Epistemic-DMr18muX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{EvidenceTimeline-sCCAdnBK.js → EvidenceTimeline-DXmmz6Fi.js} +2 -2
- package/dist/core/web/public/next/assets/{EvidenceTimeline-sCCAdnBK.js.map → EvidenceTimeline-DXmmz6Fi.js.map} +1 -1
- package/dist/core/web/public/next/assets/FleetSection-BfplcwFU.js +3 -0
- package/dist/core/web/public/next/assets/FleetSection-BfplcwFU.js.map +1 -0
- package/dist/core/web/public/next/assets/Funnel-Dh2yVHws.js +2 -0
- package/dist/core/web/public/next/assets/Funnel-Dh2yVHws.js.map +1 -0
- package/dist/core/web/public/next/assets/{GearTray-CpDt0xwj.js → GearTray-Dt-ee32-.js} +2 -2
- package/dist/core/web/public/next/assets/{GearTray-CpDt0xwj.js.map → GearTray-Dt-ee32-.js.map} +1 -1
- package/dist/core/web/public/next/assets/GrowthSection-P9EUfGeA.js +2 -0
- package/dist/core/web/public/next/assets/{GrowthSection-BvZezOsX.js.map → GrowthSection-P9EUfGeA.js.map} +1 -1
- package/dist/core/web/public/next/assets/{HandoffDialog-B1G6gQyk.js → HandoffDialog-CLJQLe7M.js} +2 -2
- package/dist/core/web/public/next/assets/{HandoffDialog-B1G6gQyk.js.map → HandoffDialog-CLJQLe7M.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Input-CI0yBHmn.js → Input-D_KRJA9V.js} +2 -2
- package/dist/core/web/public/next/assets/{Input-CI0yBHmn.js.map → Input-D_KRJA9V.js.map} +1 -1
- package/dist/core/web/public/next/assets/LeaderCard-D-7DlJuR.js +2 -0
- package/dist/core/web/public/next/assets/LeaderCard-D-7DlJuR.js.map +1 -0
- package/dist/core/web/public/next/assets/LeaderCard-DNsbLwY3.css +1 -0
- package/dist/core/web/public/next/assets/LeaderConversation-DGZjWI-E.js +2 -0
- package/dist/core/web/public/next/assets/LeaderConversation-DGZjWI-E.js.map +1 -0
- package/dist/core/web/public/next/assets/LeaderConversation-DPHUTq6W.css +1 -0
- package/dist/core/web/public/next/assets/MatrixHeatmap-C7BCG2d7.js +2 -0
- package/dist/core/web/public/next/assets/MatrixHeatmap-C7BCG2d7.js.map +1 -0
- package/dist/core/web/public/next/assets/McpSection-DGbRcyv8.js +2 -0
- package/dist/core/web/public/next/assets/{McpSection-nuXer4K-.js.map → McpSection-DGbRcyv8.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdown-BCe4TsXk.js → MessageMarkdown-DFvk06qG.js} +3 -3
- package/dist/core/web/public/next/assets/{MessageMarkdown-BCe4TsXk.js.map → MessageMarkdown-DFvk06qG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DL3LU5kL.js → MessageMarkdownRenderer-BAv4oEUf.js} +2 -2
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DL3LU5kL.js.map → MessageMarkdownRenderer-BAv4oEUf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Meter-b69LM0mU.js → Meter-CMj-VafN.js} +2 -2
- package/dist/core/web/public/next/assets/{Meter-b69LM0mU.js.map → Meter-CMj-VafN.js.map} +1 -1
- package/dist/core/web/public/next/assets/MindSection-C6kLPIjt.js +3 -0
- package/dist/core/web/public/next/assets/MindSection-C6kLPIjt.js.map +1 -0
- package/dist/core/web/public/next/assets/{MutationTokenDialog-Bm34BNVV.js → MutationTokenDialog-DbnO8aYi.js} +2 -2
- package/dist/core/web/public/next/assets/{MutationTokenDialog-Bm34BNVV.js.map → MutationTokenDialog-DbnO8aYi.js.map} +1 -1
- package/dist/core/web/public/next/assets/NeedsYouDrawer-crsiX-Nc.js +3 -0
- package/dist/core/web/public/next/assets/NeedsYouDrawer-crsiX-Nc.js.map +1 -0
- package/dist/core/web/public/next/assets/{NeedsYouList-D5Kk549g.js → NeedsYouList-CCsijdWt.js} +2 -2
- package/dist/core/web/public/next/assets/{NeedsYouList-D5Kk549g.js.map → NeedsYouList-CCsijdWt.js.map} +1 -1
- package/dist/core/web/public/next/assets/NewChatDialog-BlCHtOIr.js +3 -0
- package/dist/core/web/public/next/assets/{NewChatDialog-BqFTWgHU.js.map → NewChatDialog-BlCHtOIr.js.map} +1 -1
- package/dist/core/web/public/next/assets/{OnboardingFlow-DcDsguAM.js → OnboardingFlow-Cy9BA9eR.js} +3 -3
- package/dist/core/web/public/next/assets/{OnboardingFlow-DcDsguAM.js.map → OnboardingFlow-Cy9BA9eR.js.map} +1 -1
- package/dist/core/web/public/next/assets/OnboardingGate-BXpNFoLt.js +3 -0
- package/dist/core/web/public/next/assets/{OnboardingGate-BZafM1Vf.js.map → OnboardingGate-BXpNFoLt.js.map} +1 -1
- package/dist/core/web/public/next/assets/PreviewPane-COid5A0f.js +2 -0
- package/dist/core/web/public/next/assets/{PreviewPane-zT3gK9TD.js.map → PreviewPane-COid5A0f.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ProviderLogo-AwHn2sKm.js → ProviderLogo-Cq-CYIwT.js} +2 -2
- package/dist/core/web/public/next/assets/{ProviderLogo-AwHn2sKm.js.map → ProviderLogo-Cq-CYIwT.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RailStatus-xHrovWvI.js → RailStatus-Co5UB6We.js} +2 -2
- package/dist/core/web/public/next/assets/{RailStatus-xHrovWvI.js.map → RailStatus-Co5UB6We.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RefreshIndicator-SEFZlMB2.js → RefreshIndicator-DO9ibnSq.js} +2 -2
- package/dist/core/web/public/next/assets/{RefreshIndicator-SEFZlMB2.js.map → RefreshIndicator-DO9ibnSq.js.map} +1 -1
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-Dr2WRgkq.js +7 -0
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-CAxPQ4sZ.js.map → ResourcePoolConsoleApp-Dr2WRgkq.js.map} +1 -1
- package/dist/core/web/public/next/assets/ResourcesChrome-CwMnbqI1.js +3 -0
- package/dist/core/web/public/next/assets/ResourcesChrome-CwMnbqI1.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-B_Xp_JNc.js +2 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-B_Xp_JNc.js.map +1 -0
- package/dist/core/web/public/next/assets/ResourcesDrawer-DrGoO8KG.css +1 -0
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-C8WGiixc.js → RouteErrorBoundary-SkNhhUbt.js} +2 -2
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-C8WGiixc.js.map → RouteErrorBoundary-SkNhhUbt.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RunInCloudAction-1-IPLYhf.js → RunInCloudAction-BXPlZwJQ.js} +2 -2
- package/dist/core/web/public/next/assets/{RunInCloudAction-1-IPLYhf.js.map → RunInCloudAction-BXPlZwJQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SeatSelector-DpwNiX8F.js → SeatSelector-J5R3zDkB.js} +3 -3
- package/dist/core/web/public/next/assets/{SeatSelector-DpwNiX8F.js.map → SeatSelector-J5R3zDkB.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Segmented-Wt1ATod9.js → Segmented-CGh_-tBb.js} +2 -2
- package/dist/core/web/public/next/assets/{Segmented-Wt1ATod9.js.map → Segmented-CGh_-tBb.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Select-By-V9lMc.js → Select-CWnmUzs3.js} +2 -2
- package/dist/core/web/public/next/assets/{Select-By-V9lMc.js.map → Select-CWnmUzs3.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionGate-WROS02tK.js → SessionGate-sp4KsnUo.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionGate-WROS02tK.js.map → SessionGate-sp4KsnUo.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionInsightChip-DNUcruwp.js → SessionInsightChip-DLFAzdbi.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionInsightChip-DNUcruwp.js.map → SessionInsightChip-DLFAzdbi.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionSearch-UHtt7a8f.js → SessionSearch-DbFjwR1h.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionSearch-UHtt7a8f.js.map → SessionSearch-DbFjwR1h.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SettingsSection-Bf74l0Gj.js → SettingsSection-Ch23msJ5.js} +2 -2
- package/dist/core/web/public/next/assets/SettingsSection-Ch23msJ5.js.map +1 -0
- package/dist/core/web/public/next/assets/{SetupChecklist-CzpEcfOl.js → SetupChecklist-Bd76MBAR.js} +2 -2
- package/dist/core/web/public/next/assets/{SetupChecklist-CzpEcfOl.js.map → SetupChecklist-Bd76MBAR.js.map} +1 -1
- package/dist/core/web/public/next/assets/ShadowDecisions-C5RAY91f.js +3 -0
- package/dist/core/web/public/next/assets/ShadowDecisions-C5RAY91f.js.map +1 -0
- package/dist/core/web/public/next/assets/{Sheet-HkBOBMTT.js → Sheet-BZ2AG4Eo.js} +2 -2
- package/dist/core/web/public/next/assets/{Sheet-HkBOBMTT.js.map → Sheet-BZ2AG4Eo.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-DiigiT8H.js → ShortcutsOverlay-C8n8y3zf.js} +2 -2
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-DiigiT8H.js.map → ShortcutsOverlay-C8n8y3zf.js.map} +1 -1
- package/dist/core/web/public/next/assets/Sidebar-DN--cPYN.js +3 -0
- package/dist/core/web/public/next/assets/{Sidebar-C9YtBYVZ.js.map → Sidebar-DN--cPYN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Slider-DaEDws-b.js → Slider-KVoJLDD6.js} +2 -2
- package/dist/core/web/public/next/assets/{Slider-DaEDws-b.js.map → Slider-KVoJLDD6.js.map} +1 -1
- package/dist/core/web/public/next/assets/StatTile-C4KgjltA.js +2 -0
- package/dist/core/web/public/next/assets/StatTile-C4KgjltA.js.map +1 -0
- package/dist/core/web/public/next/assets/StatTile-CNCqDoPO.css +1 -0
- package/dist/core/web/public/next/assets/{StatusBadge-CXG3iNL4.js → StatusBadge-CXsYqmdU.js} +2 -2
- package/dist/core/web/public/next/assets/{StatusBadge-CXG3iNL4.js.map → StatusBadge-CXsYqmdU.js.map} +1 -1
- package/dist/core/web/public/next/assets/StepBand-BMtVOFpK.js +2 -0
- package/dist/core/web/public/next/assets/StepBand-BMtVOFpK.js.map +1 -0
- package/dist/core/web/public/next/assets/{Surface-5bNA08tK.js → Surface-BfDmQcKe.js} +2 -2
- package/dist/core/web/public/next/assets/{Surface-5bNA08tK.js.map → Surface-BfDmQcKe.js.map} +1 -1
- package/dist/core/web/public/next/assets/Swimlane-B9Exxekk.js +2 -0
- package/dist/core/web/public/next/assets/Swimlane-B9Exxekk.js.map +1 -0
- package/dist/core/web/public/next/assets/Swimlane-Bf4Rjoy9.css +1 -0
- package/dist/core/web/public/next/assets/{Switch-BmCzfFnu.js → Switch-9NtO_6Lj.js} +2 -2
- package/dist/core/web/public/next/assets/{Switch-BmCzfFnu.js.map → Switch-9NtO_6Lj.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Tag-WSUIaMVy.js → Tag-DscCRFcN.js} +2 -2
- package/dist/core/web/public/next/assets/{Tag-WSUIaMVy.js.map → Tag-DscCRFcN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{TerminalPane-BVFgYX6K.js → TerminalPane-B668-DJW.js} +5 -5
- package/dist/core/web/public/next/assets/{TerminalPane-BVFgYX6K.js.map → TerminalPane-B668-DJW.js.map} +1 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-BUV_brY7.js +2 -0
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-BpphLqoz.js.map → UniverseConsoleApp-BUV_brY7.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseView-DbpbSMwO.js → UniverseView-DG70zH0W.js} +4 -4
- package/dist/core/web/public/next/assets/{UniverseView-DbpbSMwO.js.map → UniverseView-DG70zH0W.js.map} +1 -1
- package/dist/core/web/public/next/assets/UsageSection-DY7uOTm1.js +3 -0
- package/dist/core/web/public/next/assets/UsageSection-DY7uOTm1.js.map +1 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CWU6R3By.js +3 -0
- package/dist/core/web/public/next/assets/VerseConsoleApp-CWU6R3By.js.map +1 -0
- package/dist/core/web/public/next/assets/Workspace-D1nP9BhD.js +10 -0
- package/dist/core/web/public/next/assets/{Workspace-RXy0pqp6.js.map → Workspace-D1nP9BhD.js.map} +1 -1
- package/dist/core/web/public/next/assets/actions-CY-PjpGc.js +2 -0
- package/dist/core/web/public/next/assets/{actions-BZTidCXZ.js.map → actions-CY-PjpGc.js.map} +1 -1
- package/dist/core/web/public/next/assets/actions-DkWhhWIg.css +1 -0
- package/dist/core/web/public/next/assets/{apps-model-CHO133qt.js → apps-model-Du02KhAf.js} +2 -2
- package/dist/core/web/public/next/assets/{apps-model-CHO133qt.js.map → apps-model-Du02KhAf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{authority-model-8NeAEwAF.js → authority-model-79SeuKlJ.js} +2 -2
- package/dist/core/web/public/next/assets/{authority-model-8NeAEwAF.js.map → authority-model-79SeuKlJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/autonomy-ladder-BGWmZzP7.css +1 -0
- package/dist/core/web/public/next/assets/autonomy-ladder.module-ArDv4bkr.js +2 -0
- package/dist/core/web/public/next/assets/autonomy-ladder.module-ArDv4bkr.js.map +1 -0
- package/dist/core/web/public/next/assets/budget-queries-D8QV5XtH.js +2 -0
- package/dist/core/web/public/next/assets/{budget-queries-DFF-3ICg.js.map → budget-queries-D8QV5XtH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{capacity-strip-model-5ViUgUlP.js → capacity-strip-model-BwZ1ZbkU.js} +2 -2
- package/dist/core/web/public/next/assets/{capacity-strip-model-5ViUgUlP.js.map → capacity-strip-model-BwZ1ZbkU.js.map} +1 -1
- package/dist/core/web/public/next/assets/charts-BZ50mZD_.js +2 -0
- package/dist/core/web/public/next/assets/charts-BZ50mZD_.js.map +1 -0
- package/dist/core/web/public/next/assets/charts-ClCB18la.css +1 -0
- package/dist/core/web/public/next/assets/{cloud-model-CfRydq8N.js → cloud-model-BDivRMqv.js} +2 -2
- package/dist/core/web/public/next/assets/{cloud-model-CfRydq8N.js.map → cloud-model-BDivRMqv.js.map} +1 -1
- package/dist/core/web/public/next/assets/{cloud-queries-DmptbjS8.js → cloud-queries-BPQQ5_pJ.js} +2 -2
- package/dist/core/web/public/next/assets/{cloud-queries-DmptbjS8.js.map → cloud-queries-BPQQ5_pJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{colors-BZ3a9wFf.js → colors-DvK0wMHH.js} +2 -2
- package/dist/core/web/public/next/assets/{colors-BZ3a9wFf.js.map → colors-DvK0wMHH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{command-catalog-ffCAijVY.js → command-catalog-BIntSa9l.js} +2 -2
- package/dist/core/web/public/next/assets/command-catalog-BIntSa9l.js.map +1 -0
- package/dist/core/web/public/next/assets/{context-model-CDeyP0cA.js → context-model-Br8t9jgG.js} +2 -2
- package/dist/core/web/public/next/assets/{context-model-CDeyP0cA.js.map → context-model-Br8t9jgG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{context-model-Bb15chFt.js → context-model-CokrgEUq.js} +3 -3
- package/dist/core/web/public/next/assets/{context-model-Bb15chFt.js.map → context-model-CokrgEUq.js.map} +1 -1
- package/dist/core/web/public/next/assets/context-queries-eL3caKVG.js +2 -0
- package/dist/core/web/public/next/assets/{context-queries-_9bFWb9v.js.map → context-queries-eL3caKVG.js.map} +1 -1
- package/dist/core/web/public/next/assets/{control-queries-CXtmZZH6.js → control-queries-B9K-wmcB.js} +2 -2
- package/dist/core/web/public/next/assets/{control-queries-CXtmZZH6.js.map → control-queries-B9K-wmcB.js.map} +1 -1
- package/dist/core/web/public/next/assets/{copy-setup-BIp0iaiZ.js → copy-setup-XMgCC5f8.js} +2 -2
- package/dist/core/web/public/next/assets/{copy-setup-BIp0iaiZ.js.map → copy-setup-XMgCC5f8.js.map} +1 -1
- package/dist/core/web/public/next/assets/{dock-icons-Cc43W7r4.js → dock-icons-BJ6ZqB2t.js} +2 -2
- package/dist/core/web/public/next/assets/{dock-icons-Cc43W7r4.js.map → dock-icons-BJ6ZqB2t.js.map} +1 -1
- package/dist/core/web/public/next/assets/{fleet-model-DOK8ZtEt.js → fleet-model-BvDR3gjp.js} +2 -2
- package/dist/core/web/public/next/assets/{fleet-model-DOK8ZtEt.js.map → fleet-model-BvDR3gjp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{fleet-queries-BeEAqD6y.js → fleet-queries-W2UFVMZJ.js} +2 -2
- package/dist/core/web/public/next/assets/{fleet-queries-BeEAqD6y.js.map → fleet-queries-W2UFVMZJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{focus-trap-ChZ5EFfM.js → focus-trap-CtI1SlMX.js} +2 -2
- package/dist/core/web/public/next/assets/{focus-trap-ChZ5EFfM.js.map → focus-trap-CtI1SlMX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{format-BmH2yWL6.js → format-CH4g_sl1.js} +2 -2
- package/dist/core/web/public/next/assets/{format-BmH2yWL6.js.map → format-CH4g_sl1.js.map} +1 -1
- package/dist/core/web/public/next/assets/{format-DKrNjdwD.js → format-D7nBg2bn.js} +2 -2
- package/dist/core/web/public/next/assets/{format-DKrNjdwD.js.map → format-D7nBg2bn.js.map} +1 -1
- package/dist/core/web/public/next/assets/{git-model-BFwAVbxF.js → git-model-Dnkd1TnK.js} +2 -2
- package/dist/core/web/public/next/assets/{git-model-BFwAVbxF.js.map → git-model-Dnkd1TnK.js.map} +1 -1
- package/dist/core/web/public/next/assets/global-CMNW_dqn.js +2 -0
- package/dist/core/web/public/next/assets/{global-y_exIyAP.js.map → global-CMNW_dqn.js.map} +1 -1
- package/dist/core/web/public/next/assets/guarded-runners-YeAc9wLQ.js +2 -0
- package/dist/core/web/public/next/assets/{guarded-runners-Cd4POBtI.js.map → guarded-runners-YeAc9wLQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{icons-CygCEFWs.js → icons-D1sYbCTQ.js} +2 -2
- package/dist/core/web/public/next/assets/{icons-CygCEFWs.js.map → icons-D1sYbCTQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{index-CyK31YRm.js → index-DZ-UQ7v8.js} +3 -3
- package/dist/core/web/public/next/assets/{index-CyK31YRm.js.map → index-DZ-UQ7v8.js.map} +1 -1
- package/dist/core/web/public/next/assets/leader-focus-BjeJv7CW.js +2 -0
- package/dist/core/web/public/next/assets/leader-focus-BjeJv7CW.js.map +1 -0
- package/dist/core/web/public/next/assets/leader-thread-types-CDb-VPPO.js +2 -0
- package/dist/core/web/public/next/assets/leader-thread-types-CDb-VPPO.js.map +1 -0
- package/dist/core/web/public/next/assets/{live-model-D7hilYFk.js → live-model-D_32RAOR.js} +2 -2
- package/dist/core/web/public/next/assets/{live-model-D7hilYFk.js.map → live-model-D_32RAOR.js.map} +1 -1
- package/dist/core/web/public/next/assets/{mind.module-B15k0Y9q.js → mind.module-7hA92hRg.js} +2 -2
- package/dist/core/web/public/next/assets/{mind.module-B15k0Y9q.js.map → mind.module-7hA92hRg.js.map} +1 -1
- package/dist/core/web/public/next/assets/mutations-DQPbFdRJ.js +2 -0
- package/dist/core/web/public/next/assets/{mutations-CWlxEMEm.js.map → mutations-DQPbFdRJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{nav-mimleI0R.js → nav-0dOYe2rJ.js} +2 -2
- package/dist/core/web/public/next/assets/{nav-mimleI0R.js.map → nav-0dOYe2rJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{overnight-queries-DJ4mZKSj.js → overnight-queries-C4wOnFtE.js} +2 -2
- package/dist/core/web/public/next/assets/{overnight-queries-DJ4mZKSj.js.map → overnight-queries-C4wOnFtE.js.map} +1 -1
- package/dist/core/web/public/next/assets/primitives-2A5Eq8FQ.js +1 -0
- package/dist/core/web/public/next/assets/{queries-Bw1McHTj.js → queries-BTXWdZzU.js} +2 -2
- package/dist/core/web/public/next/assets/{queries-Bw1McHTj.js.map → queries-BTXWdZzU.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reasoning-pref-KkhI_5-j.js → reasoning-pref-Ca6lN6x_.js} +2 -2
- package/dist/core/web/public/next/assets/{reasoning-pref-KkhI_5-j.js.map → reasoning-pref-Ca6lN6x_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reveal-anchor-CCCx_kfT.js → reveal-anchor-DfNLgK_I.js} +2 -2
- package/dist/core/web/public/next/assets/{reveal-anchor-CCCx_kfT.js.map → reveal-anchor-DfNLgK_I.js.map} +1 -1
- package/dist/core/web/public/next/assets/seat-subscription-C5uPHBsN.js +2 -0
- package/dist/core/web/public/next/assets/{seat-subscription-BhUUz7VL.js.map → seat-subscription-C5uPHBsN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{sidebar-model-Dcd437cf.js → sidebar-model-CLCdqwkR.js} +2 -2
- package/dist/core/web/public/next/assets/{sidebar-model-Dcd437cf.js.map → sidebar-model-CLCdqwkR.js.map} +1 -1
- package/dist/core/web/public/next/assets/{slots-BL_J5mmV.js → slots-C-qBeu-8.js} +3 -3
- package/dist/core/web/public/next/assets/{slots-BL_J5mmV.js.map → slots-C-qBeu-8.js.map} +1 -1
- package/dist/core/web/public/next/assets/{surface-data-C3UAQ4QX.js → surface-data-Dj71tdD-.js} +2 -2
- package/dist/core/web/public/next/assets/{surface-data-C3UAQ4QX.js.map → surface-data-Dj71tdD-.js.map} +1 -1
- package/dist/core/web/public/next/assets/surface-prefetch-B0WdJOJG.js +2 -0
- package/dist/core/web/public/next/assets/surface-prefetch-B0WdJOJG.js.map +1 -0
- package/dist/core/web/public/next/assets/{tasks-model-CzHvclVm.js → tasks-model-O8yR5YXp.js} +2 -2
- package/dist/core/web/public/next/assets/{tasks-model-CzHvclVm.js.map → tasks-model-O8yR5YXp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{terminal-icons-BwgQTQP0.js → terminal-icons-CoRZq9iO.js} +2 -2
- package/dist/core/web/public/next/assets/{terminal-icons-BwgQTQP0.js.map → terminal-icons-CoRZq9iO.js.map} +1 -1
- package/dist/core/web/public/next/assets/thread-data-DQB_g66d.js +2 -0
- package/dist/core/web/public/next/assets/thread-data-DQB_g66d.js.map +1 -0
- package/dist/core/web/public/next/assets/{usage-queries-pXxvy54x.js → usage-queries-AdjEyEtn.js} +2 -2
- package/dist/core/web/public/next/assets/{usage-queries-pXxvy54x.js.map → usage-queries-AdjEyEtn.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-guarded-action-EgVWjM5c.js → use-guarded-action-CuuMHeDX.js} +2 -2
- package/dist/core/web/public/next/assets/{use-guarded-action-EgVWjM5c.js.map → use-guarded-action-CuuMHeDX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-ticker-BoqFxRFG.js → use-ticker-BBcp02SZ.js} +2 -2
- package/dist/core/web/public/next/assets/{use-ticker-BoqFxRFG.js.map → use-ticker-BBcp02SZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-token-gate-DSNIIpI6.js → use-token-gate-CbXVYQYI.js} +2 -2
- package/dist/core/web/public/next/assets/{use-token-gate-DSNIIpI6.js.map → use-token-gate-CbXVYQYI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useOnboarding-Bk0VnkxQ.js → useOnboarding-C_Fpe_sH.js} +2 -2
- package/dist/core/web/public/next/assets/{useOnboarding-Bk0VnkxQ.js.map → useOnboarding-C_Fpe_sH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useSeatsRefresh-q7Id9RcW.js → useSeatsRefresh-Co1CnxLc.js} +2 -2
- package/dist/core/web/public/next/assets/{useSeatsRefresh-q7Id9RcW.js.map → useSeatsRefresh-Co1CnxLc.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useVerseTranscript-CqH51rt9.js → useVerseTranscript-DgbigUlV.js} +2 -2
- package/dist/core/web/public/next/assets/{useVerseTranscript-CqH51rt9.js.map → useVerseTranscript-DgbigUlV.js.map} +1 -1
- package/dist/core/web/public/next/assets/{verse-icons-DsG1dOQx.js → verse-icons-S56hIiXS.js} +2 -2
- package/dist/core/web/public/next/assets/{verse-icons-DsG1dOQx.js.map → verse-icons-S56hIiXS.js.map} +1 -1
- package/dist/core/web/public/next/assets/verse-model-DAVevkNe.js +2 -0
- package/dist/core/web/public/next/assets/{verse-model-JTuvRBVK.js.map → verse-model-DAVevkNe.js.map} +1 -1
- package/dist/core/web/public/next/assets/{warmup-Bv1RumVq.js → warmup-B_RAtNZ_.js} +3 -3
- package/dist/core/web/public/next/assets/{warmup-Bv1RumVq.js.map → warmup-B_RAtNZ_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{why-seat-model-Cau8qG6O.js → why-seat-model-M_r0wX3b.js} +2 -2
- package/dist/core/web/public/next/assets/{why-seat-model-Cau8qG6O.js.map → why-seat-model-M_r0wX3b.js.map} +1 -1
- package/dist/core/web/public/next/assets/{workspace-model-D-SLfads.js → workspace-model-dji5-Al3.js} +2 -2
- package/dist/core/web/public/next/assets/{workspace-model-D-SLfads.js.map → workspace-model-dji5-Al3.js.map} +1 -1
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/core/web/read-projection-worker.js +2 -1
- package/dist/core/web/read-projection-worker.js.map +1 -1
- package/dist/core/web/read-projections.d.ts +3 -0
- package/dist/core/web/read-projections.js +2 -2
- package/dist/core/web/read-projections.js.map +1 -1
- package/dist/core/web/visibility.js +3 -4
- package/dist/core/web/visibility.js.map +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/package.json +3 -2
- package/dist/core/web/public/next/assets/Advanced-cVYTAsfB.js +0 -2
- package/dist/core/web/public/next/assets/AppsSection-DDqeSrty.js +0 -2
- package/dist/core/web/public/next/assets/AreaTrend-C32rUaxm.js +0 -2
- package/dist/core/web/public/next/assets/AreaTrend-C32rUaxm.js.map +0 -1
- package/dist/core/web/public/next/assets/AutonomySection-Dwn8UtOy.js +0 -2
- package/dist/core/web/public/next/assets/ChartFrame-BVuBe6RP.css +0 -1
- package/dist/core/web/public/next/assets/ChartFrame-DK_BDXCt.js +0 -2
- package/dist/core/web/public/next/assets/ChartFrame-DK_BDXCt.js.map +0 -1
- package/dist/core/web/public/next/assets/ChatSection-C9myY4ei.js +0 -3
- package/dist/core/web/public/next/assets/CommandPalette-DzPsth0u.js +0 -2
- package/dist/core/web/public/next/assets/CommandPalette-DzPsth0u.js.map +0 -1
- package/dist/core/web/public/next/assets/CommandSection-Brp73iox.js +0 -3
- package/dist/core/web/public/next/assets/CommandSection-Brp73iox.js.map +0 -1
- package/dist/core/web/public/next/assets/CommandSection-CvAVd1w4.css +0 -1
- package/dist/core/web/public/next/assets/DockHost-BcEq2qaS.js +0 -2
- package/dist/core/web/public/next/assets/FleetSection-BG8iGraG.js +0 -3
- package/dist/core/web/public/next/assets/FleetSection-BG8iGraG.js.map +0 -1
- package/dist/core/web/public/next/assets/Funnel-B88_wpA4.js +0 -2
- package/dist/core/web/public/next/assets/Funnel-B88_wpA4.js.map +0 -1
- package/dist/core/web/public/next/assets/GrowthSection-BvZezOsX.js +0 -2
- package/dist/core/web/public/next/assets/LeaderCard-BxxiEg4e.js +0 -2
- package/dist/core/web/public/next/assets/LeaderCard-BxxiEg4e.js.map +0 -1
- package/dist/core/web/public/next/assets/MatrixHeatmap-iPFEU2Tv.js +0 -2
- package/dist/core/web/public/next/assets/MatrixHeatmap-iPFEU2Tv.js.map +0 -1
- package/dist/core/web/public/next/assets/McpSection-nuXer4K-.js +0 -2
- package/dist/core/web/public/next/assets/MindSection-Dc5v5rH3.js +0 -2
- package/dist/core/web/public/next/assets/MindSection-Dc5v5rH3.js.map +0 -1
- package/dist/core/web/public/next/assets/NeedsYouDrawer-N1cWJjpz.js +0 -3
- package/dist/core/web/public/next/assets/NeedsYouDrawer-N1cWJjpz.js.map +0 -1
- package/dist/core/web/public/next/assets/NewChatDialog-BqFTWgHU.js +0 -3
- package/dist/core/web/public/next/assets/OnboardingGate-BZafM1Vf.js +0 -3
- package/dist/core/web/public/next/assets/PreviewPane-zT3gK9TD.js +0 -2
- package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-CAxPQ4sZ.js +0 -7
- package/dist/core/web/public/next/assets/ResourcesChrome-BnhnEdJe.js +0 -3
- package/dist/core/web/public/next/assets/ResourcesChrome-BnhnEdJe.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcesDrawer-BAFGodny.js +0 -2
- package/dist/core/web/public/next/assets/ResourcesDrawer-BAFGodny.js.map +0 -1
- package/dist/core/web/public/next/assets/ResourcesDrawer-BCFJ2Uq8.css +0 -1
- package/dist/core/web/public/next/assets/SettingsSection-Bf74l0Gj.js.map +0 -1
- package/dist/core/web/public/next/assets/Sidebar-C9YtBYVZ.js +0 -3
- package/dist/core/web/public/next/assets/StatTile-BuLMsJMx.css +0 -1
- package/dist/core/web/public/next/assets/StatTile-CTX41O6y.js +0 -2
- package/dist/core/web/public/next/assets/StatTile-CTX41O6y.js.map +0 -1
- package/dist/core/web/public/next/assets/StepBand-jJTqYIdX.js +0 -2
- package/dist/core/web/public/next/assets/StepBand-jJTqYIdX.js.map +0 -1
- package/dist/core/web/public/next/assets/Swimlane-LrslsGxw.js +0 -2
- package/dist/core/web/public/next/assets/Swimlane-LrslsGxw.js.map +0 -1
- package/dist/core/web/public/next/assets/Swimlane-o6_Zsrnr.css +0 -1
- package/dist/core/web/public/next/assets/UniverseConsoleApp-BpphLqoz.js +0 -2
- package/dist/core/web/public/next/assets/UsageSection-CUlaKtws.js +0 -3
- package/dist/core/web/public/next/assets/UsageSection-CUlaKtws.js.map +0 -1
- package/dist/core/web/public/next/assets/VerseConsoleApp-DXDv1aOi.js +0 -3
- package/dist/core/web/public/next/assets/VerseConsoleApp-DXDv1aOi.js.map +0 -1
- package/dist/core/web/public/next/assets/Workspace-RXy0pqp6.js +0 -10
- package/dist/core/web/public/next/assets/actions-BZTidCXZ.js +0 -2
- package/dist/core/web/public/next/assets/actions-BmIf9avl.css +0 -1
- package/dist/core/web/public/next/assets/budget-queries-DFF-3ICg.js +0 -2
- package/dist/core/web/public/next/assets/charts-CzxWrZn7.js +0 -2
- package/dist/core/web/public/next/assets/charts-CzxWrZn7.js.map +0 -1
- package/dist/core/web/public/next/assets/charts-DhKTrQLw.css +0 -1
- package/dist/core/web/public/next/assets/command-catalog-ffCAijVY.js.map +0 -1
- package/dist/core/web/public/next/assets/context-queries-_9bFWb9v.js +0 -2
- package/dist/core/web/public/next/assets/global-y_exIyAP.js +0 -2
- package/dist/core/web/public/next/assets/guarded-runners-Cd4POBtI.js +0 -2
- package/dist/core/web/public/next/assets/mutations-CWlxEMEm.js +0 -2
- package/dist/core/web/public/next/assets/primitives-DMijqcu0.js +0 -1
- package/dist/core/web/public/next/assets/seat-subscription-BhUUz7VL.js +0 -2
- package/dist/core/web/public/next/assets/surface-prefetch-BXKjPsV5.js +0 -2
- package/dist/core/web/public/next/assets/surface-prefetch-BXKjPsV5.js.map +0 -1
- package/dist/core/web/public/next/assets/verse-model-JTuvRBVK.js +0 -2
package/dist/core/web/public/next/assets/{ChatSection-C9myY4ei.js.map → ChatSection-DlT4QU6a.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../../../../src/web-ui/routes/verse/chat/composer-bridge.ts","../../../../../../src/web-ui/routes/verse/chat/use-session-roots.ts","../../../../../../src/web-ui/routes/verse/chat/transcript-jump.ts","../../../../../../src/web-ui/routes/verse/verse-events.ts","../../../../../../src/web-ui/routes/verse/session-stream.ts","../../../../../../src/web-ui/routes/verse/useVerseSession.ts","../../../../../../src/web-ui/routes/verse/chat/use-chat-activity.ts","../../../../../../src/web-ui/routes/verse/chat-panel-sizing.ts","../../../../../../src/web-ui/routes/verse/ChatResizer.tsx","../../../../../../src/web-ui/routes/verse/sections/ChatSection.tsx"],"sourcesContent":["/**\n * routes/verse/chat/composer-bridge.ts — how the chat's other surfaces put\n * text INTO the composer without sending it (unit C2).\n *\n * Three dock actions draft into the message box and leave the send to the\n * operator (the first spend is always their press):\n * - Terminal ▸ \"Send selection to chat\" — the selection as a fenced block;\n * - Review ▸ \"Add to message\" — `path:line: note`;\n * - anything later that \"drafts a follow-up\".\n *\n * The composer is C3's component and owns its text state. The clean seam is\n * for it to register an inserter here (`registerComposerInserter`) — that is\n * a cross-unit request. Until it does, the fallback types into the composer's\n * textarea the way a paste would: the native value setter plus an `input`\n * event, which React's controlled textarea treats as the operator's own\n * edit (so its draft persistence, cost hint and undo stack all see it).\n * Either way the text is APPENDED on its own paragraph and never sent.\n */\n\nexport type ComposerInserter = (text: string) => void;\n\nconst inserters = new Map<string, ComposerInserter>();\n\n/** C3: `useEffect(() => registerComposerInserter(sessionId, insert), [sessionId])`. Returns the unregister. */\nexport function registerComposerInserter(sessionId: string, insert: ComposerInserter): () => void {\n inserters.set(sessionId, insert);\n return () => {\n if (inserters.get(sessionId) === insert) inserters.delete(sessionId);\n };\n}\n\n/** Join an insertion onto existing text: its own paragraph, never glued to a half-typed word. */\nexport function appendParagraph(current: string, text: string): string {\n const addition = text.replace(/\\s+$/, '');\n if (!current.trim()) return addition;\n return `${current.replace(/\\s+$/, '')}\\n\\n${addition}`;\n}\n\n/** The composer's message box in the chat surface (C3's `aria-label=\"Message\"`). */\nfunction findComposerBox(root: ParentNode = document): HTMLTextAreaElement | null {\n const node = root.querySelector('textarea[aria-label=\"Message\"]');\n return node instanceof HTMLTextAreaElement ? node : null;\n}\n\n/**\n * Append `text` to `sessionId`'s composer and focus it. False when there is\n * no composer to write into (no chat open, or it is disabled) — the caller\n * then says so rather than dropping the text silently.\n */\nexport function insertIntoComposer(sessionId: string, text: string): boolean {\n if (!text.trim()) return false;\n const registered = inserters.get(sessionId);\n if (registered) {\n registered(text);\n return true;\n }\n const box = findComposerBox();\n if (!box || box.disabled) return false;\n const next = appendParagraph(box.value, text);\n const setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value')?.set;\n if (setter) setter.call(box, next);\n else box.value = next;\n box.dispatchEvent(new Event('input', { bubbles: true }));\n box.focus();\n const end = box.value.length;\n try {\n box.setSelectionRange(end, end);\n } catch {\n /* a detached or hidden box has no selection; the text is in either way */\n }\n return true;\n}\n","/**\n * routes/verse/chat/use-session-roots.ts — one read of a chat's roots for\n * everything that needs them (unit C2): the header's `repo › branch`\n * breadcrumb, the Context pane's Folders list, and the roots handed to the\n * Branch bar, Terminal, Preview and Review slots.\n *\n * Before 3.10 only SessionRoots read `/sessions/:id/roots`, fetching on its\n * own. With four consumers that would be four requests per chat switch (each\n * one `git status` per root on the server), so the read goes through the\n * shared query cache under one key per chat. A branch goes stale the moment\n * a turn commits, so the read is refreshed whenever the chat's turnCount\n * moves — exactly as SessionRoots' `refreshKey` did.\n */\nimport { useEffect, useMemo, useRef } from 'react';\nimport type { VerseSession, VerseSessionRootsResponse } from '../../../data/api-types.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport type { QueryDef } from '../../../data/queries.js';\nimport { fetchVerseSessionRoots } from '../verse-queries.js';\n\nexport function sessionRootsKey(sessionId: string): string {\n return `verse-session-roots:${sessionId}`;\n}\n\nconst NO_SESSION: QueryDef<VerseSessionRootsResponse | null> = {\n key: 'verse-session-roots:none',\n fetch: async () => null,\n};\n\nexport interface SessionRootsView {\n data: VerseSessionRootsResponse | null;\n error: string | null;\n /** Roots in priority order: the primary first, then the pinned extras. Known before the read lands. */\n roots: readonly string[];\n /** The primary root's branch, when it is a git repo and the read landed. */\n branch: string | null;\n}\n\n/** Roots as the session RECORD states them — usable before (and without) the status read. */\nexport function recordRoots(session: Pick<VerseSession, 'projectPath' | 'extraRoots'> | null): string[] {\n if (!session) return [];\n return [session.projectPath, ...(session.extraRoots ?? []).filter((r) => r !== session.projectPath)];\n}\n\nexport function useSessionRoots(session: Pick<VerseSession, 'id' | 'projectPath' | 'extraRoots' | 'turnCount'> | null): SessionRootsView {\n const sessionId = session?.id ?? null;\n const def = useMemo<QueryDef<VerseSessionRootsResponse | null>>(\n () => (sessionId\n ? { key: sessionRootsKey(sessionId), fetch: (signal) => fetchVerseSessionRoots(sessionId, signal) }\n : NO_SESSION),\n [sessionId],\n );\n const query = useQuery(def);\n const refetch = useRefetch(def);\n\n // A finished turn may have committed or switched branch: re-read. The\n // first value for a chat is the mount's own fetch, not a change.\n const turnCount = session?.turnCount ?? 0;\n const seen = useRef<{ id: string | null; turns: number }>({ id: sessionId, turns: turnCount });\n useEffect(() => {\n const prev = seen.current;\n seen.current = { id: sessionId, turns: turnCount };\n if (prev.id === sessionId && prev.turns !== turnCount && sessionId) refetch();\n }, [sessionId, turnCount, refetch]);\n\n // A reply without a roots list (an older server, a stub) is treated as no\n // reading at all rather than trusted into a crash.\n const raw = query.data ?? null;\n const data = raw !== null && Array.isArray(raw.roots) ? raw : null;\n const fromRecord = useMemo(() => recordRoots(session), [session?.projectPath, session?.extraRoots]); // eslint-disable-line react-hooks/exhaustive-deps -- the two fields ARE the dependency\n const roots = useMemo(() => {\n if (!data || data.roots.length === 0) return fromRecord;\n const primary = data.roots.filter((r) => r.primary).map((r) => r.path);\n const rest = data.roots.filter((r) => !r.primary).map((r) => r.path);\n return [...primary, ...rest];\n }, [data, fromRecord]);\n const primary = data?.roots.find((r) => r.primary) ?? data?.roots[0] ?? null;\n return {\n data,\n error: query.status === 'error' ? query.error?.message ?? 'could not read this chat’s folders' : null,\n roots,\n branch: primary?.git?.branch ?? null,\n };\n}\n","/**\n * routes/verse/chat/transcript-jump.ts — \"scroll the open transcript to this\n * tool call\", from outside the transcript (unit C2).\n *\n * The dock's Tasks pane lists this turn's calls and a click must land on\n * the call in the transcript — but the pane is a different subtree (and, as\n * a sheet, a different layer). The mounted Transcript subscribes here and\n * performs the jump with its own machinery (opening a folded activity group,\n * the locator flash, focus). A tiny module, so the dock does not import the\n * transcript.\n */\ntype JumpListener = (anchorId: string) => boolean;\n\nconst listeners = new Set<JumpListener>();\n\nexport function onTranscriptJump(listener: JumpListener): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\n/** True when a mounted transcript took the jump. */\nexport function requestTranscriptJump(anchorId: string): boolean {\n let handled = false;\n for (const listener of [...listeners]) if (listener(anchorId)) handled = true;\n return handled;\n}\n\n// ⌘F from the palette (\"Find in chat\"): focus the transcript's own search.\nconst findListeners = new Set<() => boolean>();\n\nexport function onTranscriptFind(listener: () => boolean): () => void {\n findListeners.add(listener);\n return () => findListeners.delete(listener);\n}\n\nexport function requestTranscriptFind(): boolean {\n let handled = false;\n for (const listener of [...findListeners]) if (listener()) handled = true;\n return handled;\n}\n\n// ⌥↑ / ⌥↓ routed through the command bus (palette, native menu).\nconst stepListeners = new Set<(delta: 1 | -1) => boolean>();\n\nexport function onTranscriptStep(listener: (delta: 1 | -1) => boolean): () => void {\n stepListeners.add(listener);\n return () => stepListeners.delete(listener);\n}\n\nexport function requestTranscriptStep(delta: 1 | -1): boolean {\n let handled = false;\n for (const listener of [...stepListeners]) if (listener(delta)) handled = true;\n return handled;\n}\n","/**\n * routes/verse/verse-events.ts — the Verse console's SSE vocabulary and its\n * sidebar channel, since scoped consoles never join data/sse.ts's global feed:\n *\n * - VERSE_EVENT_TYPES + parseVerseEventFrame: every VerseEvent name a\n * session stream can carry, and the frame validation both streams share.\n * The per-session stream itself (resume by `?after=`, one store update\n * per animation frame, ref-counted connections) lives in\n * session-stream.ts (V3.10); the replay-from-zero opener that used to sit\n * here had no callers left and was removed.\n * - openVerseListChannel: one EventSource against /api/events for the\n * `verse-sessions` list digest, which just invalidates the sidebar's\n * cache keys. It subscribes with `?topics=verse-sessions` (V3.10) so the\n * server skips the dashboard snapshot and the other groups this console\n * would only discard.\n *\n * Every URL carries the per-tab client proof as `?client=` — the same\n * construction data/client.ts's eventsUrl() uses, because EventSource cannot\n * send the proof as a header (see read-session.ts readSessionClientProof).\n */\nimport type { VerseEvent, VerseEventType } from '../../data/api-types.js';\nimport { getAuthSnapshot, getReadClientProof } from '../../data/auth-store.js';\nimport { invalidateVerseLists } from './verse-queries.js';\n\n/**\n * Every VerseEvent name the stream can carry. EventSource only dispatches\n * NAMED events to listeners registered by name, so a type missing here is\n * silently dropped — the check below turns a new union member into a compile\n * error in this file instead of a meter that never moves.\n */\nconst EVENT_TYPES = [\n 'user-message',\n 'turn-started',\n 'text-delta',\n 'assistant-message',\n 'thinking',\n 'tool-use',\n 'tool-result',\n 'usage',\n 'turn-done',\n 'error',\n 'cancelled',\n // V3.9 — a server that predates them simply never sends these names.\n 'compaction',\n 'context',\n // V3.10 transient (SSE only, never replayed — see VERSE_TRANSIENT_EVENT_TYPES\n // in core/verse/types.ts). They carry the last PERSISTED seq, so a store that\n // dedupes by seq and does not know them yet simply drops them.\n 'thinking-delta',\n 'thinking-progress',\n 'progress',\n 'status',\n // V3.10 persisted.\n 'recovered',\n 'history-truncated',\n] as const satisfies readonly VerseEventType[];\n\ntype UnlistedEventType = Exclude<VerseEventType, (typeof EVENT_TYPES)[number]>;\n// Fails to compile when VerseEventType gains a member EVENT_TYPES does not list.\nconst EVENT_TYPES_EXHAUSTIVE: [UnlistedEventType] extends [never] ? true : never = true;\nvoid EVENT_TYPES_EXHAUSTIVE;\n\nexport const VERSE_EVENT_TYPES: readonly VerseEventType[] = EVENT_TYPES;\n\nfunction backoffMs(attempt: number): number {\n return Math.min(1000 * 2 ** attempt, 15_000);\n}\n\nconst nullableCount = (v: unknown): boolean => v === null || (typeof v === 'number' && Number.isFinite(v) && v >= 0);\n\n/**\n * The two V3.9 frames feed arithmetic (the meter, the compaction count), so a\n * malformed one is dropped here rather than turning the meter into `NaN`.\n * Older event types keep the original seq/type-only check.\n */\nfunction v39FieldsValid(e: Record<string, unknown>): boolean {\n if (e.type === 'context') {\n return typeof e.contextTokens === 'number' && Number.isFinite(e.contextTokens) && e.contextTokens >= 0 &&\n typeof e.exact === 'boolean' && nullableCount(e.contextWindow) &&\n (e.autoCompactAt === undefined || nullableCount(e.autoCompactAt));\n }\n if (e.type === 'compaction') {\n return (e.trigger === 'auto' || e.trigger === 'manual') &&\n nullableCount(e.preTokens) && nullableCount(e.postTokens) && nullableCount(e.durationMs);\n }\n return true;\n}\n\nconst optionalCount = (v: unknown): boolean => v === undefined || (typeof v === 'number' && Number.isFinite(v) && v >= 0);\n\n/**\n * V3.10 frames that feed arithmetic or a live label (elapsed, tok/s, token\n * estimate) — same rule as v39FieldsValid: malformed → dropped, never NaN.\n */\nfunction v310FieldsValid(e: Record<string, unknown>): boolean {\n switch (e.type) {\n case 'thinking-delta':\n return typeof e.text === 'string';\n case 'thinking-progress':\n return e.estimatedTokens !== undefined && optionalCount(e.estimatedTokens);\n case 'progress':\n return (e.phase === 'thinking' || e.phase === 'tool' || e.phase === 'writing' || e.phase === 'waiting') &&\n typeof e.elapsedMs === 'number' && Number.isFinite(e.elapsedMs) && e.elapsedMs >= 0 &&\n (e.tool === undefined || typeof e.tool === 'string') &&\n optionalCount(e.outTokens) && optionalCount(e.tokPerSec);\n case 'status':\n return (e.kind === 'retry' || e.kind === 'preflight' || e.kind === 'watchdog') && typeof e.message === 'string';\n case 'history-truncated':\n return typeof e.droppedBefore === 'number' && Number.isFinite(e.droppedBefore);\n default:\n return true;\n }\n}\n\n/** Exported for tests: one SSE frame's data → a VerseEvent, or null when malformed. */\nexport function parseVerseEventFrame(raw: string): VerseEvent | null {\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== 'object') return null;\n const candidate = parsed as Partial<VerseEvent>;\n if (typeof candidate.seq !== 'number' || typeof candidate.type !== 'string') return null;\n if (!v39FieldsValid(parsed as Record<string, unknown>)) return null;\n if (!v310FieldsValid(parsed as Record<string, unknown>)) return null;\n return parsed as VerseEvent;\n } catch {\n return null;\n }\n}\n\n/** The only /api/events group the Verse console listens to. */\nexport const VERSE_LIST_TOPICS = 'verse-sessions';\n\n/**\n * The sidebar channel's URL. `topics` narrows the server to the one group\n * this console listens to; `client` stays last, as in eventsUrl(). Without\n * `topics` the server sends every group — the historical request, which is\n * also what the refusal fallback below falls back to.\n */\nexport function verseListEventsUrl(withTopics = true): string {\n const topics = withTopics ? `topics=${VERSE_LIST_TOPICS}&` : '';\n return `/api/events?${topics}client=${encodeURIComponent(getReadClientProof())}`;\n}\n\n/**\n * Set once this page has PROVEN that the server refuses `?topics=`: a\n * connection with it failed before it ever opened, and the same channel\n * without it then opened. The read-session boundary on SSE paths used to\n * answer 401 to any parameter besides `client`, and a sidebar that never\n * updates is far worse than one that is sent (and discards) extra groups.\n * Page-lifetime only — the same rule session-stream.ts applies to `?after=`:\n * a server that gains support is used again after a reload.\n */\nlet topicsRefused = false;\n\n/** Tests: forget a proven refusal. */\nexport function resetVerseListChannelCapabilities(): void {\n topicsRefused = false;\n}\n\n/**\n * Sidebar digest channel: listens only for `verse-sessions` on /api/events\n * and refreshes the session list + bootstrap when it fires.\n */\nexport function openVerseListChannel(): () => void {\n let source: EventSource | null = null;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let attempt = 0;\n let disposed = false;\n /** This connection is the no-`topics` retry that tests whether `topics` was refused. */\n let probing = false;\n\n const connect = () => {\n if (disposed || typeof EventSource === 'undefined') return;\n if (getAuthSnapshot().phase !== 'authenticated') return;\n const withTopics = !topicsRefused && !probing;\n const es = new EventSource(verseListEventsUrl(withTopics), { withCredentials: true });\n let opened = false;\n source = es;\n es.onopen = () => {\n opened = true;\n attempt = 0;\n if (probing) {\n topicsRefused = true;\n probing = false;\n }\n };\n es.addEventListener('verse-sessions', () => invalidateVerseLists());\n es.onerror = () => {\n es.close();\n if (source === es) source = null;\n if (disposed || getAuthSnapshot().phase !== 'authenticated') return;\n if (!opened && withTopics) {\n // Refused before it opened, with `topics`: find out at once whether\n // the parameter is what was refused (see topicsRefused). One probe,\n // no delay — a real outage fails the probe too and falls through to\n // the ordinary backoff below.\n probing = true;\n connect();\n return;\n }\n probing = false;\n timer = setTimeout(() => {\n timer = null;\n attempt += 1;\n connect();\n }, backoffMs(attempt));\n };\n };\n\n connect();\n\n return () => {\n disposed = true;\n if (timer) clearTimeout(timer);\n timer = null;\n source?.close();\n source = null;\n };\n}\n","/**\n * routes/verse/session-stream.ts — the client data path for ONE open chat\n * (V3.10): load it once, resume its live stream from where the store left\n * off, batch what streams in to one store update per animation frame, and\n * keep the connection across section switches.\n *\n * WHY THIS EXISTS (measured before 3.10, scratchpad perf/):\n * - opening a chat raced a full detail fetch against an EventSource that\n * replayed the whole log from seq 0, and every replayed frame was applied\n * and rendered on its own — 2.45 s for a 5k-event chat, 17 s for 10k;\n * - every reconnect (at least one per 15-minute read session) replayed the\n * whole log again, because a hand-made EventSource sends no Last-Event-ID;\n * - every replayed `turn-done` refetched the session list and bootstrap;\n * - leaving the Chat section closed the stream, so coming back replayed.\n *\n * THE PATH NOW\n * 1. `openVerseSession(id)` fetches the detail ONCE when the store has not\n * loaded the chat, seeds the store, and only then attaches the stream —\n * so the two never race.\n * 2. The stream URL carries `?after=<lastSeq>` (the highest PERSISTED seq\n * the store holds). The server replays only what is newer; a server that\n * predates `after` replays everything and the store's seq dedupe drops\n * it. A server whose auth boundary REFUSES the extra parameter is\n * detected once and served without it (afterRefused). A dropped\n * connection is left to the browser's own reconnect, which resumes by\n * Last-Event-ID.\n * 3. Frames are queued and applied with ONE `applyVerseEvents` call per\n * animation frame (a timer backs rAF up, since a hidden tab gets none).\n * Transient frames (reasoning deltas, progress) ride the same queue in\n * arrival order.\n * 4. The session list is invalidated only when a batch really settled a\n * turn — never for a replayed duplicate.\n * 5. Streams are ref-counted. When the last user lets go (section switch,\n * another chat selected) the connection lingers for IDLE_CLOSE_MS so\n * switching back is instant and costs no replay; at most MAX_IDLE\n * lingering connections are kept, because they share the server's SSE\n * connection cap with /api/events.\n *\n * Auth: every URL carries the per-tab client proof as `?client=` (EventSource\n * cannot send it as a header — see server.ts readSessionClientProof), and a\n * stream never reconnects once the read session is gone.\n */\nimport type { VerseEvent } from '../../data/api-types.js';\nimport { getAuthSnapshot, getReadClientProof } from '../../data/auth-store.js';\nimport { parseVerseEventFrame, VERSE_EVENT_TYPES } from './verse-events.js';\nimport { fetchVerseSessionDetail, invalidateVerseLists, verseSessionPath } from './verse-queries.js';\nimport {\n applyVerseEvents,\n getVerseSessionState,\n seedVerseSession,\n setVerseLoadError,\n setVerseStreamState,\n subscribeVerseStoreLifecycle,\n} from './verse-store.js';\n\n/** How long a released stream stays connected before it is closed. */\nexport const IDLE_CLOSE_MS = 90_000;\n/** Released-but-lingering streams kept at once (they count against the server's SSE cap). */\nexport const MAX_IDLE_STREAMS = 1;\n/** Fallback flush when requestAnimationFrame does not fire (hidden tab, occluded window). */\nconst FRAME_FALLBACK_MS = 250;\n\n/**\n * Per-session stream URL: `?after=<cursor>&client=<proof>`. `after` is\n * omitted for cursor 0 — seqs start at 1, so \"after 0\" and \"from the start\"\n * are the same request, and the bare form is what a server without `after`\n * support has always seen.\n */\nexport function verseSessionStreamUrl(sessionId: string, after: number): string {\n const cursor = Number.isSafeInteger(after) && after > 0 ? `after=${after}&` : '';\n return `${verseSessionPath(sessionId, '/events')}?${cursor}client=${encodeURIComponent(getReadClientProof())}`;\n}\n\nfunction backoffMs(attempt: number): number {\n return Math.min(1000 * 2 ** attempt, 15_000);\n}\n\n// ---------------------------------------------------------------------------\n// Frame scheduling\n// ---------------------------------------------------------------------------\n\ntype FrameScheduler = (flush: () => void) => () => void;\n\n/**\n * True inside a React `act()` test environment. There, `act()` is the test\n * declaring \"everything this block causes must be visible after it\", and a\n * frame-deferred flush would land after the assertions — so frames are\n * applied as they arrive, exactly as React applies its own scheduled work\n * inside act. Production never sets the flag.\n */\nfunction inActEnvironment(): boolean {\n return (globalThis as { IS_REACT_ACT_ENVIRONMENT?: unknown }).IS_REACT_ACT_ENVIRONMENT === true;\n}\n\nconst animationFrameScheduler: FrameScheduler = (flush) => {\n let done = false;\n const run = () => {\n if (done) return;\n done = true;\n if (raf !== null && typeof cancelAnimationFrame === 'function') cancelAnimationFrame(raf);\n clearTimeout(timer);\n flush();\n };\n const hidden = typeof document !== 'undefined' && document.visibilityState === 'hidden';\n const raf = !hidden && typeof requestAnimationFrame === 'function' ? requestAnimationFrame(run) : null;\n const timer = setTimeout(run, raf === null ? 0 : FRAME_FALLBACK_MS);\n return () => {\n done = true;\n if (raf !== null && typeof cancelAnimationFrame === 'function') cancelAnimationFrame(raf);\n clearTimeout(timer);\n };\n};\n\nlet customScheduler: FrameScheduler | null = null;\n\n/**\n * Tests: replace the frame scheduler (null restores the default). A scheduler\n * that never calls `flush` lets a test assert what is queued; calling it\n * later simulates the frame.\n */\nexport function setVerseFrameScheduler(scheduler: FrameScheduler | null): void {\n customScheduler = scheduler;\n}\n\nfunction scheduleFrame(flush: () => void): (() => void) | null {\n if (customScheduler) return customScheduler(flush);\n if (inActEnvironment()) {\n flush();\n return null;\n }\n return animationFrameScheduler(flush);\n}\n\n/**\n * Collects frames for one session and applies them once per frame. Returns\n * whether the flushed batch settled a turn, for the list invalidation.\n */\nclass FrameQueue {\n private queue: VerseEvent[] = [];\n private cancel: (() => void) | null = null;\n private scheduled = false;\n\n constructor(private readonly sessionId: string) {}\n\n push(event: VerseEvent): void {\n this.queue.push(event);\n if (this.scheduled) return;\n this.scheduled = true;\n const cancel = scheduleFrame(() => this.flush());\n // A synchronous scheduler (act environment) has already flushed.\n if (this.scheduled) this.cancel = cancel;\n }\n\n /** Apply everything queued now. Safe to call with nothing queued. */\n flush(): void {\n this.scheduled = false;\n this.cancel?.();\n this.cancel = null;\n if (this.queue.length === 0) return;\n const batch = this.queue;\n this.queue = [];\n const result = applyVerseEvents(this.sessionId, batch);\n if (result.settled) invalidateVerseLists();\n }\n\n drop(): void {\n this.scheduled = false;\n this.cancel?.();\n this.cancel = null;\n this.queue = [];\n }\n}\n\n// ---------------------------------------------------------------------------\n// One resumable stream\n// ---------------------------------------------------------------------------\n\ninterface LiveStream {\n close(): void;\n /** Tear down and reconnect from the current cursor (Retry). */\n restart(): void;\n}\n\n/**\n * Set once this page has PROVEN that the server refuses `?after=`: a\n * connection with the cursor closed before it opened, and the same stream\n * without it then opened. A read-session boundary that accepts only the\n * `?client=` proof on SSE paths answers 401 to any extra parameter, and a\n * chat that cannot connect at all is far worse than one that replays (the\n * store drops what it already holds). Page-lifetime only: a server that gains\n * support is used again after a reload.\n */\nlet afterRefused = false;\n\n/** Tests: forget a proven refusal. */\nexport function resetVerseStreamCapabilities(): void {\n afterRefused = false;\n}\n\n/** `EventSource.CONNECTING` — the browser is reconnecting by itself. */\nconst ES_CONNECTING = 0;\n\nfunction openResumableStream(sessionId: string): LiveStream {\n let source: EventSource | null = null;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let attempt = 0;\n let disposed = false;\n /** This connection is the no-`after` retry that tests whether the cursor was refused. */\n let probing = false;\n const queue = new FrameQueue(sessionId);\n\n const connect = () => {\n if (disposed || typeof EventSource === 'undefined') return;\n if (getAuthSnapshot().phase !== 'authenticated') return;\n setVerseStreamState(sessionId, attempt === 0 ? 'connecting' : 'reconnecting');\n // The cursor is read at CONNECT time, after everything already received\n // was applied, so a reconnect asks only for what it has not seen.\n const cursor = afterRefused || probing ? 0 : getVerseSessionState(sessionId).lastSeq;\n const es = new EventSource(verseSessionStreamUrl(sessionId, cursor), { withCredentials: true });\n let opened = false;\n source = es;\n es.onopen = () => {\n opened = true;\n attempt = 0;\n if (probing) {\n afterRefused = true;\n probing = false;\n }\n setVerseStreamState(sessionId, 'open');\n };\n for (const type of VERSE_EVENT_TYPES) {\n es.addEventListener(type, (evt) => {\n if (source !== es) return;\n const event = parseVerseEventFrame((evt as MessageEvent<string>).data);\n if (event) queue.push(event);\n });\n }\n es.onerror = (evt) => {\n // A server-sent event NAMED `error` (a VerseEvent.type) also dispatches\n // through onerror because onerror is the handler for event type \"error\".\n // It arrives as a MessageEvent with data; a real transport failure does\n // not. Without this guard every vendor error replayed on reconnect would\n // tear the stream down again, forever.\n if (typeof MessageEvent !== 'undefined' && evt instanceof MessageEvent) return;\n // Everything received before the drop moves the cursor first.\n queue.flush();\n if (disposed) return;\n // A dropped connection (network blip, server restart, the server\n // closing a congested stream) is retried by the BROWSER, which sends\n // Last-Event-ID — the last persisted seq, since transient frames carry\n // no id — so it resumes without a replay. Only a refused one (an HTTP\n // error) ends up CLOSED and is ours to retry.\n if (typeof es.readyState === 'number' && es.readyState === ES_CONNECTING) {\n setVerseStreamState(sessionId, 'reconnecting');\n return;\n }\n es.close();\n if (source === es) source = null;\n setVerseStreamState(sessionId, 'reconnecting');\n if (getAuthSnapshot().phase !== 'authenticated') return;\n if (!opened && cursor > 0 && !probing) {\n // Refused before it opened, with a cursor: find out at once whether\n // the cursor is what was refused (see afterRefused).\n probing = true;\n connect();\n return;\n }\n probing = false;\n timer = setTimeout(() => {\n timer = null;\n attempt += 1;\n connect();\n }, backoffMs(attempt));\n };\n };\n\n const teardown = () => {\n if (timer) clearTimeout(timer);\n timer = null;\n source?.close();\n source = null;\n };\n\n connect();\n\n return {\n close() {\n if (disposed) return;\n disposed = true;\n teardown();\n // Frames already received still belong in the store (a lingering stream\n // closing mid-turn must not lose its last tokens).\n queue.flush();\n queue.drop();\n setVerseStreamState(sessionId, 'closed');\n },\n restart() {\n if (disposed) return;\n teardown();\n queue.flush();\n attempt = 0;\n connect();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Ref-counted registry\n// ---------------------------------------------------------------------------\n\ninterface RegistryEntry {\n stream: LiveStream;\n refs: number;\n idleTimer: ReturnType<typeof setTimeout> | null;\n /** When the last reference was released (for evicting the oldest lingering stream). */\n releasedAt: number;\n}\n\nconst registry = new Map<string, RegistryEntry>();\n\nfunction closeEntry(sessionId: string): void {\n const entry = registry.get(sessionId);\n if (!entry) return;\n registry.delete(sessionId);\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n entry.stream.close();\n}\n\nfunction evictIdle(): void {\n const idle = [...registry.entries()].filter(([, e]) => e.refs === 0).sort((a, b) => a[1].releasedAt - b[1].releasedAt);\n while (idle.length > MAX_IDLE_STREAMS) closeEntry(idle.shift()![0]);\n}\n\n/**\n * Hold the live stream for `sessionId` open. Returns the release. The first\n * acquire connects (resuming after the store's cursor); later ones share it.\n */\nexport function acquireVerseSessionStream(sessionId: string): () => void {\n let entry = registry.get(sessionId);\n if (entry) {\n entry.refs += 1;\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n entry.idleTimer = null;\n } else {\n entry = { stream: openResumableStream(sessionId), refs: 1, idleTimer: null, releasedAt: 0 };\n registry.set(sessionId, entry);\n }\n const held = entry;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n if (registry.get(sessionId) !== held) return;\n held.refs -= 1;\n if (held.refs > 0) return;\n held.releasedAt = Date.now();\n held.idleTimer = setTimeout(() => {\n if (registry.get(sessionId) === held && held.refs === 0) closeEntry(sessionId);\n }, IDLE_CLOSE_MS);\n evictIdle();\n };\n}\n\n/** Close every live stream (logout; tests). */\nexport function closeAllVerseSessionStreams(): void {\n for (const id of [...registry.keys()]) closeEntry(id);\n}\n\n/** Diagnostics/tests: the sessions with a stream held open, and their reference counts. */\nexport function verseStreamRegistrySnapshot(): Array<{ sessionId: string; refs: number }> {\n return [...registry.entries()].map(([sessionId, e]) => ({ sessionId, refs: e.refs }));\n}\n\n// A deleted chat has no stream to keep; a cleared store (logout, test reset)\n// has no chats at all.\nsubscribeVerseStoreLifecycle((event) => {\n if (event.kind === 'reset') closeAllVerseSessionStreams();\n else closeEntry(event.sessionId);\n});\n\n// ---------------------------------------------------------------------------\n// Opening a chat\n// ---------------------------------------------------------------------------\n\nexport interface OpenVerseSessionOptions {\n /** Re-fetch the detail and reconnect even when the store already holds the chat (the transcript's Retry). */\n reload?: boolean;\n}\n\n/**\n * Show one chat: load it (once) and keep its live stream attached until the\n * returned disposer runs.\n *\n * - Not loaded yet → fetch the detail, seed the store, THEN attach the\n * stream from the seeded cursor. No race, no full replay.\n * - Already loaded (switching back) → attach at once from the cursor; a\n * stream still lingering from the last visit has nothing to catch up.\n * - `reload` → refetch the detail and restart the connection.\n */\nexport function openVerseSession(sessionId: string, options: OpenVerseSessionOptions = {}): () => void {\n const controller = new AbortController();\n let release: (() => void) | null = null;\n let disposed = false;\n\n const attach = () => {\n if (disposed || release) return;\n release = acquireVerseSessionStream(sessionId);\n };\n\n const state = getVerseSessionState(sessionId);\n const needsLoad = options.reload === true || !state.loaded || state.loadError !== null;\n\n if (!needsLoad) {\n attach();\n } else {\n if (options.reload) registry.get(sessionId)?.stream.restart();\n void fetchVerseSessionDetail(sessionId, controller.signal)\n .then((detail) => {\n if (controller.signal.aborted) return;\n seedVerseSession(sessionId, detail.session, detail.events);\n attach();\n })\n .catch((err: unknown) => {\n if (controller.signal.aborted) return;\n setVerseLoadError(sessionId, err instanceof Error ? err.message : 'Could not load this chat.');\n });\n }\n\n return () => {\n disposed = true;\n controller.abort();\n release?.();\n release = null;\n };\n}\n","/**\n * routes/verse/useVerseSession.ts — the only React glue over verse-store /\n * session-stream (same split as data/hooks.ts over cache.ts + sse.ts).\n *\n * Three hooks, three snapshots, three render frequencies (V3.10):\n *\n * useVerseSession(id) the HEAD: session record, load/stream state and\n * the event log as of the last structural event.\n * Owns opening the chat. Does NOT change per\n * streamed token, so the Chat section, sidebar,\n * header and resources panel stop re-rendering at\n * token rate.\n * useVerseTranscript(id) the derived transcript — changes at most once per\n * animation frame while text streams. Lives in\n * useVerseTranscript.ts: the derivation it reads is\n * kept off the chat first-paint path.\n * useVerseLive(id) transient signals of the running turn\n * (reasoning, progress, retry/watchdog notices).\n *\n * Each subscribes to its own session only, so a stream feeding a lingering\n * chat in the background re-renders nothing that shows another one.\n */\nimport { useCallback, useEffect, useRef, useSyncExternalStore } from 'react';\nimport { openVerseSession } from './session-stream.js';\nimport {\n getVerseLive,\n getVerseSessionHead,\n subscribeVerseSession,\n type Transcript,\n type VerseLiveState,\n type VerseSessionHead,\n} from './verse-store.js';\n\nexport interface VerseSessionView extends VerseSessionHead {\n /**\n * A transcript supplied WITH the view — only a hand-built view (a test, a\n * preview) carries one. The live app leaves it unset and the workspace\n * subscribes to the transcript itself (useVerseTranscript), which is what\n * keeps a streamed token from re-rendering everything that holds the view.\n */\n transcript?: Transcript;\n}\n\nconst noop = () => () => {};\n\nexport function useSessionSubscription(sessionId: string | null) {\n return useCallback(\n (listener: () => void) => (sessionId ? subscribeVerseSession(sessionId, listener) : noop()),\n [sessionId],\n );\n}\n\n/**\n * @param reload bump to re-fetch the detail + reconnect for the same id\n * (the transcript's Retry button).\n */\nexport function useVerseSession(sessionId: string | null, reload = 0): VerseSessionView {\n const subscribe = useSessionSubscription(sessionId);\n const head = useSyncExternalStore(\n subscribe,\n () => getVerseSessionHead(sessionId),\n () => getVerseSessionHead(sessionId),\n );\n\n // Only a BUMP of `reload` for the chat already open means Retry; the\n // counter itself is never reset by the host, so \"reload > 0\" would turn\n // every later selection into a full refetch.\n const lastOpened = useRef<{ sessionId: string | null; reload: number }>({ sessionId: null, reload });\n useEffect(() => {\n const previous = lastOpened.current;\n lastOpened.current = { sessionId, reload };\n if (!sessionId) return undefined;\n return openVerseSession(sessionId, { reload: previous.sessionId === sessionId && previous.reload !== reload });\n }, [sessionId, reload]);\n\n return head;\n}\n\n/** Live (never persisted) signals of the chat's running turn. */\nexport function useVerseLive(sessionId: string | null): VerseLiveState {\n const subscribe = useSessionSubscription(sessionId);\n return useSyncExternalStore(\n subscribe,\n () => getVerseLive(sessionId),\n () => getVerseLive(sessionId),\n );\n}\n","/**\n * routes/verse/chat/use-chat-activity.ts — the Chat surface's view of C1's\n * activity + session-meta routes (unit C2).\n *\n * WHY NOT C1's useActivity: that hook runs the shell's CURSOR loop (it owns\n * completions, the rail badges and the native \"Finished:\" notifications).\n * The chat list needs only the present tense — who is running, what they are\n * doing, what needs the operator — so it reads the same route without a\n * cursor, through the shared query cache under VERSE_ACTIVITY_KEY. Any other\n * reader of that key (the rail, a future pane) shares the one request.\n *\n * Polls every 5 s ONLY while the Chat surface and the window are visible\n * (C0's usePollWhileVisible), and catches up the moment it is shown again.\n * Activity answers in < 5 ms from memory (SPEC-310C budget), so this is\n * cheap; it is still never faster than the 2 s floor.\n *\n * Also owns this tab's \"seen\" map: opening a chat clears its unread dot NOW,\n * whether or not the server-side POST can run (it needs a held token).\n */\nimport { useCallback, useSyncExternalStore } from 'react';\nimport { readFailureReason } from '../../../data/client.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { usePollWhileVisible } from '../shell/section-visibility.js';\nimport { markVerseSessionSeen, verseActivityQuery, verseSessionMetaQuery } from '../verse-queries.js';\n\nexport const CHAT_ACTIVITY_POLL_MS = 5_000;\n\n// ---- local seen map --------------------------------------------------------\n\nlet seen = new Map<string, number>();\nconst seenListeners = new Set<() => void>();\n\nfunction subscribeSeen(listener: () => void): () => void {\n seenListeners.add(listener);\n return () => seenListeners.delete(listener);\n}\n\nfunction getSeen(): ReadonlyMap<string, number> {\n return seen;\n}\n\n/** Record that the operator saw `sessionId` up to `turnCount`, locally and (best-effort) on the server. */\nexport function noteSessionSeen(sessionId: string, turnCount: number): void {\n if ((seen.get(sessionId) ?? -1) >= turnCount) return;\n seen = new Map(seen).set(sessionId, turnCount);\n for (const listener of [...seenListeners]) listener();\n void markVerseSessionSeen(sessionId, turnCount);\n}\n\n/** Test seam. */\nexport function resetLocalSeen(): void {\n seen = new Map();\n for (const listener of [...seenListeners]) listener();\n}\n\nexport function useLocalSeen(): ReadonlyMap<string, number> {\n return useSyncExternalStore(subscribeSeen, getSeen, getSeen);\n}\n\n// ---- queries ---------------------------------------------------------------\n\nexport function useChatActivity() {\n const activity = useQuery(verseActivityQuery, { freshMs: CHAT_ACTIVITY_POLL_MS - 500 });\n const meta = useQuery(verseSessionMetaQuery);\n const refetchActivity = useRefetch(verseActivityQuery);\n const tick = useCallback(() => refetchActivity(), [refetchActivity]);\n usePollWhileVisible(tick, CHAT_ACTIVITY_POLL_MS);\n const localSeen = useLocalSeen();\n return {\n /** null = the route is not mounted on this server (or has not answered yet). */\n activity: activity.data ?? null,\n meta: meta.data ?? null,\n /**\n * Why session-meta could not be read (the route's own sentence, e.g. the\n * chat engine is not answering), or null. A 404 is not an error here — it\n * reads as `meta: null` (\"not on this server\").\n */\n metaError: meta.status === 'error' ? readFailureReason(meta.error) : null,\n localSeen,\n };\n}\n","/**\n * routes/verse/chat-panel-sizing.ts — how wide the two side panels of the\n * Chat section are, and what the viewport will actually let them be.\n *\n * WHY THIS IS NOT `ashlr.verse.ui.v2`. That key's shape is the shell contract\n * (docs/VERSE-CONTRACT-V2.md) and verse-ui-store.test pins it field for\n * field; the same precedent that put `resources-collapse.ts` under its own\n * key applies here. This module also needs something the shell store cannot\n * express: a width is not a single number but a PAIR — what the operator\n * asked for, and what the window is currently wide enough to give them.\n *\n * DESIRED vs EFFECTIVE. A sidebar dragged to 420px on a 1900px display must\n * not strand the transcript when the same window is later 1100px wide. So the\n * operator's choice (`desired`) is what persists, and `effective` is that\n * choice re-fitted to the container on every layout change. Shrinking the\n * window narrows the panel; widening it gives the width back, because the\n * transient value was never written down.\n *\n * Pure aside from the two localStorage functions, and framework-free — the\n * React glue lives in ChatResizer.tsx, the same split as\n * verse-ui-store.ts / useVerseUi.ts.\n */\n\nexport type ChatPanelSide = 'sidebar' | 'resources';\n\nexport interface ChatPanelRange {\n readonly min: number;\n readonly max: number;\n readonly def: number;\n}\n\n/**\n * Minimum and maximum are both load-bearing. The minimum is the width below\n * which the panel stops being a panel and becomes a sliver of truncated\n * text; the maximum keeps a wide display from turning the transcript into a\n * column. Defaults match what the shell has always opened at, so nothing\n * moves for an operator who never drags anything.\n */\nexport const CHAT_PANEL_RANGES: Readonly<Record<ChatPanelSide, ChatPanelRange>> = {\n sidebar: { min: 220, max: 420, def: 264 },\n resources: { min: 240, max: 520, def: 320 },\n};\n\n/**\n * The transcript's floor. Below `--measure-read` (720px) reading is already\n * compromised; 480px is where the composer's own controls start wrapping, and\n * it is the point past which a side panel must give width back instead of\n * taking more. The narrow-width media queries in ChatSection.module.css take\n * over below that — this number only decides who yields first.\n */\nexport const MIN_TRANSCRIPT_WIDTH = 480;\n\n/** The 1px hairline track each visible resizer occupies. */\nconst HAIRLINE = 1;\n\n/** Arrow-key step, and the coarse step Shift asks for. */\nexport const CHAT_PANEL_STEP = 16;\nexport const CHAT_PANEL_STEP_COARSE = 64;\n\nexport const CHAT_PANEL_SIZING_KEY = 'ashlr.verse.panels.v1';\n\n/**\n * Read-only migration source. Panel widths lived in the shell store before\n * they were draggable; seeding from it once means an upgrade does not reset\n * a width the operator had already chosen. Never written to from here.\n */\nconst LEGACY_SHELL_KEY = 'ashlr.verse.ui.v2';\n\nexport interface ChatPanelWidths {\n readonly sidebar: number;\n readonly resources: number;\n}\n\n/** What the chat grid can currently afford. */\nexport interface ChatPanelFit {\n /**\n * Width in px of the chat grid itself (NOT the window): rail excluded,\n * because the rail is not the section's to spend. Zero or unknown — jsdom,\n * a hidden section, the first paint — disables viewport fitting entirely\n * rather than guessing, so a width is never clamped against a measurement\n * that does not exist.\n */\n readonly containerWidth: number;\n readonly sidebarVisible: boolean;\n readonly resourcesVisible: boolean;\n}\n\nexport const UNKNOWN_FIT: ChatPanelFit = {\n containerWidth: 0,\n sidebarVisible: true,\n resourcesVisible: true,\n};\n\nexport interface ChatPanelSizing {\n /** The operator's choice. This is what persists. */\n readonly desired: ChatPanelWidths;\n /** That choice, re-fitted to the current container. This is what renders. */\n readonly effective: ChatPanelWidths;\n}\n\n/**\n * Clamp one width into its own range. Nonsense — NaN, a string, a negative\n * number out of a hand-edited localStorage entry — resolves to the default\n * rather than to the minimum, so a corrupt value reads as \"never chosen\".\n */\nexport function clampPanelWidth(side: ChatPanelSide, value: unknown): number {\n const range = CHAT_PANEL_RANGES[side];\n const n = Number(value);\n if (!Number.isFinite(n) || n <= 0) return range.def;\n return Math.max(range.min, Math.min(range.max, Math.round(n)));\n}\n\n/**\n * Re-fit a chosen pair of widths to the container.\n *\n * The resources panel yields first: it is the optional one (it has a toggle,\n * the sidebar's collapse is an overlay at phone width), so on a narrowing\n * window the operator loses reference material before they lose navigation.\n * Neither panel is ever pushed below its own minimum — past that point the\n * media queries hide a panel outright, which is a better answer than a 40px\n * stub of clipped text.\n */\nexport function fitChatPanels(widths: ChatPanelWidths, fit: ChatPanelFit): ChatPanelWidths {\n let sidebar = clampPanelWidth('sidebar', widths.sidebar);\n let resources = clampPanelWidth('resources', widths.resources);\n if (!Number.isFinite(fit.containerWidth) || fit.containerWidth <= 0) return { sidebar, resources };\n\n const hairlines = (fit.sidebarVisible ? HAIRLINE : 0) + (fit.resourcesVisible ? HAIRLINE : 0);\n const budget = fit.containerWidth - MIN_TRANSCRIPT_WIDTH - hairlines;\n const spent = (fit.sidebarVisible ? sidebar : 0) + (fit.resourcesVisible ? resources : 0);\n let over = spent - budget;\n if (over <= 0) return { sidebar, resources };\n\n if (fit.resourcesVisible) {\n const give = Math.min(over, resources - CHAT_PANEL_RANGES.resources.min);\n resources -= give;\n over -= give;\n }\n if (over > 0 && fit.sidebarVisible) {\n const give = Math.min(over, sidebar - CHAT_PANEL_RANGES.sidebar.min);\n sidebar -= give;\n }\n return { sidebar, resources };\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport function defaultChatPanelWidths(): ChatPanelWidths {\n return { sidebar: CHAT_PANEL_RANGES.sidebar.def, resources: CHAT_PANEL_RANGES.resources.def };\n}\n\n/** Parse either this module's payload or the legacy shell payload. */\nexport function parseChatPanelWidths(raw: string | null): ChatPanelWidths | null {\n if (raw === null || raw === '') return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null;\n const record = parsed as Record<string, unknown>;\n // `sidebarWidth`/`resourcesWidth` is the legacy shell spelling.\n const sidebar = record.sidebar ?? record.sidebarWidth;\n const resources = record.resources ?? record.resourcesWidth;\n if (sidebar === undefined && resources === undefined) return null;\n return {\n sidebar: clampPanelWidth('sidebar', sidebar),\n resources: clampPanelWidth('resources', resources),\n };\n}\n\nexport function readChatPanelWidths(): ChatPanelWidths {\n try {\n const own = parseChatPanelWidths(localStorage.getItem(CHAT_PANEL_SIZING_KEY));\n if (own) return own;\n // First run after the upgrade: inherit whatever the shell store had.\n return parseChatPanelWidths(localStorage.getItem(LEGACY_SHELL_KEY)) ?? defaultChatPanelWidths();\n } catch {\n return defaultChatPanelWidths();\n }\n}\n\nexport function writeChatPanelWidths(widths: ChatPanelWidths): void {\n try {\n localStorage.setItem(CHAT_PANEL_SIZING_KEY, JSON.stringify({\n sidebar: widths.sidebar,\n resources: widths.resources,\n }));\n } catch {\n /* a private window without storage still runs the app */\n }\n}\n\n// ---------------------------------------------------------------------------\n// Store\n// ---------------------------------------------------------------------------\n\nlet desired: ChatPanelWidths = readChatPanelWidths();\nlet fit: ChatPanelFit = UNKNOWN_FIT;\nlet snapshot: ChatPanelSizing = { desired, effective: fitChatPanels(desired, fit) };\nconst listeners = new Set<() => void>();\n\nfunction sameWidths(a: ChatPanelWidths, b: ChatPanelWidths): boolean {\n return a.sidebar === b.sidebar && a.resources === b.resources;\n}\n\n/** Snapshot identity changes only when a number actually changed. */\nfunction publish(): void {\n const effective = fitChatPanels(desired, fit);\n if (sameWidths(snapshot.desired, desired) && sameWidths(snapshot.effective, effective)) return;\n snapshot = { desired, effective };\n for (const listener of listeners) listener();\n}\n\nexport function subscribeChatPanels(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function getChatPanelSizing(): ChatPanelSizing {\n return snapshot;\n}\n\n/**\n * Publish what the layout can afford. Called on mount, on window resize and\n * whenever a panel is shown or hidden. Deliberately does NOT persist: a\n * narrow window borrows width, it does not take it.\n */\nexport function setChatPanelFit(next: ChatPanelFit): void {\n if (\n fit.containerWidth === next.containerWidth\n && fit.sidebarVisible === next.sidebarVisible\n && fit.resourcesVisible === next.resourcesVisible\n ) return;\n fit = next;\n publish();\n}\n\nfunction commit(next: ChatPanelWidths): void {\n if (sameWidths(desired, next)) return;\n desired = next;\n writeChatPanelWidths(desired);\n publish();\n}\n\n/** A drag or a direct set. Range-clamped; the fit is applied on read. */\nexport function setChatPanelWidth(side: ChatPanelSide, value: number): void {\n commit({ ...desired, [side]: clampPanelWidth(side, value) });\n}\n\n/**\n * An arrow key. Steps from the EFFECTIVE width, so a keypress moves the\n * handle the operator can see rather than an off-screen remembered one.\n */\nexport function nudgeChatPanelWidth(side: ChatPanelSide, delta: number): void {\n setChatPanelWidth(side, snapshot.effective[side] + delta);\n}\n\n/** Double-click, and the Home/End extremes. */\nexport function resetChatPanelWidth(side: ChatPanelSide): void {\n setChatPanelWidth(side, CHAT_PANEL_RANGES[side].def);\n}\n\n/** Test hygiene — mirrors resetVerseUi(). */\nexport function resetChatPanelSizing(): void {\n desired = defaultChatPanelWidths();\n fit = UNKNOWN_FIT;\n snapshot = { desired, effective: fitChatPanels(desired, fit) };\n try {\n localStorage.removeItem(CHAT_PANEL_SIZING_KEY);\n } catch {\n /* ignore */\n }\n for (const listener of listeners) listener();\n}\n\n/** Re-read storage into the store (a fresh tab, or a test that seeded a key). */\nexport function reloadChatPanelSizing(): void {\n desired = readChatPanelWidths();\n snapshot = { desired, effective: fitChatPanels(desired, fit) };\n for (const listener of listeners) listener();\n}\n","/**\n * routes/verse/ChatResizer.tsx — the drag handle between the chat\n * transcript and a side panel.\n *\n * A 1px hairline that behaves like a 9px target: the hairline is the design\n * (DESIGN-V2 has no chrome), the grab area is the ergonomics. Three things\n * about it are not obvious and are all deliberate:\n *\n * 1. IT IS A CONTROL, NOT A DECORATION. `role=\"separator\"` with a tabindex is\n * the ARIA window-splitter pattern: arrow keys move it, Home/End take it\n * to its limits, and a double-click restores the default. A pointer-only\n * resizer simply does not exist for a keyboard operator.\n *\n * 2. IT MUST NOT EAT THE macOS DRAG STRIP. The grab area overhangs ±4px into\n * the panels either side, and the top 48px of those panels is the window's\n * own drag region (Sidebar `.headDragStrip`, Workspace `.header`\n * data-app-region=\"drag\"). It is painted after them, so without the\n * `--app-titlebar-height` inset in the stylesheet it would steal 4px of\n * the strip AND turn the macOS double-click-to-zoom into a width reset.\n * See desktop/README.md \"Desktop shell contract\".\n *\n * 3. THE DRAG IS RELEASED FROM `window`, NOT FROM THE ELEMENT. Pointer\n * capture is requested, but it is not relied on: a capture that fails, a\n * pointer that leaves the window, a button released over another app and\n * a mid-drag unmount all have to end the drag, because a stuck drag state\n * (everything selects, the cursor sticks) is the most visible bug this\n * control can have.\n */\nimport { useCallback, useEffect, useRef, useState, useSyncExternalStore, type KeyboardEvent, type PointerEvent } from 'react';\nimport {\n CHAT_PANEL_RANGES,\n CHAT_PANEL_STEP,\n CHAT_PANEL_STEP_COARSE,\n getChatPanelSizing,\n nudgeChatPanelWidth,\n resetChatPanelWidth,\n setChatPanelWidth,\n subscribeChatPanels,\n type ChatPanelSide,\n type ChatPanelSizing,\n} from './chat-panel-sizing.js';\n\n/** The React glue over chat-panel-sizing.ts (same split as useVerseUi.ts). */\nexport function useChatPanelSizing(): ChatPanelSizing {\n return useSyncExternalStore(subscribeChatPanels, getChatPanelSizing, getChatPanelSizing);\n}\n\n/**\n * Marks the body for the duration of a drag so the stylesheet can suppress\n * selection app-wide. An attribute rather than an inline style: it survives\n * React re-renders, it is one line of CSS, and a test can see it.\n */\nconst BODY_FLAG = 'verseResizing';\n\nfunction markBody(on: boolean): void {\n try {\n if (on) document.body.dataset[BODY_FLAG] = 'true';\n else delete document.body.dataset[BODY_FLAG];\n } catch {\n /* a detached document in a test teardown is not worth throwing over */\n }\n}\n\nexport interface ChatResizerProps {\n side: ChatPanelSide;\n /** The control's accessible name — what it resizes, in the operator's words. */\n label: string;\n className?: string;\n}\n\ninterface DragState {\n pointerId: number;\n originX: number;\n startWidth: number;\n}\n\nexport function ChatResizer({ side, label, className }: ChatResizerProps) {\n const sizing = useChatPanelSizing();\n const range = CHAT_PANEL_RANGES[side];\n const width = sizing.effective[side];\n const drag = useRef<DragState | null>(null);\n const [dragging, setDragging] = useState(false);\n\n /** The one way a drag ends. Idempotent, so every path can call it. */\n const endDrag = useCallback(() => {\n if (!drag.current) return;\n drag.current = null;\n setDragging(false);\n markBody(false);\n }, []);\n\n const onPointerDown = useCallback((event: PointerEvent<HTMLDivElement>) => {\n // Primary button only: a right-click here belongs to the context menu,\n // and a middle-click must not start a drag nobody asked for.\n if (event.button !== 0) return;\n event.preventDefault();\n drag.current = { pointerId: event.pointerId, originX: event.clientX, startWidth: width };\n setDragging(true);\n markBody(true);\n // Best-effort: it keeps the cursor and the events on the handle while the\n // pointer wanders. The window listeners below are the actual contract.\n try {\n event.currentTarget.setPointerCapture?.(event.pointerId);\n } catch {\n /* unsupported, or the pointer is already gone — the window listeners cover it */\n }\n }, [width]);\n\n // Move/end listeners live on the window for the whole drag, so a pointer\n // that leaves the viewport or a button released over another window still\n // lands here. Unmounting mid-drag runs the cleanup and clears the body flag.\n useEffect(() => {\n if (!dragging) return undefined;\n\n const onMove = (event: globalThis.PointerEvent) => {\n const state = drag.current;\n if (!state || event.pointerId !== state.pointerId) return;\n const delta = event.clientX - state.originX;\n // The sidebar grows to the right, the resources panel to the left.\n setChatPanelWidth(side, side === 'sidebar' ? state.startWidth + delta : state.startWidth - delta);\n };\n const onEnd = (event: globalThis.PointerEvent) => {\n const state = drag.current;\n if (state && event.pointerId !== state.pointerId) return;\n endDrag();\n };\n /** Escape puts the width back where the drag started. */\n const onKey = (event: globalThis.KeyboardEvent) => {\n const state = drag.current;\n if (!state || event.key !== 'Escape') return;\n setChatPanelWidth(side, state.startWidth);\n endDrag();\n };\n // The window losing focus (⌘-tab mid-drag, an OS dialog) never delivers a\n // pointerup, so treat it as one rather than staying stuck.\n const onBlur = () => endDrag();\n\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onEnd);\n window.addEventListener('pointercancel', onEnd);\n window.addEventListener('keydown', onKey);\n window.addEventListener('blur', onBlur);\n return () => {\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onEnd);\n window.removeEventListener('keydown', onKey);\n window.removeEventListener('blur', onBlur);\n markBody(false);\n };\n }, [dragging, side, endDrag]);\n\n const onKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n const step = event.shiftKey ? CHAT_PANEL_STEP_COARSE : CHAT_PANEL_STEP;\n // Left/Right are screen directions, so which one GROWS depends on which\n // edge of the transcript this handle is.\n const toward = side === 'sidebar' ? 1 : -1;\n switch (event.key) {\n case 'ArrowRight':\n nudgeChatPanelWidth(side, step * toward);\n break;\n case 'ArrowLeft':\n nudgeChatPanelWidth(side, -step * toward);\n break;\n case 'Home':\n setChatPanelWidth(side, range.min);\n break;\n case 'End':\n setChatPanelWidth(side, range.max);\n break;\n case 'Enter':\n resetChatPanelWidth(side);\n break;\n default:\n return;\n }\n event.preventDefault();\n }, [side, range.min, range.max]);\n\n return (\n <div\n className={className}\n data-verse-resizer={side}\n data-dragging={dragging ? 'true' : undefined}\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={label}\n aria-valuemin={range.min}\n aria-valuemax={range.max}\n aria-valuenow={width}\n aria-valuetext={`${width} pixels`}\n tabIndex={0}\n onPointerDown={onPointerDown}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onLostPointerCapture={endDrag}\n onKeyDown={onKeyDown}\n // The thing people reach for after over-dragging. In the desktop app a\n // double-click on a DRAG region zooms the window instead — which is why\n // the stylesheet keeps this handle's grab area out of the title bar.\n onDoubleClick={() => resetChatPanelWidth(side)}\n />\n );\n}\n","/**\n * routes/verse/sections/ChatSection.tsx — the Chat surface (⌘5):\n *\n * [sessions 264 | transcript ≤720 | dock 440 (tabs, or two panes split)]\n *\n * plus the new-chat dialog, the delete confirmation, and every mutation the\n * chat surface makes (SPEC-310C §2–§3, unit C2).\n *\n * Takes NO props (the shell contract): the shell lazily mounts it. The ways\n * INTO it from elsewhere in the workbench arrive two ways, both C1's:\n * - the shell's one-shot command (verse-ui-store): `new-chat` (⌘N, \"New\n * chat on…\", with a seat or project), `open-session` (a Needs-you item, a\n * notification, ⌃Tab, ⌘[ / ⌘]), `focus-composer` (⌃⌥Space);\n * - the command bus (shell/command-bus.ts): this section serves the\n * catalog's chat-scope commands — `dock.*`, `chat.sidebar`, `chat.find`,\n * `chat.turn-prev/next` — for the palette, the native menu and keys.\n * And it reports which chat is open (setVerseActiveSession), which feeds\n * ⌃Tab's recent list and back/forward.\n *\n * 3.10 changes, briefly:\n * - the resources column became the DOCK (dock/Dock.tsx): Terminal,\n * Preview and Review through C0's slots, Tasks and Context of its own;\n * below 1024px it is a sheet, below 480px a bottom sheet;\n * - the chat list gained filters, pins, archive, unread and a live second\n * line (C1's activity + session-meta routes, tolerated when absent);\n * - the ⌘K chat switcher is gone — ⌘K is the shell's command palette;\n * - the chat-scope keys (⌘\\ ⌃` ⌃⇧` ⇧⌘B ⇧⌘D ⌘B) run the same handlers,\n * matched from C0's catalog while this surface is visible — and only when\n * the shell's own key handler has not already taken the event.\n *\n * Mutations go through one guard: if no mutation token is held,\n * MutationTokenDialog opens and the action re-runs once unlocked.\n */\nimport { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState, type ComponentProps, type CSSProperties } from 'react';\nimport type { VerseCreateSessionRequest, VerseSession } from '../../../data/api-types.js';\nimport type { MutationTokenDialog as MutationTokenDialogComponent } from '../../../components/auth/MutationTokenDialog.js';\nimport { useToast } from '../../../components/primitives/Toast.js';\nimport { clearReadSession } from '../../../data/auth-store.js';\nimport { ApiError, DispatchDisabledError } from '../../../data/client.js';\nimport { useMutationHold, useQuery, useRefresh } from '../../../data/hooks.js';\nimport type { DeleteChatDialog as DeleteChatDialogComponent } from '../chat/DeleteChatDialog.js';\nimport { insertIntoComposer } from '../chat/composer-bridge.js';\nimport { forgetComposerMemory } from '../chat/composer-memory.js';\nimport type { ChatTask } from '../chat/tasks-model.js';\nimport { requestTranscriptFind, requestTranscriptStep } from '../chat/transcript-jump.js';\nimport { noteSessionSeen, useChatActivity } from '../chat/use-chat-activity.js';\nimport { useSessionRoots } from '../chat/use-session-roots.js';\nimport { ChatResizer, useChatPanelSizing } from '../ChatResizer.js';\nimport { CHAT_PANEL_RANGES, MIN_TRANSCRIPT_WIDTH, setChatPanelFit } from '../chat-panel-sizing.js';\nimport { clearDockRequests, requestTerminal, toggleDock, toggleDockPane, useDock } from '../dock/dock-store.js';\nimport type { SeatChoice } from '../SeatSelector.js';\nimport { clampDockWidth, DOCK_LAYOUT, dockPresentation } from '../shell/dock-catalog.js';\nimport { useCommandHandler } from '../shell/command-bus.js';\nimport { matchKey } from '../shell/command-keys.js';\nimport { preloadedLazy, preloadedModule } from '../shell/preloaded.js';\nimport { useSectionVisible } from '../shell/section-visibility.js';\nimport type { TurnFileChange } from '../shell/slots.js';\nimport type { Sidebar as SidebarComponent, SidebarRowActions } from '../Sidebar.js';\nimport { SkeletonLine } from '../../../components/primitives/Skeleton.js';\nimport { useVerseSession } from '../useVerseSession.js';\nimport { useVerseUi } from '../useVerseUi.js';\nimport { openVerseListChannel } from '../verse-events.js';\nimport {\n cancelVerseTurn,\n createVerseSession,\n deleteVerseSession,\n renameVerseSession,\n sendVerseTurn,\n setVerseSessionMeta,\n verseBootstrapQuery,\n verseSessionsQuery,\n verseWorkspacesQuery,\n VerseMutationLockedError,\n} from '../verse-queries.js';\nimport { forgetVerseSession, setVerseSession, setVerseSessionStatus } from '../verse-store.js';\nimport {\n clearVerseCommand,\n lastVerseSeat,\n rememberVerseSeat,\n setVerseActiveSession,\n setVerseSection,\n setVerseSidebarCollapsed,\n} from '../verse-ui-store.js';\nimport type { Workspace as WorkspaceComponent } from '../Workspace.js';\nimport styles from './ChatSection.module.css';\n\n// Loaded on first use, not with the chat: the dock starts closed and the\n// new-chat dialog opens on request (SPEC-310C budget: chat critical JS).\nconst DockHost = lazy(() => import('../dock/DockHost.js').then((m) => ({ default: m.DockHost })));\nconst NewChatDialog = lazy(() => import('../NewChatDialog.js').then((m) => ({ default: m.NewChatDialog })));\n\nconst WorkspaceModule = preloadedLazy<ComponentProps<typeof WorkspaceComponent>>(() => import('../Workspace.js').then((m) => m.Workspace));\nconst Workspace = WorkspaceModule.Slot;\nconst SidebarModule = preloadedLazy<ComponentProps<typeof SidebarComponent>>(() => import('../Sidebar.js').then((m) => m.Sidebar));\nconst Sidebar = SidebarModule.Slot;\n/**\n * The delete confirmation and the token prompt draw nothing until an\n * operator acts, and as static imports they (with the dialog primitive and\n * its focus trap, ~4 KB, and the button primitive) sat in the chat\n * first-paint critical JS. Preloaded (chat/DeleteChatDialog.tsx):\n * by the time anyone can click Delete the chunk is in and they mount in the\n * same render that opens them; the two share the dialog primitive's chunk.\n */\nconst DeleteDialogModule = preloadedLazy<ComponentProps<typeof DeleteChatDialogComponent>>(() => import('../chat/DeleteChatDialog.js').then((m) => m.DeleteChatDialog));\nconst DeleteChatDialog = DeleteDialogModule.Slot;\nconst TokenDialogModule = preloadedLazy<ComponentProps<typeof MutationTokenDialogComponent>>(\n () => import('../../../components/auth/MutationTokenDialog.js').then((m) => m.MutationTokenDialog),\n);\nconst MutationTokenDialog = TokenDialogModule.Slot;\n\n/**\n * The two derivations only the workspace's tasks row and the dock read\n * (tool-semantics, sidebar-model and line-diff come with them, ~12 KB). Both\n * consumers are lazy chunks that import these modules themselves, so the\n * download is shared and the values are in before either consumer mounts;\n * until then there is honestly nothing to show.\n */\nconst DERIVATIONS = preloadedModule(() => Promise.all([import('../chat/tasks-model.js'), import('../chat/turn-files.js')])\n .then(([tasks, files]) => ({ otherRunningChats: tasks.otherRunningChats, lastTurnFiles: files.lastTurnFiles })));\n/** Seat lookups for ⌘N \"New chat on…\" — the only first-paint-path use of verse-model (5.6 KB). */\nconst SEAT_MODEL = preloadedModule(() => import('../verse-model.js').then((m) => ({ firstRunnableModel: m.firstRunnableModel, seatById: m.seatById })));\nconst NO_TASKS: readonly ChatTask[] = [];\nconst NO_TURN_FILES: TurnFileChange[] = [];\n\n/**\n * Resolves when the chat's own chunks (workspace, chat list) are in. Tests\n * await it so a mount renders the whole surface synchronously; nothing in the\n * app needs to — the Suspense skeletons cover the gap.\n */\nexport function preloadChatSurface(): Promise<unknown> {\n return Promise.all([\n WorkspaceModule.ready(), SidebarModule.ready(), DeleteDialogModule.ready(), TokenDialogModule.ready(), DERIVATIONS.ready(), SEAT_MODEL.ready(),\n ]);\n}\n\n/**\n * The chat list's shape while its chunk loads. A <nav> like the real one, so\n * the grid rules written against `.chat > nav` (collapsed = display:none, the\n * phone-width overlay) hold for it too — but NOT named \"Chats\": that name is\n * the loaded list's, and a placeholder answering to it would be a lie.\n */\nfunction SidebarSkeleton() {\n return (\n <nav className={styles.sidebarSkeleton} aria-busy=\"true\" aria-label=\"Loading chat list\">\n {[64, 82, 58, 76, 70].map((w) => <SkeletonLine key={w} width={`${w}%`} />)}\n </nav>\n );\n}\n\n/** The workspace column's shape while its chunk loads: header, a few lines, the composer bar. */\nfunction WorkspaceSkeleton() {\n return (\n <div className={styles.workspaceSkeleton} role=\"status\" aria-label=\"Loading chat\">\n <div className={styles.skeletonHeader}><SkeletonLine width=\"32%\" /></div>\n <div className={styles.skeletonBody}>\n <SkeletonLine width=\"72%\" />\n <SkeletonLine width=\"88%\" />\n <SkeletonLine width=\"64%\" />\n </div>\n <div className={styles.skeletonComposer}><SkeletonLine width=\"100%\" /></div>\n </div>\n );\n}\n\nconst SELECTED_KEY = 'ashlr.verse.selected.v1';\n\nfunction loadSelected(): string | null {\n try {\n return localStorage.getItem(SELECTED_KEY);\n } catch {\n return null;\n }\n}\n\n/**\n * Every chat-surface failure in one sentence, branching on the route's CODE\n * before its status.\n *\n * A 409 is not always \"busy\": POST …/turns also answers 409\n * VERSE_MODEL_UNAVAILABLE when the chat's model cannot run on its seat.\n * Mapping every 409 to \"a turn is already running\" told the operator to press\n * a Stop that does nothing, with the server's actual reason thrown away.\n */\nexport function describeChatError(err: unknown): string {\n if (err instanceof DispatchDisabledError) return 'This server was started without dispatch — run `ashlr verse` to chat.';\n if (err instanceof ApiError) {\n if (err.code === 'VERSE_MODEL_UNAVAILABLE') {\n const why = err.detail ?? \"This chat's model cannot run on its seat.\";\n return `${why.replace(/\\.?$/, '.')} Continue in a fresh chat on a model this seat can run, or re-pin the seat's CLI (\\`ashlr resources profile repin\\`).`;\n }\n if (err.status === 409 && (err.code === null || err.code === 'VERSE_SESSION_BUSY')) return 'A turn is already running in this chat. Stop it first.';\n if (err.status === 413) return 'That message is too large (64 KB max).';\n if (err.status === 401) return 'Mutation token was rejected. Unlock again with the token ashlr verse printed.';\n return err.detail ?? err.message;\n }\n return err instanceof Error ? err.message : 'Something went wrong.';\n}\n\n/** The window's width, for the dock's presentation and its 60% cap. */\nfunction useWindowWidth(): number {\n const [width, setWidth] = useState(() => (typeof window === 'undefined' ? 1440 : window.innerWidth || 1440));\n useEffect(() => {\n const onResize = () => setWidth(window.innerWidth || 1440);\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, []);\n return width;\n}\n\n/** ⌃⌥Space: the composer's message box, focused (C3's `aria-label=\"Message\"`). */\nfunction focusComposer(): void {\n // After the section has painted (the command may be what mounted it).\n requestAnimationFrame(() => {\n const box = document.querySelector<HTMLTextAreaElement>('textarea[aria-label=\"Message\"]');\n box?.focus();\n });\n}\n\n/** Is the key event aimed at an overlay that owns its own keys (a dialog, a menu, the palette)? */\nfunction inOverlay(target: EventTarget | null): boolean {\n return target instanceof Element && target.closest('[role=\"dialog\"], [role=\"menu\"], [role=\"listbox\"], [aria-modal=\"true\"]') !== null;\n}\n\nexport function ChatSection() {\n const bootstrap = useQuery(verseBootstrapQuery);\n const sessionsQuery = useQuery(verseSessionsQuery);\n const refetchSessions = useRefresh(verseSessionsQuery);\n const refetchBootstrap = useRefresh(verseBootstrapQuery);\n const hold = useMutationHold();\n const toast = useToast();\n const ui = useVerseUi();\n const visible = useSectionVisible();\n const dock = useDock();\n const chatActivity = useChatActivity();\n const windowWidth = useWindowWidth();\n\n const [selectedId, setSelectedIdState] = useState<string | null>(loadSelected);\n const [query, setQuery] = useState('');\n const [newChat, setNewChat] = useState<{ open: boolean; projectPath?: string | null; seat?: SeatChoice | null }>({ open: false });\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n const [reload, setReload] = useState(0);\n const [tokenPrompt, setTokenPrompt] = useState<{ open: boolean; reason: string }>({ open: false, reason: '' });\n const [handoffFor, setHandoffFor] = useState<string | null>(null);\n const [deleteTarget, setDeleteTarget] = useState<VerseSession | null>(null);\n const [chatWidth, setChatWidth] = useState(0);\n const pendingAction = useRef<{ run: () => void; cancel: () => void } | null>(null);\n const chatRef = useRef<HTMLDivElement>(null);\n const panels = useChatPanelSizing();\n\n const seats = useMemo(() => bootstrap.data?.seats ?? [], [bootstrap.data]);\n const projects = useMemo(() => bootstrap.data?.projects ?? [], [bootstrap.data]);\n // Workspaces come from their own route (live per-root status for the dialog).\n const workspacesQuery = useQuery(verseWorkspacesQuery);\n const workspaces = useMemo(() => workspacesQuery.data?.workspaces ?? [], [workspacesQuery.data]);\n const dispatchEnabled = bootstrap.data?.dispatchEnabled ?? true;\n\n const view = useVerseSession(selectedId, reload);\n const roots = useSessionRoots(view.session);\n\n // Sidebar list: the sessions query, else bootstrap's copy, with the live\n // store record overlaid for the open chat so its running dot is immediate.\n const sessions = useMemo<VerseSession[]>(() => {\n const base = sessionsQuery.data ?? bootstrap.data?.sessions ?? [];\n if (!view.session) return base;\n const live = view.session;\n return base.some((s) => s.id === live.id) ? base.map((s) => (s.id === live.id ? live : s)) : [live, ...base];\n }, [sessionsQuery.data, bootstrap.data, view.session]);\n\n const setSelectedId = useCallback((id: string | null) => {\n setSelectedIdState(id);\n try {\n if (id) localStorage.setItem(SELECTED_KEY, id);\n else localStorage.removeItem(SELECTED_KEY);\n } catch {\n /* best-effort */\n }\n }, []);\n\n // A remembered selection that no longer exists (deleted elsewhere) is dropped once the list is known.\n useEffect(() => {\n if (!selectedId || !sessionsQuery.data) return;\n if (!sessionsQuery.data.some((s) => s.id === selectedId) && !view.session) setSelectedId(null);\n }, [selectedId, sessionsQuery.data, view.session, setSelectedId]);\n\n // Sidebar digest channel (verse-sessions on /api/events).\n useEffect(() => openVerseListChannel(), []);\n\n // ---- recency + read state -------------------------------------------------\n // Pane requests (a pasted command, a diff to open) belong to the chat they\n // were raised in: switching chats drops them. A SWITCH only — the first run\n // of this effect is the section mounting, and that is exactly when Apps'\n // [Launch ▸] (raised on another surface, which then brings Chat forward)\n // has a terminal request waiting; clearing it here left an empty dock.\n const requestsFor = useRef(selectedId);\n useEffect(() => {\n setVerseActiveSession(selectedId);\n if (requestsFor.current !== selectedId) {\n requestsFor.current = selectedId;\n clearDockRequests();\n }\n }, [selectedId]);\n\n // Reading a chat — its turns up to now — while this surface is on screen.\n const openTurnCount = view.session?.turnCount ?? null;\n useEffect(() => {\n if (!visible || !selectedId || openTurnCount === null) return;\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return;\n noteSessionSeen(selectedId, openTurnCount);\n }, [visible, selectedId, openTurnCount]);\n\n // ---- mutation guard ---------------------------------------------------------\n const withToken = useCallback(<T,>(reason: string, action: () => Promise<T>): Promise<T | null> => {\n if (hold.hasHold) return action();\n return new Promise<T | null>((resolve, reject) => {\n pendingAction.current = {\n // Pass rejections through: a parked action that fails after the token\n // unlock must reach its caller's catch, not leave it awaiting forever.\n run: () => { action().then(resolve, reject); },\n cancel: () => resolve(null),\n };\n setTokenPrompt({ open: true, reason });\n });\n }, [hold.hasHold]);\n\n const fail = useCallback((err: unknown) => {\n if (err instanceof VerseMutationLockedError) return;\n toast.show(describeChatError(err), 'danger');\n }, [toast]);\n\n // ---- actions ----------------------------------------------------------------\n /**\n * ONE resolution of what \"new chat\" pre-fills, for every entry point (the\n * sidebar \"+\", ⌘N, the empty state, the palette's \"New chat on…\"): an\n * explicit prefill wins, the open session is next, and the per-project\n * seat memory is the floor.\n */\n const openNewChat = useCallback((prefill: { projectPath?: string | null; seat?: SeatChoice | null } = {}) => {\n setCreateError(null);\n const current = view.session;\n const projectPath = prefill.projectPath !== undefined ? prefill.projectPath : current?.projectPath ?? null;\n // The open session's seat only carries forward onto its OWN project.\n const fromCurrent = current && projectPath === current.projectPath\n ? { seatId: current.seatId, model: current.model }\n : null;\n const seat = prefill.seat ?? fromCurrent ?? lastVerseSeat(projectPath);\n setNewChat({ open: true, projectPath, seat });\n }, [view.session]);\n\n const create = useCallback(async (req: VerseCreateSessionRequest) => {\n await withToken('Starting a chat spawns an agent process for this project.', async () => {\n setCreating(true);\n setCreateError(null);\n try {\n const session = await createVerseSession(req);\n rememberVerseSeat(session.projectPath, { seatId: session.seatId, model: session.model });\n setVerseSession(session.id, session);\n setNewChat({ open: false });\n setSelectedId(session.id);\n toast.show(`Started “${session.title}”`, 'success');\n } catch (err) {\n setCreateError(describeChatError(err));\n } finally {\n setCreating(false);\n }\n });\n }, [withToken, setSelectedId, toast]);\n\n const send = useCallback(async (text: string) => {\n const id = selectedId;\n if (!id) return false;\n const result = await withToken('Sending a message runs the agent against this project.', async () => {\n setVerseSessionStatus(id, 'running');\n try {\n const response = await sendVerseTurn(id, text);\n // The turn may already have settled by the time the 202 is applied;\n // the store checks the log for this turnId before trusting `running`.\n setVerseSession(id, response.session, response.turnId);\n return true;\n } catch (err) {\n setVerseSessionStatus(id, 'idle');\n fail(err);\n return false;\n }\n });\n return result === true;\n }, [selectedId, withToken, fail]);\n\n const stop = useCallback((id: string | null = selectedId) => {\n if (!id) return;\n void withToken('Stopping the running turn.', async () => {\n try {\n await cancelVerseTurn(id);\n } catch (err) {\n fail(err);\n }\n });\n }, [selectedId, withToken, fail]);\n\n const renameChat = useCallback(async (id: string, title: string) => {\n const result = await withToken('Renaming a chat.', async () => {\n try {\n const session = await renameVerseSession(id, title);\n setVerseSession(id, session);\n return true;\n } catch (err) {\n fail(err);\n return false;\n }\n });\n return result === true;\n }, [withToken, fail]);\n\n const removeChat = useCallback(async (id: string) => {\n const result = await withToken('Deleting a chat removes its transcript from disk.', async () => {\n try {\n await deleteVerseSession(id);\n forgetVerseSession(id);\n // The transcript is gone from disk; the verbatim prompts must not\n // survive it in browser storage under a dead session id.\n forgetComposerMemory(id);\n if (id === selectedId) setSelectedId(null);\n toast.show('Chat deleted.', 'neutral');\n return true;\n } catch (err) {\n fail(err);\n return false;\n }\n });\n return result === true;\n }, [withToken, fail, setSelectedId, toast, selectedId]);\n\n const setMeta = useCallback((id: string, update: { pinned?: boolean; archived?: boolean }, reason: string) => {\n void withToken(reason, async () => {\n try {\n await setVerseSessionMeta(id, update);\n } catch (err) {\n fail(err);\n }\n });\n }, [withToken, fail]);\n\n /** Sessions are seat-bound: a different seat means a new chat on the same project. */\n const changeSeat = useCallback((choice: SeatChoice) => {\n const current = view.session;\n if (!current) return;\n openNewChat({ projectPath: current.projectPath, seat: choice });\n toast.show('Chats are bound to one seat — starting a new chat on the same project.', 'neutral');\n }, [view.session, openNewChat, toast]);\n\n const requestDelete = useCallback((id: string) => {\n const target = sessions.find((s) => s.id === id) ?? null;\n if (target) setDeleteTarget(target);\n }, [sessions]);\n\n const startHandoff = useCallback((id: string) => {\n if (id !== selectedId) setSelectedId(id);\n setHandoffFor(id);\n }, [selectedId, setSelectedId]);\n\n const selectFromList = useCallback((id: string) => {\n setSelectedId(id);\n // At phone width the list floats over the chat; picking a chat closes it.\n if (window.matchMedia?.('(max-width: 760px)')?.matches === true) setVerseSidebarCollapsed(true);\n }, [setSelectedId]);\n\n // ---- commands: the shell's hand-offs, the bus, and the chat's own keys ------\n const toggleSidebar = useCallback(() => setVerseSidebarCollapsed(!ui.sidebarCollapsed), [ui.sidebarCollapsed]);\n // ⌃` : a terminal, focused — the active tab, else one at the chat's root\n // (TerminalPane resolves an empty request that way). Pressed again while\n // Terminal is on screen it hides it, like every editor's ⌃`.\n const terminalShown = dock.state.open && (dock.state.active === 'terminal' || dock.state.splitWith === 'terminal');\n const openTerminal = useCallback(() => {\n if (terminalShown) toggleDockPane('terminal');\n else requestTerminal({});\n }, [terminalShown]);\n // ⌃⇧` : always a NEW tab, in the active tab's root (else the chat's primary).\n const newTerminalTab = useCallback(() => requestTerminal({ newTab: true }), []);\n\n // The shell's one-shot command, consumed once by nonce.\n const handledCommand = useRef(0);\n const seatModel = SEAT_MODEL.useLoaded();\n useEffect(() => {\n const command = ui.command;\n if (!command || command.nonce === handledCommand.current) return;\n // \"New chat on…\" resolves its seat through verse-model, which loads just\n // after first paint: leave the command pending (unconsumed) until it is\n // in — this effect re-runs when it lands.\n if (command.name === 'new-chat' && !seatModel) return;\n handledCommand.current = command.nonce;\n switch (command.name) {\n case 'open-session':\n if (command.sessionId) setSelectedId(command.sessionId);\n break;\n case 'focus-composer':\n focusComposer();\n break;\n case 'new-chat': {\n // \"New chat on…\" carries a seat (and maybe a project); ⌘N carries neither.\n const { seatById, firstRunnableModel } = seatModel!;\n const seat = command.seatId ? seatById(seats, command.seatId) : undefined;\n // The model this project last used on that seat, else the seat's first runnable one.\n const remembered = lastVerseSeat(command.projectPath ?? null);\n const model = !seat ? undefined : remembered?.seatId === seat.id ? remembered.model : firstRunnableModel(seat)?.id;\n openNewChat({\n ...(command.projectPath !== undefined ? { projectPath: command.projectPath } : {}),\n ...(seat && model ? { seat: { seatId: seat.id, model } } : {}),\n });\n break;\n }\n default:\n // 'quick-switcher' (pre-3.10): ⌘K is the shell's palette now.\n break;\n }\n clearVerseCommand();\n }, [ui.command, openNewChat, seats, setSelectedId, seatModel]);\n\n // The catalog's chat-scope commands, for the palette, the menu and keys.\n const handlers: ReadonlyArray<[string, () => void | boolean]> = [\n ['chat.sidebar', toggleSidebar],\n ['chat.find', () => requestTranscriptFind()],\n ['chat.turn-prev', () => requestTranscriptStep(-1)],\n ['chat.turn-next', () => requestTranscriptStep(1)],\n ['dock.toggle', toggleDock],\n ['dock.terminal', openTerminal],\n ['dock.terminal-new', newTerminalTab],\n ['dock.preview', () => toggleDockPane('preview')],\n ['dock.diff', () => toggleDockPane('diff')],\n ];\n const handlerMap = new Map(handlers);\n useCommandHandler('chat.sidebar', handlerMap.get('chat.sidebar')!);\n useCommandHandler('chat.find', handlerMap.get('chat.find')!);\n useCommandHandler('chat.turn-prev', handlerMap.get('chat.turn-prev')!);\n useCommandHandler('chat.turn-next', handlerMap.get('chat.turn-next')!);\n useCommandHandler('dock.toggle', handlerMap.get('dock.toggle')!);\n useCommandHandler('dock.terminal', handlerMap.get('dock.terminal')!);\n useCommandHandler('dock.terminal-new', handlerMap.get('dock.terminal-new')!);\n useCommandHandler('dock.preview', handlerMap.get('dock.preview')!);\n useCommandHandler('dock.diff', handlerMap.get('dock.diff')!);\n\n // Keys, as a fallback: the shell's handler routes catalog keys through the\n // bus and marks the event handled (preventDefault); this listener acts only\n // on an event nobody took, and only while the surface is visible and no\n // overlay (a dialog, a menu, the palette) owns the keyboard. ⌘F and ⌥↑/↓\n // are the transcript's own listeners, which follow the same rule.\n const handlerRef = useRef(handlerMap);\n handlerRef.current = handlerMap;\n useEffect(() => {\n if (!visible) return undefined;\n const onKey = (event: KeyboardEvent) => {\n if (event.defaultPrevented || inOverlay(event.target)) return;\n const command = matchKey(event, ['chat']);\n if (!command || command.scope !== 'chat') return;\n if (command.id === 'chat.find' || command.id === 'chat.turn-prev' || command.id === 'chat.turn-next') return;\n const run = handlerRef.current.get(command.id);\n if (!run) return;\n event.preventDefault();\n run();\n };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [visible]);\n\n const dispatchOff = bootstrap.data ? !bootstrap.data.dispatchEnabled : false;\n const sidebarCollapsed = ui.sidebarCollapsed;\n\n // ---- layout -------------------------------------------------------------------\n const presentation = dockPresentation(windowWidth);\n const dockOpen = dock.state.open && dock.state.tabs.length > 0;\n const dockColumn = dockOpen && presentation === 'column';\n // The dock yields before the transcript does: never past the window's 60%,\n // and never so wide that the transcript (plus the chat list, when shown at\n // its minimum) drops under its floor. The floor for the dock is its 320px.\n const sidebarFloor = sidebarCollapsed ? 0 : CHAT_PANEL_RANGES.sidebar.min;\n const dockWidth = dockColumn\n ? Math.max(DOCK_LAYOUT.minWidth, Math.min(\n clampDockWidth(dock.state.width, windowWidth),\n chatWidth > 0 ? chatWidth - MIN_TRANSCRIPT_WIDTH - sidebarFloor : Number.POSITIVE_INFINITY,\n ))\n : 0;\n\n useEffect(() => {\n const node = chatRef.current;\n if (!node) return undefined;\n const measure = () => {\n setChatWidth(node.clientWidth);\n setChatPanelFit({\n // The dock's column is not the sidebar's to spend.\n containerWidth: Math.max(0, node.clientWidth - dockWidth),\n sidebarVisible: !sidebarCollapsed,\n resourcesVisible: false,\n });\n };\n measure();\n const observer = typeof ResizeObserver === 'function' ? new ResizeObserver(measure) : null;\n observer?.observe(node);\n window.addEventListener('resize', measure);\n return () => {\n observer?.disconnect();\n window.removeEventListener('resize', measure);\n };\n }, [sidebarCollapsed, dockWidth]);\n\n const style = {\n '--verse-sidebar-width': `${panels.effective.sidebar}px`,\n '--verse-dock-width': `${dockWidth}px`,\n } as CSSProperties;\n\n // ---- dock data ------------------------------------------------------------------\n const derive = DERIVATIONS.useLoaded();\n const otherRunning = useMemo(\n () => (derive ? derive.otherRunningChats(sessions, chatActivity.activity, selectedId) : NO_TASKS),\n [derive, sessions, chatActivity.activity, selectedId],\n );\n const turnFiles = useMemo<TurnFileChange[]>(\n () => (derive ? derive.lastTurnFiles(view.events, roots.roots) : NO_TURN_FILES),\n [derive, roots.roots, view.events],\n );\n\n const actions: SidebarRowActions = {\n setPinned: (id, pinned) => setMeta(id, { pinned }, pinned ? 'Pinning a chat.' : 'Unpinning a chat.'),\n setArchived: (id, archived) => setMeta(id, { archived }, archived ? 'Archiving a chat.' : 'Unarchiving a chat.'),\n rename: renameChat,\n handoff: startHandoff,\n requestDelete,\n dispatchEnabled,\n };\n\n return (\n <div ref={chatRef} className={styles.chat} style={style}\n data-sidebar={sidebarCollapsed ? 'collapsed' : 'open'} data-dock={dockColumn ? 'open' : 'closed'}>\n <Suspense fallback={<SidebarSkeleton />}>\n <Sidebar sessions={sessions} sessionsStatus={sessionsQuery.status} sessionsError={sessionsQuery.error?.message ?? null}\n projects={projects} seats={seats} selectedId={selectedId} query={query} onQuery={setQuery}\n onSelect={selectFromList} onNew={() => openNewChat()}\n onRetry={() => { refetchSessions(); refetchBootstrap(); }}\n onCollapse={() => setVerseSidebarCollapsed(true)} onDisconnect={() => { void clearReadSession(); }}\n activity={chatActivity.activity} meta={chatActivity.meta} metaError={chatActivity.metaError} localSeen={chatActivity.localSeen} actions={actions} />\n </Suspense>\n {sidebarCollapsed ? null : <ChatResizer side=\"sidebar\" label=\"Resize chat list\" className={styles.resize} />}\n {/* At phone width the sidebar floats over the transcript; the scrim dismisses it. */}\n <button type=\"button\" className={styles.scrim} aria-label=\"Close chat list\" tabIndex={-1}\n onClick={() => setVerseSidebarCollapsed(true)} />\n <div className={styles.main}>\n {bootstrap.status === 'error' && !bootstrap.data ? (\n <div role=\"alert\" className={styles.banner}>\n <span>{bootstrap.error?.message ?? 'Could not load Verse.'}</span>\n <button type=\"button\" onClick={refetchBootstrap}>Retry</button>\n </div>\n ) : dispatchOff ? (\n <div role=\"status\" className={styles.bannerWarn}>\n Read-only: this server was started without dispatch. Run <code>ashlr verse</code> to send messages.\n </div>\n ) : null}\n <Suspense fallback={<WorkspaceSkeleton />}>\n <Workspace view={view} seats={seats} projects={projects} dispatchEnabled={dispatchEnabled} locked={!hold.hasHold}\n hasAnySessions={sessions.length > 0} onSend={send} onStop={() => stop()}\n onRename={(title) => (selectedId ? renameChat(selectedId, title) : Promise.resolve(false))}\n onRequestDelete={() => { if (selectedId) requestDelete(selectedId); }}\n onSeatChange={changeSeat} onNew={() => openNewChat()} onRetry={() => setReload((n) => n + 1)}\n sidebarCollapsed={sidebarCollapsed} onToggleSidebar={() => setVerseSidebarCollapsed(!sidebarCollapsed)}\n onOpenSession={setSelectedId}\n handoffOpen={handoffFor !== null && handoffFor === selectedId}\n onHandoffOpenChange={(open) => setHandoffFor(open ? selectedId : null)}\n otherRunning={otherRunning} />\n </Suspense>\n </div>\n {dockOpen ? (\n <Suspense fallback={null}>\n <DockHost presentation={presentation} windowWidth={windowWidth} columnWidth={dockWidth} session={view.session} seats={seats}\n events={view.events} roots={roots.roots} rootsData={roots.data} rootsError={roots.error} turnFiles={turnFiles}\n otherRunning={otherRunning} dispatchEnabled={dispatchEnabled} onOpenSession={setSelectedId}\n onHandoff={(id) => setHandoffFor(id)}\n // Accounts & capacity live in Apps & Accounts (C6) since 3.10.\n onOpenAccounts={() => setVerseSection('apps')}\n onSendToChat={(text) => { if (!selectedId || !insertIntoComposer(selectedId, text)) toast.show('Open a chat to send this to it.', 'neutral'); }}\n onAddToMessage={(text) => { if (!selectedId || !insertIntoComposer(selectedId, text)) toast.show('Open a chat to add this to its message.', 'neutral'); }} />\n </Suspense>\n ) : null}\n\n {newChat.open ? (\n <Suspense fallback={null}>\n <NewChatDialog open onClose={() => setNewChat({ open: false })} projects={projects} seats={seats} workspaces={workspaces}\n initialProjectPath={newChat.projectPath ?? null} initialSeat={newChat.seat ?? null} busy={creating} error={createError} onCreate={create}\n // The dialog's one write of its own (a seat's default context mode)\n // goes through the same token guard as every other chat mutation.\n runMutation={withToken} />\n </Suspense>\n ) : null}\n {/* Closed dialogs render nothing, so a not-yet-loaded one (fallback null) looks the same. */}\n <Suspense fallback={null}>\n <DeleteChatDialog target={deleteTarget} onClose={() => setDeleteTarget(null)} onDelete={removeChat}\n actionsClassName={styles.dialogActions} />\n <MutationTokenDialog open={tokenPrompt.open} reason={tokenPrompt.reason} tokenLabel=\"Mutation token\"\n tokenHelp=\"the mutation token ashlr verse printed\"\n onClose={() => {\n setTokenPrompt({ open: false, reason: '' });\n // The dialog calls onClose before onUnlocked on submit, so only treat\n // this as a dismissal if nothing has claimed the pending action by\n // the next tick.\n const pending = pendingAction.current;\n if (!pending) return;\n setTimeout(() => {\n if (pendingAction.current === pending) {\n pendingAction.current = null;\n pending.cancel();\n }\n }, 0);\n }}\n onUnlocked={() => {\n const pending = pendingAction.current;\n pendingAction.current = null;\n pending?.run();\n }} />\n </Suspense>\n </div>\n );\n}\n"],"file":"ChatSection-C9myY4ei.js"}
|
|
1
|
+
{"version":3,"mappings":";quBAqBM,EAAY,IAAI,IAGtB,SAAgB,GAAyB,EAAmB,EAAsC,CAEhG,OADA,EAAU,IAAI,EAAW,CAAM,MAClB,CACP,EAAU,IAAI,CAAS,IAAM,GAAQ,EAAU,OAAO,CAAS,CACrE,CACF,CAGA,SAAgB,GAAgB,EAAiB,EAAsB,CACrE,IAAM,EAAW,EAAK,QAAQ,OAAQ,EAAE,EAExC,OADK,EAAQ,KAAK,EACX,GAAG,EAAQ,QAAQ,OAAQ,EAAE,EAAE,MAAM,IADhB,CAE9B,CAGA,SAAS,EAAgB,EAAmB,SAAsC,CAChF,IAAM,EAAO,EAAK,cAAc,gCAAgC,EAChE,OAAO,aAAgB,oBAAsB,EAAO,IACtD,CAOA,SAAgB,GAAmB,EAAmB,EAAuB,CAC3E,GAAI,CAAC,EAAK,KAAK,EAAG,MAAO,GACzB,IAAM,EAAa,EAAU,IAAI,CAAS,EAC1C,GAAI,EAEF,OADA,EAAW,CAAI,EACR,GAET,IAAM,EAAM,EAAgB,EAC5B,GAAI,CAAC,GAAO,EAAI,SAAU,MAAO,GACjC,IAAM,EAAO,GAAgB,EAAI,MAAO,CAAI,EACtC,EAAS,OAAO,yBAAyB,oBAAoB,UAAW,OAAO,CAAC,EAAE,IACpF,EAAQ,EAAO,KAAK,EAAK,CAAI,EAC5B,EAAI,MAAQ,EACjB,EAAI,cAAc,IAAI,MAAM,QAAS,CAAE,QAAS,EAAK,CAAC,CAAC,EACvD,EAAI,MAAM,EACV,IAAM,EAAM,EAAI,MAAM,OACtB,GAAI,CACF,EAAI,kBAAkB,EAAK,CAAG,CAChC,MAAQ,CAER,CACA,MAAO,EACT,CCpDA,SAAgB,EAAgB,EAA2B,CACzD,MAAO,uBAAuB,GAChC,CAEA,IAAM,GAAyD,CAC7D,IAAK,2BACL,MAAO,SAAY,IACrB,EAYA,SAAgB,GAAY,EAA4E,CAEtG,OADK,EACE,CAAC,EAAQ,YAAa,IAAI,EAAQ,YAAc,CAAC,GAAG,OAAQ,GAAM,IAAM,EAAQ,WAAW,CAAC,EAD9E,CAAC,CAExB,CAEA,SAAgB,GAAgB,EAAyG,CACvI,IAAM,EAAY,GAAS,IAAM,KAC3B,KAAM,eACH,EACH,CAAE,IAAK,EAAgB,CAAS,EAAG,MAAQ,GAAW,GAAuB,EAAW,CAAM,CAAE,EAChG,GACJ,CAAC,CAAS,CACZ,EACM,EAAQ,EAAS,CAAG,EACpB,EAAU,EAAW,CAAG,EAIxB,EAAY,GAAS,WAAa,EAClC,KAAO,UAA6C,CAAE,GAAI,EAAW,MAAO,CAAU,CAAC,GAC7F,mBAAgB,CACd,IAAM,EAAO,EAAK,QAClB,EAAK,QAAU,CAAE,GAAI,EAAW,MAAO,CAAU,EAC7C,EAAK,KAAO,GAAa,EAAK,QAAU,GAAa,GAAW,EAAQ,CAC9E,EAAG,CAAC,EAAW,EAAW,CAAO,CAAC,EAIlC,IAAM,EAAM,EAAM,MAAQ,KACpB,EAAO,IAAQ,MAAQ,MAAM,QAAQ,EAAI,KAAK,EAAI,EAAM,KACxD,KAAa,eAAc,GAAY,CAAO,EAAG,CAAC,GAAS,YAAa,GAAS,UAAU,CAAC,EAC5F,KAAQ,eAAc,CAC1B,GAAI,CAAC,GAAQ,EAAK,MAAM,SAAW,EAAG,OAAO,EAC7C,IAAM,EAAU,EAAK,MAAM,OAAQ,GAAM,EAAE,OAAO,CAAC,CAAC,IAAK,GAAM,EAAE,IAAI,EAC/D,EAAO,EAAK,MAAM,OAAQ,GAAM,CAAC,EAAE,OAAO,CAAC,CAAC,IAAK,GAAM,EAAE,IAAI,EACnE,MAAO,CAAC,GAAG,EAAS,GAAG,CAAI,CAC7B,EAAG,CAAC,EAAM,CAAU,CAAC,EACf,EAAU,GAAM,MAAM,KAAM,GAAM,EAAE,OAAO,GAAK,GAAM,MAAM,IAAM,KACxE,MAAO,CACL,OACA,MAAO,EAAM,SAAW,QAAU,EAAM,OAAO,SAAW,qCAAuC,KACjG,QACA,OAAQ,GAAS,KAAK,QAAU,IAClC,CACF,CCrEA,IAAM,EAAY,IAAI,IAEtB,SAAgB,EAAiB,EAAoC,CAEnE,OADA,EAAU,IAAI,CAAQ,MACT,EAAU,OAAO,CAAQ,CACxC,CAGA,SAAgB,EAAsB,EAA2B,CAC/D,IAAI,EAAU,GACd,IAAK,IAAM,IAAY,CAAC,GAAG,CAAS,EAAO,EAAS,CAAQ,IAAG,EAAU,IACzE,OAAO,CACT,CAGA,IAAM,EAAgB,IAAI,IAE1B,SAAgB,EAAiB,EAAqC,CAEpE,OADA,EAAc,IAAI,CAAQ,MACb,EAAc,OAAO,CAAQ,CAC5C,CAEA,SAAgB,IAAiC,CAC/C,IAAI,EAAU,GACd,IAAK,IAAM,IAAY,CAAC,GAAG,CAAa,EAAO,EAAS,IAAG,EAAU,IACrE,OAAO,CACT,CAGA,IAAM,EAAgB,IAAI,IAE1B,SAAgB,GAAiB,EAAkD,CAEjF,OADA,EAAc,IAAI,CAAQ,MACb,EAAc,OAAO,CAAQ,CAC5C,CAEA,SAAgB,GAAsB,EAAwB,CAC5D,IAAI,EAAU,GACd,IAAK,IAAM,IAAY,CAAC,GAAG,CAAa,EAAO,EAAS,CAAK,IAAG,EAAU,IAC1E,OAAO,CACT,WCSa,EAA+C,CA/B1D,eACA,eACA,aACA,oBACA,WACA,WACA,cACA,QACA,YACA,QACA,YAEA,aACA,UAIA,iBACA,oBACA,WACA,SAEA,YACA,mBAQ0D,EAE5D,SAAS,EAAU,EAAyB,CAC1C,OAAO,KAAK,IAAI,IAAO,GAAK,EAAS,IAAM,CAC7C,CAEA,IAAM,EAAiB,GAAwB,IAAM,MAAS,OAAO,GAAM,UAAY,OAAO,SAAS,CAAC,GAAK,GAAK,EAOlH,SAAS,GAAe,EAAqC,CAU3D,OATI,EAAE,OAAS,UACN,OAAO,EAAE,eAAkB,UAAY,OAAO,SAAS,EAAE,aAAa,GAAK,EAAE,eAAiB,GACnG,OAAO,EAAE,OAAU,WAAa,EAAc,EAAE,aAAa,IAC5D,EAAE,gBAAkB,QAAa,EAAc,EAAE,aAAa,GAE/D,EAAE,OAAS,eACL,EAAE,UAAY,QAAU,EAAE,UAAY,WAC5C,EAAc,EAAE,SAAS,GAAK,EAAc,EAAE,UAAU,GAAK,EAAc,EAAE,UAAU,CAG7F,CAEA,IAAM,EAAiB,GAAwB,IAAM,QAAc,OAAO,GAAM,UAAY,OAAO,SAAS,CAAC,GAAK,GAAK,EAMvH,SAAS,GAAgB,EAAqC,CAC5D,OAAQ,EAAE,KAAV,CACE,IAAK,iBACH,OAAO,OAAO,EAAE,MAAS,SAC3B,IAAK,oBACH,OAAO,EAAE,kBAAoB,QAAa,EAAc,EAAE,eAAe,EAC3E,IAAK,WACH,OAAQ,EAAE,QAAU,YAAc,EAAE,QAAU,QAAU,EAAE,QAAU,WAAa,EAAE,QAAU,YAC3F,OAAO,EAAE,WAAc,UAAY,OAAO,SAAS,EAAE,SAAS,GAAK,EAAE,WAAa,IACjF,EAAE,OAAS,QAAa,OAAO,EAAE,MAAS,WAC3C,EAAc,EAAE,SAAS,GAAK,EAAc,EAAE,SAAS,EAC3D,IAAK,SACH,OAAQ,EAAE,OAAS,SAAW,EAAE,OAAS,aAAe,EAAE,OAAS,aAAe,OAAO,EAAE,SAAY,SACzG,IAAK,oBACH,OAAO,OAAO,EAAE,eAAkB,UAAY,OAAO,SAAS,EAAE,aAAa,EAC/E,QACE,MAAO,EACX,CACF,CAGA,SAAgB,GAAqB,EAAgC,CACnE,GAAI,CACF,IAAM,EAAS,KAAK,MAAM,CAAG,EAC7B,GAAI,CAAC,GAAU,OAAO,GAAW,SAAU,OAAO,KAClD,IAAM,EAAY,EAIlB,OAHI,OAAO,EAAU,KAAQ,UAAY,OAAO,EAAU,MAAS,UAC/D,CAAC,GAAe,CAAiC,GACjD,CAAC,GAAgB,CAAiC,EAAU,KACzD,CACT,MAAQ,CACN,OAAO,IACT,CACF,CAGA,IAAa,GAAoB,iBAQjC,SAAgB,GAAmB,EAAa,GAAc,CAE5D,MAAO,eADQ,EAAa,UAAU,GAAkB,GAAK,GAChC,SAAS,mBAAmB,EAAmB,CAAC,GAC/E,CAWA,IAAI,GAAgB,GAWpB,SAAgB,IAAmC,CACjD,IAAI,EAA6B,KAC7B,EAA8C,KAC9C,EAAU,EACV,EAAW,GAEX,EAAU,GAER,MAAgB,CAEpB,GADI,GAAY,OAAO,YAAgB,KACnC,EAAgB,CAAC,CAAC,QAAU,gBAAiB,OACjD,IAAM,EAAa,CAAC,IAAiB,CAAC,EAChC,EAAK,IAAI,YAAY,GAAmB,CAAU,EAAG,CAAE,gBAAiB,EAAK,CAAC,EAChF,EAAS,GACb,EAAS,EACT,EAAG,WAAe,CAChB,EAAS,GACT,EAAU,EACV,CAEE,IADA,GAAgB,GACN,GAEd,EACA,EAAG,iBAAiB,qBAAwB,EAAqB,CAAC,EAClE,EAAG,YAAgB,CACjB,KAAG,MAAM,EACL,IAAW,IAAI,EAAS,MACxB,KAAY,EAAgB,CAAC,CAAC,QAAU,iBAC5C,IAAI,CAAC,GAAU,EAAY,CAKzB,EAAU,GACV,EAAQ,EACR,MACF,CACA,EAAU,GACV,EAAQ,eAAiB,CACvB,EAAQ,KACR,GAAW,EACX,EAAQ,CACV,EAAG,EAAU,CAAO,CAAC,CANrB,CAOF,CACF,EAIA,OAFA,EAAQ,MAEK,CACX,EAAW,GACP,GAAO,aAAa,CAAK,EAC7B,EAAQ,KACR,GAAQ,MAAM,EACd,EAAS,IACX,CACF,CClKA,IAAa,GAAgB,IAIvB,GAAoB,IAQ1B,SAAgB,GAAsB,EAAmB,EAAuB,CAC9E,IAAM,EAAS,OAAO,cAAc,CAAK,GAAK,EAAQ,EAAI,SAAS,EAAM,GAAK,GAC9E,MAAO,GAAG,GAAiB,EAAW,SAAS,EAAE,GAAG,EAAO,SAAS,mBAAmB,EAAmB,CAAC,GAC7G,CAEA,SAAS,GAAU,EAAyB,CAC1C,OAAO,KAAK,IAAI,IAAO,GAAK,EAAS,IAAM,CAC7C,CAeA,SAAS,IAA4B,CACnC,OAAQ,WAAsD,2BAA6B,EAC7F,CAEA,IAAM,GAA2C,GAAU,CACzD,IAAI,EAAO,GACL,MAAY,CACZ,IACJ,EAAO,GACH,IAAQ,MAAQ,OAAO,sBAAyB,YAAY,qBAAqB,CAAG,EACxF,aAAa,CAAK,EAClB,EAAM,EACR,EAEM,GADS,OAAO,SAAa,KAAe,SAAS,kBAAoB,WACxD,OAAO,uBAA0B,WAAa,sBAAsB,CAAG,EAAI,KAC5F,EAAQ,WAAW,EAAK,IAAQ,KAAO,EAAI,EAAiB,EAClE,UAAa,CACX,EAAO,GACH,IAAQ,MAAQ,OAAO,sBAAyB,YAAY,qBAAqB,CAAG,EACxF,aAAa,CAAK,CACpB,CACF,EAaA,SAAS,GAAc,EAAwC,CAM7D,OAJI,GAAiB,GACnB,EAAM,EACC,MAEF,GAAwB,CAAK,CACtC,CAMA,IAAM,GAAN,KAAiB,CAKc,UAJ7B,MAA8B,CAAC,EAC/B,OAAsC,KACtC,UAAoB,GAEpB,YAAY,EAAoC,CAAnB,gBAAoB,CAEjD,KAAK,EAAyB,CAE5B,GADA,KAAK,MAAM,KAAK,CAAK,EACjB,KAAK,UAAW,OACpB,KAAK,UAAY,GACjB,IAAM,EAAS,OAAoB,KAAK,MAAM,CAAC,EAE3C,KAAK,YAAW,KAAK,OAAS,EACpC,CAGA,OAAc,CAIZ,GAHA,KAAK,UAAY,GACjB,KAAK,SAAS,EACd,KAAK,OAAS,KACV,KAAK,MAAM,SAAW,EAAG,OAC7B,IAAM,EAAQ,KAAK,MACnB,KAAK,MAAQ,CAAC,EACC,GAAiB,KAAK,UAAW,CAC5C,EAAO,SAAS,EAAqB,CAC3C,CAEA,MAAa,CACX,KAAK,UAAY,GACjB,KAAK,SAAS,EACd,KAAK,OAAS,KACd,KAAK,MAAQ,CAAC,CAChB,CACF,EAqBI,EAAe,GAQb,EAAgB,EAEtB,SAAS,GAAoB,EAA+B,CAC1D,IAAI,EAA6B,KAC7B,EAA8C,KAC9C,EAAU,EACV,EAAW,GAEX,EAAU,GACR,EAAQ,IAAI,GAAW,CAAS,EAEhC,MAAgB,CAEpB,GADI,GAAY,OAAO,YAAgB,KACnC,EAAgB,CAAC,CAAC,QAAU,gBAAiB,OACjD,EAAoB,EAAW,IAAY,EAAI,aAAe,cAAc,EAG5E,IAAM,EAAS,GAAgB,EAAU,EAAI,GAAqB,CAAS,CAAC,CAAC,QACvE,EAAK,IAAI,YAAY,GAAsB,EAAW,CAAM,EAAG,CAAE,gBAAiB,EAAK,CAAC,EAC1F,EAAS,GACb,EAAS,EACT,EAAG,WAAe,CAChB,EAAS,GACT,EAAU,EACV,CAEE,IADA,EAAe,GACL,IAEZ,EAAoB,EAAW,MAAM,CACvC,EACA,IAAK,IAAM,KAAQ,EACjB,EAAG,iBAAiB,EAAO,GAAQ,CACjC,GAAI,IAAW,EAAI,OACnB,IAAM,EAAQ,GAAsB,EAA6B,IAAI,EACjE,GAAO,EAAM,KAAK,CAAK,CAC7B,CAAC,EAEH,EAAG,QAAW,GAAQ,CAMhB,YAAO,aAAiB,KAAe,aAAe,gBAE1D,EAAM,MAAM,EACR,IAMJ,IAAI,OAAO,EAAG,YAAe,UAAY,EAAG,aAAe,EAAe,CACxE,EAAoB,EAAW,cAAc,EAC7C,MACF,CACA,KAAG,MAAM,EACL,IAAW,IAAI,EAAS,MAC5B,EAAoB,EAAW,cAAc,EACzC,EAAgB,CAAC,CAAC,QAAU,gBAChC,IAAI,CAAC,GAAU,EAAS,GAAK,CAAC,EAAS,CAGrC,EAAU,GACV,EAAQ,EACR,MACF,CACA,EAAU,GACV,EAAQ,eAAiB,CACvB,EAAQ,KACR,GAAW,EACX,EAAQ,CACV,EAAG,GAAU,CAAO,CAAC,CANrB,CAXA,CAkBF,CACF,EAEM,MAAiB,CACjB,GAAO,aAAa,CAAK,EAC7B,EAAQ,KACR,GAAQ,MAAM,EACd,EAAS,IACX,EAIA,OAFA,EAAQ,EAED,CACL,OAAQ,CACF,IACJ,EAAW,GACX,EAAS,EAGT,EAAM,MAAM,EACZ,EAAM,KAAK,EACX,EAAoB,EAAW,QAAQ,EACzC,EACA,SAAU,CACJ,IACJ,EAAS,EACT,EAAM,MAAM,EACZ,EAAU,EACV,EAAQ,EACV,CACF,CACF,CAcA,IAAM,EAAW,IAAI,IAErB,SAAS,EAAW,EAAyB,CAC3C,IAAM,EAAQ,EAAS,IAAI,CAAS,EAC/B,IACL,EAAS,OAAO,CAAS,EACrB,EAAM,WAAW,aAAa,EAAM,SAAS,EACjD,EAAM,OAAO,MAAM,EACrB,CAEA,SAAS,IAAkB,CACzB,IAAM,EAAO,CAAC,GAAG,EAAS,QAAQ,CAAC,CAAC,CAAC,QAAQ,EAAG,KAAO,EAAE,OAAS,CAAC,CAAC,CAAC,MAAM,EAAG,IAAM,EAAE,EAAE,CAAC,WAAa,EAAE,EAAE,CAAC,UAAU,EACrH,KAAO,EAAK,UAA2B,EAAW,EAAK,MAAM,CAAC,CAAE,EAAE,CACpE,CAMA,SAAgB,GAA0B,EAA+B,CACvE,IAAI,EAAQ,EAAS,IAAI,CAAS,EAC9B,GACF,EAAM,MAAQ,EACV,EAAM,WAAW,aAAa,EAAM,SAAS,EACjD,EAAM,UAAY,OAElB,EAAQ,CAAE,OAAQ,GAAoB,CAAS,EAAG,KAAM,EAAG,UAAW,KAAM,WAAY,CAAE,EAC1F,EAAS,IAAI,EAAW,CAAK,GAE/B,IAAM,EAAO,EACT,EAAW,GACf,UAAa,CACP,IACJ,EAAW,GACP,EAAS,IAAI,CAAS,IAAM,IAChC,IAAK,KACD,IAAK,KAAO,KAChB,EAAK,WAAa,KAAK,IAAI,EAC3B,EAAK,UAAY,eAAiB,CAC5B,EAAS,IAAI,CAAS,IAAM,GAAQ,EAAK,OAAS,GAAG,EAAW,CAAS,CAC/E,EAAG,EAAa,EAChB,GAAU,IACZ,CACF,CAGA,SAAgB,IAAoC,CAClD,IAAK,IAAM,IAAM,CAAC,GAAG,EAAS,KAAK,CAAC,EAAG,EAAW,CAAE,CACtD,CASA,GAA8B,GAAU,CAClC,EAAM,OAAS,QAAS,GAA4B,EACnD,EAAW,EAAM,SAAS,CACjC,CAAC,EAqBD,SAAgB,GAAiB,EAAmB,EAAmC,CAAC,EAAe,CACrG,IAAM,EAAa,IAAI,gBACnB,EAA+B,KAC/B,EAAW,GAET,MAAe,CACf,GAAY,IAChB,EAAU,GAA0B,CAAS,EAC/C,EAEM,EAAQ,GAAqB,CAAS,EAmB5C,OAlBkB,EAAQ,SAAW,IAAS,EAAM,QAAU,EAAM,YAAc,KAGhF,EAAO,GAEH,EAAQ,QAAQ,EAAS,IAAI,CAAS,CAAC,EAAE,OAAO,QAAQ,EAC5D,EAA6B,EAAW,EAAW,MAAM,CAAC,CACvD,KAAM,GAAW,CACZ,EAAW,OAAO,UACtB,GAAiB,EAAW,EAAO,QAAS,EAAO,MAAM,EACzD,EAAO,EACT,CAAC,CAAC,CACD,MAAO,GAAiB,CACnB,EAAW,OAAO,SACtB,GAAkB,EAAW,aAAe,MAAQ,EAAI,QAAU,2BAA2B,CAC/F,CAAC,OAGQ,CACX,EAAW,GACX,EAAW,MAAM,EACjB,IAAU,EACV,EAAU,IACZ,CACF,CCvYA,IAAM,UAAmB,CAAC,EAE1B,SAAgB,EAAuB,EAA0B,CAC/D,SAAO,eACJ,GAA0B,EAAY,GAAsB,EAAW,CAAQ,EAAI,EAAK,EACzF,CAAC,CAAS,CACZ,CACF,CAMA,SAAgB,GAAgB,EAA0B,EAAS,EAAqB,CACtF,IAAM,EAAY,EAAuB,CAAS,EAC5C,KAAO,wBACX,MACM,EAAoB,CAAS,MAC7B,EAAoB,CAAS,CACrC,EAKM,KAAa,UAAqD,CAAE,UAAW,KAAM,QAAO,CAAC,EAQnG,OAPA,mBAAgB,CACd,IAAM,EAAW,EAAW,QAC5B,KAAW,QAAU,CAAE,YAAW,QAAO,EACpC,EACL,OAAO,GAAiB,EAAW,CAAE,OAAQ,EAAS,YAAc,GAAa,EAAS,SAAW,CAAO,CAAC,CAC/G,EAAG,CAAC,EAAW,CAAM,CAAC,EAEf,CACT,CAGA,SAAgB,EAAa,EAA0C,CACrE,IAAM,EAAY,EAAuB,CAAS,EAClD,SAAO,wBACL,MACM,GAAa,CAAS,MACtB,GAAa,CAAS,CAC9B,CACF,CC7DA,IAAa,GAAwB,IAIjC,EAAO,IAAI,IACT,GAAgB,IAAI,IAE1B,SAAS,GAAc,EAAkC,CAEvD,OADA,GAAc,IAAI,CAAQ,MACb,GAAc,OAAO,CAAQ,CAC5C,CAEA,SAAS,IAAuC,CAC9C,OAAO,CACT,CAGA,SAAgB,GAAgB,EAAmB,EAAyB,CAC1E,MAAK,EAAK,IAAI,CAAS,GAAK,KAAO,GACnC,GAAO,IAAI,IAAI,CAAI,CAAC,CAAC,IAAI,EAAW,CAAS,EAC7C,IAAK,IAAM,IAAY,CAAC,GAAG,EAAa,EAAG,EAAS,EACpD,GAA0B,EAAW,CAAS,CAFD,CAG/C,CAQA,SAAgB,IAA4C,CAC1D,SAAO,wBAAqB,GAAe,GAAS,EAAO,CAC7D,CAIA,SAAgB,IAAkB,CAChC,IAAM,EAAW,EAAS,EAAoB,CAAE,QAAS,IAA4B,CAAC,EAChF,EAAO,EAAS,EAAqB,EACrC,EAAkB,EAAW,CAAkB,EAC/C,KAAO,mBAAkB,EAAgB,EAAG,CAAC,CAAe,CAAC,EACnE,GAAoB,EAAM,EAAqB,EAC/C,IAAM,EAAY,GAAa,EAC/B,MAAO,CAEL,SAAU,EAAS,MAAQ,KAC3B,KAAM,EAAK,MAAQ,KAMnB,UAAW,EAAK,SAAW,QAAU,EAAkB,EAAK,KAAK,EAAI,KACrE,WACF,CACF,CC1CA,IAAa,EAAqE,CAChF,QAAS,CAAE,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,EACxC,UAAW,CAAE,IAAK,IAAK,IAAK,IAAK,IAAK,GAAI,CAC5C,EAYM,GAAW,EAMJ,GAAwB,wBAO/B,GAAmB,oBAqBZ,GAA4B,CACvC,eAAgB,EAChB,eAAgB,GAChB,iBAAkB,EACpB,EAcA,SAAgB,EAAgB,EAAqB,EAAwB,CAC3E,IAAM,EAAQ,EAAkB,GAC1B,EAAI,OAAO,CAAK,EAEtB,MADI,CAAC,OAAO,SAAS,CAAC,GAAK,GAAK,EAAU,EAAM,IACzC,KAAK,IAAI,EAAM,IAAK,KAAK,IAAI,EAAM,IAAK,KAAK,MAAM,CAAC,CAAC,CAAC,CAC/D,CAYA,SAAgB,GAAc,EAAyB,EAAoC,CACzF,IAAI,EAAU,EAAgB,UAAW,EAAO,OAAO,EACnD,EAAY,EAAgB,YAAa,EAAO,SAAS,EAC7D,GAAI,CAAC,OAAO,SAAS,EAAI,cAAc,GAAK,EAAI,gBAAkB,EAAG,MAAO,CAAE,UAAS,WAAU,EAEjG,IAAM,GAAa,EAAI,eAAiB,GAAW,IAAM,EAAI,iBAAmB,GAAW,GACrF,EAAS,EAAI,mBAAwC,EAEvD,GADW,EAAI,eAAiB,EAAU,IAAM,EAAI,iBAAmB,EAAY,GACpE,EACnB,GAAI,GAAQ,EAAG,MAAO,CAAE,UAAS,WAAU,EAE3C,GAAI,EAAI,iBAAkB,CACxB,IAAM,EAAO,KAAK,IAAI,EAAM,EAAY,EAAkB,UAAU,GAAG,EACvE,GAAa,EACb,GAAQ,CACV,CACA,GAAI,EAAO,GAAK,EAAI,eAAgB,CAClC,IAAM,EAAO,KAAK,IAAI,EAAM,EAAU,EAAkB,QAAQ,GAAG,EACnE,GAAW,CACb,CACA,MAAO,CAAE,UAAS,WAAU,CAC9B,CAMA,SAAgB,IAA0C,CACxD,MAAO,CAAE,QAAS,EAAkB,QAAQ,IAAK,UAAW,EAAkB,UAAU,GAAI,CAC9F,CAGA,SAAgB,GAAqB,EAA4C,CAC/E,GAAI,IAAQ,MAAQ,IAAQ,GAAI,OAAO,KACvC,IAAI,EACJ,GAAI,CACF,EAAS,KAAK,MAAM,CAAG,CACzB,MAAQ,CACN,OAAO,IACT,CACA,GAAI,CAAC,GAAU,OAAO,GAAW,UAAY,MAAM,QAAQ,CAAM,EAAG,OAAO,KAC3E,IAAM,EAAS,EAET,EAAU,EAAO,SAAW,EAAO,aACnC,EAAY,EAAO,WAAa,EAAO,eAE7C,OADI,IAAY,QAAa,IAAc,OAAkB,KACtD,CACL,QAAS,EAAgB,UAAW,CAAO,EAC3C,UAAW,EAAgB,YAAa,CAAS,CACnD,CACF,CAEA,SAAgB,IAAuC,CACrD,GAAI,CAIF,OAHY,GAAqB,aAAa,QAAQ,EAAqB,CACvE,IAEG,GAAqB,aAAa,QAAQ,EAAgB,CAAC,GAAK,GAAuB,EAChG,MAAQ,CACN,OAAO,GAAuB,CAChC,CACF,CAEA,SAAgB,GAAqB,EAA+B,CAClE,GAAI,CACF,aAAa,QAAQ,GAAuB,KAAK,UAAU,CACzD,QAAS,EAAO,QAChB,UAAW,EAAO,SACpB,CAAC,CAAC,CACJ,MAAQ,CAER,CACF,CAMA,IAAI,EAA2B,GAAoB,EAC/C,EAAoB,GACpB,EAA4B,CAAE,UAAS,UAAW,GAAc,EAAS,CAAG,CAAE,EAC5E,GAAY,IAAI,IAEtB,SAAS,GAAW,EAAoB,EAA6B,CACnE,OAAO,EAAE,UAAY,EAAE,SAAW,EAAE,YAAc,EAAE,SACtD,CAGA,SAAS,IAAgB,CACvB,IAAM,EAAY,GAAc,EAAS,CAAG,EACxC,QAAW,EAAS,QAAS,CAAO,GAAK,GAAW,EAAS,UAAW,CAAS,GACrF,GAAW,CAAE,UAAS,WAAU,EAChC,IAAK,IAAM,KAAY,GAAW,EAAS,CADX,CAElC,CAEA,SAAgB,GAAoB,EAAkC,CAEpE,OADA,GAAU,IAAI,CAAQ,MACT,CACX,GAAU,OAAO,CAAQ,CAC3B,CACF,CAEA,SAAgB,IAAsC,CACpD,OAAO,CACT,CAOA,SAAgB,GAAgB,EAA0B,EAEtD,EAAI,iBAAmB,EAAK,gBACzB,EAAI,iBAAmB,EAAK,gBAC5B,EAAI,mBAAqB,EAAK,oBAEnC,EAAM,EACN,GAAQ,EACV,CAEA,SAAS,GAAO,EAA6B,CACvC,GAAW,EAAS,CAAI,IAC5B,EAAU,EACV,GAAqB,CAAO,EAC5B,GAAQ,EACV,CAGA,SAAgB,EAAkB,EAAqB,EAAqB,CAC1E,GAAO,CAAE,GAAG,GAAU,GAAO,EAAgB,EAAM,CAAK,CAAE,CAAC,CAC7D,CAMA,SAAgB,GAAoB,EAAqB,EAAqB,CAC5E,EAAkB,EAAM,EAAS,UAAU,GAAQ,CAAK,CAC1D,CAGA,SAAgB,GAAoB,EAA2B,CAC7D,EAAkB,EAAM,EAAkB,EAAK,CAAC,GAAG,CACrD,CC/NA,SAAgB,IAAsC,CACpD,SAAO,wBAAqB,GAAqB,GAAoB,EAAkB,CACzF,CAOA,IAAM,GAAY,gBAElB,SAAS,GAAS,EAAmB,CACnC,GAAI,CACE,EAAI,SAAS,KAAK,QAAQ,IAAa,OACtC,OAAO,SAAS,KAAK,QAAQ,GACpC,MAAQ,CAER,CACF,CAeA,SAAgB,GAAY,CAAE,OAAM,QAAO,aAA+B,CACxE,IAAM,EAAS,GAAmB,EAC5B,EAAQ,EAAkB,GAC1B,EAAQ,EAAO,UAAU,GACzB,KAAO,UAAyB,IAAI,EACpC,CAAC,EAAU,MAAe,YAAS,EAAK,EAGxC,KAAU,mBAAkB,CAC3B,EAAK,UACV,EAAK,QAAU,KACf,EAAY,EAAK,EACjB,GAAS,EAAK,EAChB,EAAG,CAAC,CAAC,EAEC,KAAgB,eAAa,GAAwC,CAGrE,KAAM,SAAW,EAIrB,CAHA,EAAM,eAAe,EACrB,EAAK,QAAU,CAAE,UAAW,EAAM,UAAW,QAAS,EAAM,QAAS,WAAY,CAAM,EACvF,EAAY,EAAI,EAChB,GAAS,EAAI,EAGb,GAAI,CACF,EAAM,cAAc,oBAAoB,EAAM,SAAS,CACzD,MAAQ,CAER,CAPa,CAQf,EAAG,CAAC,CAAK,CAAC,GAKV,mBAAgB,CACd,GAAI,CAAC,EAAU,OAEf,IAAM,EAAU,GAAmC,CACjD,IAAM,EAAQ,EAAK,QACnB,GAAI,CAAC,GAAS,EAAM,YAAc,EAAM,UAAW,OACnD,IAAM,EAAQ,EAAM,QAAU,EAAM,QAEpC,EAAkB,EAAM,IAAS,UAAY,EAAM,WAAa,EAAQ,EAAM,WAAa,CAAK,CAClG,EACM,EAAS,GAAmC,CAChD,IAAM,EAAQ,EAAK,QACf,GAAS,EAAM,YAAc,EAAM,WACvC,EAAQ,CACV,EAEM,EAAS,GAAoC,CACjD,IAAM,EAAQ,EAAK,QACd,GAAS,EAAM,MAAQ,WAC5B,EAAkB,EAAM,EAAM,UAAU,EACxC,EAAQ,EACV,EAGM,MAAe,EAAQ,EAO7B,OALA,OAAO,iBAAiB,cAAe,CAAM,EAC7C,OAAO,iBAAiB,YAAa,CAAK,EAC1C,OAAO,iBAAiB,gBAAiB,CAAK,EAC9C,OAAO,iBAAiB,UAAW,CAAK,EACxC,OAAO,iBAAiB,OAAQ,CAAM,MACzB,CACX,OAAO,oBAAoB,cAAe,CAAM,EAChD,OAAO,oBAAoB,YAAa,CAAK,EAC7C,OAAO,oBAAoB,gBAAiB,CAAK,EACjD,OAAO,oBAAoB,UAAW,CAAK,EAC3C,OAAO,oBAAoB,OAAQ,CAAM,EACzC,GAAS,EAAK,CAChB,CACF,EAAG,CAAC,EAAU,EAAM,CAAO,CAAC,EAE5B,IAAM,KAAY,eAAa,GAAyC,CACtE,IAAM,EAAO,EAAM,eAGb,EAAS,IAAS,UAAY,EAAI,GACxC,OAAQ,EAAM,IAAd,CACE,IAAK,aACH,GAAoB,EAAM,EAAO,CAAM,EACvC,MACF,IAAK,YACH,GAAoB,EAAM,CAAC,EAAO,CAAM,EACxC,MACF,IAAK,OACH,EAAkB,EAAM,EAAM,GAAG,EACjC,MACF,IAAK,MACH,EAAkB,EAAM,EAAM,GAAG,EACjC,MACF,IAAK,QACH,GAAoB,CAAI,EACxB,MACF,QACE,MACJ,CACA,EAAM,eAAe,CACvB,EAAG,CAAC,EAAM,EAAM,IAAK,EAAM,GAAG,CAAC,EAE/B,OACE,SAAC,MAAD,CACa,YACX,qBAAoB,EACpB,gBAAe,EAAW,OAAS,OACnC,KAAK,YACL,mBAAiB,WACjB,aAAY,EACZ,gBAAe,EAAM,IACrB,gBAAe,EAAM,IACrB,gBAAe,EACf,iBAAgB,GAAG,EAAM,SACzB,SAAU,EACK,gBACf,YAAa,EACb,gBAAiB,EACjB,qBAAsB,EACX,YAIX,kBAAqB,GAAoB,CAAI,CAC9C,EAEL,yfCnHM,MAAW,kBAAW,OAAO,yBAAsB,CAAC,KAAM,IAAO,CAAE,QAAS,EAAE,QAAS,EAAE,6HAAC,EAC1F,MAAgB,kBAAW,OAAO,8BAAsB,CAAC,KAAM,IAAO,CAAE,QAAS,EAAE,aAAc,EAAE,0GAAC,EAEpG,GAAkB,YAA+D,OAAO,0BAAkB,CAAC,KAAM,GAAM,EAAE,SAAS,6JAAC,EACnI,GAAY,GAAgB,KAC5B,GAAgB,YAA6D,OAAO,wBAAgB,CAAC,KAAM,GAAM,EAAE,OAAO,oGAAC,EAC3H,GAAU,GAAc,KASxB,GAAqB,YAAsE,OAAO,iCAA8B,CAAC,KAAM,GAAM,EAAE,gBAAgB,qCAAC,EAChK,GAAmB,GAAmB,KACtC,GAAoB,YAClB,OAAO,oCAAkD,cAAC,KAAM,GAAM,EAAE,mBAAmB,oCACnG,EACM,GAAsB,GAAkB,KASxC,GAAc,MAAsB,QAAQ,IAAI,OAAC,OAAO,8EAA2B,OAAO,wDAAwB,CAAC,CAAC,CACvH,MAAM,CAAC,EAAO,MAAY,CAAE,kBAAmB,EAAM,kBAAmB,cAAe,EAAM,aAAc,EAAE,CAAC,EAE3G,GAAa,YAAsB,OAAO,4BAAoB,cAAC,KAAM,IAAO,CAAE,mBAAoB,EAAE,mBAAoB,SAAU,EAAE,QAAS,EAAE,gCAAC,EAChJ,GAAgC,CAAC,EACjC,GAAkC,CAAC,EAOzC,SAAgB,IAAuC,CACrD,OAAO,QAAQ,IAAI,CACjB,GAAgB,MAAM,EAAG,GAAc,MAAM,EAAG,GAAmB,MAAM,EAAG,GAAkB,MAAM,EAAG,GAAY,MAAM,EAAG,GAAW,MAAM,CAC/I,CAAC,CACH,CAQA,SAAS,IAAkB,CACzB,OACE,SAAC,MAAD,CAAK,UAAW,EAAO,gBAAiB,YAAU,OAAO,aAAW,oBACjE,UAAC,GAAI,GAAI,GAAI,GAAI,EAAE,CAAC,CAAC,IAAK,IAAM,SAAC,EAAD,CAAsB,MAAO,GAAG,EAAE,EAAK,EAApB,CAAoB,CAAC,CACtE,EAET,CAGA,SAAS,IAAoB,CAC3B,OACE,UAAC,MAAD,CAAK,UAAW,EAAO,kBAAmB,KAAK,SAAS,aAAW,eAAnE,WACE,SAAC,MAAD,CAAK,UAAW,EAAO,eAAgB,mBAAC,EAAD,CAAc,MAAM,KAAO,EAAM,IACxE,UAAC,MAAD,CAAK,UAAW,EAAO,aAAvB,WACE,SAAC,EAAD,CAAc,MAAM,KAAO,IAC3B,SAAC,EAAD,CAAc,MAAM,KAAO,IAC3B,SAAC,EAAD,CAAc,MAAM,KAAO,EACxB,KACL,SAAC,MAAD,CAAK,UAAW,EAAO,iBAAkB,mBAAC,EAAD,CAAc,MAAM,MAAQ,EAAM,EACxE,GAET,CAEA,IAAM,GAAe,0BAErB,SAAS,IAA8B,CACrC,GAAI,CACF,OAAO,aAAa,QAAQ,EAAY,CAC1C,MAAQ,CACN,OAAO,IACT,CACF,CAWA,SAAgB,GAAkB,EAAsB,CAYtD,OAXI,aAAe,EAA8B,wEAC7C,aAAe,GACb,EAAI,OAAS,0BAER,IADK,EAAI,QAAU,6CACZ,QAAQ,OAAQ,GAAG,EAAE,uHAEjC,EAAI,SAAW,MAAQ,EAAI,OAAS,MAAQ,EAAI,OAAS,sBAA8B,yDACvF,EAAI,SAAW,IAAY,yCAC3B,EAAI,SAAW,IAAY,gFACxB,EAAI,QAAU,EAAI,QAEpB,aAAe,MAAQ,EAAI,QAAU,uBAC9C,CAGA,SAAS,IAAyB,CAChC,GAAM,CAAC,EAAO,MAAY,gBAAgB,OAAO,OAAW,IAAc,KAAO,OAAO,YAAc,IAAK,EAM3G,OALA,mBAAgB,CACd,IAAM,MAAiB,EAAS,OAAO,YAAc,IAAI,EAEzD,OADA,OAAO,iBAAiB,SAAU,CAAQ,MAC7B,OAAO,oBAAoB,SAAU,CAAQ,CAC5D,EAAG,CAAC,CAAC,EACE,CACT,CAGA,SAAS,IAAsB,CAE7B,0BAA4B,CAE1B,SADqB,cAAmC,gCACxD,GAAK,MAAM,CACb,CAAC,CACH,CAGA,SAAS,GAAU,EAAqC,CACtD,OAAO,aAAkB,SAAW,EAAO,QAAQ,uEAAuE,IAAM,IAClI,CAEA,SAAgB,IAAc,CAC5B,IAAM,EAAY,EAAS,EAAmB,EACxC,EAAgB,EAAS,EAAkB,EAC3C,EAAkB,EAAW,EAAkB,EAC/C,EAAmB,EAAW,EAAmB,EACjD,EAAO,GAAgB,EACvB,EAAQ,GAAS,EACjB,EAAK,GAAW,EAChB,EAAU,GAAkB,EAC5B,EAAO,GAAQ,EACf,EAAe,GAAgB,EAC/B,GAAc,GAAe,EAE7B,CAAC,EAAY,OAAsB,YAAwB,EAAY,EACvE,CAAC,GAAO,MAAY,YAAS,EAAE,EAC/B,CAAC,EAAS,MAAc,YAAmF,CAAE,KAAM,EAAM,CAAC,EAC1H,CAAC,GAAU,MAAe,YAAS,EAAK,EACxC,CAAC,GAAa,MAAkB,YAAwB,IAAI,EAC5D,CAAC,GAAQ,OAAa,YAAS,CAAC,EAChC,CAAC,GAAa,MAAkB,YAA4C,CAAE,KAAM,GAAO,OAAQ,EAAG,CAAC,EACvG,CAAC,GAAY,MAAiB,YAAwB,IAAI,EAC1D,CAAC,GAAc,OAAmB,YAA8B,IAAI,EACpE,CAAC,GAAW,OAAgB,YAAS,CAAC,EACtC,KAAgB,UAAuD,IAAI,EAC3E,MAAU,UAAuB,IAAI,EACrC,GAAS,GAAmB,EAE5B,KAAQ,eAAc,EAAU,MAAM,OAAS,CAAC,EAAG,CAAC,EAAU,IAAI,CAAC,EACnE,KAAW,eAAc,EAAU,MAAM,UAAY,CAAC,EAAG,CAAC,EAAU,IAAI,CAAC,EAEzE,GAAkB,EAAS,EAAoB,EAC/C,MAAa,eAAc,GAAgB,MAAM,YAAc,CAAC,EAAG,CAAC,GAAgB,IAAI,CAAC,EACzF,EAAkB,EAAU,MAAM,iBAAmB,GAErD,EAAO,GAAgB,EAAY,EAAM,EACzC,EAAQ,GAAgB,EAAK,OAAO,EAIpC,KAAW,eAA8B,CAC7C,IAAM,EAAO,EAAc,MAAQ,EAAU,MAAM,UAAY,CAAC,EAChE,GAAI,CAAC,EAAK,QAAS,OAAO,EAC1B,IAAM,EAAO,EAAK,QAClB,OAAO,EAAK,KAAM,GAAM,EAAE,KAAO,EAAK,EAAE,EAAI,EAAK,IAAK,GAAO,EAAE,KAAO,EAAK,GAAK,EAAO,CAAE,EAAI,CAAC,EAAM,GAAG,CAAI,CAC7G,EAAG,CAAC,EAAc,KAAM,EAAU,KAAM,EAAK,OAAO,CAAC,EAE/C,KAAgB,eAAa,GAAsB,CACvD,GAAmB,CAAE,EACrB,GAAI,CACE,EAAI,aAAa,QAAQ,GAAc,CAAE,EACxC,aAAa,WAAW,EAAY,CAC3C,MAAQ,CAER,CACF,EAAG,CAAC,CAAC,GAGL,mBAAgB,CACT,GAAe,EAAc,MAC9B,CAAC,EAAc,KAAK,KAAM,GAAM,EAAE,KAAO,CAAU,GAAK,CAAC,EAAK,SAAS,EAAc,IAAI,CAC/F,EAAG,CAAC,EAAY,EAAc,KAAM,EAAK,QAAS,CAAa,CAAC,GAGhE,mBAAgB,GAAqB,EAAG,CAAC,CAAC,EAQ1C,IAAM,KAAc,UAAO,CAAU,GACrC,mBAAgB,CACd,GAAsB,CAAU,EAC5B,EAAY,UAAY,IAC1B,EAAY,QAAU,EACtB,GAAkB,EAEtB,EAAG,CAAC,CAAU,CAAC,EAGf,IAAM,GAAgB,EAAK,SAAS,WAAa,MACjD,mBAAgB,CACT,GAAY,GAAc,KAAkB,OAC7C,OAAO,SAAa,KAAe,SAAS,kBAAoB,WACpE,GAAgB,EAAY,EAAa,CAC3C,EAAG,CAAC,EAAS,EAAY,EAAa,CAAC,EAGvC,IAAM,KAAY,gBAAiB,EAAgB,IAC7C,EAAK,QAAgB,EAAO,EACzB,IAAI,SAAmB,EAAS,IAAW,CAChD,EAAc,QAAU,CAGtB,QAAW,CAAE,EAAO,CAAC,CAAC,KAAK,EAAS,CAAM,CAAG,EAC7C,WAAc,EAAQ,IAAI,CAC5B,EACA,EAAe,CAAE,KAAM,GAAM,QAAO,CAAC,CACvC,CAAC,EACA,CAAC,EAAK,OAAO,CAAC,EAEX,KAAO,eAAa,GAAiB,CACrC,aAAe,IACnB,EAAM,KAAK,GAAkB,CAAG,EAAG,QAAQ,CAC7C,EAAG,CAAC,CAAK,CAAC,EASJ,KAAc,gBAAa,EAAqE,CAAC,IAAM,CAC3G,EAAe,IAAI,EACnB,IAAM,EAAU,EAAK,QACf,EAAc,EAAQ,cAAgB,OAAkC,GAAS,aAAe,KAA9C,EAAQ,YAE1D,EAAc,GAAW,IAAgB,EAAQ,YACnD,CAAE,OAAQ,EAAQ,OAAQ,MAAO,EAAQ,KAAM,EAC/C,KACE,EAAO,EAAQ,MAAQ,GAAe,GAAc,CAAW,EACrE,EAAW,CAAE,KAAM,GAAM,cAAa,MAAK,CAAC,CAC9C,EAAG,CAAC,EAAK,OAAO,CAAC,EAEX,MAAS,eAAY,KAAO,IAAmC,CACnE,MAAM,EAAU,4DAA6D,SAAY,CACvF,EAAY,EAAI,EAChB,EAAe,IAAI,EACnB,GAAI,CACF,IAAM,EAAU,MAAM,GAAmB,CAAG,EAC5C,GAAkB,EAAQ,YAAa,CAAE,OAAQ,EAAQ,OAAQ,MAAO,EAAQ,KAAM,CAAC,EACvF,GAAgB,EAAQ,GAAI,CAAO,EACnC,EAAW,CAAE,KAAM,EAAM,CAAC,EAC1B,EAAc,EAAQ,EAAE,EACxB,EAAM,KAAK,YAAY,EAAQ,MAAM,GAAI,SAAS,CACpD,OAAS,EAAK,CACZ,EAAe,GAAkB,CAAG,CAAC,CACvC,QAAU,CACR,EAAY,EAAK,CACnB,CACF,CAAC,CACH,EAAG,CAAC,EAAW,EAAe,CAAK,CAAC,EAE9B,KAAO,eAAY,KAAO,IAAiB,CAC/C,IAAM,EAAK,EAgBX,OAfK,EAeE,MAdc,EAAU,yDAA0D,SAAY,CACnG,GAAsB,EAAI,SAAS,EACnC,GAAI,CACF,IAAM,EAAW,MAAM,GAAc,EAAI,CAAI,EAI7C,OADA,GAAgB,EAAI,EAAS,QAAS,EAAS,MAAM,EAC9C,EACT,OAAS,EAAK,CAGZ,OAFA,GAAsB,EAAI,MAAM,EAChC,EAAK,CAAG,EACD,EACT,CACF,CAAC,IACiB,GAfF,EAgBlB,EAAG,CAAC,EAAY,EAAW,CAAI,CAAC,EAE1B,MAAO,gBAAa,EAAoB,IAAe,CACtD,GACL,EAAe,6BAA8B,SAAY,CACvD,GAAI,CACF,MAAM,GAAgB,CAAE,CAC1B,OAAS,EAAK,CACZ,EAAK,CAAG,CACV,CACF,CAAC,CACH,EAAG,CAAC,EAAY,EAAW,CAAI,CAAC,EAE1B,MAAa,eAAY,MAAO,EAAY,IAWzC,MAVc,EAAU,mBAAoB,SAAY,CAC7D,GAAI,CACF,IAAM,EAAU,MAAM,GAAmB,EAAI,CAAK,EAElD,OADA,GAAgB,EAAI,CAAO,EACpB,EACT,OAAS,EAAK,CAEZ,OADA,EAAK,CAAG,EACD,EACT,CACF,CAAC,IACiB,GACjB,CAAC,EAAW,CAAI,CAAC,EAEd,MAAa,eAAY,KAAO,IAgB7B,MAfc,EAAU,oDAAqD,SAAY,CAC9F,GAAI,CAQF,OAPA,MAAM,GAAmB,CAAE,EAC3B,GAAmB,CAAE,EAGrB,EAAqB,CAAE,EACnB,IAAO,GAAY,EAAc,IAAI,EACzC,EAAM,KAAK,gBAAiB,SAAS,EAC9B,EACT,OAAS,EAAK,CAEZ,OADA,EAAK,CAAG,EACD,EACT,CACF,CAAC,IACiB,GACjB,CAAC,EAAW,EAAM,EAAe,EAAO,CAAU,CAAC,EAEhD,MAAU,gBAAa,EAAY,EAAkD,IAAmB,CAC5G,EAAe,EAAQ,SAAY,CACjC,GAAI,CACF,MAAM,GAAoB,EAAI,CAAM,CACtC,OAAS,EAAK,CACZ,EAAK,CAAG,CACV,CACF,CAAC,CACH,EAAG,CAAC,EAAW,CAAI,CAAC,EAGd,MAAa,eAAa,GAAuB,CACrD,IAAM,EAAU,EAAK,QAChB,IACL,EAAY,CAAE,YAAa,EAAQ,YAAa,KAAM,CAAO,CAAC,EAC9D,EAAM,KAAK,yEAA0E,SAAS,EAChG,EAAG,CAAC,EAAK,QAAS,EAAa,CAAK,CAAC,EAE/B,MAAgB,eAAa,GAAe,CAChD,IAAM,EAAS,EAAS,KAAM,GAAM,EAAE,KAAO,CAAE,GAAK,KAChD,GAAQ,GAAgB,CAAM,CACpC,EAAG,CAAC,CAAQ,CAAC,EAEP,MAAe,eAAa,GAAe,CAC3C,IAAO,GAAY,EAAc,CAAE,EACvC,EAAc,CAAE,CAClB,EAAG,CAAC,EAAY,CAAa,CAAC,EAExB,MAAiB,eAAa,GAAe,CACjD,EAAc,CAAE,EAEZ,OAAO,aAAa,oBAAoB,CAAC,EAAE,UAAY,IAAM,EAAyB,EAAI,CAChG,EAAG,CAAC,CAAa,CAAC,EAGZ,MAAgB,mBAAkB,EAAyB,CAAC,EAAG,gBAAgB,EAAG,CAAC,EAAG,gBAAgB,CAAC,EAIvG,GAAgB,EAAK,MAAM,OAAS,EAAK,MAAM,SAAW,YAAc,EAAK,MAAM,YAAc,YACjG,MAAe,mBAAkB,CACjC,GAAe,GAAe,UAAU,EACvC,GAAgB,CAAC,CAAC,CACzB,EAAG,CAAC,EAAa,CAAC,EAEZ,MAAiB,mBAAkB,GAAgB,CAAE,OAAQ,EAAK,CAAC,EAAG,CAAC,CAAC,EAGxE,MAAiB,UAAO,CAAC,EACzB,EAAY,GAAW,UAAU,GACvC,mBAAgB,CACd,IAAM,EAAU,EAAG,QACf,GAAC,GAAW,EAAQ,QAAU,GAAe,UAI7C,EAAQ,OAAS,YAAe,GAEpC,QADA,GAAe,QAAU,EAAQ,MACzB,EAAQ,KAAhB,CACE,IAAK,eACC,EAAQ,WAAW,EAAc,EAAQ,SAAS,EACtD,MACF,IAAK,iBACH,GAAc,EACd,MACF,IAAK,WAAY,CAEf,GAAM,CAAE,WAAU,sBAAuB,EACnC,EAAO,EAAQ,OAAS,EAAS,EAAO,EAAQ,MAAM,EAAI,OAE1D,EAAa,GAAc,EAAQ,aAAe,IAAI,EACtD,EAAS,EAAmB,GAAY,SAAW,EAAK,GAAK,EAAW,MAAQ,EAAmB,CAAI,CAAC,EAAE,GAA1F,OACtB,EAAY,CACV,GAAI,EAAQ,cAAgB,OAAmD,CAAC,EAAxC,CAAE,YAAa,EAAQ,WAAY,EAC3E,GAAI,GAAQ,EAAQ,CAAE,KAAM,CAAE,OAAQ,EAAK,GAAI,OAAM,CAAE,EAAI,CAAC,CAC9D,CAAC,EACD,KACF,CAIF,CACA,GAAkB,CADlB,CAEF,EAAG,CAAC,EAAG,QAAS,EAAa,EAAO,EAAe,CAAS,CAAC,EAc7D,IAAM,EAAa,IAAI,IAAI,CAVzB,CAAC,eAAgB,EAAa,EAC9B,CAAC,gBAAmB,GAAsB,CAAC,EAC3C,CAAC,qBAAwB,GAAsB,EAAE,CAAC,EAClD,CAAC,qBAAwB,GAAsB,CAAC,CAAC,EACjD,CAAC,cAAe,EAAU,EAC1B,CAAC,gBAAiB,EAAY,EAC9B,CAAC,oBAAqB,EAAc,EACpC,CAAC,mBAAsB,GAAe,SAAS,CAAC,EAChD,CAAC,gBAAmB,GAAe,MAAM,CAAC,CAEjB,CAAQ,EACnC,EAAkB,eAAgB,EAAW,IAAI,cAAc,CAAE,EACjE,EAAkB,YAAa,EAAW,IAAI,WAAW,CAAE,EAC3D,EAAkB,iBAAkB,EAAW,IAAI,gBAAgB,CAAE,EACrE,EAAkB,iBAAkB,EAAW,IAAI,gBAAgB,CAAE,EACrE,EAAkB,cAAe,EAAW,IAAI,aAAa,CAAE,EAC/D,EAAkB,gBAAiB,EAAW,IAAI,eAAe,CAAE,EACnE,EAAkB,oBAAqB,EAAW,IAAI,mBAAmB,CAAE,EAC3E,EAAkB,eAAgB,EAAW,IAAI,cAAc,CAAE,EACjE,EAAkB,YAAa,EAAW,IAAI,WAAW,CAAE,EAO3D,IAAM,MAAa,UAAO,CAAU,EACpC,GAAW,QAAU,GACrB,mBAAgB,CACd,GAAI,CAAC,EAAS,OACd,IAAM,EAAS,GAAyB,CACtC,GAAI,EAAM,kBAAoB,GAAU,EAAM,MAAM,EAAG,OACvD,IAAM,EAAU,GAAS,EAAO,CAAC,MAAM,CAAC,EAExC,GADI,CAAC,GAAW,EAAQ,QAAU,QAC9B,EAAQ,KAAO,aAAe,EAAQ,KAAO,kBAAoB,EAAQ,KAAO,iBAAkB,OACtG,IAAM,EAAM,GAAW,QAAQ,IAAI,EAAQ,EAAE,EACxC,IACL,EAAM,eAAe,EACrB,EAAI,EACN,EAEA,OADA,SAAS,iBAAiB,UAAW,CAAK,MAC7B,SAAS,oBAAoB,UAAW,CAAK,CAC5D,EAAG,CAAC,CAAO,CAAC,EAEZ,IAAM,EAAc,EAAU,KAAO,CAAC,EAAU,KAAK,gBAAkB,GACjE,EAAmB,EAAG,iBAGtB,GAAe,GAAiB,EAAW,EAC3C,GAAW,EAAK,MAAM,MAAQ,EAAK,MAAM,KAAK,OAAS,EACvD,GAAa,IAAY,KAAiB,SAI1C,GAAe,EAAmB,EAAI,EAAkB,QAAQ,IAChE,EAAY,GACd,KAAK,IAAI,GAAY,SAAU,KAAK,IACpC,GAAe,EAAK,MAAM,MAAO,EAAW,EAC5C,GAAY,EAAI,OAAmC,GAAe,GACpE,CAAC,EACC,GAEJ,mBAAgB,CACd,IAAM,EAAO,GAAQ,QACrB,GAAI,CAAC,EAAM,OACX,IAAM,MAAgB,CACpB,GAAa,EAAK,WAAW,EAC7B,GAAgB,CAEd,eAAgB,KAAK,IAAI,EAAG,EAAK,YAAc,CAAS,EACxD,eAAgB,CAAC,EACjB,iBAAkB,EACpB,CAAC,CACH,EACA,EAAQ,EACR,IAAM,EAAW,OAAO,gBAAmB,WAAa,IAAI,eAAe,CAAO,EAAI,KAGtF,OAFA,GAAU,QAAQ,CAAI,EACtB,OAAO,iBAAiB,SAAU,CAAO,MAC5B,CACX,GAAU,WAAW,EACrB,OAAO,oBAAoB,SAAU,CAAO,CAC9C,CACF,EAAG,CAAC,EAAkB,CAAS,CAAC,EAEhC,IAAM,EAAQ,CACZ,wBAAyB,GAAG,GAAO,UAAU,QAAQ,IACrD,qBAAsB,GAAG,EAAU,GACrC,EAGM,EAAS,GAAY,UAAU,EAC/B,MAAe,eACZ,EAAS,EAAO,kBAAkB,EAAU,EAAa,SAAU,CAAU,EAAI,GACxF,CAAC,EAAQ,EAAU,EAAa,SAAU,CAAU,CACtD,EACM,KAAY,eACT,EAAS,EAAO,cAAc,EAAK,OAAQ,EAAM,KAAK,EAAI,GACjE,CAAC,EAAQ,EAAM,MAAO,EAAK,MAAM,CACnC,EAEM,GAA6B,CACjC,WAAY,EAAI,IAAW,GAAQ,EAAI,CAAE,QAAO,EAAG,EAAS,kBAAoB,mBAAmB,EACnG,aAAc,EAAI,IAAa,GAAQ,EAAI,CAAE,UAAS,EAAG,EAAW,oBAAsB,qBAAqB,EAC/G,OAAQ,GACR,QAAS,GACT,iBACA,iBACF,EAEA,OACE,UAAC,MAAD,CAAK,IAAK,GAAS,UAAW,EAAO,KAAa,QAChD,eAAc,EAAmB,YAAc,OAAQ,YAAW,GAAa,OAAS,SAD1F,WAEE,SAAC,WAAD,CAAU,UAAU,SAAC,GAAD,CAAkB,GACtC,mBAAC,GAAD,CAAmB,WAAU,eAAgB,EAAc,OAAQ,cAAe,EAAc,OAAO,SAAW,KACtG,WAAiB,QAAmB,aAAmB,SAAO,QAAS,EACjF,SAAU,GAAgB,UAAa,EAAY,EACnD,YAAe,CAAE,EAAgB,EAAG,EAAiB,CAAG,EACxD,eAAkB,EAAyB,EAAI,EAAG,iBAAoB,CAAE,EAAsB,CAAG,EACjG,SAAU,EAAa,SAAU,KAAM,EAAa,KAAM,UAAW,EAAa,UAAW,UAAW,EAAa,UAAoB,UAAU,EAC3I,GACT,EAAmB,MAAO,SAAC,GAAD,CAAa,KAAK,UAAU,MAAM,mBAAmB,UAAW,EAAO,MAAS,IAE3G,SAAC,SAAD,CAAQ,KAAK,SAAS,UAAW,EAAO,MAAO,aAAW,kBAAkB,SAAU,GACpF,YAAe,EAAyB,EAAI,CAAI,IAClD,UAAC,MAAD,CAAK,UAAW,EAAO,KAAvB,UACG,EAAU,SAAW,SAAW,CAAC,EAAU,MAC1C,UAAC,MAAD,CAAK,KAAK,QAAQ,UAAW,EAAO,OAApC,WACE,SAAC,OAAD,UAAO,EAAU,OAAO,SAAW,uBAA8B,IACjE,SAAC,SAAD,CAAQ,KAAK,SAAS,QAAS,EAAkB,gBAAa,EAC3D,CACH,MACF,UAAC,MAAD,CAAK,KAAK,SAAS,UAAW,EAAO,WAArC,UAAiD,6DACU,SAAC,OAAD,UAAM,aAAiB,GAAC,oBAC9E,CACH,SACJ,SAAC,WAAD,CAAU,UAAU,SAAC,GAAD,CAAoB,GACxC,mBAAC,GAAD,CAAiB,OAAa,QAAiB,WAA2B,kBAAiB,OAAQ,CAAC,EAAK,QACvG,eAAgB,EAAS,OAAS,EAAG,OAAQ,EAAM,WAAc,GAAK,EACtE,SAAW,GAAW,EAAa,GAAW,EAAY,CAAK,EAAI,QAAQ,QAAQ,EAAK,EACxF,oBAAuB,CAAM,GAAY,GAAc,CAAU,CAAG,EACpE,aAAc,GAAY,UAAa,EAAY,EAAG,YAAe,GAAW,GAAM,EAAI,CAAC,EACzE,mBAAkB,oBAAuB,EAAyB,CAAC,CAAgB,EACrG,cAAe,EACf,YAAa,KAAe,MAAQ,KAAe,EACnD,oBAAsB,GAAS,EAAc,EAAO,EAAa,IAAI,EACvD,eAAe,EACrB,EACP,IACJ,IACC,SAAC,WAAD,CAAU,SAAU,KAClB,mBAAC,GAAD,CAAwB,gBAA2B,eAAa,YAAa,EAAW,QAAS,EAAK,QAAgB,QACpH,OAAQ,EAAK,OAAQ,MAAO,EAAM,MAAO,UAAW,EAAM,KAAM,WAAY,EAAM,MAAkB,YACtF,gBAA+B,kBAAiB,cAAe,EAC7E,UAAY,GAAO,EAAc,CAAE,EAEnC,mBAAsB,GAAgB,MAAM,EAC5C,aAAe,GAAS,EAAM,CAAC,GAAc,CAAC,GAAmB,EAAY,CAAI,IAAG,EAAM,KAAK,kCAAmC,SAAS,CAAG,EAC9I,eAAiB,GAAS,EAAM,CAAC,GAAc,CAAC,GAAmB,EAAY,CAAI,IAAG,EAAM,KAAK,0CAA2C,SAAS,CAAG,CAAI,EACtJ,GACR,KAEH,EAAQ,MACP,SAAC,WAAD,CAAU,SAAU,KAClB,mBAAC,GAAD,CAAe,QAAK,YAAe,EAAW,CAAE,KAAM,EAAM,CAAC,EAAa,WAAiB,QAAmB,cAC5G,mBAAoB,EAAQ,aAAe,KAAM,YAAa,EAAQ,MAAQ,KAAM,KAAM,GAAU,MAAO,GAAa,SAAU,GAGlI,YAAa,CAAY,EACnB,GACR,MAEJ,UAAC,WAAD,CAAU,SAAU,KAApB,WACA,SAAC,GAAD,CAAkB,OAAQ,GAAc,YAAe,GAAgB,IAAI,EAAG,SAAU,GACtF,iBAAkB,EAAO,aAAgB,IAC3C,SAAC,GAAD,CAAqB,KAAM,GAAY,KAAM,OAAQ,GAAY,OAAQ,WAAW,iBAClF,UAAU,yCACV,YAAe,CACb,EAAe,CAAE,KAAM,GAAO,OAAQ,EAAG,CAAC,EAI1C,IAAM,EAAU,EAAc,QACzB,GACL,eAAiB,CACX,EAAc,UAAY,IAC5B,EAAc,QAAU,KACxB,EAAQ,OAAO,EAEnB,EAAG,CAAC,CACN,EACA,eAAkB,CAChB,IAAM,EAAU,EAAc,QAC9B,EAAc,QAAU,KACxB,GAAS,IAAI,CACf,CAAI,EACI,GACP,GAET","names":[],"ignoreList":[],"sources":["../../../../../../src/web-ui/routes/verse/chat/composer-bridge.ts","../../../../../../src/web-ui/routes/verse/chat/use-session-roots.ts","../../../../../../src/web-ui/routes/verse/chat/transcript-jump.ts","../../../../../../src/web-ui/routes/verse/verse-events.ts","../../../../../../src/web-ui/routes/verse/session-stream.ts","../../../../../../src/web-ui/routes/verse/useVerseSession.ts","../../../../../../src/web-ui/routes/verse/chat/use-chat-activity.ts","../../../../../../src/web-ui/routes/verse/chat-panel-sizing.ts","../../../../../../src/web-ui/routes/verse/ChatResizer.tsx","../../../../../../src/web-ui/routes/verse/sections/ChatSection.tsx"],"sourcesContent":["/**\n * routes/verse/chat/composer-bridge.ts — how the chat's other surfaces put\n * text INTO the composer without sending it (unit C2).\n *\n * Three dock actions draft into the message box and leave the send to the\n * operator (the first spend is always their press):\n * - Terminal ▸ \"Send selection to chat\" — the selection as a fenced block;\n * - Review ▸ \"Add to message\" — `path:line: note`;\n * - anything later that \"drafts a follow-up\".\n *\n * The composer is C3's component and owns its text state. The clean seam is\n * for it to register an inserter here (`registerComposerInserter`) — that is\n * a cross-unit request. Until it does, the fallback types into the composer's\n * textarea the way a paste would: the native value setter plus an `input`\n * event, which React's controlled textarea treats as the operator's own\n * edit (so its draft persistence, cost hint and undo stack all see it).\n * Either way the text is APPENDED on its own paragraph and never sent.\n */\n\nexport type ComposerInserter = (text: string) => void;\n\nconst inserters = new Map<string, ComposerInserter>();\n\n/** C3: `useEffect(() => registerComposerInserter(sessionId, insert), [sessionId])`. Returns the unregister. */\nexport function registerComposerInserter(sessionId: string, insert: ComposerInserter): () => void {\n inserters.set(sessionId, insert);\n return () => {\n if (inserters.get(sessionId) === insert) inserters.delete(sessionId);\n };\n}\n\n/** Join an insertion onto existing text: its own paragraph, never glued to a half-typed word. */\nexport function appendParagraph(current: string, text: string): string {\n const addition = text.replace(/\\s+$/, '');\n if (!current.trim()) return addition;\n return `${current.replace(/\\s+$/, '')}\\n\\n${addition}`;\n}\n\n/** The composer's message box in the chat surface (C3's `aria-label=\"Message\"`). */\nfunction findComposerBox(root: ParentNode = document): HTMLTextAreaElement | null {\n const node = root.querySelector('textarea[aria-label=\"Message\"]');\n return node instanceof HTMLTextAreaElement ? node : null;\n}\n\n/**\n * Append `text` to `sessionId`'s composer and focus it. False when there is\n * no composer to write into (no chat open, or it is disabled) — the caller\n * then says so rather than dropping the text silently.\n */\nexport function insertIntoComposer(sessionId: string, text: string): boolean {\n if (!text.trim()) return false;\n const registered = inserters.get(sessionId);\n if (registered) {\n registered(text);\n return true;\n }\n const box = findComposerBox();\n if (!box || box.disabled) return false;\n const next = appendParagraph(box.value, text);\n const setter = Object.getOwnPropertyDescriptor(HTMLTextAreaElement.prototype, 'value')?.set;\n if (setter) setter.call(box, next);\n else box.value = next;\n box.dispatchEvent(new Event('input', { bubbles: true }));\n box.focus();\n const end = box.value.length;\n try {\n box.setSelectionRange(end, end);\n } catch {\n /* a detached or hidden box has no selection; the text is in either way */\n }\n return true;\n}\n","/**\n * routes/verse/chat/use-session-roots.ts — one read of a chat's roots for\n * everything that needs them (unit C2): the header's `repo › branch`\n * breadcrumb, the Context pane's Folders list, and the roots handed to the\n * Branch bar, Terminal, Preview and Review slots.\n *\n * Before 3.10 only SessionRoots read `/sessions/:id/roots`, fetching on its\n * own. With four consumers that would be four requests per chat switch (each\n * one `git status` per root on the server), so the read goes through the\n * shared query cache under one key per chat. A branch goes stale the moment\n * a turn commits, so the read is refreshed whenever the chat's turnCount\n * moves — exactly as SessionRoots' `refreshKey` did.\n */\nimport { useEffect, useMemo, useRef } from 'react';\nimport type { VerseSession, VerseSessionRootsResponse } from '../../../data/api-types.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport type { QueryDef } from '../../../data/queries.js';\nimport { fetchVerseSessionRoots } from '../verse-queries.js';\n\nexport function sessionRootsKey(sessionId: string): string {\n return `verse-session-roots:${sessionId}`;\n}\n\nconst NO_SESSION: QueryDef<VerseSessionRootsResponse | null> = {\n key: 'verse-session-roots:none',\n fetch: async () => null,\n};\n\nexport interface SessionRootsView {\n data: VerseSessionRootsResponse | null;\n error: string | null;\n /** Roots in priority order: the primary first, then the pinned extras. Known before the read lands. */\n roots: readonly string[];\n /** The primary root's branch, when it is a git repo and the read landed. */\n branch: string | null;\n}\n\n/** Roots as the session RECORD states them — usable before (and without) the status read. */\nexport function recordRoots(session: Pick<VerseSession, 'projectPath' | 'extraRoots'> | null): string[] {\n if (!session) return [];\n return [session.projectPath, ...(session.extraRoots ?? []).filter((r) => r !== session.projectPath)];\n}\n\nexport function useSessionRoots(session: Pick<VerseSession, 'id' | 'projectPath' | 'extraRoots' | 'turnCount'> | null): SessionRootsView {\n const sessionId = session?.id ?? null;\n const def = useMemo<QueryDef<VerseSessionRootsResponse | null>>(\n () => (sessionId\n ? { key: sessionRootsKey(sessionId), fetch: (signal) => fetchVerseSessionRoots(sessionId, signal) }\n : NO_SESSION),\n [sessionId],\n );\n const query = useQuery(def);\n const refetch = useRefetch(def);\n\n // A finished turn may have committed or switched branch: re-read. The\n // first value for a chat is the mount's own fetch, not a change.\n const turnCount = session?.turnCount ?? 0;\n const seen = useRef<{ id: string | null; turns: number }>({ id: sessionId, turns: turnCount });\n useEffect(() => {\n const prev = seen.current;\n seen.current = { id: sessionId, turns: turnCount };\n if (prev.id === sessionId && prev.turns !== turnCount && sessionId) refetch();\n }, [sessionId, turnCount, refetch]);\n\n // A reply without a roots list (an older server, a stub) is treated as no\n // reading at all rather than trusted into a crash.\n const raw = query.data ?? null;\n const data = raw !== null && Array.isArray(raw.roots) ? raw : null;\n const fromRecord = useMemo(() => recordRoots(session), [session?.projectPath, session?.extraRoots]); // eslint-disable-line react-hooks/exhaustive-deps -- the two fields ARE the dependency\n const roots = useMemo(() => {\n if (!data || data.roots.length === 0) return fromRecord;\n const primary = data.roots.filter((r) => r.primary).map((r) => r.path);\n const rest = data.roots.filter((r) => !r.primary).map((r) => r.path);\n return [...primary, ...rest];\n }, [data, fromRecord]);\n const primary = data?.roots.find((r) => r.primary) ?? data?.roots[0] ?? null;\n return {\n data,\n error: query.status === 'error' ? query.error?.message ?? 'could not read this chat’s folders' : null,\n roots,\n branch: primary?.git?.branch ?? null,\n };\n}\n","/**\n * routes/verse/chat/transcript-jump.ts — \"scroll the open transcript to this\n * tool call\", from outside the transcript (unit C2).\n *\n * The dock's Tasks pane lists this turn's calls and a click must land on\n * the call in the transcript — but the pane is a different subtree (and, as\n * a sheet, a different layer). The mounted Transcript subscribes here and\n * performs the jump with its own machinery (opening a folded activity group,\n * the locator flash, focus). A tiny module, so the dock does not import the\n * transcript.\n */\ntype JumpListener = (anchorId: string) => boolean;\n\nconst listeners = new Set<JumpListener>();\n\nexport function onTranscriptJump(listener: JumpListener): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\n/** True when a mounted transcript took the jump. */\nexport function requestTranscriptJump(anchorId: string): boolean {\n let handled = false;\n for (const listener of [...listeners]) if (listener(anchorId)) handled = true;\n return handled;\n}\n\n// ⌘F from the palette (\"Find in chat\"): focus the transcript's own search.\nconst findListeners = new Set<() => boolean>();\n\nexport function onTranscriptFind(listener: () => boolean): () => void {\n findListeners.add(listener);\n return () => findListeners.delete(listener);\n}\n\nexport function requestTranscriptFind(): boolean {\n let handled = false;\n for (const listener of [...findListeners]) if (listener()) handled = true;\n return handled;\n}\n\n// ⌥↑ / ⌥↓ routed through the command bus (palette, native menu).\nconst stepListeners = new Set<(delta: 1 | -1) => boolean>();\n\nexport function onTranscriptStep(listener: (delta: 1 | -1) => boolean): () => void {\n stepListeners.add(listener);\n return () => stepListeners.delete(listener);\n}\n\nexport function requestTranscriptStep(delta: 1 | -1): boolean {\n let handled = false;\n for (const listener of [...stepListeners]) if (listener(delta)) handled = true;\n return handled;\n}\n","/**\n * routes/verse/verse-events.ts — the Verse console's SSE vocabulary and its\n * sidebar channel, since scoped consoles never join data/sse.ts's global feed:\n *\n * - VERSE_EVENT_TYPES + parseVerseEventFrame: every VerseEvent name a\n * session stream can carry, and the frame validation both streams share.\n * The per-session stream itself (resume by `?after=`, one store update\n * per animation frame, ref-counted connections) lives in\n * session-stream.ts (V3.10); the replay-from-zero opener that used to sit\n * here had no callers left and was removed.\n * - openVerseListChannel: one EventSource against /api/events for the\n * `verse-sessions` list digest, which just invalidates the sidebar's\n * cache keys. It subscribes with `?topics=verse-sessions` (V3.10) so the\n * server skips the dashboard snapshot and the other groups this console\n * would only discard.\n *\n * Every URL carries the per-tab client proof as `?client=` — the same\n * construction data/client.ts's eventsUrl() uses, because EventSource cannot\n * send the proof as a header (see read-session.ts readSessionClientProof).\n */\nimport type { VerseEvent, VerseEventType } from '../../data/api-types.js';\nimport { getAuthSnapshot, getReadClientProof } from '../../data/auth-store.js';\nimport { invalidateVerseLists } from './verse-queries.js';\n\n/**\n * Every VerseEvent name the stream can carry. EventSource only dispatches\n * NAMED events to listeners registered by name, so a type missing here is\n * silently dropped — the check below turns a new union member into a compile\n * error in this file instead of a meter that never moves.\n */\nconst EVENT_TYPES = [\n 'user-message',\n 'turn-started',\n 'text-delta',\n 'assistant-message',\n 'thinking',\n 'tool-use',\n 'tool-result',\n 'usage',\n 'turn-done',\n 'error',\n 'cancelled',\n // V3.9 — a server that predates them simply never sends these names.\n 'compaction',\n 'context',\n // V3.10 transient (SSE only, never replayed — see VERSE_TRANSIENT_EVENT_TYPES\n // in core/verse/types.ts). They carry the last PERSISTED seq, so a store that\n // dedupes by seq and does not know them yet simply drops them.\n 'thinking-delta',\n 'thinking-progress',\n 'progress',\n 'status',\n // V3.10 persisted.\n 'recovered',\n 'history-truncated',\n] as const satisfies readonly VerseEventType[];\n\ntype UnlistedEventType = Exclude<VerseEventType, (typeof EVENT_TYPES)[number]>;\n// Fails to compile when VerseEventType gains a member EVENT_TYPES does not list.\nconst EVENT_TYPES_EXHAUSTIVE: [UnlistedEventType] extends [never] ? true : never = true;\nvoid EVENT_TYPES_EXHAUSTIVE;\n\nexport const VERSE_EVENT_TYPES: readonly VerseEventType[] = EVENT_TYPES;\n\nfunction backoffMs(attempt: number): number {\n return Math.min(1000 * 2 ** attempt, 15_000);\n}\n\nconst nullableCount = (v: unknown): boolean => v === null || (typeof v === 'number' && Number.isFinite(v) && v >= 0);\n\n/**\n * The two V3.9 frames feed arithmetic (the meter, the compaction count), so a\n * malformed one is dropped here rather than turning the meter into `NaN`.\n * Older event types keep the original seq/type-only check.\n */\nfunction v39FieldsValid(e: Record<string, unknown>): boolean {\n if (e.type === 'context') {\n return typeof e.contextTokens === 'number' && Number.isFinite(e.contextTokens) && e.contextTokens >= 0 &&\n typeof e.exact === 'boolean' && nullableCount(e.contextWindow) &&\n (e.autoCompactAt === undefined || nullableCount(e.autoCompactAt));\n }\n if (e.type === 'compaction') {\n return (e.trigger === 'auto' || e.trigger === 'manual') &&\n nullableCount(e.preTokens) && nullableCount(e.postTokens) && nullableCount(e.durationMs);\n }\n return true;\n}\n\nconst optionalCount = (v: unknown): boolean => v === undefined || (typeof v === 'number' && Number.isFinite(v) && v >= 0);\n\n/**\n * V3.10 frames that feed arithmetic or a live label (elapsed, tok/s, token\n * estimate) — same rule as v39FieldsValid: malformed → dropped, never NaN.\n */\nfunction v310FieldsValid(e: Record<string, unknown>): boolean {\n switch (e.type) {\n case 'thinking-delta':\n return typeof e.text === 'string';\n case 'thinking-progress':\n return e.estimatedTokens !== undefined && optionalCount(e.estimatedTokens);\n case 'progress':\n return (e.phase === 'thinking' || e.phase === 'tool' || e.phase === 'writing' || e.phase === 'waiting') &&\n typeof e.elapsedMs === 'number' && Number.isFinite(e.elapsedMs) && e.elapsedMs >= 0 &&\n (e.tool === undefined || typeof e.tool === 'string') &&\n optionalCount(e.outTokens) && optionalCount(e.tokPerSec);\n case 'status':\n return (e.kind === 'retry' || e.kind === 'preflight' || e.kind === 'watchdog') && typeof e.message === 'string';\n case 'history-truncated':\n return typeof e.droppedBefore === 'number' && Number.isFinite(e.droppedBefore);\n default:\n return true;\n }\n}\n\n/** Exported for tests: one SSE frame's data → a VerseEvent, or null when malformed. */\nexport function parseVerseEventFrame(raw: string): VerseEvent | null {\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== 'object') return null;\n const candidate = parsed as Partial<VerseEvent>;\n if (typeof candidate.seq !== 'number' || typeof candidate.type !== 'string') return null;\n if (!v39FieldsValid(parsed as Record<string, unknown>)) return null;\n if (!v310FieldsValid(parsed as Record<string, unknown>)) return null;\n return parsed as VerseEvent;\n } catch {\n return null;\n }\n}\n\n/** The only /api/events group the Verse console listens to. */\nexport const VERSE_LIST_TOPICS = 'verse-sessions';\n\n/**\n * The sidebar channel's URL. `topics` narrows the server to the one group\n * this console listens to; `client` stays last, as in eventsUrl(). Without\n * `topics` the server sends every group — the historical request, which is\n * also what the refusal fallback below falls back to.\n */\nexport function verseListEventsUrl(withTopics = true): string {\n const topics = withTopics ? `topics=${VERSE_LIST_TOPICS}&` : '';\n return `/api/events?${topics}client=${encodeURIComponent(getReadClientProof())}`;\n}\n\n/**\n * Set once this page has PROVEN that the server refuses `?topics=`: a\n * connection with it failed before it ever opened, and the same channel\n * without it then opened. The read-session boundary on SSE paths used to\n * answer 401 to any parameter besides `client`, and a sidebar that never\n * updates is far worse than one that is sent (and discards) extra groups.\n * Page-lifetime only — the same rule session-stream.ts applies to `?after=`:\n * a server that gains support is used again after a reload.\n */\nlet topicsRefused = false;\n\n/** Tests: forget a proven refusal. */\nexport function resetVerseListChannelCapabilities(): void {\n topicsRefused = false;\n}\n\n/**\n * Sidebar digest channel: listens only for `verse-sessions` on /api/events\n * and refreshes the session list + bootstrap when it fires.\n */\nexport function openVerseListChannel(): () => void {\n let source: EventSource | null = null;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let attempt = 0;\n let disposed = false;\n /** This connection is the no-`topics` retry that tests whether `topics` was refused. */\n let probing = false;\n\n const connect = () => {\n if (disposed || typeof EventSource === 'undefined') return;\n if (getAuthSnapshot().phase !== 'authenticated') return;\n const withTopics = !topicsRefused && !probing;\n const es = new EventSource(verseListEventsUrl(withTopics), { withCredentials: true });\n let opened = false;\n source = es;\n es.onopen = () => {\n opened = true;\n attempt = 0;\n if (probing) {\n topicsRefused = true;\n probing = false;\n }\n };\n es.addEventListener('verse-sessions', () => invalidateVerseLists());\n es.onerror = () => {\n es.close();\n if (source === es) source = null;\n if (disposed || getAuthSnapshot().phase !== 'authenticated') return;\n if (!opened && withTopics) {\n // Refused before it opened, with `topics`: find out at once whether\n // the parameter is what was refused (see topicsRefused). One probe,\n // no delay — a real outage fails the probe too and falls through to\n // the ordinary backoff below.\n probing = true;\n connect();\n return;\n }\n probing = false;\n timer = setTimeout(() => {\n timer = null;\n attempt += 1;\n connect();\n }, backoffMs(attempt));\n };\n };\n\n connect();\n\n return () => {\n disposed = true;\n if (timer) clearTimeout(timer);\n timer = null;\n source?.close();\n source = null;\n };\n}\n","/**\n * routes/verse/session-stream.ts — the client data path for ONE open chat\n * (V3.10): load it once, resume its live stream from where the store left\n * off, batch what streams in to one store update per animation frame, and\n * keep the connection across section switches.\n *\n * WHY THIS EXISTS (measured before 3.10, scratchpad perf/):\n * - opening a chat raced a full detail fetch against an EventSource that\n * replayed the whole log from seq 0, and every replayed frame was applied\n * and rendered on its own — 2.45 s for a 5k-event chat, 17 s for 10k;\n * - every reconnect (at least one per 15-minute read session) replayed the\n * whole log again, because a hand-made EventSource sends no Last-Event-ID;\n * - every replayed `turn-done` refetched the session list and bootstrap;\n * - leaving the Chat section closed the stream, so coming back replayed.\n *\n * THE PATH NOW\n * 1. `openVerseSession(id)` fetches the detail ONCE when the store has not\n * loaded the chat, seeds the store, and only then attaches the stream —\n * so the two never race.\n * 2. The stream URL carries `?after=<lastSeq>` (the highest PERSISTED seq\n * the store holds). The server replays only what is newer; a server that\n * predates `after` replays everything and the store's seq dedupe drops\n * it. A server whose auth boundary REFUSES the extra parameter is\n * detected once and served without it (afterRefused). A dropped\n * connection is left to the browser's own reconnect, which resumes by\n * Last-Event-ID.\n * 3. Frames are queued and applied with ONE `applyVerseEvents` call per\n * animation frame (a timer backs rAF up, since a hidden tab gets none).\n * Transient frames (reasoning deltas, progress) ride the same queue in\n * arrival order.\n * 4. The session list is invalidated only when a batch really settled a\n * turn — never for a replayed duplicate.\n * 5. Streams are ref-counted. When the last user lets go (section switch,\n * another chat selected) the connection lingers for IDLE_CLOSE_MS so\n * switching back is instant and costs no replay; at most MAX_IDLE\n * lingering connections are kept, because they share the server's SSE\n * connection cap with /api/events.\n *\n * Auth: every URL carries the per-tab client proof as `?client=` (EventSource\n * cannot send it as a header — see server.ts readSessionClientProof), and a\n * stream never reconnects once the read session is gone.\n */\nimport type { VerseEvent } from '../../data/api-types.js';\nimport { getAuthSnapshot, getReadClientProof } from '../../data/auth-store.js';\nimport { parseVerseEventFrame, VERSE_EVENT_TYPES } from './verse-events.js';\nimport { fetchVerseSessionDetail, invalidateVerseLists, verseSessionPath } from './verse-queries.js';\nimport {\n applyVerseEvents,\n getVerseSessionState,\n seedVerseSession,\n setVerseLoadError,\n setVerseStreamState,\n subscribeVerseStoreLifecycle,\n} from './verse-store.js';\n\n/** How long a released stream stays connected before it is closed. */\nexport const IDLE_CLOSE_MS = 90_000;\n/** Released-but-lingering streams kept at once (they count against the server's SSE cap). */\nexport const MAX_IDLE_STREAMS = 1;\n/** Fallback flush when requestAnimationFrame does not fire (hidden tab, occluded window). */\nconst FRAME_FALLBACK_MS = 250;\n\n/**\n * Per-session stream URL: `?after=<cursor>&client=<proof>`. `after` is\n * omitted for cursor 0 — seqs start at 1, so \"after 0\" and \"from the start\"\n * are the same request, and the bare form is what a server without `after`\n * support has always seen.\n */\nexport function verseSessionStreamUrl(sessionId: string, after: number): string {\n const cursor = Number.isSafeInteger(after) && after > 0 ? `after=${after}&` : '';\n return `${verseSessionPath(sessionId, '/events')}?${cursor}client=${encodeURIComponent(getReadClientProof())}`;\n}\n\nfunction backoffMs(attempt: number): number {\n return Math.min(1000 * 2 ** attempt, 15_000);\n}\n\n// ---------------------------------------------------------------------------\n// Frame scheduling\n// ---------------------------------------------------------------------------\n\ntype FrameScheduler = (flush: () => void) => () => void;\n\n/**\n * True inside a React `act()` test environment. There, `act()` is the test\n * declaring \"everything this block causes must be visible after it\", and a\n * frame-deferred flush would land after the assertions — so frames are\n * applied as they arrive, exactly as React applies its own scheduled work\n * inside act. Production never sets the flag.\n */\nfunction inActEnvironment(): boolean {\n return (globalThis as { IS_REACT_ACT_ENVIRONMENT?: unknown }).IS_REACT_ACT_ENVIRONMENT === true;\n}\n\nconst animationFrameScheduler: FrameScheduler = (flush) => {\n let done = false;\n const run = () => {\n if (done) return;\n done = true;\n if (raf !== null && typeof cancelAnimationFrame === 'function') cancelAnimationFrame(raf);\n clearTimeout(timer);\n flush();\n };\n const hidden = typeof document !== 'undefined' && document.visibilityState === 'hidden';\n const raf = !hidden && typeof requestAnimationFrame === 'function' ? requestAnimationFrame(run) : null;\n const timer = setTimeout(run, raf === null ? 0 : FRAME_FALLBACK_MS);\n return () => {\n done = true;\n if (raf !== null && typeof cancelAnimationFrame === 'function') cancelAnimationFrame(raf);\n clearTimeout(timer);\n };\n};\n\nlet customScheduler: FrameScheduler | null = null;\n\n/**\n * Tests: replace the frame scheduler (null restores the default). A scheduler\n * that never calls `flush` lets a test assert what is queued; calling it\n * later simulates the frame.\n */\nexport function setVerseFrameScheduler(scheduler: FrameScheduler | null): void {\n customScheduler = scheduler;\n}\n\nfunction scheduleFrame(flush: () => void): (() => void) | null {\n if (customScheduler) return customScheduler(flush);\n if (inActEnvironment()) {\n flush();\n return null;\n }\n return animationFrameScheduler(flush);\n}\n\n/**\n * Collects frames for one session and applies them once per frame. Returns\n * whether the flushed batch settled a turn, for the list invalidation.\n */\nclass FrameQueue {\n private queue: VerseEvent[] = [];\n private cancel: (() => void) | null = null;\n private scheduled = false;\n\n constructor(private readonly sessionId: string) {}\n\n push(event: VerseEvent): void {\n this.queue.push(event);\n if (this.scheduled) return;\n this.scheduled = true;\n const cancel = scheduleFrame(() => this.flush());\n // A synchronous scheduler (act environment) has already flushed.\n if (this.scheduled) this.cancel = cancel;\n }\n\n /** Apply everything queued now. Safe to call with nothing queued. */\n flush(): void {\n this.scheduled = false;\n this.cancel?.();\n this.cancel = null;\n if (this.queue.length === 0) return;\n const batch = this.queue;\n this.queue = [];\n const result = applyVerseEvents(this.sessionId, batch);\n if (result.settled) invalidateVerseLists();\n }\n\n drop(): void {\n this.scheduled = false;\n this.cancel?.();\n this.cancel = null;\n this.queue = [];\n }\n}\n\n// ---------------------------------------------------------------------------\n// One resumable stream\n// ---------------------------------------------------------------------------\n\ninterface LiveStream {\n close(): void;\n /** Tear down and reconnect from the current cursor (Retry). */\n restart(): void;\n}\n\n/**\n * Set once this page has PROVEN that the server refuses `?after=`: a\n * connection with the cursor closed before it opened, and the same stream\n * without it then opened. A read-session boundary that accepts only the\n * `?client=` proof on SSE paths answers 401 to any extra parameter, and a\n * chat that cannot connect at all is far worse than one that replays (the\n * store drops what it already holds). Page-lifetime only: a server that gains\n * support is used again after a reload.\n */\nlet afterRefused = false;\n\n/** Tests: forget a proven refusal. */\nexport function resetVerseStreamCapabilities(): void {\n afterRefused = false;\n}\n\n/** `EventSource.CONNECTING` — the browser is reconnecting by itself. */\nconst ES_CONNECTING = 0;\n\nfunction openResumableStream(sessionId: string): LiveStream {\n let source: EventSource | null = null;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let attempt = 0;\n let disposed = false;\n /** This connection is the no-`after` retry that tests whether the cursor was refused. */\n let probing = false;\n const queue = new FrameQueue(sessionId);\n\n const connect = () => {\n if (disposed || typeof EventSource === 'undefined') return;\n if (getAuthSnapshot().phase !== 'authenticated') return;\n setVerseStreamState(sessionId, attempt === 0 ? 'connecting' : 'reconnecting');\n // The cursor is read at CONNECT time, after everything already received\n // was applied, so a reconnect asks only for what it has not seen.\n const cursor = afterRefused || probing ? 0 : getVerseSessionState(sessionId).lastSeq;\n const es = new EventSource(verseSessionStreamUrl(sessionId, cursor), { withCredentials: true });\n let opened = false;\n source = es;\n es.onopen = () => {\n opened = true;\n attempt = 0;\n if (probing) {\n afterRefused = true;\n probing = false;\n }\n setVerseStreamState(sessionId, 'open');\n };\n for (const type of VERSE_EVENT_TYPES) {\n es.addEventListener(type, (evt) => {\n if (source !== es) return;\n const event = parseVerseEventFrame((evt as MessageEvent<string>).data);\n if (event) queue.push(event);\n });\n }\n es.onerror = (evt) => {\n // A server-sent event NAMED `error` (a VerseEvent.type) also dispatches\n // through onerror because onerror is the handler for event type \"error\".\n // It arrives as a MessageEvent with data; a real transport failure does\n // not. Without this guard every vendor error replayed on reconnect would\n // tear the stream down again, forever.\n if (typeof MessageEvent !== 'undefined' && evt instanceof MessageEvent) return;\n // Everything received before the drop moves the cursor first.\n queue.flush();\n if (disposed) return;\n // A dropped connection (network blip, server restart, the server\n // closing a congested stream) is retried by the BROWSER, which sends\n // Last-Event-ID — the last persisted seq, since transient frames carry\n // no id — so it resumes without a replay. Only a refused one (an HTTP\n // error) ends up CLOSED and is ours to retry.\n if (typeof es.readyState === 'number' && es.readyState === ES_CONNECTING) {\n setVerseStreamState(sessionId, 'reconnecting');\n return;\n }\n es.close();\n if (source === es) source = null;\n setVerseStreamState(sessionId, 'reconnecting');\n if (getAuthSnapshot().phase !== 'authenticated') return;\n if (!opened && cursor > 0 && !probing) {\n // Refused before it opened, with a cursor: find out at once whether\n // the cursor is what was refused (see afterRefused).\n probing = true;\n connect();\n return;\n }\n probing = false;\n timer = setTimeout(() => {\n timer = null;\n attempt += 1;\n connect();\n }, backoffMs(attempt));\n };\n };\n\n const teardown = () => {\n if (timer) clearTimeout(timer);\n timer = null;\n source?.close();\n source = null;\n };\n\n connect();\n\n return {\n close() {\n if (disposed) return;\n disposed = true;\n teardown();\n // Frames already received still belong in the store (a lingering stream\n // closing mid-turn must not lose its last tokens).\n queue.flush();\n queue.drop();\n setVerseStreamState(sessionId, 'closed');\n },\n restart() {\n if (disposed) return;\n teardown();\n queue.flush();\n attempt = 0;\n connect();\n },\n };\n}\n\n// ---------------------------------------------------------------------------\n// Ref-counted registry\n// ---------------------------------------------------------------------------\n\ninterface RegistryEntry {\n stream: LiveStream;\n refs: number;\n idleTimer: ReturnType<typeof setTimeout> | null;\n /** When the last reference was released (for evicting the oldest lingering stream). */\n releasedAt: number;\n}\n\nconst registry = new Map<string, RegistryEntry>();\n\nfunction closeEntry(sessionId: string): void {\n const entry = registry.get(sessionId);\n if (!entry) return;\n registry.delete(sessionId);\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n entry.stream.close();\n}\n\nfunction evictIdle(): void {\n const idle = [...registry.entries()].filter(([, e]) => e.refs === 0).sort((a, b) => a[1].releasedAt - b[1].releasedAt);\n while (idle.length > MAX_IDLE_STREAMS) closeEntry(idle.shift()![0]);\n}\n\n/**\n * Hold the live stream for `sessionId` open. Returns the release. The first\n * acquire connects (resuming after the store's cursor); later ones share it.\n */\nexport function acquireVerseSessionStream(sessionId: string): () => void {\n let entry = registry.get(sessionId);\n if (entry) {\n entry.refs += 1;\n if (entry.idleTimer) clearTimeout(entry.idleTimer);\n entry.idleTimer = null;\n } else {\n entry = { stream: openResumableStream(sessionId), refs: 1, idleTimer: null, releasedAt: 0 };\n registry.set(sessionId, entry);\n }\n const held = entry;\n let released = false;\n return () => {\n if (released) return;\n released = true;\n if (registry.get(sessionId) !== held) return;\n held.refs -= 1;\n if (held.refs > 0) return;\n held.releasedAt = Date.now();\n held.idleTimer = setTimeout(() => {\n if (registry.get(sessionId) === held && held.refs === 0) closeEntry(sessionId);\n }, IDLE_CLOSE_MS);\n evictIdle();\n };\n}\n\n/** Close every live stream (logout; tests). */\nexport function closeAllVerseSessionStreams(): void {\n for (const id of [...registry.keys()]) closeEntry(id);\n}\n\n/** Diagnostics/tests: the sessions with a stream held open, and their reference counts. */\nexport function verseStreamRegistrySnapshot(): Array<{ sessionId: string; refs: number }> {\n return [...registry.entries()].map(([sessionId, e]) => ({ sessionId, refs: e.refs }));\n}\n\n// A deleted chat has no stream to keep; a cleared store (logout, test reset)\n// has no chats at all.\nsubscribeVerseStoreLifecycle((event) => {\n if (event.kind === 'reset') closeAllVerseSessionStreams();\n else closeEntry(event.sessionId);\n});\n\n// ---------------------------------------------------------------------------\n// Opening a chat\n// ---------------------------------------------------------------------------\n\nexport interface OpenVerseSessionOptions {\n /** Re-fetch the detail and reconnect even when the store already holds the chat (the transcript's Retry). */\n reload?: boolean;\n}\n\n/**\n * Show one chat: load it (once) and keep its live stream attached until the\n * returned disposer runs.\n *\n * - Not loaded yet → fetch the detail, seed the store, THEN attach the\n * stream from the seeded cursor. No race, no full replay.\n * - Already loaded (switching back) → attach at once from the cursor; a\n * stream still lingering from the last visit has nothing to catch up.\n * - `reload` → refetch the detail and restart the connection.\n */\nexport function openVerseSession(sessionId: string, options: OpenVerseSessionOptions = {}): () => void {\n const controller = new AbortController();\n let release: (() => void) | null = null;\n let disposed = false;\n\n const attach = () => {\n if (disposed || release) return;\n release = acquireVerseSessionStream(sessionId);\n };\n\n const state = getVerseSessionState(sessionId);\n const needsLoad = options.reload === true || !state.loaded || state.loadError !== null;\n\n if (!needsLoad) {\n attach();\n } else {\n if (options.reload) registry.get(sessionId)?.stream.restart();\n void fetchVerseSessionDetail(sessionId, controller.signal)\n .then((detail) => {\n if (controller.signal.aborted) return;\n seedVerseSession(sessionId, detail.session, detail.events);\n attach();\n })\n .catch((err: unknown) => {\n if (controller.signal.aborted) return;\n setVerseLoadError(sessionId, err instanceof Error ? err.message : 'Could not load this chat.');\n });\n }\n\n return () => {\n disposed = true;\n controller.abort();\n release?.();\n release = null;\n };\n}\n","/**\n * routes/verse/useVerseSession.ts — the only React glue over verse-store /\n * session-stream (same split as data/hooks.ts over cache.ts + sse.ts).\n *\n * Three hooks, three snapshots, three render frequencies (V3.10):\n *\n * useVerseSession(id) the HEAD: session record, load/stream state and\n * the event log as of the last structural event.\n * Owns opening the chat. Does NOT change per\n * streamed token, so the Chat section, sidebar,\n * header and resources panel stop re-rendering at\n * token rate.\n * useVerseTranscript(id) the derived transcript — changes at most once per\n * animation frame while text streams. Lives in\n * useVerseTranscript.ts: the derivation it reads is\n * kept off the chat first-paint path.\n * useVerseLive(id) transient signals of the running turn\n * (reasoning, progress, retry/watchdog notices).\n *\n * Each subscribes to its own session only, so a stream feeding a lingering\n * chat in the background re-renders nothing that shows another one.\n */\nimport { useCallback, useEffect, useRef, useSyncExternalStore } from 'react';\nimport { openVerseSession } from './session-stream.js';\nimport {\n getVerseLive,\n getVerseSessionHead,\n subscribeVerseSession,\n type Transcript,\n type VerseLiveState,\n type VerseSessionHead,\n} from './verse-store.js';\n\nexport interface VerseSessionView extends VerseSessionHead {\n /**\n * A transcript supplied WITH the view — only a hand-built view (a test, a\n * preview) carries one. The live app leaves it unset and the workspace\n * subscribes to the transcript itself (useVerseTranscript), which is what\n * keeps a streamed token from re-rendering everything that holds the view.\n */\n transcript?: Transcript;\n}\n\nconst noop = () => () => {};\n\nexport function useSessionSubscription(sessionId: string | null) {\n return useCallback(\n (listener: () => void) => (sessionId ? subscribeVerseSession(sessionId, listener) : noop()),\n [sessionId],\n );\n}\n\n/**\n * @param reload bump to re-fetch the detail + reconnect for the same id\n * (the transcript's Retry button).\n */\nexport function useVerseSession(sessionId: string | null, reload = 0): VerseSessionView {\n const subscribe = useSessionSubscription(sessionId);\n const head = useSyncExternalStore(\n subscribe,\n () => getVerseSessionHead(sessionId),\n () => getVerseSessionHead(sessionId),\n );\n\n // Only a BUMP of `reload` for the chat already open means Retry; the\n // counter itself is never reset by the host, so \"reload > 0\" would turn\n // every later selection into a full refetch.\n const lastOpened = useRef<{ sessionId: string | null; reload: number }>({ sessionId: null, reload });\n useEffect(() => {\n const previous = lastOpened.current;\n lastOpened.current = { sessionId, reload };\n if (!sessionId) return undefined;\n return openVerseSession(sessionId, { reload: previous.sessionId === sessionId && previous.reload !== reload });\n }, [sessionId, reload]);\n\n return head;\n}\n\n/** Live (never persisted) signals of the chat's running turn. */\nexport function useVerseLive(sessionId: string | null): VerseLiveState {\n const subscribe = useSessionSubscription(sessionId);\n return useSyncExternalStore(\n subscribe,\n () => getVerseLive(sessionId),\n () => getVerseLive(sessionId),\n );\n}\n","/**\n * routes/verse/chat/use-chat-activity.ts — the Chat surface's view of C1's\n * activity + session-meta routes (unit C2).\n *\n * WHY NOT C1's useActivity: that hook runs the shell's CURSOR loop (it owns\n * completions, the rail badges and the native \"Finished:\" notifications).\n * The chat list needs only the present tense — who is running, what they are\n * doing, what needs the operator — so it reads the same route without a\n * cursor, through the shared query cache under VERSE_ACTIVITY_KEY. Any other\n * reader of that key (the rail, a future pane) shares the one request.\n *\n * Polls every 5 s ONLY while the Chat surface and the window are visible\n * (C0's usePollWhileVisible), and catches up the moment it is shown again.\n * Activity answers in < 5 ms from memory (SPEC-310C budget), so this is\n * cheap; it is still never faster than the 2 s floor.\n *\n * Also owns this tab's \"seen\" map: opening a chat clears its unread dot NOW,\n * whether or not the server-side POST can run (it needs a held token).\n */\nimport { useCallback, useSyncExternalStore } from 'react';\nimport { readFailureReason } from '../../../data/client.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { usePollWhileVisible } from '../shell/section-visibility.js';\nimport { markVerseSessionSeen, verseActivityQuery, verseSessionMetaQuery } from '../verse-queries.js';\n\nexport const CHAT_ACTIVITY_POLL_MS = 5_000;\n\n// ---- local seen map --------------------------------------------------------\n\nlet seen = new Map<string, number>();\nconst seenListeners = new Set<() => void>();\n\nfunction subscribeSeen(listener: () => void): () => void {\n seenListeners.add(listener);\n return () => seenListeners.delete(listener);\n}\n\nfunction getSeen(): ReadonlyMap<string, number> {\n return seen;\n}\n\n/** Record that the operator saw `sessionId` up to `turnCount`, locally and (best-effort) on the server. */\nexport function noteSessionSeen(sessionId: string, turnCount: number): void {\n if ((seen.get(sessionId) ?? -1) >= turnCount) return;\n seen = new Map(seen).set(sessionId, turnCount);\n for (const listener of [...seenListeners]) listener();\n void markVerseSessionSeen(sessionId, turnCount);\n}\n\n/** Test seam. */\nexport function resetLocalSeen(): void {\n seen = new Map();\n for (const listener of [...seenListeners]) listener();\n}\n\nexport function useLocalSeen(): ReadonlyMap<string, number> {\n return useSyncExternalStore(subscribeSeen, getSeen, getSeen);\n}\n\n// ---- queries ---------------------------------------------------------------\n\nexport function useChatActivity() {\n const activity = useQuery(verseActivityQuery, { freshMs: CHAT_ACTIVITY_POLL_MS - 500 });\n const meta = useQuery(verseSessionMetaQuery);\n const refetchActivity = useRefetch(verseActivityQuery);\n const tick = useCallback(() => refetchActivity(), [refetchActivity]);\n usePollWhileVisible(tick, CHAT_ACTIVITY_POLL_MS);\n const localSeen = useLocalSeen();\n return {\n /** null = the route is not mounted on this server (or has not answered yet). */\n activity: activity.data ?? null,\n meta: meta.data ?? null,\n /**\n * Why session-meta could not be read (the route's own sentence, e.g. the\n * chat engine is not answering), or null. A 404 is not an error here — it\n * reads as `meta: null` (\"not on this server\").\n */\n metaError: meta.status === 'error' ? readFailureReason(meta.error) : null,\n localSeen,\n };\n}\n","/**\n * routes/verse/chat-panel-sizing.ts — how wide the two side panels of the\n * Chat section are, and what the viewport will actually let them be.\n *\n * WHY THIS IS NOT `ashlr.verse.ui.v2`. That key's shape is the shell contract\n * (docs/VERSE-CONTRACT-V2.md) and verse-ui-store.test pins it field for\n * field; the same precedent that put `resources-collapse.ts` under its own\n * key applies here. This module also needs something the shell store cannot\n * express: a width is not a single number but a PAIR — what the operator\n * asked for, and what the window is currently wide enough to give them.\n *\n * DESIRED vs EFFECTIVE. A sidebar dragged to 420px on a 1900px display must\n * not strand the transcript when the same window is later 1100px wide. So the\n * operator's choice (`desired`) is what persists, and `effective` is that\n * choice re-fitted to the container on every layout change. Shrinking the\n * window narrows the panel; widening it gives the width back, because the\n * transient value was never written down.\n *\n * Pure aside from the two localStorage functions, and framework-free — the\n * React glue lives in ChatResizer.tsx, the same split as\n * verse-ui-store.ts / useVerseUi.ts.\n */\n\nexport type ChatPanelSide = 'sidebar' | 'resources';\n\nexport interface ChatPanelRange {\n readonly min: number;\n readonly max: number;\n readonly def: number;\n}\n\n/**\n * Minimum and maximum are both load-bearing. The minimum is the width below\n * which the panel stops being a panel and becomes a sliver of truncated\n * text; the maximum keeps a wide display from turning the transcript into a\n * column. Defaults match what the shell has always opened at, so nothing\n * moves for an operator who never drags anything.\n */\nexport const CHAT_PANEL_RANGES: Readonly<Record<ChatPanelSide, ChatPanelRange>> = {\n sidebar: { min: 220, max: 420, def: 264 },\n resources: { min: 240, max: 520, def: 320 },\n};\n\n/**\n * The transcript's floor. Below `--measure-read` (720px) reading is already\n * compromised; 480px is where the composer's own controls start wrapping, and\n * it is the point past which a side panel must give width back instead of\n * taking more. The narrow-width media queries in ChatSection.module.css take\n * over below that — this number only decides who yields first.\n */\nexport const MIN_TRANSCRIPT_WIDTH = 480;\n\n/** The 1px hairline track each visible resizer occupies. */\nconst HAIRLINE = 1;\n\n/** Arrow-key step, and the coarse step Shift asks for. */\nexport const CHAT_PANEL_STEP = 16;\nexport const CHAT_PANEL_STEP_COARSE = 64;\n\nexport const CHAT_PANEL_SIZING_KEY = 'ashlr.verse.panels.v1';\n\n/**\n * Read-only migration source. Panel widths lived in the shell store before\n * they were draggable; seeding from it once means an upgrade does not reset\n * a width the operator had already chosen. Never written to from here.\n */\nconst LEGACY_SHELL_KEY = 'ashlr.verse.ui.v2';\n\nexport interface ChatPanelWidths {\n readonly sidebar: number;\n readonly resources: number;\n}\n\n/** What the chat grid can currently afford. */\nexport interface ChatPanelFit {\n /**\n * Width in px of the chat grid itself (NOT the window): rail excluded,\n * because the rail is not the section's to spend. Zero or unknown — jsdom,\n * a hidden section, the first paint — disables viewport fitting entirely\n * rather than guessing, so a width is never clamped against a measurement\n * that does not exist.\n */\n readonly containerWidth: number;\n readonly sidebarVisible: boolean;\n readonly resourcesVisible: boolean;\n}\n\nexport const UNKNOWN_FIT: ChatPanelFit = {\n containerWidth: 0,\n sidebarVisible: true,\n resourcesVisible: true,\n};\n\nexport interface ChatPanelSizing {\n /** The operator's choice. This is what persists. */\n readonly desired: ChatPanelWidths;\n /** That choice, re-fitted to the current container. This is what renders. */\n readonly effective: ChatPanelWidths;\n}\n\n/**\n * Clamp one width into its own range. Nonsense — NaN, a string, a negative\n * number out of a hand-edited localStorage entry — resolves to the default\n * rather than to the minimum, so a corrupt value reads as \"never chosen\".\n */\nexport function clampPanelWidth(side: ChatPanelSide, value: unknown): number {\n const range = CHAT_PANEL_RANGES[side];\n const n = Number(value);\n if (!Number.isFinite(n) || n <= 0) return range.def;\n return Math.max(range.min, Math.min(range.max, Math.round(n)));\n}\n\n/**\n * Re-fit a chosen pair of widths to the container.\n *\n * The resources panel yields first: it is the optional one (it has a toggle,\n * the sidebar's collapse is an overlay at phone width), so on a narrowing\n * window the operator loses reference material before they lose navigation.\n * Neither panel is ever pushed below its own minimum — past that point the\n * media queries hide a panel outright, which is a better answer than a 40px\n * stub of clipped text.\n */\nexport function fitChatPanels(widths: ChatPanelWidths, fit: ChatPanelFit): ChatPanelWidths {\n let sidebar = clampPanelWidth('sidebar', widths.sidebar);\n let resources = clampPanelWidth('resources', widths.resources);\n if (!Number.isFinite(fit.containerWidth) || fit.containerWidth <= 0) return { sidebar, resources };\n\n const hairlines = (fit.sidebarVisible ? HAIRLINE : 0) + (fit.resourcesVisible ? HAIRLINE : 0);\n const budget = fit.containerWidth - MIN_TRANSCRIPT_WIDTH - hairlines;\n const spent = (fit.sidebarVisible ? sidebar : 0) + (fit.resourcesVisible ? resources : 0);\n let over = spent - budget;\n if (over <= 0) return { sidebar, resources };\n\n if (fit.resourcesVisible) {\n const give = Math.min(over, resources - CHAT_PANEL_RANGES.resources.min);\n resources -= give;\n over -= give;\n }\n if (over > 0 && fit.sidebarVisible) {\n const give = Math.min(over, sidebar - CHAT_PANEL_RANGES.sidebar.min);\n sidebar -= give;\n }\n return { sidebar, resources };\n}\n\n// ---------------------------------------------------------------------------\n// Persistence\n// ---------------------------------------------------------------------------\n\nexport function defaultChatPanelWidths(): ChatPanelWidths {\n return { sidebar: CHAT_PANEL_RANGES.sidebar.def, resources: CHAT_PANEL_RANGES.resources.def };\n}\n\n/** Parse either this module's payload or the legacy shell payload. */\nexport function parseChatPanelWidths(raw: string | null): ChatPanelWidths | null {\n if (raw === null || raw === '') return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(raw);\n } catch {\n return null;\n }\n if (!parsed || typeof parsed !== 'object' || Array.isArray(parsed)) return null;\n const record = parsed as Record<string, unknown>;\n // `sidebarWidth`/`resourcesWidth` is the legacy shell spelling.\n const sidebar = record.sidebar ?? record.sidebarWidth;\n const resources = record.resources ?? record.resourcesWidth;\n if (sidebar === undefined && resources === undefined) return null;\n return {\n sidebar: clampPanelWidth('sidebar', sidebar),\n resources: clampPanelWidth('resources', resources),\n };\n}\n\nexport function readChatPanelWidths(): ChatPanelWidths {\n try {\n const own = parseChatPanelWidths(localStorage.getItem(CHAT_PANEL_SIZING_KEY));\n if (own) return own;\n // First run after the upgrade: inherit whatever the shell store had.\n return parseChatPanelWidths(localStorage.getItem(LEGACY_SHELL_KEY)) ?? defaultChatPanelWidths();\n } catch {\n return defaultChatPanelWidths();\n }\n}\n\nexport function writeChatPanelWidths(widths: ChatPanelWidths): void {\n try {\n localStorage.setItem(CHAT_PANEL_SIZING_KEY, JSON.stringify({\n sidebar: widths.sidebar,\n resources: widths.resources,\n }));\n } catch {\n /* a private window without storage still runs the app */\n }\n}\n\n// ---------------------------------------------------------------------------\n// Store\n// ---------------------------------------------------------------------------\n\nlet desired: ChatPanelWidths = readChatPanelWidths();\nlet fit: ChatPanelFit = UNKNOWN_FIT;\nlet snapshot: ChatPanelSizing = { desired, effective: fitChatPanels(desired, fit) };\nconst listeners = new Set<() => void>();\n\nfunction sameWidths(a: ChatPanelWidths, b: ChatPanelWidths): boolean {\n return a.sidebar === b.sidebar && a.resources === b.resources;\n}\n\n/** Snapshot identity changes only when a number actually changed. */\nfunction publish(): void {\n const effective = fitChatPanels(desired, fit);\n if (sameWidths(snapshot.desired, desired) && sameWidths(snapshot.effective, effective)) return;\n snapshot = { desired, effective };\n for (const listener of listeners) listener();\n}\n\nexport function subscribeChatPanels(listener: () => void): () => void {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n}\n\nexport function getChatPanelSizing(): ChatPanelSizing {\n return snapshot;\n}\n\n/**\n * Publish what the layout can afford. Called on mount, on window resize and\n * whenever a panel is shown or hidden. Deliberately does NOT persist: a\n * narrow window borrows width, it does not take it.\n */\nexport function setChatPanelFit(next: ChatPanelFit): void {\n if (\n fit.containerWidth === next.containerWidth\n && fit.sidebarVisible === next.sidebarVisible\n && fit.resourcesVisible === next.resourcesVisible\n ) return;\n fit = next;\n publish();\n}\n\nfunction commit(next: ChatPanelWidths): void {\n if (sameWidths(desired, next)) return;\n desired = next;\n writeChatPanelWidths(desired);\n publish();\n}\n\n/** A drag or a direct set. Range-clamped; the fit is applied on read. */\nexport function setChatPanelWidth(side: ChatPanelSide, value: number): void {\n commit({ ...desired, [side]: clampPanelWidth(side, value) });\n}\n\n/**\n * An arrow key. Steps from the EFFECTIVE width, so a keypress moves the\n * handle the operator can see rather than an off-screen remembered one.\n */\nexport function nudgeChatPanelWidth(side: ChatPanelSide, delta: number): void {\n setChatPanelWidth(side, snapshot.effective[side] + delta);\n}\n\n/** Double-click, and the Home/End extremes. */\nexport function resetChatPanelWidth(side: ChatPanelSide): void {\n setChatPanelWidth(side, CHAT_PANEL_RANGES[side].def);\n}\n\n/** Test hygiene — mirrors resetVerseUi(). */\nexport function resetChatPanelSizing(): void {\n desired = defaultChatPanelWidths();\n fit = UNKNOWN_FIT;\n snapshot = { desired, effective: fitChatPanels(desired, fit) };\n try {\n localStorage.removeItem(CHAT_PANEL_SIZING_KEY);\n } catch {\n /* ignore */\n }\n for (const listener of listeners) listener();\n}\n\n/** Re-read storage into the store (a fresh tab, or a test that seeded a key). */\nexport function reloadChatPanelSizing(): void {\n desired = readChatPanelWidths();\n snapshot = { desired, effective: fitChatPanels(desired, fit) };\n for (const listener of listeners) listener();\n}\n","/**\n * routes/verse/ChatResizer.tsx — the drag handle between the chat\n * transcript and a side panel.\n *\n * A 1px hairline that behaves like a 9px target: the hairline is the design\n * (DESIGN-V2 has no chrome), the grab area is the ergonomics. Three things\n * about it are not obvious and are all deliberate:\n *\n * 1. IT IS A CONTROL, NOT A DECORATION. `role=\"separator\"` with a tabindex is\n * the ARIA window-splitter pattern: arrow keys move it, Home/End take it\n * to its limits, and a double-click restores the default. A pointer-only\n * resizer simply does not exist for a keyboard operator.\n *\n * 2. IT MUST NOT EAT THE macOS DRAG STRIP. The grab area overhangs ±4px into\n * the panels either side, and the top 48px of those panels is the window's\n * own drag region (Sidebar `.headDragStrip`, Workspace `.header`\n * data-app-region=\"drag\"). It is painted after them, so without the\n * `--app-titlebar-height` inset in the stylesheet it would steal 4px of\n * the strip AND turn the macOS double-click-to-zoom into a width reset.\n * See desktop/README.md \"Desktop shell contract\".\n *\n * 3. THE DRAG IS RELEASED FROM `window`, NOT FROM THE ELEMENT. Pointer\n * capture is requested, but it is not relied on: a capture that fails, a\n * pointer that leaves the window, a button released over another app and\n * a mid-drag unmount all have to end the drag, because a stuck drag state\n * (everything selects, the cursor sticks) is the most visible bug this\n * control can have.\n */\nimport { useCallback, useEffect, useRef, useState, useSyncExternalStore, type KeyboardEvent, type PointerEvent } from 'react';\nimport {\n CHAT_PANEL_RANGES,\n CHAT_PANEL_STEP,\n CHAT_PANEL_STEP_COARSE,\n getChatPanelSizing,\n nudgeChatPanelWidth,\n resetChatPanelWidth,\n setChatPanelWidth,\n subscribeChatPanels,\n type ChatPanelSide,\n type ChatPanelSizing,\n} from './chat-panel-sizing.js';\n\n/** The React glue over chat-panel-sizing.ts (same split as useVerseUi.ts). */\nexport function useChatPanelSizing(): ChatPanelSizing {\n return useSyncExternalStore(subscribeChatPanels, getChatPanelSizing, getChatPanelSizing);\n}\n\n/**\n * Marks the body for the duration of a drag so the stylesheet can suppress\n * selection app-wide. An attribute rather than an inline style: it survives\n * React re-renders, it is one line of CSS, and a test can see it.\n */\nconst BODY_FLAG = 'verseResizing';\n\nfunction markBody(on: boolean): void {\n try {\n if (on) document.body.dataset[BODY_FLAG] = 'true';\n else delete document.body.dataset[BODY_FLAG];\n } catch {\n /* a detached document in a test teardown is not worth throwing over */\n }\n}\n\nexport interface ChatResizerProps {\n side: ChatPanelSide;\n /** The control's accessible name — what it resizes, in the operator's words. */\n label: string;\n className?: string;\n}\n\ninterface DragState {\n pointerId: number;\n originX: number;\n startWidth: number;\n}\n\nexport function ChatResizer({ side, label, className }: ChatResizerProps) {\n const sizing = useChatPanelSizing();\n const range = CHAT_PANEL_RANGES[side];\n const width = sizing.effective[side];\n const drag = useRef<DragState | null>(null);\n const [dragging, setDragging] = useState(false);\n\n /** The one way a drag ends. Idempotent, so every path can call it. */\n const endDrag = useCallback(() => {\n if (!drag.current) return;\n drag.current = null;\n setDragging(false);\n markBody(false);\n }, []);\n\n const onPointerDown = useCallback((event: PointerEvent<HTMLDivElement>) => {\n // Primary button only: a right-click here belongs to the context menu,\n // and a middle-click must not start a drag nobody asked for.\n if (event.button !== 0) return;\n event.preventDefault();\n drag.current = { pointerId: event.pointerId, originX: event.clientX, startWidth: width };\n setDragging(true);\n markBody(true);\n // Best-effort: it keeps the cursor and the events on the handle while the\n // pointer wanders. The window listeners below are the actual contract.\n try {\n event.currentTarget.setPointerCapture?.(event.pointerId);\n } catch {\n /* unsupported, or the pointer is already gone — the window listeners cover it */\n }\n }, [width]);\n\n // Move/end listeners live on the window for the whole drag, so a pointer\n // that leaves the viewport or a button released over another window still\n // lands here. Unmounting mid-drag runs the cleanup and clears the body flag.\n useEffect(() => {\n if (!dragging) return undefined;\n\n const onMove = (event: globalThis.PointerEvent) => {\n const state = drag.current;\n if (!state || event.pointerId !== state.pointerId) return;\n const delta = event.clientX - state.originX;\n // The sidebar grows to the right, the resources panel to the left.\n setChatPanelWidth(side, side === 'sidebar' ? state.startWidth + delta : state.startWidth - delta);\n };\n const onEnd = (event: globalThis.PointerEvent) => {\n const state = drag.current;\n if (state && event.pointerId !== state.pointerId) return;\n endDrag();\n };\n /** Escape puts the width back where the drag started. */\n const onKey = (event: globalThis.KeyboardEvent) => {\n const state = drag.current;\n if (!state || event.key !== 'Escape') return;\n setChatPanelWidth(side, state.startWidth);\n endDrag();\n };\n // The window losing focus (⌘-tab mid-drag, an OS dialog) never delivers a\n // pointerup, so treat it as one rather than staying stuck.\n const onBlur = () => endDrag();\n\n window.addEventListener('pointermove', onMove);\n window.addEventListener('pointerup', onEnd);\n window.addEventListener('pointercancel', onEnd);\n window.addEventListener('keydown', onKey);\n window.addEventListener('blur', onBlur);\n return () => {\n window.removeEventListener('pointermove', onMove);\n window.removeEventListener('pointerup', onEnd);\n window.removeEventListener('pointercancel', onEnd);\n window.removeEventListener('keydown', onKey);\n window.removeEventListener('blur', onBlur);\n markBody(false);\n };\n }, [dragging, side, endDrag]);\n\n const onKeyDown = useCallback((event: KeyboardEvent<HTMLDivElement>) => {\n const step = event.shiftKey ? CHAT_PANEL_STEP_COARSE : CHAT_PANEL_STEP;\n // Left/Right are screen directions, so which one GROWS depends on which\n // edge of the transcript this handle is.\n const toward = side === 'sidebar' ? 1 : -1;\n switch (event.key) {\n case 'ArrowRight':\n nudgeChatPanelWidth(side, step * toward);\n break;\n case 'ArrowLeft':\n nudgeChatPanelWidth(side, -step * toward);\n break;\n case 'Home':\n setChatPanelWidth(side, range.min);\n break;\n case 'End':\n setChatPanelWidth(side, range.max);\n break;\n case 'Enter':\n resetChatPanelWidth(side);\n break;\n default:\n return;\n }\n event.preventDefault();\n }, [side, range.min, range.max]);\n\n return (\n <div\n className={className}\n data-verse-resizer={side}\n data-dragging={dragging ? 'true' : undefined}\n role=\"separator\"\n aria-orientation=\"vertical\"\n aria-label={label}\n aria-valuemin={range.min}\n aria-valuemax={range.max}\n aria-valuenow={width}\n aria-valuetext={`${width} pixels`}\n tabIndex={0}\n onPointerDown={onPointerDown}\n onPointerUp={endDrag}\n onPointerCancel={endDrag}\n onLostPointerCapture={endDrag}\n onKeyDown={onKeyDown}\n // The thing people reach for after over-dragging. In the desktop app a\n // double-click on a DRAG region zooms the window instead — which is why\n // the stylesheet keeps this handle's grab area out of the title bar.\n onDoubleClick={() => resetChatPanelWidth(side)}\n />\n );\n}\n","/**\n * routes/verse/sections/ChatSection.tsx — the Chat surface (⌘5):\n *\n * [sessions 264 | transcript ≤720 | dock 440 (tabs, or two panes split)]\n *\n * plus the new-chat dialog, the delete confirmation, and every mutation the\n * chat surface makes (SPEC-310C §2–§3, unit C2).\n *\n * Takes NO props (the shell contract): the shell lazily mounts it. The ways\n * INTO it from elsewhere in the workbench arrive two ways, both C1's:\n * - the shell's one-shot command (verse-ui-store): `new-chat` (⌘N, \"New\n * chat on…\", with a seat or project), `open-session` (a Needs-you item, a\n * notification, ⌃Tab, ⌘[ / ⌘]), `focus-composer` (⌃⌥Space);\n * - the command bus (shell/command-bus.ts): this section serves the\n * catalog's chat-scope commands — `dock.*`, `chat.sidebar`, `chat.find`,\n * `chat.turn-prev/next` — for the palette, the native menu and keys.\n * And it reports which chat is open (setVerseActiveSession), which feeds\n * ⌃Tab's recent list and back/forward.\n *\n * 3.10 changes, briefly:\n * - the resources column became the DOCK (dock/Dock.tsx): Terminal,\n * Preview and Review through C0's slots, Tasks and Context of its own;\n * below 1024px it is a sheet, below 480px a bottom sheet;\n * - the chat list gained filters, pins, archive, unread and a live second\n * line (C1's activity + session-meta routes, tolerated when absent);\n * - the ⌘K chat switcher is gone — ⌘K is the shell's command palette;\n * - the chat-scope keys (⌘\\ ⌃` ⌃⇧` ⇧⌘B ⇧⌘D ⌘B) run the same handlers,\n * matched from C0's catalog while this surface is visible — and only when\n * the shell's own key handler has not already taken the event.\n *\n * Mutations go through one guard: if no mutation token is held,\n * MutationTokenDialog opens and the action re-runs once unlocked.\n */\nimport { lazy, Suspense, useCallback, useEffect, useMemo, useRef, useState, type ComponentProps, type CSSProperties } from 'react';\nimport type { VerseCreateSessionRequest, VerseSession } from '../../../data/api-types.js';\nimport type { MutationTokenDialog as MutationTokenDialogComponent } from '../../../components/auth/MutationTokenDialog.js';\nimport { useToast } from '../../../components/primitives/Toast.js';\nimport { clearReadSession } from '../../../data/auth-store.js';\nimport { ApiError, DispatchDisabledError } from '../../../data/client.js';\nimport { useMutationHold, useQuery, useRefresh } from '../../../data/hooks.js';\nimport type { DeleteChatDialog as DeleteChatDialogComponent } from '../chat/DeleteChatDialog.js';\nimport { insertIntoComposer } from '../chat/composer-bridge.js';\nimport { forgetComposerMemory } from '../chat/composer-memory.js';\nimport type { ChatTask } from '../chat/tasks-model.js';\nimport { requestTranscriptFind, requestTranscriptStep } from '../chat/transcript-jump.js';\nimport { noteSessionSeen, useChatActivity } from '../chat/use-chat-activity.js';\nimport { useSessionRoots } from '../chat/use-session-roots.js';\nimport { ChatResizer, useChatPanelSizing } from '../ChatResizer.js';\nimport { CHAT_PANEL_RANGES, MIN_TRANSCRIPT_WIDTH, setChatPanelFit } from '../chat-panel-sizing.js';\nimport { clearDockRequests, requestTerminal, toggleDock, toggleDockPane, useDock } from '../dock/dock-store.js';\nimport type { SeatChoice } from '../SeatSelector.js';\nimport { clampDockWidth, DOCK_LAYOUT, dockPresentation } from '../shell/dock-catalog.js';\nimport { useCommandHandler } from '../shell/command-bus.js';\nimport { matchKey } from '../shell/command-keys.js';\nimport { preloadedLazy, preloadedModule } from '../shell/preloaded.js';\nimport { useSectionVisible } from '../shell/section-visibility.js';\nimport type { TurnFileChange } from '../shell/slots.js';\nimport type { Sidebar as SidebarComponent, SidebarRowActions } from '../Sidebar.js';\nimport { SkeletonLine } from '../../../components/primitives/Skeleton.js';\nimport { useVerseSession } from '../useVerseSession.js';\nimport { useVerseUi } from '../useVerseUi.js';\nimport { openVerseListChannel } from '../verse-events.js';\nimport {\n cancelVerseTurn,\n createVerseSession,\n deleteVerseSession,\n renameVerseSession,\n sendVerseTurn,\n setVerseSessionMeta,\n verseBootstrapQuery,\n verseSessionsQuery,\n verseWorkspacesQuery,\n VerseMutationLockedError,\n} from '../verse-queries.js';\nimport { forgetVerseSession, setVerseSession, setVerseSessionStatus } from '../verse-store.js';\nimport {\n clearVerseCommand,\n lastVerseSeat,\n rememberVerseSeat,\n setVerseActiveSession,\n setVerseSection,\n setVerseSidebarCollapsed,\n} from '../verse-ui-store.js';\nimport type { Workspace as WorkspaceComponent } from '../Workspace.js';\nimport styles from './ChatSection.module.css';\n\n// Loaded on first use, not with the chat: the dock starts closed and the\n// new-chat dialog opens on request (SPEC-310C budget: chat critical JS).\nconst DockHost = lazy(() => import('../dock/DockHost.js').then((m) => ({ default: m.DockHost })));\nconst NewChatDialog = lazy(() => import('../NewChatDialog.js').then((m) => ({ default: m.NewChatDialog })));\n\nconst WorkspaceModule = preloadedLazy<ComponentProps<typeof WorkspaceComponent>>(() => import('../Workspace.js').then((m) => m.Workspace));\nconst Workspace = WorkspaceModule.Slot;\nconst SidebarModule = preloadedLazy<ComponentProps<typeof SidebarComponent>>(() => import('../Sidebar.js').then((m) => m.Sidebar));\nconst Sidebar = SidebarModule.Slot;\n/**\n * The delete confirmation and the token prompt draw nothing until an\n * operator acts, and as static imports they (with the dialog primitive and\n * its focus trap, ~4 KB, and the button primitive) sat in the chat\n * first-paint critical JS. Preloaded (chat/DeleteChatDialog.tsx):\n * by the time anyone can click Delete the chunk is in and they mount in the\n * same render that opens them; the two share the dialog primitive's chunk.\n */\nconst DeleteDialogModule = preloadedLazy<ComponentProps<typeof DeleteChatDialogComponent>>(() => import('../chat/DeleteChatDialog.js').then((m) => m.DeleteChatDialog));\nconst DeleteChatDialog = DeleteDialogModule.Slot;\nconst TokenDialogModule = preloadedLazy<ComponentProps<typeof MutationTokenDialogComponent>>(\n () => import('../../../components/auth/MutationTokenDialog.js').then((m) => m.MutationTokenDialog),\n);\nconst MutationTokenDialog = TokenDialogModule.Slot;\n\n/**\n * The two derivations only the workspace's tasks row and the dock read\n * (tool-semantics, sidebar-model and line-diff come with them, ~12 KB). Both\n * consumers are lazy chunks that import these modules themselves, so the\n * download is shared and the values are in before either consumer mounts;\n * until then there is honestly nothing to show.\n */\nconst DERIVATIONS = preloadedModule(() => Promise.all([import('../chat/tasks-model.js'), import('../chat/turn-files.js')])\n .then(([tasks, files]) => ({ otherRunningChats: tasks.otherRunningChats, lastTurnFiles: files.lastTurnFiles })));\n/** Seat lookups for ⌘N \"New chat on…\" — the only first-paint-path use of verse-model (5.6 KB). */\nconst SEAT_MODEL = preloadedModule(() => import('../verse-model.js').then((m) => ({ firstRunnableModel: m.firstRunnableModel, seatById: m.seatById })));\nconst NO_TASKS: readonly ChatTask[] = [];\nconst NO_TURN_FILES: TurnFileChange[] = [];\n\n/**\n * Resolves when the chat's own chunks (workspace, chat list) are in. Tests\n * await it so a mount renders the whole surface synchronously; nothing in the\n * app needs to — the Suspense skeletons cover the gap.\n */\nexport function preloadChatSurface(): Promise<unknown> {\n return Promise.all([\n WorkspaceModule.ready(), SidebarModule.ready(), DeleteDialogModule.ready(), TokenDialogModule.ready(), DERIVATIONS.ready(), SEAT_MODEL.ready(),\n ]);\n}\n\n/**\n * The chat list's shape while its chunk loads. A <nav> like the real one, so\n * the grid rules written against `.chat > nav` (collapsed = display:none, the\n * phone-width overlay) hold for it too — but NOT named \"Chats\": that name is\n * the loaded list's, and a placeholder answering to it would be a lie.\n */\nfunction SidebarSkeleton() {\n return (\n <nav className={styles.sidebarSkeleton} aria-busy=\"true\" aria-label=\"Loading chat list\">\n {[64, 82, 58, 76, 70].map((w) => <SkeletonLine key={w} width={`${w}%`} />)}\n </nav>\n );\n}\n\n/** The workspace column's shape while its chunk loads: header, a few lines, the composer bar. */\nfunction WorkspaceSkeleton() {\n return (\n <div className={styles.workspaceSkeleton} role=\"status\" aria-label=\"Loading chat\">\n <div className={styles.skeletonHeader}><SkeletonLine width=\"32%\" /></div>\n <div className={styles.skeletonBody}>\n <SkeletonLine width=\"72%\" />\n <SkeletonLine width=\"88%\" />\n <SkeletonLine width=\"64%\" />\n </div>\n <div className={styles.skeletonComposer}><SkeletonLine width=\"100%\" /></div>\n </div>\n );\n}\n\nconst SELECTED_KEY = 'ashlr.verse.selected.v1';\n\nfunction loadSelected(): string | null {\n try {\n return localStorage.getItem(SELECTED_KEY);\n } catch {\n return null;\n }\n}\n\n/**\n * Every chat-surface failure in one sentence, branching on the route's CODE\n * before its status.\n *\n * A 409 is not always \"busy\": POST …/turns also answers 409\n * VERSE_MODEL_UNAVAILABLE when the chat's model cannot run on its seat.\n * Mapping every 409 to \"a turn is already running\" told the operator to press\n * a Stop that does nothing, with the server's actual reason thrown away.\n */\nexport function describeChatError(err: unknown): string {\n if (err instanceof DispatchDisabledError) return 'This server was started without dispatch — run `ashlr verse` to chat.';\n if (err instanceof ApiError) {\n if (err.code === 'VERSE_MODEL_UNAVAILABLE') {\n const why = err.detail ?? \"This chat's model cannot run on its seat.\";\n return `${why.replace(/\\.?$/, '.')} Continue in a fresh chat on a model this seat can run, or re-pin the seat's CLI (\\`ashlr resources profile repin\\`).`;\n }\n if (err.status === 409 && (err.code === null || err.code === 'VERSE_SESSION_BUSY')) return 'A turn is already running in this chat. Stop it first.';\n if (err.status === 413) return 'That message is too large (64 KB max).';\n if (err.status === 401) return 'Mutation token was rejected. Unlock again with the token ashlr verse printed.';\n return err.detail ?? err.message;\n }\n return err instanceof Error ? err.message : 'Something went wrong.';\n}\n\n/** The window's width, for the dock's presentation and its 60% cap. */\nfunction useWindowWidth(): number {\n const [width, setWidth] = useState(() => (typeof window === 'undefined' ? 1440 : window.innerWidth || 1440));\n useEffect(() => {\n const onResize = () => setWidth(window.innerWidth || 1440);\n window.addEventListener('resize', onResize);\n return () => window.removeEventListener('resize', onResize);\n }, []);\n return width;\n}\n\n/** ⌃⌥Space: the composer's message box, focused (C3's `aria-label=\"Message\"`). */\nfunction focusComposer(): void {\n // After the section has painted (the command may be what mounted it).\n requestAnimationFrame(() => {\n const box = document.querySelector<HTMLTextAreaElement>('textarea[aria-label=\"Message\"]');\n box?.focus();\n });\n}\n\n/** Is the key event aimed at an overlay that owns its own keys (a dialog, a menu, the palette)? */\nfunction inOverlay(target: EventTarget | null): boolean {\n return target instanceof Element && target.closest('[role=\"dialog\"], [role=\"menu\"], [role=\"listbox\"], [aria-modal=\"true\"]') !== null;\n}\n\nexport function ChatSection() {\n const bootstrap = useQuery(verseBootstrapQuery);\n const sessionsQuery = useQuery(verseSessionsQuery);\n const refetchSessions = useRefresh(verseSessionsQuery);\n const refetchBootstrap = useRefresh(verseBootstrapQuery);\n const hold = useMutationHold();\n const toast = useToast();\n const ui = useVerseUi();\n const visible = useSectionVisible();\n const dock = useDock();\n const chatActivity = useChatActivity();\n const windowWidth = useWindowWidth();\n\n const [selectedId, setSelectedIdState] = useState<string | null>(loadSelected);\n const [query, setQuery] = useState('');\n const [newChat, setNewChat] = useState<{ open: boolean; projectPath?: string | null; seat?: SeatChoice | null }>({ open: false });\n const [creating, setCreating] = useState(false);\n const [createError, setCreateError] = useState<string | null>(null);\n const [reload, setReload] = useState(0);\n const [tokenPrompt, setTokenPrompt] = useState<{ open: boolean; reason: string }>({ open: false, reason: '' });\n const [handoffFor, setHandoffFor] = useState<string | null>(null);\n const [deleteTarget, setDeleteTarget] = useState<VerseSession | null>(null);\n const [chatWidth, setChatWidth] = useState(0);\n const pendingAction = useRef<{ run: () => void; cancel: () => void } | null>(null);\n const chatRef = useRef<HTMLDivElement>(null);\n const panels = useChatPanelSizing();\n\n const seats = useMemo(() => bootstrap.data?.seats ?? [], [bootstrap.data]);\n const projects = useMemo(() => bootstrap.data?.projects ?? [], [bootstrap.data]);\n // Workspaces come from their own route (live per-root status for the dialog).\n const workspacesQuery = useQuery(verseWorkspacesQuery);\n const workspaces = useMemo(() => workspacesQuery.data?.workspaces ?? [], [workspacesQuery.data]);\n const dispatchEnabled = bootstrap.data?.dispatchEnabled ?? true;\n\n const view = useVerseSession(selectedId, reload);\n const roots = useSessionRoots(view.session);\n\n // Sidebar list: the sessions query, else bootstrap's copy, with the live\n // store record overlaid for the open chat so its running dot is immediate.\n const sessions = useMemo<VerseSession[]>(() => {\n const base = sessionsQuery.data ?? bootstrap.data?.sessions ?? [];\n if (!view.session) return base;\n const live = view.session;\n return base.some((s) => s.id === live.id) ? base.map((s) => (s.id === live.id ? live : s)) : [live, ...base];\n }, [sessionsQuery.data, bootstrap.data, view.session]);\n\n const setSelectedId = useCallback((id: string | null) => {\n setSelectedIdState(id);\n try {\n if (id) localStorage.setItem(SELECTED_KEY, id);\n else localStorage.removeItem(SELECTED_KEY);\n } catch {\n /* best-effort */\n }\n }, []);\n\n // A remembered selection that no longer exists (deleted elsewhere) is dropped once the list is known.\n useEffect(() => {\n if (!selectedId || !sessionsQuery.data) return;\n if (!sessionsQuery.data.some((s) => s.id === selectedId) && !view.session) setSelectedId(null);\n }, [selectedId, sessionsQuery.data, view.session, setSelectedId]);\n\n // Sidebar digest channel (verse-sessions on /api/events).\n useEffect(() => openVerseListChannel(), []);\n\n // ---- recency + read state -------------------------------------------------\n // Pane requests (a pasted command, a diff to open) belong to the chat they\n // were raised in: switching chats drops them. A SWITCH only — the first run\n // of this effect is the section mounting, and that is exactly when Apps'\n // [Launch ▸] (raised on another surface, which then brings Chat forward)\n // has a terminal request waiting; clearing it here left an empty dock.\n const requestsFor = useRef(selectedId);\n useEffect(() => {\n setVerseActiveSession(selectedId);\n if (requestsFor.current !== selectedId) {\n requestsFor.current = selectedId;\n clearDockRequests();\n }\n }, [selectedId]);\n\n // Reading a chat — its turns up to now — while this surface is on screen.\n const openTurnCount = view.session?.turnCount ?? null;\n useEffect(() => {\n if (!visible || !selectedId || openTurnCount === null) return;\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return;\n noteSessionSeen(selectedId, openTurnCount);\n }, [visible, selectedId, openTurnCount]);\n\n // ---- mutation guard ---------------------------------------------------------\n const withToken = useCallback(<T,>(reason: string, action: () => Promise<T>): Promise<T | null> => {\n if (hold.hasHold) return action();\n return new Promise<T | null>((resolve, reject) => {\n pendingAction.current = {\n // Pass rejections through: a parked action that fails after the token\n // unlock must reach its caller's catch, not leave it awaiting forever.\n run: () => { action().then(resolve, reject); },\n cancel: () => resolve(null),\n };\n setTokenPrompt({ open: true, reason });\n });\n }, [hold.hasHold]);\n\n const fail = useCallback((err: unknown) => {\n if (err instanceof VerseMutationLockedError) return;\n toast.show(describeChatError(err), 'danger');\n }, [toast]);\n\n // ---- actions ----------------------------------------------------------------\n /**\n * ONE resolution of what \"new chat\" pre-fills, for every entry point (the\n * sidebar \"+\", ⌘N, the empty state, the palette's \"New chat on…\"): an\n * explicit prefill wins, the open session is next, and the per-project\n * seat memory is the floor.\n */\n const openNewChat = useCallback((prefill: { projectPath?: string | null; seat?: SeatChoice | null } = {}) => {\n setCreateError(null);\n const current = view.session;\n const projectPath = prefill.projectPath !== undefined ? prefill.projectPath : current?.projectPath ?? null;\n // The open session's seat only carries forward onto its OWN project.\n const fromCurrent = current && projectPath === current.projectPath\n ? { seatId: current.seatId, model: current.model }\n : null;\n const seat = prefill.seat ?? fromCurrent ?? lastVerseSeat(projectPath);\n setNewChat({ open: true, projectPath, seat });\n }, [view.session]);\n\n const create = useCallback(async (req: VerseCreateSessionRequest) => {\n await withToken('Starting a chat spawns an agent process for this project.', async () => {\n setCreating(true);\n setCreateError(null);\n try {\n const session = await createVerseSession(req);\n rememberVerseSeat(session.projectPath, { seatId: session.seatId, model: session.model });\n setVerseSession(session.id, session);\n setNewChat({ open: false });\n setSelectedId(session.id);\n toast.show(`Started “${session.title}”`, 'success');\n } catch (err) {\n setCreateError(describeChatError(err));\n } finally {\n setCreating(false);\n }\n });\n }, [withToken, setSelectedId, toast]);\n\n const send = useCallback(async (text: string) => {\n const id = selectedId;\n if (!id) return false;\n const result = await withToken('Sending a message runs the agent against this project.', async () => {\n setVerseSessionStatus(id, 'running');\n try {\n const response = await sendVerseTurn(id, text);\n // The turn may already have settled by the time the 202 is applied;\n // the store checks the log for this turnId before trusting `running`.\n setVerseSession(id, response.session, response.turnId);\n return true;\n } catch (err) {\n setVerseSessionStatus(id, 'idle');\n fail(err);\n return false;\n }\n });\n return result === true;\n }, [selectedId, withToken, fail]);\n\n const stop = useCallback((id: string | null = selectedId) => {\n if (!id) return;\n void withToken('Stopping the running turn.', async () => {\n try {\n await cancelVerseTurn(id);\n } catch (err) {\n fail(err);\n }\n });\n }, [selectedId, withToken, fail]);\n\n const renameChat = useCallback(async (id: string, title: string) => {\n const result = await withToken('Renaming a chat.', async () => {\n try {\n const session = await renameVerseSession(id, title);\n setVerseSession(id, session);\n return true;\n } catch (err) {\n fail(err);\n return false;\n }\n });\n return result === true;\n }, [withToken, fail]);\n\n const removeChat = useCallback(async (id: string) => {\n const result = await withToken('Deleting a chat removes its transcript from disk.', async () => {\n try {\n await deleteVerseSession(id);\n forgetVerseSession(id);\n // The transcript is gone from disk; the verbatim prompts must not\n // survive it in browser storage under a dead session id.\n forgetComposerMemory(id);\n if (id === selectedId) setSelectedId(null);\n toast.show('Chat deleted.', 'neutral');\n return true;\n } catch (err) {\n fail(err);\n return false;\n }\n });\n return result === true;\n }, [withToken, fail, setSelectedId, toast, selectedId]);\n\n const setMeta = useCallback((id: string, update: { pinned?: boolean; archived?: boolean }, reason: string) => {\n void withToken(reason, async () => {\n try {\n await setVerseSessionMeta(id, update);\n } catch (err) {\n fail(err);\n }\n });\n }, [withToken, fail]);\n\n /** Sessions are seat-bound: a different seat means a new chat on the same project. */\n const changeSeat = useCallback((choice: SeatChoice) => {\n const current = view.session;\n if (!current) return;\n openNewChat({ projectPath: current.projectPath, seat: choice });\n toast.show('Chats are bound to one seat — starting a new chat on the same project.', 'neutral');\n }, [view.session, openNewChat, toast]);\n\n const requestDelete = useCallback((id: string) => {\n const target = sessions.find((s) => s.id === id) ?? null;\n if (target) setDeleteTarget(target);\n }, [sessions]);\n\n const startHandoff = useCallback((id: string) => {\n if (id !== selectedId) setSelectedId(id);\n setHandoffFor(id);\n }, [selectedId, setSelectedId]);\n\n const selectFromList = useCallback((id: string) => {\n setSelectedId(id);\n // At phone width the list floats over the chat; picking a chat closes it.\n if (window.matchMedia?.('(max-width: 760px)')?.matches === true) setVerseSidebarCollapsed(true);\n }, [setSelectedId]);\n\n // ---- commands: the shell's hand-offs, the bus, and the chat's own keys ------\n const toggleSidebar = useCallback(() => setVerseSidebarCollapsed(!ui.sidebarCollapsed), [ui.sidebarCollapsed]);\n // ⌃` : a terminal, focused — the active tab, else one at the chat's root\n // (TerminalPane resolves an empty request that way). Pressed again while\n // Terminal is on screen it hides it, like every editor's ⌃`.\n const terminalShown = dock.state.open && (dock.state.active === 'terminal' || dock.state.splitWith === 'terminal');\n const openTerminal = useCallback(() => {\n if (terminalShown) toggleDockPane('terminal');\n else requestTerminal({});\n }, [terminalShown]);\n // ⌃⇧` : always a NEW tab, in the active tab's root (else the chat's primary).\n const newTerminalTab = useCallback(() => requestTerminal({ newTab: true }), []);\n\n // The shell's one-shot command, consumed once by nonce.\n const handledCommand = useRef(0);\n const seatModel = SEAT_MODEL.useLoaded();\n useEffect(() => {\n const command = ui.command;\n if (!command || command.nonce === handledCommand.current) return;\n // \"New chat on…\" resolves its seat through verse-model, which loads just\n // after first paint: leave the command pending (unconsumed) until it is\n // in — this effect re-runs when it lands.\n if (command.name === 'new-chat' && !seatModel) return;\n handledCommand.current = command.nonce;\n switch (command.name) {\n case 'open-session':\n if (command.sessionId) setSelectedId(command.sessionId);\n break;\n case 'focus-composer':\n focusComposer();\n break;\n case 'new-chat': {\n // \"New chat on…\" carries a seat (and maybe a project); ⌘N carries neither.\n const { seatById, firstRunnableModel } = seatModel!;\n const seat = command.seatId ? seatById(seats, command.seatId) : undefined;\n // The model this project last used on that seat, else the seat's first runnable one.\n const remembered = lastVerseSeat(command.projectPath ?? null);\n const model = !seat ? undefined : remembered?.seatId === seat.id ? remembered.model : firstRunnableModel(seat)?.id;\n openNewChat({\n ...(command.projectPath !== undefined ? { projectPath: command.projectPath } : {}),\n ...(seat && model ? { seat: { seatId: seat.id, model } } : {}),\n });\n break;\n }\n default:\n // 'quick-switcher' (pre-3.10): ⌘K is the shell's palette now.\n break;\n }\n clearVerseCommand();\n }, [ui.command, openNewChat, seats, setSelectedId, seatModel]);\n\n // The catalog's chat-scope commands, for the palette, the menu and keys.\n const handlers: ReadonlyArray<[string, () => void | boolean]> = [\n ['chat.sidebar', toggleSidebar],\n ['chat.find', () => requestTranscriptFind()],\n ['chat.turn-prev', () => requestTranscriptStep(-1)],\n ['chat.turn-next', () => requestTranscriptStep(1)],\n ['dock.toggle', toggleDock],\n ['dock.terminal', openTerminal],\n ['dock.terminal-new', newTerminalTab],\n ['dock.preview', () => toggleDockPane('preview')],\n ['dock.diff', () => toggleDockPane('diff')],\n ];\n const handlerMap = new Map(handlers);\n useCommandHandler('chat.sidebar', handlerMap.get('chat.sidebar')!);\n useCommandHandler('chat.find', handlerMap.get('chat.find')!);\n useCommandHandler('chat.turn-prev', handlerMap.get('chat.turn-prev')!);\n useCommandHandler('chat.turn-next', handlerMap.get('chat.turn-next')!);\n useCommandHandler('dock.toggle', handlerMap.get('dock.toggle')!);\n useCommandHandler('dock.terminal', handlerMap.get('dock.terminal')!);\n useCommandHandler('dock.terminal-new', handlerMap.get('dock.terminal-new')!);\n useCommandHandler('dock.preview', handlerMap.get('dock.preview')!);\n useCommandHandler('dock.diff', handlerMap.get('dock.diff')!);\n\n // Keys, as a fallback: the shell's handler routes catalog keys through the\n // bus and marks the event handled (preventDefault); this listener acts only\n // on an event nobody took, and only while the surface is visible and no\n // overlay (a dialog, a menu, the palette) owns the keyboard. ⌘F and ⌥↑/↓\n // are the transcript's own listeners, which follow the same rule.\n const handlerRef = useRef(handlerMap);\n handlerRef.current = handlerMap;\n useEffect(() => {\n if (!visible) return undefined;\n const onKey = (event: KeyboardEvent) => {\n if (event.defaultPrevented || inOverlay(event.target)) return;\n const command = matchKey(event, ['chat']);\n if (!command || command.scope !== 'chat') return;\n if (command.id === 'chat.find' || command.id === 'chat.turn-prev' || command.id === 'chat.turn-next') return;\n const run = handlerRef.current.get(command.id);\n if (!run) return;\n event.preventDefault();\n run();\n };\n document.addEventListener('keydown', onKey);\n return () => document.removeEventListener('keydown', onKey);\n }, [visible]);\n\n const dispatchOff = bootstrap.data ? !bootstrap.data.dispatchEnabled : false;\n const sidebarCollapsed = ui.sidebarCollapsed;\n\n // ---- layout -------------------------------------------------------------------\n const presentation = dockPresentation(windowWidth);\n const dockOpen = dock.state.open && dock.state.tabs.length > 0;\n const dockColumn = dockOpen && presentation === 'column';\n // The dock yields before the transcript does: never past the window's 60%,\n // and never so wide that the transcript (plus the chat list, when shown at\n // its minimum) drops under its floor. The floor for the dock is its 320px.\n const sidebarFloor = sidebarCollapsed ? 0 : CHAT_PANEL_RANGES.sidebar.min;\n const dockWidth = dockColumn\n ? Math.max(DOCK_LAYOUT.minWidth, Math.min(\n clampDockWidth(dock.state.width, windowWidth),\n chatWidth > 0 ? chatWidth - MIN_TRANSCRIPT_WIDTH - sidebarFloor : Number.POSITIVE_INFINITY,\n ))\n : 0;\n\n useEffect(() => {\n const node = chatRef.current;\n if (!node) return undefined;\n const measure = () => {\n setChatWidth(node.clientWidth);\n setChatPanelFit({\n // The dock's column is not the sidebar's to spend.\n containerWidth: Math.max(0, node.clientWidth - dockWidth),\n sidebarVisible: !sidebarCollapsed,\n resourcesVisible: false,\n });\n };\n measure();\n const observer = typeof ResizeObserver === 'function' ? new ResizeObserver(measure) : null;\n observer?.observe(node);\n window.addEventListener('resize', measure);\n return () => {\n observer?.disconnect();\n window.removeEventListener('resize', measure);\n };\n }, [sidebarCollapsed, dockWidth]);\n\n const style = {\n '--verse-sidebar-width': `${panels.effective.sidebar}px`,\n '--verse-dock-width': `${dockWidth}px`,\n } as CSSProperties;\n\n // ---- dock data ------------------------------------------------------------------\n const derive = DERIVATIONS.useLoaded();\n const otherRunning = useMemo(\n () => (derive ? derive.otherRunningChats(sessions, chatActivity.activity, selectedId) : NO_TASKS),\n [derive, sessions, chatActivity.activity, selectedId],\n );\n const turnFiles = useMemo<TurnFileChange[]>(\n () => (derive ? derive.lastTurnFiles(view.events, roots.roots) : NO_TURN_FILES),\n [derive, roots.roots, view.events],\n );\n\n const actions: SidebarRowActions = {\n setPinned: (id, pinned) => setMeta(id, { pinned }, pinned ? 'Pinning a chat.' : 'Unpinning a chat.'),\n setArchived: (id, archived) => setMeta(id, { archived }, archived ? 'Archiving a chat.' : 'Unarchiving a chat.'),\n rename: renameChat,\n handoff: startHandoff,\n requestDelete,\n dispatchEnabled,\n };\n\n return (\n <div ref={chatRef} className={styles.chat} style={style}\n data-sidebar={sidebarCollapsed ? 'collapsed' : 'open'} data-dock={dockColumn ? 'open' : 'closed'}>\n <Suspense fallback={<SidebarSkeleton />}>\n <Sidebar sessions={sessions} sessionsStatus={sessionsQuery.status} sessionsError={sessionsQuery.error?.message ?? null}\n projects={projects} seats={seats} selectedId={selectedId} query={query} onQuery={setQuery}\n onSelect={selectFromList} onNew={() => openNewChat()}\n onRetry={() => { refetchSessions(); refetchBootstrap(); }}\n onCollapse={() => setVerseSidebarCollapsed(true)} onDisconnect={() => { void clearReadSession(); }}\n activity={chatActivity.activity} meta={chatActivity.meta} metaError={chatActivity.metaError} localSeen={chatActivity.localSeen} actions={actions} />\n </Suspense>\n {sidebarCollapsed ? null : <ChatResizer side=\"sidebar\" label=\"Resize chat list\" className={styles.resize} />}\n {/* At phone width the sidebar floats over the transcript; the scrim dismisses it. */}\n <button type=\"button\" className={styles.scrim} aria-label=\"Close chat list\" tabIndex={-1}\n onClick={() => setVerseSidebarCollapsed(true)} />\n <div className={styles.main}>\n {bootstrap.status === 'error' && !bootstrap.data ? (\n <div role=\"alert\" className={styles.banner}>\n <span>{bootstrap.error?.message ?? 'Could not load Verse.'}</span>\n <button type=\"button\" onClick={refetchBootstrap}>Retry</button>\n </div>\n ) : dispatchOff ? (\n <div role=\"status\" className={styles.bannerWarn}>\n Read-only: this server was started without dispatch. Run <code>ashlr verse</code> to send messages.\n </div>\n ) : null}\n <Suspense fallback={<WorkspaceSkeleton />}>\n <Workspace view={view} seats={seats} projects={projects} dispatchEnabled={dispatchEnabled} locked={!hold.hasHold}\n hasAnySessions={sessions.length > 0} onSend={send} onStop={() => stop()}\n onRename={(title) => (selectedId ? renameChat(selectedId, title) : Promise.resolve(false))}\n onRequestDelete={() => { if (selectedId) requestDelete(selectedId); }}\n onSeatChange={changeSeat} onNew={() => openNewChat()} onRetry={() => setReload((n) => n + 1)}\n sidebarCollapsed={sidebarCollapsed} onToggleSidebar={() => setVerseSidebarCollapsed(!sidebarCollapsed)}\n onOpenSession={setSelectedId}\n handoffOpen={handoffFor !== null && handoffFor === selectedId}\n onHandoffOpenChange={(open) => setHandoffFor(open ? selectedId : null)}\n otherRunning={otherRunning} />\n </Suspense>\n </div>\n {dockOpen ? (\n <Suspense fallback={null}>\n <DockHost presentation={presentation} windowWidth={windowWidth} columnWidth={dockWidth} session={view.session} seats={seats}\n events={view.events} roots={roots.roots} rootsData={roots.data} rootsError={roots.error} turnFiles={turnFiles}\n otherRunning={otherRunning} dispatchEnabled={dispatchEnabled} onOpenSession={setSelectedId}\n onHandoff={(id) => setHandoffFor(id)}\n // Accounts & capacity live in Apps & Accounts (C6) since 3.10.\n onOpenAccounts={() => setVerseSection('apps')}\n onSendToChat={(text) => { if (!selectedId || !insertIntoComposer(selectedId, text)) toast.show('Open a chat to send this to it.', 'neutral'); }}\n onAddToMessage={(text) => { if (!selectedId || !insertIntoComposer(selectedId, text)) toast.show('Open a chat to add this to its message.', 'neutral'); }} />\n </Suspense>\n ) : null}\n\n {newChat.open ? (\n <Suspense fallback={null}>\n <NewChatDialog open onClose={() => setNewChat({ open: false })} projects={projects} seats={seats} workspaces={workspaces}\n initialProjectPath={newChat.projectPath ?? null} initialSeat={newChat.seat ?? null} busy={creating} error={createError} onCreate={create}\n // The dialog's one write of its own (a seat's default context mode)\n // goes through the same token guard as every other chat mutation.\n runMutation={withToken} />\n </Suspense>\n ) : null}\n {/* Closed dialogs render nothing, so a not-yet-loaded one (fallback null) looks the same. */}\n <Suspense fallback={null}>\n <DeleteChatDialog target={deleteTarget} onClose={() => setDeleteTarget(null)} onDelete={removeChat}\n actionsClassName={styles.dialogActions} />\n <MutationTokenDialog open={tokenPrompt.open} reason={tokenPrompt.reason} tokenLabel=\"Mutation token\"\n tokenHelp=\"the mutation token ashlr verse printed\"\n onClose={() => {\n setTokenPrompt({ open: false, reason: '' });\n // The dialog calls onClose before onUnlocked on submit, so only treat\n // this as a dismissal if nothing has claimed the pending action by\n // the next tick.\n const pending = pendingAction.current;\n if (!pending) return;\n setTimeout(() => {\n if (pendingAction.current === pending) {\n pendingAction.current = null;\n pending.cancel();\n }\n }, 0);\n }}\n onUnlocked={() => {\n const pending = pendingAction.current;\n pendingAction.current = null;\n pending?.run();\n }} />\n </Suspense>\n </div>\n );\n}\n"],"file":"ChatSection-DlT4QU6a.js"}
|