@ashlr/hub 3.11.2 → 3.11.3
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 +8 -0
- package/dist/build-identity.json +2 -2
- package/dist/core/web/public/next/assets/{ActionMenu-_DhtX2gO.js → ActionMenu-FxXeRbPx.js} +2 -2
- package/dist/core/web/public/next/assets/{ActionMenu-_DhtX2gO.js.map → ActionMenu-FxXeRbPx.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Advanced-CAAfaBke.js → Advanced-D_eS4472.js} +2 -2
- package/dist/core/web/public/next/assets/{Advanced-CAAfaBke.js.map → Advanced-D_eS4472.js.map} +1 -1
- package/dist/core/web/public/next/assets/{App-BAywyjE8.js → App-Cj4zKbG3.js} +2 -2
- package/dist/core/web/public/next/assets/{App-BAywyjE8.js.map → App-Cj4zKbG3.js.map} +1 -1
- package/dist/core/web/public/next/assets/{AppsSection-CUypKeog.js → AppsSection-Ddu_RCQE.js} +2 -2
- package/dist/core/web/public/next/assets/{AppsSection-CUypKeog.js.map → AppsSection-Ddu_RCQE.js.map} +1 -1
- package/dist/core/web/public/next/assets/{AreaTrend-CblDqC8Q.js → AreaTrend-CDxrQU4b.js} +2 -2
- package/dist/core/web/public/next/assets/{AreaTrend-CblDqC8Q.js.map → AreaTrend-CDxrQU4b.js.map} +1 -1
- package/dist/core/web/public/next/assets/AutonomySection-DuQkHGD_.js +2 -0
- package/dist/core/web/public/next/assets/{AutonomySection-D3d8lYO3.js.map → AutonomySection-DuQkHGD_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{BranchBar-DU0jAV1E.js → BranchBar-CLsvOcyK.js} +2 -2
- package/dist/core/web/public/next/assets/{BranchBar-DU0jAV1E.js.map → BranchBar-CLsvOcyK.js.map} +1 -1
- package/dist/core/web/public/next/assets/{BudgetControl-Mm1ZL4u6.js → BudgetControl-TL3FeZ1D.js} +2 -2
- package/dist/core/web/public/next/assets/{BudgetControl-Mm1ZL4u6.js.map → BudgetControl-TL3FeZ1D.js.map} +1 -1
- package/dist/core/web/public/next/assets/{BurnDown-C1fgcFqo.js → BurnDown-sFXkUGdB.js} +2 -2
- package/dist/core/web/public/next/assets/{BurnDown-C1fgcFqo.js.map → BurnDown-sFXkUGdB.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Button-DqgLUZvd.js → Button-HHXgoXGr.js} +2 -2
- package/dist/core/web/public/next/assets/{Button-DqgLUZvd.js.map → Button-HHXgoXGr.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CapacityStrip-nWFHvqFB.js → CapacityStrip-qReu0RaF.js} +2 -2
- package/dist/core/web/public/next/assets/{CapacityStrip-nWFHvqFB.js.map → CapacityStrip-qReu0RaF.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ChatSection-DUZNpiVr.js → ChatSection-DZuZfTaC.js} +3 -3
- package/dist/core/web/public/next/assets/{ChatSection-DUZNpiVr.js.map → ChatSection-DZuZfTaC.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CloudBudgetForm-2OW38o_C.js → CloudBudgetForm-DJbiT1wi.js} +2 -2
- package/dist/core/web/public/next/assets/{CloudBudgetForm-2OW38o_C.js.map → CloudBudgetForm-DJbiT1wi.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CommandPalette-C5w2o1-r.js → CommandPalette-zYLFZRnj.js} +2 -2
- package/dist/core/web/public/next/assets/{CommandPalette-C5w2o1-r.js.map → CommandPalette-zYLFZRnj.js.map} +1 -1
- package/dist/core/web/public/next/assets/{CommandSection-Bx2knNqY.js → CommandSection-rIeMK5Ch.js} +2 -2
- package/dist/core/web/public/next/assets/{CommandSection-Bx2knNqY.js.map → CommandSection-rIeMK5Ch.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ConfirmDialog-B7ZwCQOX.js → ConfirmDialog-DLrLKM0c.js} +2 -2
- package/dist/core/web/public/next/assets/{ConfirmDialog-B7ZwCQOX.js.map → ConfirmDialog-DLrLKM0c.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Dialog-BpgcEW6b.js → Dialog-BS9Dxi3G.js} +2 -2
- package/dist/core/web/public/next/assets/{Dialog-BpgcEW6b.js.map → Dialog-BS9Dxi3G.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffPane-DpqRUtCx.js → DiffPane-TOmUf3b2.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffPane-DpqRUtCx.js.map → DiffPane-TOmUf3b2.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DiffViewer-CoV5-nUf.js → DiffViewer-BpH56302.js} +2 -2
- package/dist/core/web/public/next/assets/{DiffViewer-CoV5-nUf.js.map → DiffViewer-BpH56302.js.map} +1 -1
- package/dist/core/web/public/next/assets/{DockHost-C0Pq7Jak.js → DockHost-DzkzR-HD.js} +2 -2
- package/dist/core/web/public/next/assets/{DockHost-C0Pq7Jak.js.map → DockHost-DzkzR-HD.js.map} +1 -1
- package/dist/core/web/public/next/assets/{EmptyState-DYW29ncw.js → EmptyState-BqR5YAmf.js} +2 -2
- package/dist/core/web/public/next/assets/{EmptyState-DYW29ncw.js.map → EmptyState-BqR5YAmf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Epistemic-DVx6oHzp.js → Epistemic-dhvDTwAZ.js} +2 -2
- package/dist/core/web/public/next/assets/{Epistemic-DVx6oHzp.js.map → Epistemic-dhvDTwAZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{FleetSection-DSETviPK.js → FleetSection-ViAb549H.js} +3 -3
- package/dist/core/web/public/next/assets/{FleetSection-DSETviPK.js.map → FleetSection-ViAb549H.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Funnel-DxiGqJrt.js → Funnel-D2u7Wlzc.js} +2 -2
- package/dist/core/web/public/next/assets/{Funnel-DxiGqJrt.js.map → Funnel-D2u7Wlzc.js.map} +1 -1
- package/dist/core/web/public/next/assets/{GearTray-C3I89sIt.js → GearTray-Cb2npoxM.js} +2 -2
- package/dist/core/web/public/next/assets/{GearTray-C3I89sIt.js.map → GearTray-Cb2npoxM.js.map} +1 -1
- package/dist/core/web/public/next/assets/{GrowthSection-C3m2bPEz.js → GrowthSection-C5aDPs8B.js} +2 -2
- package/dist/core/web/public/next/assets/{GrowthSection-C3m2bPEz.js.map → GrowthSection-C5aDPs8B.js.map} +1 -1
- package/dist/core/web/public/next/assets/{HandoffDialog-Bjb96a0N.js → HandoffDialog-BF3AYg-X.js} +2 -2
- package/dist/core/web/public/next/assets/{HandoffDialog-Bjb96a0N.js.map → HandoffDialog-BF3AYg-X.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Input-ekTehVaH.js → Input-B5dmGLZx.js} +2 -2
- package/dist/core/web/public/next/assets/{Input-ekTehVaH.js.map → Input-B5dmGLZx.js.map} +1 -1
- package/dist/core/web/public/next/assets/{LeaderCard-85VBbbaZ.js → LeaderCard-DZrmjDbI.js} +2 -2
- package/dist/core/web/public/next/assets/{LeaderCard-85VBbbaZ.js.map → LeaderCard-DZrmjDbI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MatrixHeatmap-Bo8j0QPC.js → MatrixHeatmap-BgEUs2Eu.js} +2 -2
- package/dist/core/web/public/next/assets/{MatrixHeatmap-Bo8j0QPC.js.map → MatrixHeatmap-BgEUs2Eu.js.map} +1 -1
- package/dist/core/web/public/next/assets/McpSection-DZkiOuoq.js +2 -0
- package/dist/core/web/public/next/assets/{McpSection-DvHFaVyp.js.map → McpSection-DZkiOuoq.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdown-fsY_ltVa.js → MessageMarkdown-BauY8ZTY.js} +3 -3
- package/dist/core/web/public/next/assets/{MessageMarkdown-fsY_ltVa.js.map → MessageMarkdown-BauY8ZTY.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DDdtu82l.js → MessageMarkdownRenderer-DLBNLfsn.js} +2 -2
- package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DDdtu82l.js.map → MessageMarkdownRenderer-DLBNLfsn.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Meter-CeGDXdDM.js → Meter-DNeocJnD.js} +2 -2
- package/dist/core/web/public/next/assets/{Meter-CeGDXdDM.js.map → Meter-DNeocJnD.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MindSection-CDVhHvXl.js → MindSection-BvJXFjyX.js} +2 -2
- package/dist/core/web/public/next/assets/{MindSection-CDVhHvXl.js.map → MindSection-BvJXFjyX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{MutationTokenDialog-DTQzEOHR.js → MutationTokenDialog-mxrw0Yvy.js} +2 -2
- package/dist/core/web/public/next/assets/{MutationTokenDialog-DTQzEOHR.js.map → MutationTokenDialog-mxrw0Yvy.js.map} +1 -1
- package/dist/core/web/public/next/assets/{NeedsYouDrawer-6AuN0BF3.js → NeedsYouDrawer-CO-Balfp.js} +2 -2
- package/dist/core/web/public/next/assets/{NeedsYouDrawer-6AuN0BF3.js.map → NeedsYouDrawer-CO-Balfp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{NeedsYouList-ChnRmbSk.js → NeedsYouList-CzDZbzRD.js} +2 -2
- package/dist/core/web/public/next/assets/{NeedsYouList-ChnRmbSk.js.map → NeedsYouList-CzDZbzRD.js.map} +1 -1
- package/dist/core/web/public/next/assets/{NewChatDialog-B06E7sqg.js → NewChatDialog-B8eJjlFf.js} +2 -2
- package/dist/core/web/public/next/assets/{NewChatDialog-B06E7sqg.js.map → NewChatDialog-B8eJjlFf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{OnboardingFlow-C2M3zov9.js → OnboardingFlow-Cij6KWat.js} +2 -2
- package/dist/core/web/public/next/assets/{OnboardingFlow-C2M3zov9.js.map → OnboardingFlow-Cij6KWat.js.map} +1 -1
- package/dist/core/web/public/next/assets/{PreviewPane-Bd6HsX1k.js → PreviewPane-BS-CleCd.js} +2 -2
- package/dist/core/web/public/next/assets/{PreviewPane-Bd6HsX1k.js.map → PreviewPane-BS-CleCd.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ProviderLogo-Bz7KR5j3.js → ProviderLogo-C5mBg8i0.js} +2 -2
- package/dist/core/web/public/next/assets/{ProviderLogo-Bz7KR5j3.js.map → ProviderLogo-C5mBg8i0.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RailStatus-CctCuuLy.js → RailStatus-cPRyOmrk.js} +2 -2
- package/dist/core/web/public/next/assets/{RailStatus-CctCuuLy.js.map → RailStatus-cPRyOmrk.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RefreshIndicator-CKY5BGdD.js → RefreshIndicator-CMwSCiz5.js} +2 -2
- package/dist/core/web/public/next/assets/{RefreshIndicator-CKY5BGdD.js.map → RefreshIndicator-CMwSCiz5.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-CspIsW_G.js → ResourcePoolConsoleApp-BFi1opsC.js} +2 -2
- package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-CspIsW_G.js.map → ResourcePoolConsoleApp-BFi1opsC.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ResourcesChrome-B7fHZ6zX.js → ResourcesChrome-BJCauW_t.js} +3 -3
- package/dist/core/web/public/next/assets/{ResourcesChrome-B7fHZ6zX.js.map → ResourcesChrome-BJCauW_t.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ResourcesDrawer-B7-N9n7-.js → ResourcesDrawer-BDecg6nO.js} +2 -2
- package/dist/core/web/public/next/assets/{ResourcesDrawer-B7-N9n7-.js.map → ResourcesDrawer-BDecg6nO.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-C_B11J0s.js → RouteErrorBoundary-DYtwc2ja.js} +2 -2
- package/dist/core/web/public/next/assets/{RouteErrorBoundary-C_B11J0s.js.map → RouteErrorBoundary-DYtwc2ja.js.map} +1 -1
- package/dist/core/web/public/next/assets/{RunInCloudAction-_juw4EXd.js → RunInCloudAction-BEGEEM8O.js} +2 -2
- package/dist/core/web/public/next/assets/{RunInCloudAction-_juw4EXd.js.map → RunInCloudAction-BEGEEM8O.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SeatSelector-D_YXvkPy.js → SeatSelector-CYHRR7Wp.js} +2 -2
- package/dist/core/web/public/next/assets/{SeatSelector-D_YXvkPy.js.map → SeatSelector-CYHRR7Wp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Segmented-DnKP6rr7.js → Segmented-BE53BenI.js} +2 -2
- package/dist/core/web/public/next/assets/{Segmented-DnKP6rr7.js.map → Segmented-BE53BenI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Select-DlbUupTX.js → Select-BwSGkHCS.js} +2 -2
- package/dist/core/web/public/next/assets/{Select-DlbUupTX.js.map → Select-BwSGkHCS.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionGate-DnuTZACL.js → SessionGate-e0dFJm9d.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionGate-DnuTZACL.js.map → SessionGate-e0dFJm9d.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionInsightChip-C33-k-Q5.js → SessionInsightChip-CxlSyueJ.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionInsightChip-C33-k-Q5.js.map → SessionInsightChip-CxlSyueJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SessionSearch-DhhR9Csg.js → SessionSearch-_yp7S2TP.js} +2 -2
- package/dist/core/web/public/next/assets/{SessionSearch-DhhR9Csg.js.map → SessionSearch-_yp7S2TP.js.map} +1 -1
- package/dist/core/web/public/next/assets/{SettingsSection-C0xQvCz3.js → SettingsSection-wGnpWeGW.js} +2 -2
- package/dist/core/web/public/next/assets/{SettingsSection-C0xQvCz3.js.map → SettingsSection-wGnpWeGW.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Sheet-BvNYOYv5.js → Sheet-DVP2Mgy6.js} +2 -2
- package/dist/core/web/public/next/assets/{Sheet-BvNYOYv5.js.map → Sheet-DVP2Mgy6.js.map} +1 -1
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-1nUBVO-Z.js → ShortcutsOverlay-BcIcoClX.js} +2 -2
- package/dist/core/web/public/next/assets/{ShortcutsOverlay-1nUBVO-Z.js.map → ShortcutsOverlay-BcIcoClX.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Sidebar-YrVvvBNM.js → Sidebar-DjQOqPbm.js} +3 -3
- package/dist/core/web/public/next/assets/{Sidebar-YrVvvBNM.js.map → Sidebar-DjQOqPbm.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Slider-B2c-dbQb.js → Slider-BypUWjpH.js} +2 -2
- package/dist/core/web/public/next/assets/{Slider-B2c-dbQb.js.map → Slider-BypUWjpH.js.map} +1 -1
- package/dist/core/web/public/next/assets/{StatusBadge-Q9YYkijx.js → StatusBadge-HCZp416_.js} +2 -2
- package/dist/core/web/public/next/assets/{StatusBadge-Q9YYkijx.js.map → StatusBadge-HCZp416_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{StepBand-Ci-C0GUG.js → StepBand-Duz1PUes.js} +2 -2
- package/dist/core/web/public/next/assets/{StepBand-Ci-C0GUG.js.map → StepBand-Duz1PUes.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Surface-DBovMq4P.js → Surface-B75lVfzm.js} +2 -2
- package/dist/core/web/public/next/assets/{Surface-DBovMq4P.js.map → Surface-B75lVfzm.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Swimlane-Cdc4TqDe.js → Swimlane-DGcIcnNA.js} +2 -2
- package/dist/core/web/public/next/assets/{Swimlane-Cdc4TqDe.js.map → Swimlane-DGcIcnNA.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Switch-CUrvzO2k.js → Switch-iveI-8NY.js} +2 -2
- package/dist/core/web/public/next/assets/{Switch-CUrvzO2k.js.map → Switch-iveI-8NY.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Tag-Bv8u6APt.js → Tag-DH15CUJp.js} +2 -2
- package/dist/core/web/public/next/assets/{Tag-Bv8u6APt.js.map → Tag-DH15CUJp.js.map} +1 -1
- package/dist/core/web/public/next/assets/{TerminalPane-BE4Xlqi5.js → TerminalPane-MQT-veKZ.js} +2 -2
- package/dist/core/web/public/next/assets/{TerminalPane-BE4Xlqi5.js.map → TerminalPane-MQT-veKZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-BGwejf0m.js → UniverseConsoleApp-C8yQ0AaR.js} +2 -2
- package/dist/core/web/public/next/assets/{UniverseConsoleApp-BGwejf0m.js.map → UniverseConsoleApp-C8yQ0AaR.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UniverseView-CgKa-WXC.js → UniverseView-_nPURPqe.js} +2 -2
- package/dist/core/web/public/next/assets/{UniverseView-CgKa-WXC.js.map → UniverseView-_nPURPqe.js.map} +1 -1
- package/dist/core/web/public/next/assets/{UsageSection-CazsHm1f.js → UsageSection-CqxRGJ40.js} +2 -2
- package/dist/core/web/public/next/assets/{UsageSection-CazsHm1f.js.map → UsageSection-CqxRGJ40.js.map} +1 -1
- package/dist/core/web/public/next/assets/{VerseConsoleApp-CTF3Shs0.js → VerseConsoleApp-DTjDpGCd.js} +3 -3
- package/dist/core/web/public/next/assets/{VerseConsoleApp-CTF3Shs0.js.map → VerseConsoleApp-DTjDpGCd.js.map} +1 -1
- package/dist/core/web/public/next/assets/{Workspace-CgdyXiEV.js → Workspace-DfcFGzME.js} +5 -5
- package/dist/core/web/public/next/assets/{Workspace-CgdyXiEV.js.map → Workspace-DfcFGzME.js.map} +1 -1
- package/dist/core/web/public/next/assets/{actions-MtxBGS5B.js → actions-tWevL9HV.js} +2 -2
- package/dist/core/web/public/next/assets/{actions-MtxBGS5B.js.map → actions-tWevL9HV.js.map} +1 -1
- package/dist/core/web/public/next/assets/{budget-queries-CP7hgR-p.js → budget-queries-V3wcJVK_.js} +2 -2
- package/dist/core/web/public/next/assets/{budget-queries-CP7hgR-p.js.map → budget-queries-V3wcJVK_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{capacity-strip-model-fHfu5cph.js → capacity-strip-model-BDbmQ3e3.js} +2 -2
- package/dist/core/web/public/next/assets/{capacity-strip-model-fHfu5cph.js.map → capacity-strip-model-BDbmQ3e3.js.map} +1 -1
- package/dist/core/web/public/next/assets/{charts-Bis9WSiS.js → charts-CfAjuKMv.js} +2 -2
- package/dist/core/web/public/next/assets/{charts-Bis9WSiS.js.map → charts-CfAjuKMv.js.map} +1 -1
- package/dist/core/web/public/next/assets/{cloud-queries-BsOepFz6.js → cloud-queries-Br_r0UAz.js} +2 -2
- package/dist/core/web/public/next/assets/{cloud-queries-BsOepFz6.js.map → cloud-queries-Br_r0UAz.js.map} +1 -1
- package/dist/core/web/public/next/assets/{cloud.module-DoFnr8ZH.js → cloud.module-ascz58c3.js} +2 -2
- package/dist/core/web/public/next/assets/{cloud.module-DoFnr8ZH.js.map → cloud.module-ascz58c3.js.map} +1 -1
- package/dist/core/web/public/next/assets/{command-bus-CMvbYP5K.js → command-bus-xYZoK9nQ.js} +2 -2
- package/dist/core/web/public/next/assets/{command-bus-CMvbYP5K.js.map → command-bus-xYZoK9nQ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{context-model-Ci3Ch9t5.js → context-model-BC-HOmPo.js} +2 -2
- package/dist/core/web/public/next/assets/{context-model-Ci3Ch9t5.js.map → context-model-BC-HOmPo.js.map} +1 -1
- package/dist/core/web/public/next/assets/{context-model-CjiJTnf1.js → context-model-CIBmSugV.js} +2 -2
- package/dist/core/web/public/next/assets/{context-model-CjiJTnf1.js.map → context-model-CIBmSugV.js.map} +1 -1
- package/dist/core/web/public/next/assets/{context-queries-BDXT6LQ3.js → context-queries-CrPcHWTz.js} +2 -2
- package/dist/core/web/public/next/assets/{context-queries-BDXT6LQ3.js.map → context-queries-CrPcHWTz.js.map} +1 -1
- package/dist/core/web/public/next/assets/{control-queries-Dv-h1Clu.js → control-queries-CmgBgKV7.js} +2 -2
- package/dist/core/web/public/next/assets/{control-queries-Dv-h1Clu.js.map → control-queries-CmgBgKV7.js.map} +1 -1
- package/dist/core/web/public/next/assets/{dock-icons-t--Eugrd.js → dock-icons-CUh8dOxJ.js} +2 -2
- package/dist/core/web/public/next/assets/{dock-icons-t--Eugrd.js.map → dock-icons-CUh8dOxJ.js.map} +1 -1
- package/dist/core/web/public/next/assets/{dock-store-qIu7kSQE.js → dock-store-B2vlxqPu.js} +2 -2
- package/dist/core/web/public/next/assets/{dock-store-qIu7kSQE.js.map → dock-store-B2vlxqPu.js.map} +1 -1
- package/dist/core/web/public/next/assets/{fleet-model-IRbwfhkR.js → fleet-model-7i-FbzKI.js} +2 -2
- package/dist/core/web/public/next/assets/{fleet-model-IRbwfhkR.js.map → fleet-model-7i-FbzKI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{fleet-queries-7FVNByX1.js → fleet-queries-DzGoqq8X.js} +2 -2
- package/dist/core/web/public/next/assets/{fleet-queries-7FVNByX1.js.map → fleet-queries-DzGoqq8X.js.map} +1 -1
- package/dist/core/web/public/next/assets/{focus-trap-QqQxQdvH.js → focus-trap-HtcoXeEq.js} +2 -2
- package/dist/core/web/public/next/assets/{focus-trap-QqQxQdvH.js.map → focus-trap-HtcoXeEq.js.map} +1 -1
- package/dist/core/web/public/next/assets/{format-CaMmVQCn.js → format-BkWdOQDL.js} +2 -2
- package/dist/core/web/public/next/assets/{format-CaMmVQCn.js.map → format-BkWdOQDL.js.map} +1 -1
- package/dist/core/web/public/next/assets/{git-model-B4S_GUNA.js → git-model-bk_RXh3y.js} +2 -2
- package/dist/core/web/public/next/assets/{git-model-B4S_GUNA.js.map → git-model-bk_RXh3y.js.map} +1 -1
- package/dist/core/web/public/next/assets/{global-BkNl4e6E.js → global-oEl9Qj8u.js} +2 -2
- package/dist/core/web/public/next/assets/{global-BkNl4e6E.js.map → global-oEl9Qj8u.js.map} +1 -1
- package/dist/core/web/public/next/assets/{guarded-action-DHiL8tY5.js → guarded-action-OzqcPjmh.js} +3 -3
- package/dist/core/web/public/next/assets/{guarded-action-DHiL8tY5.js.map → guarded-action-OzqcPjmh.js.map} +1 -1
- package/dist/core/web/public/next/assets/{guarded-runners-DmGEkM2P.js → guarded-runners-LHLXmXIk.js} +2 -2
- package/dist/core/web/public/next/assets/{guarded-runners-DmGEkM2P.js.map → guarded-runners-LHLXmXIk.js.map} +1 -1
- package/dist/core/web/public/next/assets/{icon-base-NtFmP2yB.js → icon-base-DvM1eI5V.js} +2 -2
- package/dist/core/web/public/next/assets/{icon-base-NtFmP2yB.js.map → icon-base-DvM1eI5V.js.map} +1 -1
- package/dist/core/web/public/next/assets/{icons-C5EFt_Ts.js → icons-DEQa2rTx.js} +2 -2
- package/dist/core/web/public/next/assets/{icons-C5EFt_Ts.js.map → icons-DEQa2rTx.js.map} +1 -1
- package/dist/core/web/public/next/assets/{index-DbDw9UAs.js → index-BVxOlseC.js} +3 -3
- package/dist/core/web/public/next/assets/{index-DbDw9UAs.js.map → index-BVxOlseC.js.map} +1 -1
- package/dist/core/web/public/next/assets/{live-model-DEwrl7_A.js → live-model-bmsJgnYD.js} +2 -2
- package/dist/core/web/public/next/assets/{live-model-DEwrl7_A.js.map → live-model-bmsJgnYD.js.map} +1 -1
- package/dist/core/web/public/next/assets/{mind.module-CLhqMQak.js → mind.module-gTGAuJt1.js} +2 -2
- package/dist/core/web/public/next/assets/{mind.module-CLhqMQak.js.map → mind.module-gTGAuJt1.js.map} +1 -1
- package/dist/core/web/public/next/assets/{mutations-Kvzsg-iK.js → mutations-C5S7okTW.js} +2 -2
- package/dist/core/web/public/next/assets/{mutations-Kvzsg-iK.js.map → mutations-C5S7okTW.js.map} +1 -1
- package/dist/core/web/public/next/assets/{nav-C0IunEYF.js → nav-NVtnuG7A.js} +2 -2
- package/dist/core/web/public/next/assets/{nav-C0IunEYF.js.map → nav-NVtnuG7A.js.map} +1 -1
- package/dist/core/web/public/next/assets/{overnight-queries-C_AfcL7q.js → overnight-queries-DGm3qL1b.js} +2 -2
- package/dist/core/web/public/next/assets/{overnight-queries-C_AfcL7q.js.map → overnight-queries-DGm3qL1b.js.map} +1 -1
- package/dist/core/web/public/next/assets/{preloaded-CctOitLu.js → preloaded-Cwf9rsnZ.js} +2 -2
- package/dist/core/web/public/next/assets/{preloaded-CctOitLu.js.map → preloaded-Cwf9rsnZ.js.map} +1 -1
- package/dist/core/web/public/next/assets/primitives-DyCKYSBG.js +1 -0
- package/dist/core/web/public/next/assets/{queries-THD05gHP.js → queries-CYisSAAB.js} +2 -2
- package/dist/core/web/public/next/assets/{queries-THD05gHP.js.map → queries-CYisSAAB.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reasoning-pref-BVPu0SME.js → reasoning-pref-BUcFF_5G.js} +2 -2
- package/dist/core/web/public/next/assets/{reasoning-pref-BVPu0SME.js.map → reasoning-pref-BUcFF_5G.js.map} +1 -1
- package/dist/core/web/public/next/assets/{reveal-anchor-wCT5b4m3.js → reveal-anchor-D-tV8xau.js} +2 -2
- package/dist/core/web/public/next/assets/{reveal-anchor-wCT5b4m3.js.map → reveal-anchor-D-tV8xau.js.map} +1 -1
- package/dist/core/web/public/next/assets/{seat-subscription-CR_VylsK.js → seat-subscription-B-f9ViU2.js} +2 -2
- package/dist/core/web/public/next/assets/{seat-subscription-CR_VylsK.js.map → seat-subscription-B-f9ViU2.js.map} +1 -1
- package/dist/core/web/public/next/assets/{section-visibility-B0xXUQJ0.js → section-visibility-Yctxu-if.js} +2 -2
- package/dist/core/web/public/next/assets/{section-visibility-B0xXUQJ0.js.map → section-visibility-Yctxu-if.js.map} +1 -1
- package/dist/core/web/public/next/assets/{sidebar-model-C5wVXGpb.js → sidebar-model-DQ-FyBHW.js} +2 -2
- package/dist/core/web/public/next/assets/{sidebar-model-C5wVXGpb.js.map → sidebar-model-DQ-FyBHW.js.map} +1 -1
- package/dist/core/web/public/next/assets/{slots-DDd8cEoh.js → slots-BhP8b8tf.js} +3 -3
- package/dist/core/web/public/next/assets/{slots-DDd8cEoh.js.map → slots-BhP8b8tf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{surface-data-BFxAlefI.js → surface-data-DTI7LjvH.js} +2 -2
- package/dist/core/web/public/next/assets/{surface-data-BFxAlefI.js.map → surface-data-DTI7LjvH.js.map} +1 -1
- package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js +2 -0
- package/dist/core/web/public/next/assets/{surface-prefetch-CHusyO9q.js.map → surface-prefetch-CdUEBFrl.js.map} +1 -1
- package/dist/core/web/public/next/assets/{tasks-model-DvkWveXs.js → tasks-model-BKDNqmmt.js} +2 -2
- package/dist/core/web/public/next/assets/{tasks-model-DvkWveXs.js.map → tasks-model-BKDNqmmt.js.map} +1 -1
- package/dist/core/web/public/next/assets/{terminal-icons-Dp6pJgV2.js → terminal-icons-D2xe-aM1.js} +2 -2
- package/dist/core/web/public/next/assets/{terminal-icons-Dp6pJgV2.js.map → terminal-icons-D2xe-aM1.js.map} +1 -1
- package/dist/core/web/public/next/assets/{usage-queries-CUTmnegA.js → usage-queries-BZuAANlI.js} +2 -2
- package/dist/core/web/public/next/assets/{usage-queries-CUTmnegA.js.map → usage-queries-BZuAANlI.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-guarded-action-UCX2u1t1.js → use-guarded-action-Cf4MeNBa.js} +2 -2
- package/dist/core/web/public/next/assets/{use-guarded-action-UCX2u1t1.js.map → use-guarded-action-Cf4MeNBa.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-ticker-OXAjob3y.js → use-ticker-D9yi49my.js} +2 -2
- package/dist/core/web/public/next/assets/{use-ticker-OXAjob3y.js.map → use-ticker-D9yi49my.js.map} +1 -1
- package/dist/core/web/public/next/assets/{use-token-gate-CDDRAoKH.js → use-token-gate-DqrSXdX6.js} +2 -2
- package/dist/core/web/public/next/assets/{use-token-gate-CDDRAoKH.js.map → use-token-gate-DqrSXdX6.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useChartWidth-D9M7kUw7.js → useChartWidth-owwodNVz.js} +2 -2
- package/dist/core/web/public/next/assets/{useChartWidth-D9M7kUw7.js.map → useChartWidth-owwodNVz.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useSeatsRefresh-B2dCVcj9.js → useSeatsRefresh-DgFy-Ph4.js} +2 -2
- package/dist/core/web/public/next/assets/{useSeatsRefresh-B2dCVcj9.js.map → useSeatsRefresh-DgFy-Ph4.js.map} +1 -1
- package/dist/core/web/public/next/assets/{useVerseTranscript-BL3CljSI.js → useVerseTranscript-CDYrrWOO.js} +2 -2
- package/dist/core/web/public/next/assets/{useVerseTranscript-BL3CljSI.js.map → useVerseTranscript-CDYrrWOO.js.map} +1 -1
- package/dist/core/web/public/next/assets/{verse-icons-DASWdYuE.js → verse-icons-F9VwX07_.js} +2 -2
- package/dist/core/web/public/next/assets/{verse-icons-DASWdYuE.js.map → verse-icons-F9VwX07_.js.map} +1 -1
- package/dist/core/web/public/next/assets/{verse-model-BQ0Y2CSr.js → verse-model-DyCwZF-M.js} +2 -2
- package/dist/core/web/public/next/assets/{verse-model-BQ0Y2CSr.js.map → verse-model-DyCwZF-M.js.map} +1 -1
- package/dist/core/web/public/next/assets/{verse-ui-store-D7YXi63q.js → verse-ui-store-62DxpVHS.js} +3 -3
- package/dist/core/web/public/next/assets/{verse-ui-store-D7YXi63q.js.map → verse-ui-store-62DxpVHS.js.map} +1 -1
- package/dist/core/web/public/next/assets/{viewport-BYGH5EgA.js → viewport-nTubFCwf.js} +2 -2
- package/dist/core/web/public/next/assets/{viewport-BYGH5EgA.js.map → viewport-nTubFCwf.js.map} +1 -1
- package/dist/core/web/public/next/assets/{warmup-AsqwWCUi.js → warmup-HG5vYbsN.js} +3 -3
- package/dist/core/web/public/next/assets/{warmup-AsqwWCUi.js.map → warmup-HG5vYbsN.js.map} +1 -1
- package/dist/core/web/public/next/assets/{workspace-model-CXorJr0G.js → workspace-model-CbhdPhei.js} +2 -2
- package/dist/core/web/public/next/assets/{workspace-model-CXorJr0G.js.map → workspace-model-CbhdPhei.js.map} +1 -1
- package/dist/core/web/public/next/index.html +1 -1
- package/dist/release-dependency-inventory.json +1 -1
- package/package.json +1 -1
- package/dist/core/web/public/next/assets/AutonomySection-D3d8lYO3.js +0 -2
- package/dist/core/web/public/next/assets/McpSection-DvHFaVyp.js +0 -2
- package/dist/core/web/public/next/assets/primitives-CbAGCNKt.js +0 -1
- package/dist/core/web/public/next/assets/surface-prefetch-CHusyO9q.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/nav-history.ts","../../../../../../src/web-ui/routes/verse/shell/section-modules.ts","../../../../../../src/web-ui/routes/verse/verse-ui-store.ts"],"sourcesContent":["/**\n * routes/verse/shell/nav-history.ts — ⌘[ / ⌘] through surfaces AND chats\n * (unit C1; SPEC-310C §1 \"Keep-alive\").\n *\n * One linear history, like a browser's: visiting a place after going back\n * drops the forward entries. A chat is a place of its own — Chat ▸ A and\n * Chat ▸ B are two entries — so \"back\" after jumping from one chat to another\n * returns to the first chat, not to whatever surface was before Chat.\n *\n * Pure: the ui store holds the value and decides when to push.\n */\nimport type { WorkbenchSectionId } from '../../../../core/verse/workbench-types.js';\n\nexport interface NavEntry {\n section: WorkbenchSectionId;\n /** The chat open at the time; only meaningful when `section` is chat. */\n sessionId: string | null;\n}\n\nexport interface NavHistory {\n entries: readonly NavEntry[];\n /** Index of the current entry; -1 only for an empty history. */\n index: number;\n}\n\n/** Bounded: a long day of switching must not grow without limit. */\nexport const NAV_HISTORY_LIMIT = 50;\n\nexport const EMPTY_NAV_HISTORY: NavHistory = Object.freeze({ entries: Object.freeze([]) as readonly NavEntry[], index: -1 });\n\nfunction sameEntry(a: NavEntry | undefined, b: NavEntry): boolean {\n return !!a && a.section === b.section && (a.section !== 'chat' || a.sessionId === b.sessionId);\n}\n\n/** Visit `entry`: drop the forward stack, skip a no-op repeat, cap the length. */\nexport function pushNav(history: NavHistory, entry: NavEntry): NavHistory {\n const normalised: NavEntry = { section: entry.section, sessionId: entry.section === 'chat' ? entry.sessionId : null };\n const current = history.entries[history.index];\n if (sameEntry(current, normalised)) return history;\n // \"Chat, no chat open yet\" followed by the chat that then opened is ONE\n // visit: refine the entry in place (dropping any forward stack) rather\n // than leaving a back-stop that shows an empty chat.\n if (current && current.section === 'chat' && current.sessionId === null && normalised.section === 'chat') {\n const entries = [...history.entries.slice(0, history.index), normalised];\n return { entries, index: entries.length - 1 };\n }\n const kept = history.entries.slice(0, history.index + 1);\n const entries = [...kept, normalised].slice(-NAV_HISTORY_LIMIT);\n return { entries, index: entries.length - 1 };\n}\n\nexport function canGoBack(history: NavHistory): boolean {\n return history.index > 0;\n}\n\nexport function canGoForward(history: NavHistory): boolean {\n return history.index >= 0 && history.index < history.entries.length - 1;\n}\n\n/** Step `delta` (−1 back, +1 forward). Null when there is nowhere to go. */\nexport function stepNav(history: NavHistory, delta: -1 | 1): { history: NavHistory; entry: NavEntry } | null {\n const index = history.index + delta;\n const entry = history.entries[index];\n if (!entry) return null;\n return { history: { entries: history.entries, index }, entry };\n}\n\n/**\n * ⌃Tab through recent chats: the most-recently-used list, current chat first.\n * Consecutive presses inside `windowMs` keep walking the SAME snapshot of\n * the list (the Alt-Tab rule), so ⌃Tab ⌃Tab reaches the third-most-recent\n * chat instead of bouncing between two.\n */\nexport interface RecentCycle {\n order: readonly string[];\n position: number;\n at: number;\n}\n\nexport const RECENT_CYCLE_WINDOW_MS = 1_500;\nexport const RECENT_CHATS_LIMIT = 10;\n\nexport function cycleRecent(\n recent: readonly string[],\n cycle: RecentCycle | null,\n direction: 1 | -1,\n now: number,\n windowMs: number = RECENT_CYCLE_WINDOW_MS,\n): { sessionId: string; cycle: RecentCycle } | null {\n const fresh = !cycle || now - cycle.at > windowMs;\n const order = fresh ? recent : cycle!.order;\n if (order.length < 2) return null;\n const from = fresh ? 0 : cycle!.position;\n const position = (from + direction + order.length) % order.length;\n return { sessionId: order[position]!, cycle: { order, position, at: now } };\n}\n\n/** Move `sessionId` to the front of the MRU list. */\nexport function touchRecent(recent: readonly string[], sessionId: string, limit: number = RECENT_CHATS_LIMIT): string[] {\n return [sessionId, ...recent.filter((id) => id !== sessionId)].slice(0, limit);\n}\n","/**\n * routes/verse/shell/section-modules.ts — every `sections/*Section.tsx` that\n * exists at build time, lazily (unit C1).\n *\n * The rail's surfaces are written by other owners and land at different\n * times (C7's Command/Fleet/Growth/Mind, C6's Apps). A glob yields real\n * per-section code splitting for a module that is present and a missing KEY\n * — not an unresolved import — for one that is not, so the shell builds and\n * runs at every stage of the landing.\n *\n * Lives here rather than in VerseApp.tsx so the framework-free ui store can\n * ask \"has Command landed?\" (for the first-launch-of-the-day rule) without\n * importing the shell component. Keys are re-based to `./sections/<Module>.tsx`\n * — relative to routes/verse, the form VerseApp and VerseConsoleApp's\n * first-paint preload have always used.\n *\n * THE COST OF A GLOB, paid once: a finished section outside `sections/` is\n * invisible, with nothing failing to say so (MCP shipped that way for a\n * release). VerseApp.test.tsx walks this map for every VERSE_SECTIONS entry.\n */\ntype Importer = () => Promise<unknown>;\n\nconst RAW: Record<string, Importer> = import.meta.glob('../sections/*Section.tsx');\n\nexport const SECTION_MODULES: Record<string, Importer> = Object.fromEntries(\n Object.entries(RAW).map(([key, load]) => [key.replace(/^\\.\\.\\//, './'), load]),\n);\n\n/** The importer for one module name (`ChatSection`), or undefined when it has not landed. */\nexport function sectionImporter(module: string, modules: Record<string, Importer> = SECTION_MODULES): Importer | undefined {\n return modules[`./sections/${module}.tsx`];\n}\n","/**\n * routes/verse/verse-ui-store.ts — the workbench shell's own state (unit C1):\n * which surface is on screen and which stay mounted behind it, the overlays\n * (⌘K palette, ⌘J Needs you, ⌘/ shortcuts), back/forward history, recent\n * chats, and the layout preferences the chat reads. Framework-free (one\n * `useSyncExternalStore` hook in useVerseUi.ts), same split as verse-store.ts.\n *\n * PERSISTED under `ashlr.verse.ui.v3` — ONE blob with ONE writer (this\n * module). The dock's state is its `dock` field, owned by C2's dock-store and\n * folded in here on every change (dock-catalog.ts: two writers must never\n * race for the key).\n *\n * v2 → v3 MIGRATION (SPEC-310C §0.1). 3.10 renumbered the rail: ⌘1 Command …\n * ⌘5 Chat, with Settings / Apps / Usage in the gear tray. A saved v2 section\n * migrates through workbench-types `migrateSectionId`: autonomy → fleet,\n * approvals → Command WITH the Needs-you drawer open, mcp → apps. The v2 key\n * is left in place (a downgrade still finds its own state) and is never read\n * again once v3 exists.\n *\n * LAUNCH RULE. The first launch each local day opens Command — the overnight\n * digest is the point of opening the app in the morning. Later launches\n * return to the last surface. A surface whose module has not landed yet is\n * never forced (the rule falls through to the saved section).\n *\n * NOT PERSISTED, on purpose: the overlays, `command` (a one-shot hand-off to\n * the chat), history, the keep-alive list and `activeSessionId` — all\n * evidence about this page's life, not preferences.\n *\n * NOT HERE: appearance (theme, accent, density — data/appearance-store.ts owns\n * <html>), the reasoning display (chat/reasoning-pref.ts, C2), chat panel\n * widths (chat-panel-sizing.ts, C2), and the desktop preferences (system-wide\n * hotkey, notifications) — the desktop app stores those itself\n * (desktop_prefs.rs) and reports what actually took effect (a chord another\n * app holds comes back unregistered), so a copy here could only disagree\n * with it. Settings ▸ Desktop reads app/desktop-shell.ts useDesktopState().\n */\nimport {\n migrateSectionId,\n NEEDS_YOU_CATEGORIES,\n type NeedsYouCategory,\n type WorkbenchSectionId,\n} from '../../../core/verse/workbench-types.js';\nimport { getDockState, subscribeDockState } from './dock/dock-store.js';\nimport { VERSE_UI_STORAGE_KEY as V3_KEY, VERSE_UI_STORAGE_KEY_V2 as V2_KEY } from './shell/dock-catalog.js';\nimport {\n cycleRecent,\n pushNav,\n stepNav,\n touchRecent,\n RECENT_CHATS_LIMIT,\n type NavHistory,\n type RecentCycle,\n} from './shell/nav-history.js';\nimport { sectionImporter } from './shell/section-modules.js';\n\n// ===========================================================================\n// Sections\n// ===========================================================================\n\nexport type VerseSectionId = WorkbenchSectionId;\n\nexport interface VerseSectionEntry {\n id: VerseSectionId;\n label: string;\n /** The file `sections/<module>.tsx` the shell mounts (and first paint preloads). */\n module: string;\n /**\n * Modules to mount while `module` has not landed: Fleet shows the legacy\n * Autonomy panels until C7's FleetSection arrives. Never a guess at a\n * different surface. (Apps no longer falls back to MCP: C6's AppsSection\n * folds MCP in, and a stale MCP page under the \"Apps & Accounts\" name would\n * hide the seats and agents the operator went there for.)\n */\n fallbackModules?: readonly string[];\n /** Rail (⌘1–⌘5) or gear tray. */\n placement: 'rail' | 'tray';\n /** One line for the onboarding tour and the palette. */\n blurb: string;\n}\n\n/**\n * Rail order IS the ⌘1–⌘5 order (SPEC-310B §6); tray entries follow. A\n * section missing from this list is unreachable however complete it is.\n */\nexport const VERSE_SECTIONS: readonly VerseSectionEntry[] = [\n { id: 'command', label: 'Command', module: 'CommandSection', placement: 'rail', blurb: 'What the fleet did, what needs you, and the autonomy switch — the morning read.' },\n { id: 'fleet', label: 'Fleet', module: 'FleetSection', fallbackModules: ['AutonomySection'], placement: 'rail', blurb: 'Every lane live: what is building, what the gates refused, and why each seat was chosen.' },\n { id: 'growth', label: 'Growth', module: 'GrowthSection', placement: 'rail', blurb: 'Is the fleet getting better? Merges, cost per merge and the experiments behind them.' },\n { id: 'mind', label: 'Mind', module: 'MindSection', placement: 'rail', blurb: \"The Leader's memos, what came of each move, and what the reasoning shows.\" },\n { id: 'chat', label: 'Chat', module: 'ChatSection', placement: 'rail', blurb: 'Talk to a seat. Chats are grouped by project and resume where they stopped.' },\n { id: 'settings', label: 'Settings', module: 'SettingsSection', placement: 'tray', blurb: 'Theme, chat, desktop and keyboard — and this tour again.' },\n { id: 'apps', label: 'Apps & Accounts', module: 'AppsSection', placement: 'tray', blurb: 'Seats, terminal agents, local models and MCP servers in one list.' },\n { id: 'usage', label: 'Usage', module: 'UsageSection', placement: 'tray', blurb: 'Which account you can actually use right now, and what it costs.' },\n];\n\nexport const RAIL_SECTIONS: readonly VerseSectionEntry[] = VERSE_SECTIONS.filter((s) => s.placement === 'rail');\nexport const TRAY_SECTIONS: readonly VerseSectionEntry[] = VERSE_SECTIONS.filter((s) => s.placement === 'tray');\n\nconst SECTION_IDS = new Set<string>(VERSE_SECTIONS.map((s) => s.id));\n\nexport function sectionEntry(id: VerseSectionId): VerseSectionEntry {\n return VERSE_SECTIONS.find((s) => s.id === id)!;\n}\n\n/** The module that will actually mount for `id` (primary first, then fallbacks); null when none landed. */\nexport function landedModule(id: VerseSectionId, landed: (module: string) => boolean = (m) => sectionImporter(m) !== undefined): string | null {\n const entry = sectionEntry(id);\n for (const module of [entry.module, ...(entry.fallbackModules ?? [])]) if (landed(module)) return module;\n return null;\n}\n\n// ===========================================================================\n// State\n// ===========================================================================\n\n/**\n * One-shot shell → chat requests. The chat surface is lazily mounted and takes\n * no props, so the shell raises a command here and the chat consumes it by\n * nonce, then clears it.\n * new-chat ⌘N / \"New chat on…\" — optional seat or project prefill\n * quick-switcher (pre-3.10; kept until C2 retires QuickSwitcher)\n * open-session the palette, the drawer, ⌘[ ⌘], ⌃Tab, a notification\n * focus-composer the system-wide hotkey (⌃⌥Space)\n */\nexport type VerseCommandName = 'new-chat' | 'quick-switcher' | 'open-session' | 'focus-composer';\n\nexport interface VerseCommand {\n name: VerseCommandName;\n /** Monotonic; a section reacts when it sees a nonce it has not handled. */\n nonce: number;\n sessionId?: string;\n seatId?: string;\n projectPath?: string;\n}\n\nexport type VerseCommandArgs = Pick<VerseCommand, 'sessionId' | 'seatId' | 'projectPath'>;\n\nexport type VerseOverlay = 'palette' | 'needs-you' | 'shortcuts' | null;\nexport type NeedsYouSplit = 'all' | NeedsYouCategory;\nexport const NEEDS_YOU_SPLITS: readonly NeedsYouSplit[] = ['all', ...NEEDS_YOU_CATEGORIES];\n\nexport interface VerseUiState {\n section: VerseSectionId;\n /** Rail shows labels beside its icons (⌘⇧\\). Defaults collapsed: the 56px rail is shipped muscle memory. */\n railExpanded: boolean;\n sidebarWidth: number;\n sidebarCollapsed: boolean;\n resourcesOpen: boolean;\n resourcesWidth: number;\n /** The last this-many palette actions run (empty query shows them). */\n recentActions: readonly string[];\n /** Most-recently-used chats, current first (⌃Tab). */\n recentChats: readonly string[];\n // ── not persisted ──\n /** Surfaces kept mounted (hidden + inert) behind the current one, most recent first. */\n mounted: readonly VerseSectionId[];\n overlay: VerseOverlay;\n needsYouSplit: NeedsYouSplit;\n /** An item the drawer should select when it opens (from the palette or a notification). */\n needsYouFocus: string | null;\n history: NavHistory;\n /** The chat open in the Chat surface, as reported by the chat (or by the shell when it opened one). */\n activeSessionId: string | null;\n command: VerseCommand | null;\n /** Set when a v2 blob was migrated this load: the shell announces \"Chat moved to ⌘5\" once. */\n announceChatMoved: boolean;\n}\n\nexport const VERSE_SIDEBAR = { min: 240, max: 360, def: 264 } as const;\nexport const VERSE_RESOURCES = { min: 260, max: 480, def: 320 } as const;\n/** Surfaces kept alive besides Chat (which, once visited, always stays). */\nexport const KEEP_ALIVE_SURFACES = 3;\nexport const RECENT_ACTIONS_LIMIT = 5;\n\nexport const VERSE_UI_STORAGE_KEY = V3_KEY;\nexport const VERSE_UI_STORAGE_KEY_V2 = V2_KEY;\n\nconst DEFAULTS: VerseUiState = {\n section: 'chat',\n railExpanded: false,\n sidebarWidth: VERSE_SIDEBAR.def,\n sidebarCollapsed: false,\n resourcesOpen: true,\n resourcesWidth: VERSE_RESOURCES.def,\n recentActions: [],\n recentChats: [],\n mounted: ['chat'],\n overlay: null,\n needsYouSplit: 'all',\n needsYouFocus: null,\n history: { entries: [{ section: 'chat', sessionId: null }], index: 0 },\n activeSessionId: null,\n command: null,\n announceChatMoved: false,\n};\n\nexport function clampWidth(value: unknown, range: { min: number; max: number; def: number }): number {\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/** Local calendar day, `YYYY-MM-DD` — \"first launch each day\" is the operator's day, not UTC's. */\nexport function localDay(ms: number): string {\n const d = new Date(ms);\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n}\n\ninterface PersistedV3 {\n version: 3;\n section: VerseSectionId;\n railExpanded: boolean;\n sidebarWidth: number;\n sidebarCollapsed: boolean;\n resourcesOpen: boolean;\n resourcesWidth: number;\n recentActions: string[];\n recentChats: string[];\n lastLaunchDay: string | null;\n chatMovedAnnounced: boolean;\n dock: unknown;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction stringList(value: unknown, limit: number, re: RegExp): string[] {\n if (!Array.isArray(value)) return [];\n const out: string[] = [];\n for (const v of value) {\n if (typeof v === 'string' && re.test(v) && !out.includes(v)) out.push(v);\n if (out.length >= limit) break;\n }\n return out;\n}\n\nfunction readJson(key: string): Record<string, unknown> | null {\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as unknown;\n return isObject(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/** Bookkeeping that is persisted but is not UI state. */\nlet lastLaunchDay: string | null = null;\nlet chatMovedAnnounced = false;\n\nexport interface LoadOptions {\n now?: number;\n /** Has this module landed? (Injected by tests; the build's glob otherwise.) */\n landed?: (module: string) => boolean;\n}\n\n/**\n * Read v3, else migrate v2, else defaults — then apply the launch rule.\n * Total: a hand-edited or future blob falls back field by field.\n */\nexport function loadVerseUi(options: LoadOptions = {}): VerseUiState {\n const now = options.now ?? Date.now();\n const landed = options.landed ?? ((m: string) => sectionImporter(m) !== undefined);\n const v3 = readJson(V3_KEY);\n const v2 = v3 ? null : readJson(V2_KEY);\n const src = v3 ?? v2 ?? {};\n\n let section: VerseSectionId = DEFAULTS.section;\n let overlay: VerseOverlay = null;\n const migration = migrateSectionId(src['section']);\n if (migration && SECTION_IDS.has(migration.section)) {\n section = migration.section;\n if (migration.openNeedsYou && !v3) overlay = 'needs-you';\n }\n\n lastLaunchDay = v3 && typeof v3['lastLaunchDay'] === 'string' ? v3['lastLaunchDay'] : null;\n chatMovedAnnounced = v3 ? v3['chatMovedAnnounced'] === true : false;\n\n const today = localDay(now);\n // First launch of the day → Command, when Command exists in this build.\n if (lastLaunchDay !== today && landedModule('command', landed) !== null) section = 'command';\n lastLaunchDay = today;\n\n const state: VerseUiState = {\n ...DEFAULTS,\n section,\n railExpanded: src['railExpanded'] === true,\n sidebarWidth: clampWidth(src['sidebarWidth'], VERSE_SIDEBAR),\n sidebarCollapsed: src['sidebarCollapsed'] === true,\n resourcesOpen: src['resourcesOpen'] !== false,\n resourcesWidth: clampWidth(src['resourcesWidth'], VERSE_RESOURCES),\n recentActions: stringList(src['recentActions'], RECENT_ACTIONS_LIMIT, /^[a-z][a-z0-9.-]{0,63}$/),\n recentChats: stringList(src['recentChats'], RECENT_CHATS_LIMIT, /^[\\w.-]{1,200}$/),\n mounted: [section],\n overlay,\n history: { entries: [{ section, sessionId: null }], index: 0 },\n // A v2 blob means this operator had ⌘1 = Chat in their hands yesterday.\n announceChatMoved: v2 !== null && !chatMovedAnnounced,\n };\n return state;\n}\n\nlet state: VerseUiState = DEFAULTS;\nlet nonce = 0;\nlet recentCycle: RecentCycle | null = null;\nconst listeners = new Set<() => void>();\n\nfunction persist(next: VerseUiState): void {\n const payload: PersistedV3 = {\n version: 3,\n section: next.section,\n railExpanded: next.railExpanded,\n sidebarWidth: next.sidebarWidth,\n sidebarCollapsed: next.sidebarCollapsed,\n resourcesOpen: next.resourcesOpen,\n resourcesWidth: next.resourcesWidth,\n recentActions: [...next.recentActions],\n recentChats: [...next.recentChats],\n lastLaunchDay,\n chatMovedAnnounced,\n dock: getDockState(),\n };\n try {\n localStorage.setItem(V3_KEY, JSON.stringify(payload));\n } catch {\n /* best-effort: a private window without storage still runs the app */\n }\n}\n\nconst PERSISTED_FIELDS = [\n 'section',\n 'railExpanded',\n 'sidebarWidth',\n 'sidebarCollapsed',\n 'resourcesOpen',\n 'resourcesWidth',\n 'recentActions',\n 'recentChats',\n] as const satisfies readonly (keyof VerseUiState)[];\n\n/** Snapshot identity only changes when something actually changed. */\nfunction patch(delta: Partial<VerseUiState>): void {\n const next = { ...state, ...delta };\n if ((Object.keys(delta) as (keyof VerseUiState)[]).every((k) => Object.is(state[k], next[k]))) return;\n const shouldPersist = PERSISTED_FIELDS.some((k) => !Object.is(state[k], next[k]));\n state = next;\n if (shouldPersist) persist(next);\n for (const l of [...listeners]) l();\n}\n\nfunction init(): void {\n state = loadVerseUi();\n // Write the migrated / launch-ruled state straight away, so the day's first\n // launch is recorded even if the operator closes the app without a click.\n persist(state);\n}\n\ninit();\n\n// C2's dock changes are folded into the blob as they happen.\nlet lastDockJson = '';\nsubscribeDockState(() => {\n let json = '';\n try { json = JSON.stringify(getDockState()); } catch { json = ''; }\n if (json === lastDockJson) return;\n lastDockJson = json;\n persist(state);\n});\n\nexport function subscribeVerseUi(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function getVerseUiState(): VerseUiState {\n return state;\n}\n\n// ===========================================================================\n// Navigation\n// ===========================================================================\n\nfunction withMounted(mounted: readonly VerseSectionId[], section: VerseSectionId): VerseSectionId[] {\n // The last KEEP_ALIVE_SURFACES surfaces other than Chat, most recent first…\n const chatVisited = section === 'chat' || mounted.includes('chat');\n const others = mounted.filter((id) => id !== 'chat' && id !== section);\n const nonChat = (section === 'chat' ? others : [section, ...others]).slice(0, KEEP_ALIVE_SURFACES);\n const alive: VerseSectionId[] = section === 'chat' ? ['chat', ...nonChat] : nonChat;\n // …and Chat, once visited, always: its streams, scroll and draft are the\n // most expensive state in the app to rebuild.\n if (chatVisited && !alive.includes('chat')) alive.push('chat');\n return alive;\n}\n\nfunction go(section: VerseSectionId, options: { history: boolean }): void {\n if (!SECTION_IDS.has(section)) return;\n const history = options.history\n ? pushNav(state.history, { section, sessionId: section === 'chat' ? state.activeSessionId : null })\n : state.history;\n patch({ section, mounted: withMounted(state.mounted, section), history });\n}\n\n/** The window event that asks the shell to reveal an anchor on a surface (shell/reveal-anchor.ts). */\nexport const VERSE_ANCHOR_EVENT = 'ashlr:verse-anchor';\n\nexport interface VerseAnchorRequest {\n section: VerseSectionId;\n /** A surface's own anchor key (\"memo:m-7\", \"seat:claude-a\"); the element carries `c7-anchor-<key>` or `data-verse-anchor`. */\n anchor: string;\n}\n\n/**\n * Switch surface; with `anchor`, also ask the shell to scroll that card or\n * row into view once the surface has painted. The anchor travels as a window\n * event rather than store state because it is a one-shot gesture about DOM\n * that may not exist yet (a lazy chunk), and every unit that owns a surface\n * can dispatch the same event without importing the shell.\n */\nexport function setVerseSection(section: VerseSectionId, anchor: string | null = null): void {\n go(section, { history: true });\n if (!anchor || typeof window === 'undefined') return;\n const detail: VerseAnchorRequest = { section, anchor };\n window.dispatchEvent(new CustomEvent(VERSE_ANCHOR_EVENT, { detail }));\n}\n\n/** ⌘[ / ⌘]. Returns false when there is nowhere to go. */\nexport function stepVerseHistory(delta: -1 | 1): boolean {\n const step = stepNav(state.history, delta);\n if (!step) return false;\n patch({ history: step.history });\n go(step.entry.section, { history: false });\n const target = step.entry.sessionId;\n if (step.entry.section === 'chat' && target && target !== state.activeSessionId) {\n raise('open-session', { sessionId: target }, false);\n // Set directly, NOT through setVerseActiveSession: that would push a new\n // history entry and drop the forward stack this step just walked.\n patch({ activeSessionId: target, recentChats: touchRecent(state.recentChats, target) });\n }\n return true;\n}\n\n/**\n * The chat reports which chat is open (C2: call on every selection). Feeds\n * back/forward, ⌃Tab's recent list, and the drawer's \"you are looking at it\".\n */\nexport function setVerseActiveSession(sessionId: string | null): void {\n if (sessionId === state.activeSessionId) return;\n const recentChats = sessionId ? touchRecent(state.recentChats, sessionId) : state.recentChats;\n const history = sessionId && state.section === 'chat' ? pushNav(state.history, { section: 'chat', sessionId }) : state.history;\n patch({ activeSessionId: sessionId, recentChats, history });\n}\n\n/** ⌃Tab / ⌃⇧Tab. Returns the chat opened, or null when there is no other recent chat. */\nexport function cycleVerseRecentChat(direction: 1 | -1, now: number = Date.now()): string | null {\n const recent = state.activeSessionId ? touchRecent(state.recentChats, state.activeSessionId) : [...state.recentChats];\n const step = cycleRecent(recent, recentCycle, direction, now);\n if (!step) return null;\n recentCycle = step.cycle;\n openVerseSession(step.sessionId);\n return step.sessionId;\n}\n\n// ===========================================================================\n// Chat hand-off\n// ===========================================================================\n\n/** The chat's own selection key (ChatSection, C2) — see openVerseSession. */\nconst CHAT_SELECTED_KEY = 'ashlr.verse.selected.v1';\n\nfunction raise(name: VerseCommandName, args: VerseCommandArgs, switchTo: boolean): void {\n nonce += 1;\n const command: VerseCommand = { name, nonce, ...args };\n if (switchTo && state.section !== 'chat') {\n go('chat', { history: true });\n }\n patch({ command });\n}\n\n/** ⌘N, \"New chat on…\", the palette's chat actions: switch to Chat and hand it a one-shot request. */\nexport function requestVerseCommand(name: VerseCommandName, args: VerseCommandArgs = {}): void {\n raise(name, args, true);\n}\n\n/**\n * Open a chat by id from anywhere (palette, drawer, a notification, ⌃Tab).\n * Raises `open-session` for a mounted chat surface; when Chat is not mounted\n * yet it also writes the chat's own selection key, so the surface opens on\n * that chat when it mounts (the command then confirms it).\n */\nexport function openVerseSession(sessionId: string): void {\n if (!/^[\\w.-]{1,200}$/.test(sessionId)) return;\n if (!state.mounted.includes('chat')) {\n try { localStorage.setItem(CHAT_SELECTED_KEY, sessionId); } catch { /* the command still carries it */ }\n }\n raise('open-session', { sessionId }, true);\n setVerseActiveSession(sessionId);\n}\n\nexport function clearVerseCommand(): void {\n patch({ command: null });\n}\n\n// ===========================================================================\n// Overlays\n// ===========================================================================\n\nexport function openVerseOverlay(overlay: Exclude<VerseOverlay, null>): void {\n patch({ overlay });\n}\n\nexport function closeVerseOverlay(): void {\n patch({ overlay: null, needsYouFocus: null });\n}\n\nexport function toggleVerseOverlay(overlay: Exclude<VerseOverlay, null>): void {\n patch({ overlay: state.overlay === overlay ? null : overlay, needsYouFocus: null });\n}\n\n/** ⌘J — optionally on a split, optionally selecting one item. */\nexport function openVerseNeedsYou(options: { split?: NeedsYouSplit; focusId?: string | null } = {}): void {\n patch({\n overlay: 'needs-you',\n needsYouSplit: options.split ?? state.needsYouSplit,\n needsYouFocus: options.focusId ?? null,\n });\n}\n\nexport function setVerseNeedsYouSplit(split: NeedsYouSplit): void {\n if (NEEDS_YOU_SPLITS.includes(split)) patch({ needsYouSplit: split });\n}\n\n// ===========================================================================\n// Preferences\n// ===========================================================================\n\nexport function setVerseRailExpanded(expanded: boolean): void {\n patch({ railExpanded: expanded });\n}\n\nexport function toggleVerseRail(): void {\n patch({ railExpanded: !state.railExpanded });\n}\n\nexport function setVerseSidebarWidth(width: number): void {\n patch({ sidebarWidth: clampWidth(width, VERSE_SIDEBAR) });\n}\n\nexport function setVerseSidebarCollapsed(collapsed: boolean): void {\n patch({ sidebarCollapsed: collapsed });\n}\n\nexport function toggleVerseSidebar(): void {\n patch({ sidebarCollapsed: !state.sidebarCollapsed });\n}\n\nexport function setVerseResourcesOpen(open: boolean): void {\n patch({ resourcesOpen: open });\n}\n\nexport function setVerseResourcesWidth(width: number): void {\n patch({ resourcesWidth: clampWidth(width, VERSE_RESOURCES) });\n}\n\n/** The palette ran a catalog action: remember it for the empty-query list. */\nexport function recordVerseAction(commandId: string): void {\n if (!/^[a-z][a-z0-9.-]{0,63}$/.test(commandId)) return;\n patch({ recentActions: [commandId, ...state.recentActions.filter((id) => id !== commandId)].slice(0, RECENT_ACTIONS_LIMIT) });\n}\n\n/** The \"Chat moved to ⌘5\" toast was shown: never again. */\nexport function acknowledgeChatMoved(): void {\n chatMovedAnnounced = true;\n if (state.announceChatMoved) patch({ announceChatMoved: false });\n persist(state);\n}\n\n// ===========================================================================\n// Test hygiene\n// ===========================================================================\n\n/** Back to defaults, storage cleared. Does NOT re-run the launch rule. */\nexport function resetVerseUi(): void {\n state = DEFAULTS;\n nonce = 0;\n recentCycle = null;\n lastLaunchDay = null;\n chatMovedAnnounced = false;\n seatMemory = null;\n adviceDismissals.clear();\n try {\n localStorage.removeItem(V3_KEY);\n localStorage.removeItem(V2_KEY);\n localStorage.removeItem(SEAT_STORAGE_KEY);\n } catch {\n /* ignore */\n }\n for (const l of [...listeners]) l();\n}\n\n/** Re-read storage as a fresh page load would (migration + launch rule). */\nexport function reloadVerseUiForTest(options: LoadOptions = {}): void {\n state = loadVerseUi(options);\n persist(state);\n for (const l of [...listeners]) l();\n}\n\n// ---------------------------------------------------------------------------\n// Last-used seat, per project\n// ---------------------------------------------------------------------------\n\n/**\n * Which seat + model a project's last chat was started on.\n *\n * WHY THIS IS PERSISTED. A new chat is seat-bound at creation, and the two\n * ways to start one — the sidebar \"+\" and ⌘N — both carry the CURRENT\n * session's seat forward. That works right up until there is no current\n * session (first load, or after deleting the last chat), where both fall\n * through to `defaultSeatChoice()`, which walks ENGINE_ORDER and lands on\n * Claude: the scarcest and most expensive account, chosen by alphabet rather\n * than by intent. Remembering the last seat per project makes \"New chat\" mean\n * the same thing across a reload as it does within one.\n *\n * NOT part of `VerseUiState`: a per-project memory that grows with the\n * project list has no business in a snapshot compared by identity on every\n * render.\n */\nexport interface VerseSeatMemory {\n seatId: string;\n model: string;\n}\n\nconst SEAT_STORAGE_KEY = 'ashlr.verse.seats.v1';\n/** Bounded so a long-lived browser cannot accumulate an unbounded map. */\nconst SEAT_MEMORY_LIMIT = 50;\n\n/** Lazily read, then held in memory; `null` means \"not read yet\". */\nlet seatMemory: Record<string, VerseSeatMemory> | null = null;\n\nfunction readSeatMemory(): Record<string, VerseSeatMemory> {\n if (seatMemory) return seatMemory;\n const out: Record<string, VerseSeatMemory> = {};\n try {\n const raw = localStorage.getItem(SEAT_STORAGE_KEY);\n const parsed = raw ? (JSON.parse(raw) as unknown) : null;\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n for (const [path, value] of Object.entries(parsed as Record<string, unknown>)) {\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue;\n const { seatId, model } = value as Record<string, unknown>;\n if (typeof seatId !== 'string' || seatId.length === 0) continue;\n if (typeof model !== 'string' || model.length === 0) continue;\n out[path] = { seatId, model };\n }\n }\n } catch {\n /* a private window without storage still runs the app */\n }\n seatMemory = out;\n return out;\n}\n\n/**\n * The seat a chat on `projectPath` was last started with, or the most recent\n * seat on any project when that project has no record yet — a brand-new\n * project inherits the operator's current working habit rather than resetting\n * to the default engine. Null only when nothing has ever been started.\n */\nexport function lastVerseSeat(projectPath?: string | null): VerseSeatMemory | null {\n const memory = readSeatMemory();\n if (projectPath) {\n const exact = memory[projectPath];\n if (exact) return exact;\n }\n // Insertion order is recency order: rememberVerseSeat re-inserts on write.\n const keys = Object.keys(memory);\n const newest = keys[keys.length - 1];\n return newest ? memory[newest] ?? null : null;\n}\n\n/** Record the seat a chat was just created with. Never throws. */\nexport function rememberVerseSeat(projectPath: string, seat: VerseSeatMemory): void {\n if (!projectPath || !seat.seatId || !seat.model) return;\n const memory = readSeatMemory();\n // Delete before re-inserting so key order stays newest-last.\n delete memory[projectPath];\n memory[projectPath] = { seatId: seat.seatId, model: seat.model };\n const keys = Object.keys(memory);\n for (const stale of keys.slice(0, Math.max(0, keys.length - SEAT_MEMORY_LIMIT))) {\n delete memory[stale];\n }\n try {\n localStorage.setItem(SEAT_STORAGE_KEY, JSON.stringify(memory));\n } catch {\n /* best-effort */\n }\n}\n\nexport const VERSE_SEAT_STORAGE_KEY = SEAT_STORAGE_KEY;\n\n// ---------------------------------------------------------------------------\n// Dismissed context advice, per session (NOT persisted)\n// ---------------------------------------------------------------------------\n\n/**\n * Which context-advice notes (\"continue in a fresh chat\", \"expansive may\n * help\") the operator waved off, per session.\n *\n * WHY IN MEMORY ONLY. Advice is evidence about the session as it is NOW: a\n * dismissal restored from storage after a reload would silence a note whose\n * evidence has since grown. Held here rather than in component state so that\n * switching surfaces and back does not bring back a note just dismissed.\n *\n * The key names the EVIDENCE (ContextAdvice composes it from the advice level\n * and the compaction count), so a note returns on its own when it escalates.\n */\nconst adviceDismissals = new Map<string, Set<string>>();\n/** Bounded like the other per-session memories. */\nconst ADVICE_SESSION_LIMIT = 50;\n\nexport function dismissVerseAdvice(sessionId: string, key: string): void {\n if (!sessionId || !key) return;\n const set = adviceDismissals.get(sessionId) ?? new Set<string>();\n set.add(key);\n // Re-insert so Map order stays recency order, then trim the oldest.\n adviceDismissals.delete(sessionId);\n adviceDismissals.set(sessionId, set);\n for (const stale of [...adviceDismissals.keys()].slice(0, Math.max(0, adviceDismissals.size - ADVICE_SESSION_LIMIT))) {\n adviceDismissals.delete(stale);\n }\n}\n\nexport function isVerseAdviceDismissed(sessionId: string, key: string): boolean {\n return adviceDismissals.get(sessionId)?.has(key) ?? false;\n}\n"],"file":"verse-ui-store-D7YXi63q.js"}
|
|
1
|
+
{"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/nav-history.ts","../../../../../../src/web-ui/routes/verse/shell/section-modules.ts","../../../../../../src/web-ui/routes/verse/verse-ui-store.ts"],"sourcesContent":["/**\n * routes/verse/shell/nav-history.ts — ⌘[ / ⌘] through surfaces AND chats\n * (unit C1; SPEC-310C §1 \"Keep-alive\").\n *\n * One linear history, like a browser's: visiting a place after going back\n * drops the forward entries. A chat is a place of its own — Chat ▸ A and\n * Chat ▸ B are two entries — so \"back\" after jumping from one chat to another\n * returns to the first chat, not to whatever surface was before Chat.\n *\n * Pure: the ui store holds the value and decides when to push.\n */\nimport type { WorkbenchSectionId } from '../../../../core/verse/workbench-types.js';\n\nexport interface NavEntry {\n section: WorkbenchSectionId;\n /** The chat open at the time; only meaningful when `section` is chat. */\n sessionId: string | null;\n}\n\nexport interface NavHistory {\n entries: readonly NavEntry[];\n /** Index of the current entry; -1 only for an empty history. */\n index: number;\n}\n\n/** Bounded: a long day of switching must not grow without limit. */\nexport const NAV_HISTORY_LIMIT = 50;\n\nexport const EMPTY_NAV_HISTORY: NavHistory = Object.freeze({ entries: Object.freeze([]) as readonly NavEntry[], index: -1 });\n\nfunction sameEntry(a: NavEntry | undefined, b: NavEntry): boolean {\n return !!a && a.section === b.section && (a.section !== 'chat' || a.sessionId === b.sessionId);\n}\n\n/** Visit `entry`: drop the forward stack, skip a no-op repeat, cap the length. */\nexport function pushNav(history: NavHistory, entry: NavEntry): NavHistory {\n const normalised: NavEntry = { section: entry.section, sessionId: entry.section === 'chat' ? entry.sessionId : null };\n const current = history.entries[history.index];\n if (sameEntry(current, normalised)) return history;\n // \"Chat, no chat open yet\" followed by the chat that then opened is ONE\n // visit: refine the entry in place (dropping any forward stack) rather\n // than leaving a back-stop that shows an empty chat.\n if (current && current.section === 'chat' && current.sessionId === null && normalised.section === 'chat') {\n const entries = [...history.entries.slice(0, history.index), normalised];\n return { entries, index: entries.length - 1 };\n }\n const kept = history.entries.slice(0, history.index + 1);\n const entries = [...kept, normalised].slice(-NAV_HISTORY_LIMIT);\n return { entries, index: entries.length - 1 };\n}\n\nexport function canGoBack(history: NavHistory): boolean {\n return history.index > 0;\n}\n\nexport function canGoForward(history: NavHistory): boolean {\n return history.index >= 0 && history.index < history.entries.length - 1;\n}\n\n/** Step `delta` (−1 back, +1 forward). Null when there is nowhere to go. */\nexport function stepNav(history: NavHistory, delta: -1 | 1): { history: NavHistory; entry: NavEntry } | null {\n const index = history.index + delta;\n const entry = history.entries[index];\n if (!entry) return null;\n return { history: { entries: history.entries, index }, entry };\n}\n\n/**\n * ⌃Tab through recent chats: the most-recently-used list, current chat first.\n * Consecutive presses inside `windowMs` keep walking the SAME snapshot of\n * the list (the Alt-Tab rule), so ⌃Tab ⌃Tab reaches the third-most-recent\n * chat instead of bouncing between two.\n */\nexport interface RecentCycle {\n order: readonly string[];\n position: number;\n at: number;\n}\n\nexport const RECENT_CYCLE_WINDOW_MS = 1_500;\nexport const RECENT_CHATS_LIMIT = 10;\n\nexport function cycleRecent(\n recent: readonly string[],\n cycle: RecentCycle | null,\n direction: 1 | -1,\n now: number,\n windowMs: number = RECENT_CYCLE_WINDOW_MS,\n): { sessionId: string; cycle: RecentCycle } | null {\n const fresh = !cycle || now - cycle.at > windowMs;\n const order = fresh ? recent : cycle!.order;\n if (order.length < 2) return null;\n const from = fresh ? 0 : cycle!.position;\n const position = (from + direction + order.length) % order.length;\n return { sessionId: order[position]!, cycle: { order, position, at: now } };\n}\n\n/** Move `sessionId` to the front of the MRU list. */\nexport function touchRecent(recent: readonly string[], sessionId: string, limit: number = RECENT_CHATS_LIMIT): string[] {\n return [sessionId, ...recent.filter((id) => id !== sessionId)].slice(0, limit);\n}\n","/**\n * routes/verse/shell/section-modules.ts — every `sections/*Section.tsx` that\n * exists at build time, lazily (unit C1).\n *\n * The rail's surfaces are written by other owners and land at different\n * times (C7's Command/Fleet/Growth/Mind, C6's Apps). A glob yields real\n * per-section code splitting for a module that is present and a missing KEY\n * — not an unresolved import — for one that is not, so the shell builds and\n * runs at every stage of the landing.\n *\n * Lives here rather than in VerseApp.tsx so the framework-free ui store can\n * ask \"has Command landed?\" (for the first-launch-of-the-day rule) without\n * importing the shell component. Keys are re-based to `./sections/<Module>.tsx`\n * — relative to routes/verse, the form VerseApp and VerseConsoleApp's\n * first-paint preload have always used.\n *\n * THE COST OF A GLOB, paid once: a finished section outside `sections/` is\n * invisible, with nothing failing to say so (MCP shipped that way for a\n * release). VerseApp.test.tsx walks this map for every VERSE_SECTIONS entry.\n */\ntype Importer = () => Promise<unknown>;\n\nconst RAW: Record<string, Importer> = import.meta.glob('../sections/*Section.tsx');\n\nexport const SECTION_MODULES: Record<string, Importer> = Object.fromEntries(\n Object.entries(RAW).map(([key, load]) => [key.replace(/^\\.\\.\\//, './'), load]),\n);\n\n/** The importer for one module name (`ChatSection`), or undefined when it has not landed. */\nexport function sectionImporter(module: string, modules: Record<string, Importer> = SECTION_MODULES): Importer | undefined {\n return modules[`./sections/${module}.tsx`];\n}\n","/**\n * routes/verse/verse-ui-store.ts — the workbench shell's own state (unit C1):\n * which surface is on screen and which stay mounted behind it, the overlays\n * (⌘K palette, ⌘J Needs you, ⌘/ shortcuts), back/forward history, recent\n * chats, and the layout preferences the chat reads. Framework-free (one\n * `useSyncExternalStore` hook in useVerseUi.ts), same split as verse-store.ts.\n *\n * PERSISTED under `ashlr.verse.ui.v3` — ONE blob with ONE writer (this\n * module). The dock's state is its `dock` field, owned by C2's dock-store and\n * folded in here on every change (dock-catalog.ts: two writers must never\n * race for the key).\n *\n * v2 → v3 MIGRATION (SPEC-310C §0.1). 3.10 renumbered the rail: ⌘1 Command …\n * ⌘5 Chat, with Settings / Apps / Usage in the gear tray. A saved v2 section\n * migrates through workbench-types `migrateSectionId`: autonomy → fleet,\n * approvals → Command WITH the Needs-you drawer open, mcp → apps. The v2 key\n * is left in place (a downgrade still finds its own state) and is never read\n * again once v3 exists.\n *\n * LAUNCH RULE. The first launch each local day opens Command — the overnight\n * digest is the point of opening the app in the morning. Later launches\n * return to the last surface. A surface whose module has not landed yet is\n * never forced (the rule falls through to the saved section).\n *\n * NOT PERSISTED, on purpose: the overlays, `command` (a one-shot hand-off to\n * the chat), history, the keep-alive list and `activeSessionId` — all\n * evidence about this page's life, not preferences.\n *\n * NOT HERE: appearance (theme, accent, density — data/appearance-store.ts owns\n * <html>), the reasoning display (chat/reasoning-pref.ts, C2), chat panel\n * widths (chat-panel-sizing.ts, C2), and the desktop preferences (system-wide\n * hotkey, notifications) — the desktop app stores those itself\n * (desktop_prefs.rs) and reports what actually took effect (a chord another\n * app holds comes back unregistered), so a copy here could only disagree\n * with it. Settings ▸ Desktop reads app/desktop-shell.ts useDesktopState().\n */\nimport {\n migrateSectionId,\n NEEDS_YOU_CATEGORIES,\n type NeedsYouCategory,\n type WorkbenchSectionId,\n} from '../../../core/verse/workbench-types.js';\nimport { getDockState, subscribeDockState } from './dock/dock-store.js';\nimport { VERSE_UI_STORAGE_KEY as V3_KEY, VERSE_UI_STORAGE_KEY_V2 as V2_KEY } from './shell/dock-catalog.js';\nimport {\n cycleRecent,\n pushNav,\n stepNav,\n touchRecent,\n RECENT_CHATS_LIMIT,\n type NavHistory,\n type RecentCycle,\n} from './shell/nav-history.js';\nimport { sectionImporter } from './shell/section-modules.js';\n\n// ===========================================================================\n// Sections\n// ===========================================================================\n\nexport type VerseSectionId = WorkbenchSectionId;\n\nexport interface VerseSectionEntry {\n id: VerseSectionId;\n label: string;\n /** The file `sections/<module>.tsx` the shell mounts (and first paint preloads). */\n module: string;\n /**\n * Modules to mount while `module` has not landed: Fleet shows the legacy\n * Autonomy panels until C7's FleetSection arrives. Never a guess at a\n * different surface. (Apps no longer falls back to MCP: C6's AppsSection\n * folds MCP in, and a stale MCP page under the \"Apps & Accounts\" name would\n * hide the seats and agents the operator went there for.)\n */\n fallbackModules?: readonly string[];\n /** Rail (⌘1–⌘5) or gear tray. */\n placement: 'rail' | 'tray';\n /** One line for the onboarding tour and the palette. */\n blurb: string;\n}\n\n/**\n * Rail order IS the ⌘1–⌘5 order (SPEC-310B §6); tray entries follow. A\n * section missing from this list is unreachable however complete it is.\n */\nexport const VERSE_SECTIONS: readonly VerseSectionEntry[] = [\n { id: 'command', label: 'Command', module: 'CommandSection', placement: 'rail', blurb: 'What the fleet did, what needs you, and the autonomy switch — the morning read.' },\n { id: 'fleet', label: 'Fleet', module: 'FleetSection', fallbackModules: ['AutonomySection'], placement: 'rail', blurb: 'Every lane live: what is building, what the gates refused, and why each seat was chosen.' },\n { id: 'growth', label: 'Growth', module: 'GrowthSection', placement: 'rail', blurb: 'Is the fleet getting better? Merges, cost per merge and the experiments behind them.' },\n { id: 'mind', label: 'Mind', module: 'MindSection', placement: 'rail', blurb: \"The Leader's memos, what came of each move, and what the reasoning shows.\" },\n { id: 'chat', label: 'Chat', module: 'ChatSection', placement: 'rail', blurb: 'Talk to a seat. Chats are grouped by project and resume where they stopped.' },\n { id: 'settings', label: 'Settings', module: 'SettingsSection', placement: 'tray', blurb: 'Theme, chat, desktop and keyboard — and this tour again.' },\n { id: 'apps', label: 'Apps & Accounts', module: 'AppsSection', placement: 'tray', blurb: 'Seats, terminal agents, local models and MCP servers in one list.' },\n { id: 'usage', label: 'Usage', module: 'UsageSection', placement: 'tray', blurb: 'Which account you can actually use right now, and what it costs.' },\n];\n\nexport const RAIL_SECTIONS: readonly VerseSectionEntry[] = VERSE_SECTIONS.filter((s) => s.placement === 'rail');\nexport const TRAY_SECTIONS: readonly VerseSectionEntry[] = VERSE_SECTIONS.filter((s) => s.placement === 'tray');\n\nconst SECTION_IDS = new Set<string>(VERSE_SECTIONS.map((s) => s.id));\n\nexport function sectionEntry(id: VerseSectionId): VerseSectionEntry {\n return VERSE_SECTIONS.find((s) => s.id === id)!;\n}\n\n/** The module that will actually mount for `id` (primary first, then fallbacks); null when none landed. */\nexport function landedModule(id: VerseSectionId, landed: (module: string) => boolean = (m) => sectionImporter(m) !== undefined): string | null {\n const entry = sectionEntry(id);\n for (const module of [entry.module, ...(entry.fallbackModules ?? [])]) if (landed(module)) return module;\n return null;\n}\n\n// ===========================================================================\n// State\n// ===========================================================================\n\n/**\n * One-shot shell → chat requests. The chat surface is lazily mounted and takes\n * no props, so the shell raises a command here and the chat consumes it by\n * nonce, then clears it.\n * new-chat ⌘N / \"New chat on…\" — optional seat or project prefill\n * quick-switcher (pre-3.10; kept until C2 retires QuickSwitcher)\n * open-session the palette, the drawer, ⌘[ ⌘], ⌃Tab, a notification\n * focus-composer the system-wide hotkey (⌃⌥Space)\n */\nexport type VerseCommandName = 'new-chat' | 'quick-switcher' | 'open-session' | 'focus-composer';\n\nexport interface VerseCommand {\n name: VerseCommandName;\n /** Monotonic; a section reacts when it sees a nonce it has not handled. */\n nonce: number;\n sessionId?: string;\n seatId?: string;\n projectPath?: string;\n}\n\nexport type VerseCommandArgs = Pick<VerseCommand, 'sessionId' | 'seatId' | 'projectPath'>;\n\nexport type VerseOverlay = 'palette' | 'needs-you' | 'shortcuts' | null;\nexport type NeedsYouSplit = 'all' | NeedsYouCategory;\nexport const NEEDS_YOU_SPLITS: readonly NeedsYouSplit[] = ['all', ...NEEDS_YOU_CATEGORIES];\n\nexport interface VerseUiState {\n section: VerseSectionId;\n /** Rail shows labels beside its icons (⌘⇧\\). Defaults collapsed: the 56px rail is shipped muscle memory. */\n railExpanded: boolean;\n sidebarWidth: number;\n sidebarCollapsed: boolean;\n resourcesOpen: boolean;\n resourcesWidth: number;\n /** The last this-many palette actions run (empty query shows them). */\n recentActions: readonly string[];\n /** Most-recently-used chats, current first (⌃Tab). */\n recentChats: readonly string[];\n // ── not persisted ──\n /** Surfaces kept mounted (hidden + inert) behind the current one, most recent first. */\n mounted: readonly VerseSectionId[];\n overlay: VerseOverlay;\n needsYouSplit: NeedsYouSplit;\n /** An item the drawer should select when it opens (from the palette or a notification). */\n needsYouFocus: string | null;\n history: NavHistory;\n /** The chat open in the Chat surface, as reported by the chat (or by the shell when it opened one). */\n activeSessionId: string | null;\n command: VerseCommand | null;\n /** Set when a v2 blob was migrated this load: the shell announces \"Chat moved to ⌘5\" once. */\n announceChatMoved: boolean;\n}\n\nexport const VERSE_SIDEBAR = { min: 240, max: 360, def: 264 } as const;\nexport const VERSE_RESOURCES = { min: 260, max: 480, def: 320 } as const;\n/** Surfaces kept alive besides Chat (which, once visited, always stays). */\nexport const KEEP_ALIVE_SURFACES = 3;\nexport const RECENT_ACTIONS_LIMIT = 5;\n\nexport const VERSE_UI_STORAGE_KEY = V3_KEY;\nexport const VERSE_UI_STORAGE_KEY_V2 = V2_KEY;\n\nconst DEFAULTS: VerseUiState = {\n section: 'chat',\n railExpanded: false,\n sidebarWidth: VERSE_SIDEBAR.def,\n sidebarCollapsed: false,\n resourcesOpen: true,\n resourcesWidth: VERSE_RESOURCES.def,\n recentActions: [],\n recentChats: [],\n mounted: ['chat'],\n overlay: null,\n needsYouSplit: 'all',\n needsYouFocus: null,\n history: { entries: [{ section: 'chat', sessionId: null }], index: 0 },\n activeSessionId: null,\n command: null,\n announceChatMoved: false,\n};\n\nexport function clampWidth(value: unknown, range: { min: number; max: number; def: number }): number {\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/** Local calendar day, `YYYY-MM-DD` — \"first launch each day\" is the operator's day, not UTC's. */\nexport function localDay(ms: number): string {\n const d = new Date(ms);\n const pad = (n: number) => String(n).padStart(2, '0');\n return `${d.getFullYear()}-${pad(d.getMonth() + 1)}-${pad(d.getDate())}`;\n}\n\ninterface PersistedV3 {\n version: 3;\n section: VerseSectionId;\n railExpanded: boolean;\n sidebarWidth: number;\n sidebarCollapsed: boolean;\n resourcesOpen: boolean;\n resourcesWidth: number;\n recentActions: string[];\n recentChats: string[];\n lastLaunchDay: string | null;\n chatMovedAnnounced: boolean;\n dock: unknown;\n}\n\nfunction isObject(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value);\n}\n\nfunction stringList(value: unknown, limit: number, re: RegExp): string[] {\n if (!Array.isArray(value)) return [];\n const out: string[] = [];\n for (const v of value) {\n if (typeof v === 'string' && re.test(v) && !out.includes(v)) out.push(v);\n if (out.length >= limit) break;\n }\n return out;\n}\n\nfunction readJson(key: string): Record<string, unknown> | null {\n try {\n const raw = localStorage.getItem(key);\n if (!raw) return null;\n const parsed = JSON.parse(raw) as unknown;\n return isObject(parsed) ? parsed : null;\n } catch {\n return null;\n }\n}\n\n/** Bookkeeping that is persisted but is not UI state. */\nlet lastLaunchDay: string | null = null;\nlet chatMovedAnnounced = false;\n\nexport interface LoadOptions {\n now?: number;\n /** Has this module landed? (Injected by tests; the build's glob otherwise.) */\n landed?: (module: string) => boolean;\n}\n\n/**\n * Read v3, else migrate v2, else defaults — then apply the launch rule.\n * Total: a hand-edited or future blob falls back field by field.\n */\nexport function loadVerseUi(options: LoadOptions = {}): VerseUiState {\n const now = options.now ?? Date.now();\n const landed = options.landed ?? ((m: string) => sectionImporter(m) !== undefined);\n const v3 = readJson(V3_KEY);\n const v2 = v3 ? null : readJson(V2_KEY);\n const src = v3 ?? v2 ?? {};\n\n let section: VerseSectionId = DEFAULTS.section;\n let overlay: VerseOverlay = null;\n const migration = migrateSectionId(src['section']);\n if (migration && SECTION_IDS.has(migration.section)) {\n section = migration.section;\n if (migration.openNeedsYou && !v3) overlay = 'needs-you';\n }\n\n lastLaunchDay = v3 && typeof v3['lastLaunchDay'] === 'string' ? v3['lastLaunchDay'] : null;\n chatMovedAnnounced = v3 ? v3['chatMovedAnnounced'] === true : false;\n\n const today = localDay(now);\n // First launch of the day → Command, when Command exists in this build.\n if (lastLaunchDay !== today && landedModule('command', landed) !== null) section = 'command';\n lastLaunchDay = today;\n\n const state: VerseUiState = {\n ...DEFAULTS,\n section,\n railExpanded: src['railExpanded'] === true,\n sidebarWidth: clampWidth(src['sidebarWidth'], VERSE_SIDEBAR),\n sidebarCollapsed: src['sidebarCollapsed'] === true,\n resourcesOpen: src['resourcesOpen'] !== false,\n resourcesWidth: clampWidth(src['resourcesWidth'], VERSE_RESOURCES),\n recentActions: stringList(src['recentActions'], RECENT_ACTIONS_LIMIT, /^[a-z][a-z0-9.-]{0,63}$/),\n recentChats: stringList(src['recentChats'], RECENT_CHATS_LIMIT, /^[\\w.-]{1,200}$/),\n mounted: [section],\n overlay,\n history: { entries: [{ section, sessionId: null }], index: 0 },\n // A v2 blob means this operator had ⌘1 = Chat in their hands yesterday.\n announceChatMoved: v2 !== null && !chatMovedAnnounced,\n };\n return state;\n}\n\nlet state: VerseUiState = DEFAULTS;\nlet nonce = 0;\nlet recentCycle: RecentCycle | null = null;\nconst listeners = new Set<() => void>();\n\nfunction persist(next: VerseUiState): void {\n const payload: PersistedV3 = {\n version: 3,\n section: next.section,\n railExpanded: next.railExpanded,\n sidebarWidth: next.sidebarWidth,\n sidebarCollapsed: next.sidebarCollapsed,\n resourcesOpen: next.resourcesOpen,\n resourcesWidth: next.resourcesWidth,\n recentActions: [...next.recentActions],\n recentChats: [...next.recentChats],\n lastLaunchDay,\n chatMovedAnnounced,\n dock: getDockState(),\n };\n try {\n localStorage.setItem(V3_KEY, JSON.stringify(payload));\n } catch {\n /* best-effort: a private window without storage still runs the app */\n }\n}\n\nconst PERSISTED_FIELDS = [\n 'section',\n 'railExpanded',\n 'sidebarWidth',\n 'sidebarCollapsed',\n 'resourcesOpen',\n 'resourcesWidth',\n 'recentActions',\n 'recentChats',\n] as const satisfies readonly (keyof VerseUiState)[];\n\n/** Snapshot identity only changes when something actually changed. */\nfunction patch(delta: Partial<VerseUiState>): void {\n const next = { ...state, ...delta };\n if ((Object.keys(delta) as (keyof VerseUiState)[]).every((k) => Object.is(state[k], next[k]))) return;\n const shouldPersist = PERSISTED_FIELDS.some((k) => !Object.is(state[k], next[k]));\n state = next;\n if (shouldPersist) persist(next);\n for (const l of [...listeners]) l();\n}\n\nfunction init(): void {\n state = loadVerseUi();\n // Write the migrated / launch-ruled state straight away, so the day's first\n // launch is recorded even if the operator closes the app without a click.\n persist(state);\n}\n\ninit();\n\n// C2's dock changes are folded into the blob as they happen.\nlet lastDockJson = '';\nsubscribeDockState(() => {\n let json = '';\n try { json = JSON.stringify(getDockState()); } catch { json = ''; }\n if (json === lastDockJson) return;\n lastDockJson = json;\n persist(state);\n});\n\nexport function subscribeVerseUi(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function getVerseUiState(): VerseUiState {\n return state;\n}\n\n// ===========================================================================\n// Navigation\n// ===========================================================================\n\nfunction withMounted(mounted: readonly VerseSectionId[], section: VerseSectionId): VerseSectionId[] {\n // The last KEEP_ALIVE_SURFACES surfaces other than Chat, most recent first…\n const chatVisited = section === 'chat' || mounted.includes('chat');\n const others = mounted.filter((id) => id !== 'chat' && id !== section);\n const nonChat = (section === 'chat' ? others : [section, ...others]).slice(0, KEEP_ALIVE_SURFACES);\n const alive: VerseSectionId[] = section === 'chat' ? ['chat', ...nonChat] : nonChat;\n // …and Chat, once visited, always: its streams, scroll and draft are the\n // most expensive state in the app to rebuild.\n if (chatVisited && !alive.includes('chat')) alive.push('chat');\n return alive;\n}\n\nfunction go(section: VerseSectionId, options: { history: boolean }): void {\n if (!SECTION_IDS.has(section)) return;\n const history = options.history\n ? pushNav(state.history, { section, sessionId: section === 'chat' ? state.activeSessionId : null })\n : state.history;\n patch({ section, mounted: withMounted(state.mounted, section), history });\n}\n\n/** The window event that asks the shell to reveal an anchor on a surface (shell/reveal-anchor.ts). */\nexport const VERSE_ANCHOR_EVENT = 'ashlr:verse-anchor';\n\nexport interface VerseAnchorRequest {\n section: VerseSectionId;\n /** A surface's own anchor key (\"memo:m-7\", \"seat:claude-a\"); the element carries `c7-anchor-<key>` or `data-verse-anchor`. */\n anchor: string;\n}\n\n/**\n * Switch surface; with `anchor`, also ask the shell to scroll that card or\n * row into view once the surface has painted. The anchor travels as a window\n * event rather than store state because it is a one-shot gesture about DOM\n * that may not exist yet (a lazy chunk), and every unit that owns a surface\n * can dispatch the same event without importing the shell.\n */\nexport function setVerseSection(section: VerseSectionId, anchor: string | null = null): void {\n go(section, { history: true });\n if (!anchor || typeof window === 'undefined') return;\n const detail: VerseAnchorRequest = { section, anchor };\n window.dispatchEvent(new CustomEvent(VERSE_ANCHOR_EVENT, { detail }));\n}\n\n/** ⌘[ / ⌘]. Returns false when there is nowhere to go. */\nexport function stepVerseHistory(delta: -1 | 1): boolean {\n const step = stepNav(state.history, delta);\n if (!step) return false;\n patch({ history: step.history });\n go(step.entry.section, { history: false });\n const target = step.entry.sessionId;\n if (step.entry.section === 'chat' && target && target !== state.activeSessionId) {\n raise('open-session', { sessionId: target }, false);\n // Set directly, NOT through setVerseActiveSession: that would push a new\n // history entry and drop the forward stack this step just walked.\n patch({ activeSessionId: target, recentChats: touchRecent(state.recentChats, target) });\n }\n return true;\n}\n\n/**\n * The chat reports which chat is open (C2: call on every selection). Feeds\n * back/forward, ⌃Tab's recent list, and the drawer's \"you are looking at it\".\n */\nexport function setVerseActiveSession(sessionId: string | null): void {\n if (sessionId === state.activeSessionId) return;\n const recentChats = sessionId ? touchRecent(state.recentChats, sessionId) : state.recentChats;\n const history = sessionId && state.section === 'chat' ? pushNav(state.history, { section: 'chat', sessionId }) : state.history;\n patch({ activeSessionId: sessionId, recentChats, history });\n}\n\n/** ⌃Tab / ⌃⇧Tab. Returns the chat opened, or null when there is no other recent chat. */\nexport function cycleVerseRecentChat(direction: 1 | -1, now: number = Date.now()): string | null {\n const recent = state.activeSessionId ? touchRecent(state.recentChats, state.activeSessionId) : [...state.recentChats];\n const step = cycleRecent(recent, recentCycle, direction, now);\n if (!step) return null;\n recentCycle = step.cycle;\n openVerseSession(step.sessionId);\n return step.sessionId;\n}\n\n// ===========================================================================\n// Chat hand-off\n// ===========================================================================\n\n/** The chat's own selection key (ChatSection, C2) — see openVerseSession. */\nconst CHAT_SELECTED_KEY = 'ashlr.verse.selected.v1';\n\nfunction raise(name: VerseCommandName, args: VerseCommandArgs, switchTo: boolean): void {\n nonce += 1;\n const command: VerseCommand = { name, nonce, ...args };\n if (switchTo && state.section !== 'chat') {\n go('chat', { history: true });\n }\n patch({ command });\n}\n\n/** ⌘N, \"New chat on…\", the palette's chat actions: switch to Chat and hand it a one-shot request. */\nexport function requestVerseCommand(name: VerseCommandName, args: VerseCommandArgs = {}): void {\n raise(name, args, true);\n}\n\n/**\n * Open a chat by id from anywhere (palette, drawer, a notification, ⌃Tab).\n * Raises `open-session` for a mounted chat surface; when Chat is not mounted\n * yet it also writes the chat's own selection key, so the surface opens on\n * that chat when it mounts (the command then confirms it).\n */\nexport function openVerseSession(sessionId: string): void {\n if (!/^[\\w.-]{1,200}$/.test(sessionId)) return;\n if (!state.mounted.includes('chat')) {\n try { localStorage.setItem(CHAT_SELECTED_KEY, sessionId); } catch { /* the command still carries it */ }\n }\n raise('open-session', { sessionId }, true);\n setVerseActiveSession(sessionId);\n}\n\nexport function clearVerseCommand(): void {\n patch({ command: null });\n}\n\n// ===========================================================================\n// Overlays\n// ===========================================================================\n\nexport function openVerseOverlay(overlay: Exclude<VerseOverlay, null>): void {\n patch({ overlay });\n}\n\nexport function closeVerseOverlay(): void {\n patch({ overlay: null, needsYouFocus: null });\n}\n\nexport function toggleVerseOverlay(overlay: Exclude<VerseOverlay, null>): void {\n patch({ overlay: state.overlay === overlay ? null : overlay, needsYouFocus: null });\n}\n\n/** ⌘J — optionally on a split, optionally selecting one item. */\nexport function openVerseNeedsYou(options: { split?: NeedsYouSplit; focusId?: string | null } = {}): void {\n patch({\n overlay: 'needs-you',\n needsYouSplit: options.split ?? state.needsYouSplit,\n needsYouFocus: options.focusId ?? null,\n });\n}\n\nexport function setVerseNeedsYouSplit(split: NeedsYouSplit): void {\n if (NEEDS_YOU_SPLITS.includes(split)) patch({ needsYouSplit: split });\n}\n\n// ===========================================================================\n// Preferences\n// ===========================================================================\n\nexport function setVerseRailExpanded(expanded: boolean): void {\n patch({ railExpanded: expanded });\n}\n\nexport function toggleVerseRail(): void {\n patch({ railExpanded: !state.railExpanded });\n}\n\nexport function setVerseSidebarWidth(width: number): void {\n patch({ sidebarWidth: clampWidth(width, VERSE_SIDEBAR) });\n}\n\nexport function setVerseSidebarCollapsed(collapsed: boolean): void {\n patch({ sidebarCollapsed: collapsed });\n}\n\nexport function toggleVerseSidebar(): void {\n patch({ sidebarCollapsed: !state.sidebarCollapsed });\n}\n\nexport function setVerseResourcesOpen(open: boolean): void {\n patch({ resourcesOpen: open });\n}\n\nexport function setVerseResourcesWidth(width: number): void {\n patch({ resourcesWidth: clampWidth(width, VERSE_RESOURCES) });\n}\n\n/** The palette ran a catalog action: remember it for the empty-query list. */\nexport function recordVerseAction(commandId: string): void {\n if (!/^[a-z][a-z0-9.-]{0,63}$/.test(commandId)) return;\n patch({ recentActions: [commandId, ...state.recentActions.filter((id) => id !== commandId)].slice(0, RECENT_ACTIONS_LIMIT) });\n}\n\n/** The \"Chat moved to ⌘5\" toast was shown: never again. */\nexport function acknowledgeChatMoved(): void {\n chatMovedAnnounced = true;\n if (state.announceChatMoved) patch({ announceChatMoved: false });\n persist(state);\n}\n\n// ===========================================================================\n// Test hygiene\n// ===========================================================================\n\n/** Back to defaults, storage cleared. Does NOT re-run the launch rule. */\nexport function resetVerseUi(): void {\n state = DEFAULTS;\n nonce = 0;\n recentCycle = null;\n lastLaunchDay = null;\n chatMovedAnnounced = false;\n seatMemory = null;\n adviceDismissals.clear();\n try {\n localStorage.removeItem(V3_KEY);\n localStorage.removeItem(V2_KEY);\n localStorage.removeItem(SEAT_STORAGE_KEY);\n } catch {\n /* ignore */\n }\n for (const l of [...listeners]) l();\n}\n\n/** Re-read storage as a fresh page load would (migration + launch rule). */\nexport function reloadVerseUiForTest(options: LoadOptions = {}): void {\n state = loadVerseUi(options);\n persist(state);\n for (const l of [...listeners]) l();\n}\n\n// ---------------------------------------------------------------------------\n// Last-used seat, per project\n// ---------------------------------------------------------------------------\n\n/**\n * Which seat + model a project's last chat was started on.\n *\n * WHY THIS IS PERSISTED. A new chat is seat-bound at creation, and the two\n * ways to start one — the sidebar \"+\" and ⌘N — both carry the CURRENT\n * session's seat forward. That works right up until there is no current\n * session (first load, or after deleting the last chat), where both fall\n * through to `defaultSeatChoice()`, which walks ENGINE_ORDER and lands on\n * Claude: the scarcest and most expensive account, chosen by alphabet rather\n * than by intent. Remembering the last seat per project makes \"New chat\" mean\n * the same thing across a reload as it does within one.\n *\n * NOT part of `VerseUiState`: a per-project memory that grows with the\n * project list has no business in a snapshot compared by identity on every\n * render.\n */\nexport interface VerseSeatMemory {\n seatId: string;\n model: string;\n}\n\nconst SEAT_STORAGE_KEY = 'ashlr.verse.seats.v1';\n/** Bounded so a long-lived browser cannot accumulate an unbounded map. */\nconst SEAT_MEMORY_LIMIT = 50;\n\n/** Lazily read, then held in memory; `null` means \"not read yet\". */\nlet seatMemory: Record<string, VerseSeatMemory> | null = null;\n\nfunction readSeatMemory(): Record<string, VerseSeatMemory> {\n if (seatMemory) return seatMemory;\n const out: Record<string, VerseSeatMemory> = {};\n try {\n const raw = localStorage.getItem(SEAT_STORAGE_KEY);\n const parsed = raw ? (JSON.parse(raw) as unknown) : null;\n if (parsed && typeof parsed === 'object' && !Array.isArray(parsed)) {\n for (const [path, value] of Object.entries(parsed as Record<string, unknown>)) {\n if (!value || typeof value !== 'object' || Array.isArray(value)) continue;\n const { seatId, model } = value as Record<string, unknown>;\n if (typeof seatId !== 'string' || seatId.length === 0) continue;\n if (typeof model !== 'string' || model.length === 0) continue;\n out[path] = { seatId, model };\n }\n }\n } catch {\n /* a private window without storage still runs the app */\n }\n seatMemory = out;\n return out;\n}\n\n/**\n * The seat a chat on `projectPath` was last started with, or the most recent\n * seat on any project when that project has no record yet — a brand-new\n * project inherits the operator's current working habit rather than resetting\n * to the default engine. Null only when nothing has ever been started.\n */\nexport function lastVerseSeat(projectPath?: string | null): VerseSeatMemory | null {\n const memory = readSeatMemory();\n if (projectPath) {\n const exact = memory[projectPath];\n if (exact) return exact;\n }\n // Insertion order is recency order: rememberVerseSeat re-inserts on write.\n const keys = Object.keys(memory);\n const newest = keys[keys.length - 1];\n return newest ? memory[newest] ?? null : null;\n}\n\n/** Record the seat a chat was just created with. Never throws. */\nexport function rememberVerseSeat(projectPath: string, seat: VerseSeatMemory): void {\n if (!projectPath || !seat.seatId || !seat.model) return;\n const memory = readSeatMemory();\n // Delete before re-inserting so key order stays newest-last.\n delete memory[projectPath];\n memory[projectPath] = { seatId: seat.seatId, model: seat.model };\n const keys = Object.keys(memory);\n for (const stale of keys.slice(0, Math.max(0, keys.length - SEAT_MEMORY_LIMIT))) {\n delete memory[stale];\n }\n try {\n localStorage.setItem(SEAT_STORAGE_KEY, JSON.stringify(memory));\n } catch {\n /* best-effort */\n }\n}\n\nexport const VERSE_SEAT_STORAGE_KEY = SEAT_STORAGE_KEY;\n\n// ---------------------------------------------------------------------------\n// Dismissed context advice, per session (NOT persisted)\n// ---------------------------------------------------------------------------\n\n/**\n * Which context-advice notes (\"continue in a fresh chat\", \"expansive may\n * help\") the operator waved off, per session.\n *\n * WHY IN MEMORY ONLY. Advice is evidence about the session as it is NOW: a\n * dismissal restored from storage after a reload would silence a note whose\n * evidence has since grown. Held here rather than in component state so that\n * switching surfaces and back does not bring back a note just dismissed.\n *\n * The key names the EVIDENCE (ContextAdvice composes it from the advice level\n * and the compaction count), so a note returns on its own when it escalates.\n */\nconst adviceDismissals = new Map<string, Set<string>>();\n/** Bounded like the other per-session memories. */\nconst ADVICE_SESSION_LIMIT = 50;\n\nexport function dismissVerseAdvice(sessionId: string, key: string): void {\n if (!sessionId || !key) return;\n const set = adviceDismissals.get(sessionId) ?? new Set<string>();\n set.add(key);\n // Re-insert so Map order stays recency order, then trim the oldest.\n adviceDismissals.delete(sessionId);\n adviceDismissals.set(sessionId, set);\n for (const stale of [...adviceDismissals.keys()].slice(0, Math.max(0, adviceDismissals.size - ADVICE_SESSION_LIMIT))) {\n adviceDismissals.delete(stale);\n }\n}\n\nexport function isVerseAdviceDismissed(sessionId: string, key: string): boolean {\n return adviceDismissals.get(sessionId)?.has(key) ?? false;\n}\n"],"file":"verse-ui-store-62DxpVHS.js"}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{a as e,s as t}from"./index-
|
|
2
|
-
//# sourceMappingURL=viewport-
|
|
1
|
+
import{a as e,s as t}from"./index-BVxOlseC.js";var n=t(e(),1),r=Object.freeze({compact:480,wide:1024}),i=Object.freeze({compact:`(max-width: ${r.compact-.02}px)`,wide:`(min-width: ${r.wide}px)`});function a(e){return e<r.compact?`compact`:e<r.wide?`medium`:`wide`}function o(){return typeof window>`u`?`wide`:typeof window.matchMedia==`function`?window.matchMedia(i.compact).matches?`compact`:window.matchMedia(i.wide).matches?`wide`:`medium`:a(window.innerWidth||r.wide)}function s(e){if(typeof window>`u`)return()=>{};if(typeof window.matchMedia!=`function`)return window.addEventListener(`resize`,e),()=>window.removeEventListener(`resize`,e);let t=[window.matchMedia(i.compact),window.matchMedia(i.wide)];for(let n of t)n.addEventListener(`change`,e);return()=>{for(let n of t)n.removeEventListener(`change`,e)}}function c(){let e=(0,n.useSyncExternalStore)(s,o,()=>`wide`);return(0,n.useMemo)(()=>({viewport:e,compact:e===`compact`,wide:e===`wide`}),[e])}export{c as n,r as t};
|
|
2
|
+
//# sourceMappingURL=viewport-nTubFCwf.js.map
|
package/dist/core/web/public/next/assets/{viewport-BYGH5EgA.js.map → viewport-nTubFCwf.js.map}
RENAMED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"viewport-
|
|
1
|
+
{"version":3,"file":"viewport-nTubFCwf.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/viewport.ts"],"sourcesContent":["/**\n * routes/verse/shell/viewport.ts — the workbench's width classes (unit C0).\n *\n * ONE set of breakpoints for every 3.10 surface, so the dock, the drawer, the\n * surfaces and the composer footer all change shape at the same widths\n * (SPEC-310C §1–§5):\n *\n * compact < 480 the phone layout the 375 screenshots show: one column,\n * bottom sheets (dock at 75vh), the composer footer folds\n * its pickers into a sheet, charts render at width 375.\n * medium 480–1023 the dock and the Needs-you drawer become sheets over\n * the chat instead of columns beside it.\n * wide ≥ 1024 the full workbench: rail, sidebar, transcript, dock.\n *\n * Read through matchMedia — the browser's own answer, which is also what the\n * test support mocks — never by polling window size.\n */\nimport { useMemo, useSyncExternalStore } from 'react';\n\nexport const VIEWPORT_BREAKPOINTS = Object.freeze({\n /** Below this width: the compact (phone) layout. */\n compact: 480,\n /** At or above this width: the wide workbench (dock as a column). */\n wide: 1024,\n});\n\nexport type ViewportClass = 'compact' | 'medium' | 'wide';\n\n/**\n * The two queries every class derives from. `max-width` uses .98 so the\n * compact and medium ranges meet without overlapping at fractional widths\n * (the same convention Bootstrap and Tailwind use for zoomed displays).\n */\nexport const VIEWPORT_QUERIES = Object.freeze({\n compact: `(max-width: ${VIEWPORT_BREAKPOINTS.compact - 0.02}px)`,\n wide: `(min-width: ${VIEWPORT_BREAKPOINTS.wide}px)`,\n});\n\n/** The class a width falls in (pure; for layout math and tests). */\nexport function viewportClassFor(width: number): ViewportClass {\n if (width < VIEWPORT_BREAKPOINTS.compact) return 'compact';\n if (width < VIEWPORT_BREAKPOINTS.wide) return 'medium';\n return 'wide';\n}\n\nfunction currentClass(): ViewportClass {\n if (typeof window === 'undefined') return 'wide';\n if (typeof window.matchMedia === 'function') {\n if (window.matchMedia(VIEWPORT_QUERIES.compact).matches) return 'compact';\n return window.matchMedia(VIEWPORT_QUERIES.wide).matches ? 'wide' : 'medium';\n }\n // jsdom without a mock, and old webviews: the window's own width.\n return viewportClassFor(window.innerWidth || VIEWPORT_BREAKPOINTS.wide);\n}\n\nfunction subscribe(onChange: () => void): () => void {\n if (typeof window === 'undefined') return () => {};\n if (typeof window.matchMedia !== 'function') {\n window.addEventListener('resize', onChange);\n return () => window.removeEventListener('resize', onChange);\n }\n const lists = [window.matchMedia(VIEWPORT_QUERIES.compact), window.matchMedia(VIEWPORT_QUERIES.wide)];\n for (const list of lists) list.addEventListener('change', onChange);\n return () => {\n for (const list of lists) list.removeEventListener('change', onChange);\n };\n}\n\nexport interface ViewportState {\n viewport: ViewportClass;\n /** < 480: phone layout. */\n compact: boolean;\n /** ≥ 1024: the full workbench. */\n wide: boolean;\n}\n\n/** The current width class; re-renders only when the CLASS changes, not on every resize. */\nexport function useViewport(): ViewportState {\n const viewport = useSyncExternalStore(subscribe, currentClass, () => 'wide' as const);\n return useMemo(() => ({ viewport, compact: viewport === 'compact', wide: viewport === 'wide' }), [viewport]);\n}\n\n/** Non-hook read, for event handlers and effects. */\nexport function readViewport(): ViewportClass {\n return currentClass();\n}\n"],"mappings":"8DAmBa,EAAuB,OAAO,OAAO,CAEhD,QAAS,IAET,KAAM,IACR,CAAC,EASY,EAAmB,OAAO,OAAO,CAC5C,QAAS,eAAe,EAAqB,QAAU,IAAK,KAC5D,KAAM,eAAe,EAAqB,KAAK,IACjD,CAAC,EAGD,SAAgB,EAAiB,EAA8B,CAG7D,OAFI,EAAQ,EAAqB,QAAgB,UAC7C,EAAQ,EAAqB,KAAa,SACvC,MACT,CAEA,SAAS,GAA8B,CAOrC,OANI,OAAO,OAAW,IAAoB,OACtC,OAAO,OAAO,YAAe,WAC3B,OAAO,WAAW,EAAiB,OAAO,CAAC,CAAC,QAAgB,UACzD,OAAO,WAAW,EAAiB,IAAI,CAAC,CAAC,QAAU,OAAS,SAG9D,EAAiB,OAAO,YAAc,EAAqB,IAAI,CACxE,CAEA,SAAS,EAAU,EAAkC,CACnD,GAAI,OAAO,OAAW,IAAa,UAAa,CAAC,EACjD,GAAI,OAAO,OAAO,YAAe,WAE/B,OADA,OAAO,iBAAiB,SAAU,CAAQ,MAC7B,OAAO,oBAAoB,SAAU,CAAQ,EAE5D,IAAM,EAAQ,CAAC,OAAO,WAAW,EAAiB,OAAO,EAAG,OAAO,WAAW,EAAiB,IAAI,CAAC,EACpG,IAAK,IAAM,KAAQ,EAAO,EAAK,iBAAiB,SAAU,CAAQ,EAClE,UAAa,CACX,IAAK,IAAM,KAAQ,EAAO,EAAK,oBAAoB,SAAU,CAAQ,CACvE,CACF,CAWA,SAAgB,GAA6B,CAC3C,IAAM,GAAA,EAAW,EAAA,qBAAA,CAAqB,EAAW,MAAoB,MAAe,EACpF,OAAA,EAAO,EAAA,QAAA,MAAe,CAAE,WAAU,QAAS,IAAa,UAAW,KAAM,IAAa,MAAO,GAAI,CAAC,CAAQ,CAAC,CAC7G"}
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/surface-prefetch-
|
|
2
|
-
import{t as e}from"./index-
|
|
3
|
-
//# sourceMappingURL=warmup-
|
|
1
|
+
const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/surface-prefetch-CdUEBFrl.js","assets/global-oEl9Qj8u.js","assets/index-BVxOlseC.js","assets/global-BlI2BYa1.css","assets/queries-CYisSAAB.js","assets/VerseConsoleApp-DTjDpGCd.js","assets/RouteErrorBoundary-DYtwc2ja.js","assets/RouteErrorBoundary-DdxhTdZ6.css","assets/command-catalog-Bb_PxC5w.js","assets/workbench-types-DzN-5trg.js","assets/guarded-action-OzqcPjmh.js","assets/preloaded-Cwf9rsnZ.js","assets/viewport-nTubFCwf.js","assets/verse-ui-store-62DxpVHS.js","assets/dock-store-B2vlxqPu.js","assets/composer-keys-su0g1h9o.js","assets/command-bus-xYZoK9nQ.js","assets/section-visibility-Yctxu-if.js","assets/icon-base-DvM1eI5V.js","assets/VerseConsoleApp-Cxqr-3qc.css","assets/budget-queries-V3wcJVK_.js","assets/cloud-queries-Br_r0UAz.js","assets/types-D5XOdyw8.js","assets/overnight-queries-DGm3qL1b.js","assets/format-BkWdOQDL.js","assets/format-DKrNjdwD.js","assets/verse-model-DyCwZF-M.js","assets/compaction-point-VL9oegWS.js","assets/control-queries-CmgBgKV7.js","assets/mutations-C5S7okTW.js","assets/surface-data-DTI7LjvH.js"])))=>i.map(i=>d[i]);
|
|
2
|
+
import{t as e}from"./index-BVxOlseC.js";import{n as t,u as n}from"./verse-ui-store-62DxpVHS.js";var r=[`pointerdown`,`keydown`,`wheel`,`touchstart`],i={capture:!0,passive:!0};function a(e={}){let t=e.win??window,n=e.doc??document,a=e.now??(()=>Date.now()),o=e.quietMs??2e3,s=Math.max(1,e.pollMs??250),c=e.busy??(()=>!1),l=e.timeoutMs??3e3,u=!1,d=a(),f=new Set,p=()=>{d=a()};for(let e of r)n.addEventListener(e,p,i);let m=()=>d+o-a(),h=()=>n.visibilityState!==`hidden`&&m()<=0&&!c();function g(){return u?Promise.resolve(!1):new Promise(e=>{let r=()=>void 0,i=()=>{r(),e(!1)},o=()=>{f.delete(i),e(!0)};f.add(i);let u=()=>{if(r=()=>void 0,n.visibilityState===`hidden`){let e=()=>{n.visibilityState!==`hidden`&&(n.removeEventListener(`visibilitychange`,e),d=a(),u())};n.addEventListener(`visibilitychange`,e),r=()=>n.removeEventListener(`visibilitychange`,e);return}let e=m();if(e>0||c()){let n=t.setTimeout(u,e>0?e:s);r=()=>t.clearTimeout(n);return}if(typeof t.requestIdleCallback==`function`){let e=t.requestIdleCallback(()=>h()?o():u(),{timeout:l});r=()=>t.cancelIdleCallback?.(e);return}o()};u()})}function _(e){return u?Promise.resolve(!1):new Promise(n=>{let r=0,i=()=>{t.clearTimeout(r),n(!1)};r=t.setTimeout(()=>{f.delete(i),n(!0)},e),f.add(i)})}function v(){if(!u){u=!0;for(let e of r)n.removeEventListener(e,p,i);for(let e of[...f])e();f.clear()}}return{wait:g,pause:_,cancel:v}}function o(e,t={}){let n=a(t),r=t.gapMs??400;return(async()=>{for(let[t,i]of e.entries()){if(t>0&&r>0&&!await n.pause(r)||!await n.wait())return;try{await i(n)}catch{}}n.cancel()})(),n.cancel}var s=()=>e(()=>import(`./surface-prefetch-CdUEBFrl.js`),__vite__mapDeps([0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30]));function c(e,r={}){let i=e=>async()=>{await e()},a=t=>async r=>{if(n().mounted.includes(t))return;await e.loadSection(t);let{prefetchSurfaceData:i}=await s();await i(t,{beforeEach:()=>r.wait()})};return o([...e.overlays.map(i),...t.map(e=>a(e.id))],{busy:e.readsInFlight,...r})}export{c as warmUpAfterFirstPaint};
|
|
3
|
+
//# sourceMappingURL=warmup-HG5vYbsN.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"mappings":";gGAwEA,IAAa,EAAoB,CAAC,cAAe,UAAW,QAAS,YAAY,EAE3E,EAAS,CAAE,QAAS,GAAM,QAAS,EAAK,EAE9C,SAAgB,EAAe,EAA2B,CAAC,EAAa,CACtE,IAAM,EAAM,EAAQ,KAAQ,OACtB,EAAM,EAAQ,KAAO,SACrB,EAAM,EAAQ,UAAc,KAAK,IAAI,GACrC,EAAU,EAAQ,aAClB,EAAS,KAAK,IAAI,EAAG,EAAQ,WAAsB,EACnD,EAAO,EAAQ,WAAe,IAC9B,EAAY,EAAQ,eAEtB,EAAY,GAEZ,EAAY,EAAI,EAEd,EAAO,IAAI,IAEX,MAAsB,CAC1B,EAAY,EAAI,CAClB,EACA,IAAK,IAAM,KAAQ,EAAmB,EAAI,iBAAiB,EAAM,EAAS,CAAM,EAEhF,IAAM,MAA0B,EAAY,EAAU,EAAI,EACpD,MAAyB,EAAI,kBAAoB,UAAY,EAAU,GAAK,GAAK,CAAC,EAAK,EAE7F,SAAS,GAAyB,CAEhC,OADI,EAAkB,QAAQ,QAAQ,EAAK,EACpC,IAAI,QAAkB,GAAY,CACvC,IAAI,MAAqB,OACnB,MAAoB,CACxB,EAAO,EACP,EAAQ,EAAK,CACf,EACM,MAAmB,CACvB,EAAK,OAAO,CAAK,EACjB,EAAQ,EAAI,CACd,EACA,EAAK,IAAI,CAAK,EAEd,IAAM,MAAoB,CAExB,GADA,MAAe,OACX,EAAI,kBAAoB,SAAU,CACpC,IAAM,MAAsB,CACtB,EAAI,kBAAoB,WAC5B,EAAI,oBAAoB,mBAAoB,CAAO,EACnD,EAAY,EAAI,EAChB,EAAM,EACR,EACA,EAAI,iBAAiB,mBAAoB,CAAO,EAChD,MAAe,EAAI,oBAAoB,mBAAoB,CAAO,EAClE,MACF,CACA,IAAM,EAAO,EAAU,EACvB,GAAI,EAAO,GAAK,EAAK,EAAG,CACtB,IAAM,EAAK,EAAI,WAAW,EAAO,EAAO,EAAI,EAAO,CAAM,EACzD,MAAe,EAAI,aAAa,CAAE,EAClC,MACF,CACA,GAAI,OAAO,EAAI,qBAAwB,WAAY,CAEjD,IAAM,EAAK,EAAI,wBAA2B,EAAQ,EAAI,EAAK,EAAI,EAAM,EAAI,CAAE,QAAS,CAAU,CAAC,EAC/F,MAAe,EAAI,qBAAqB,CAAE,EAC1C,MACF,CACA,EAAK,CACP,EACA,EAAM,CACR,CAAC,CACH,CAEA,SAAS,EAAM,EAA8B,CAE3C,OADI,EAAkB,QAAQ,QAAQ,EAAK,EACpC,IAAI,QAAkB,GAAY,CACvC,IAAI,EAAK,EACH,MAAoB,CACxB,EAAI,aAAa,CAAE,EACnB,EAAQ,EAAK,CACf,EACA,EAAK,EAAI,eAAiB,CACxB,EAAK,OAAO,CAAK,EACjB,EAAQ,EAAI,CACd,EAAG,CAAE,EACL,EAAK,IAAI,CAAK,CAChB,CAAC,CACH,CAEA,SAAS,GAAe,CAClB,MACJ,GAAY,GACZ,IAAK,IAAM,KAAQ,EAAmB,EAAI,oBAAoB,EAAM,EAAS,CAAM,EACnF,IAAK,IAAM,IAAS,CAAC,GAAG,CAAI,EAAG,EAAM,EACrC,EAAK,MAAM,CAHC,CAId,CAEA,MAAO,CAAE,OAAM,QAAO,QAAO,CAC/B,CAgBA,SAAgB,EAAa,EAA4B,EAA4B,CAAC,EAAe,CACnG,IAAM,EAAO,EAAe,CAAO,EAC7B,EAAQ,EAAQ,WAatB,OAZM,SAAY,CAChB,IAAK,GAAM,CAAC,EAAO,KAAS,EAAM,QAAQ,EAAG,CAE3C,GADI,EAAQ,GAAK,EAAQ,GAAK,CAAE,MAAM,EAAK,MAAM,CAAK,GAClD,CAAE,MAAM,EAAK,KAAK,EAAI,OAC1B,GAAI,CACF,MAAM,EAAK,CAAI,CACjB,MAAQ,CAER,CACF,CACA,EAAK,OAAO,CACd,GAAG,EACI,EAAK,MACd,CC7JA,IAAM,YAA8B,OAAO,yIAG3C,SAAgB,EAAsB,EAAkB,EAAyB,CAAC,EAAe,CAC/F,IAAM,EAAW,GAA2C,SAAY,CACtE,MAAM,EAAK,CACb,EACM,EAAW,GAAiC,KAAO,IAAmB,CAE1E,GAAI,EAAgB,CAAC,CAAC,QAAQ,SAAS,CAAE,EAAG,OAC5C,MAAM,EAAK,YAAY,CAAE,EACzB,GAAM,CAAE,uBAAwB,MAAM,EAAsB,EAC5D,MAAM,EAAoB,EAAI,CAAE,eAAkB,EAAK,KAAK,CAAE,CAAC,CACjE,EACA,OAAO,EAAa,CAAC,GAAG,EAAK,SAAS,IAAI,CAAO,EAAG,GAAG,EAAc,IAAK,GAAM,EAAQ,EAAE,EAAE,CAAC,CAAC,EAAG,CAC/F,KAAM,EAAK,cACX,GAAG,CACL,CAAC,CACH","names":[],"ignoreList":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/idle-prefetch.ts","../../../../../../src/web-ui/routes/verse/shell/warmup.ts"],"sourcesContent":["/**\n * routes/verse/shell/idle-prefetch.ts — run warm-up work in the gaps the\n * operator leaves, never in front of them (unit C1; review 3.10.1).\n *\n * createIdleGate() \"is the operator idle?\" as a promise: the window\n * is shown, no input for `quietMs`, none of the\n * operator's reads in flight (`busy`), and — where\n * the browser can tell — an idle callback;\n * runIdleSteps(steps) the steps one at a time: each waits for the gate,\n * and the next starts only after the previous one\n * has FINISHED (its promise settled) plus `gapMs`.\n *\n * WHY A GATE AND NOT A TIMER. WebKit — so the desktop app's WKWebView — has\n * no requestIdleCallback. 3.10.1 first fell back to fixed timers there (1.5 s,\n * then a step every 400 ms counted from each step's kickoff, not its end), so\n * the warm-up started ~9 reads in about a second whatever the operator was\n * doing, and a chat opened two seconds after launch queued behind the 90-day\n * history and the reasoning digest. The gate instead measures the two things\n * that matter: the operator's hands (pointer, keys, wheel, touch — observed\n * in the capture phase, passively, never delayed) and the operator's reads\n * (the caller's `busy`, which the shell wires to the query cache's gate).\n * Every wait re-checks both, so warm-up work yields the moment the operator\n * does something and resumes only after a fresh quiet period.\n *\n * A HIDDEN document runs nothing: a wait parks on `visibilitychange`, and\n * coming back counts as input (a fresh quiet period — the operator is about\n * to act). Cancel stops everything still pending — timers, idle callbacks,\n * the visibility and input listeners — and resolves every open wait `false`;\n * a step already running finishes on its own. The runner cancels its gate\n * when the last step is done, so a finished warm-up listens to nothing.\n *\n * LAZY ONLY. Framework- and dependency-free, and never imported statically by\n * VerseApp: shell/warmup.ts (itself loaded with import()) is its only user,\n * so none of this costs chat first-paint bytes (VerseApp.first-paint.test.ts).\n */\n\ntype IdleWindow = Pick<Window, 'setTimeout' | 'clearTimeout'> & {\n requestIdleCallback?: (cb: () => void, options?: { timeout: number }) => number;\n cancelIdleCallback?: (id: number) => void;\n};\n\ntype GateDocument = Pick<Document, 'visibilityState' | 'addEventListener' | 'removeEventListener'>;\n\nexport interface IdleGateOptions {\n /** No operator input for this long before anything runs. */\n quietMs?: number;\n /** How often a wait re-checks `busy` once the quiet period is met. */\n pollMs?: number;\n /** True while the operator's own work is in flight (the shell: the query cache's gate). */\n busy?: () => boolean;\n /** requestIdleCallback's deadline, where it exists. */\n timeoutMs?: number;\n /** Test seams. */\n win?: IdleWindow;\n doc?: GateDocument;\n now?: () => number;\n}\n\nexport interface IdleGate {\n /** Resolves true once the operator is idle; false if the gate is (or gets) cancelled first. */\n wait(): Promise<boolean>;\n /** A plain pause that cancel also ends (false). */\n pause(ms: number): Promise<boolean>;\n cancel(): void;\n}\n\nexport const IDLE_QUIET_MS = 2_000;\nexport const IDLE_POLL_MS = 250;\nexport const IDLE_TIMEOUT_MS = 3_000;\nexport const IDLE_STEP_GAP_MS = 400;\n\n/** What counts as the operator doing something. */\nexport const IDLE_INPUT_EVENTS = ['pointerdown', 'keydown', 'wheel', 'touchstart'] as const;\n\nconst LISTEN = { capture: true, passive: true } as const;\n\nexport function createIdleGate(options: IdleGateOptions = {}): IdleGate {\n const win = options.win ?? (window as IdleWindow);\n const doc = options.doc ?? document;\n const now = options.now ?? (() => Date.now());\n const quietMs = options.quietMs ?? IDLE_QUIET_MS;\n const pollMs = Math.max(1, options.pollMs ?? IDLE_POLL_MS);\n const busy = options.busy ?? (() => false);\n const timeoutMs = options.timeoutMs ?? IDLE_TIMEOUT_MS;\n\n let cancelled = false;\n // The gate is created at first paint: the quiet period counts from there.\n let lastInput = now();\n /** One abort per open wait / pause: disarms what it armed and settles it `false`. */\n const open = new Set<() => void>();\n\n const onInput = (): void => {\n lastInput = now();\n };\n for (const type of IDLE_INPUT_EVENTS) doc.addEventListener(type, onInput, LISTEN);\n\n const quietLeft = (): number => lastInput + quietMs - now();\n const idleNow = (): boolean => doc.visibilityState !== 'hidden' && quietLeft() <= 0 && !busy();\n\n function wait(): Promise<boolean> {\n if (cancelled) return Promise.resolve(false);\n return new Promise<boolean>((resolve) => {\n let disarm = (): void => undefined;\n const abort = (): void => {\n disarm();\n resolve(false);\n };\n const done = (): void => {\n open.delete(abort);\n resolve(true);\n };\n open.add(abort);\n\n const check = (): void => {\n disarm = () => undefined;\n if (doc.visibilityState === 'hidden') {\n const onShown = (): void => {\n if (doc.visibilityState === 'hidden') return;\n doc.removeEventListener('visibilitychange', onShown);\n lastInput = now();\n check();\n };\n doc.addEventListener('visibilitychange', onShown);\n disarm = () => doc.removeEventListener('visibilitychange', onShown);\n return;\n }\n const left = quietLeft();\n if (left > 0 || busy()) {\n const id = win.setTimeout(check, left > 0 ? left : pollMs);\n disarm = () => win.clearTimeout(id);\n return;\n }\n if (typeof win.requestIdleCallback === 'function') {\n // Input or a read may have started while the browser was busy: re-check on the way out.\n const id = win.requestIdleCallback(() => (idleNow() ? done() : check()), { timeout: timeoutMs });\n disarm = () => win.cancelIdleCallback?.(id);\n return;\n }\n done();\n };\n check();\n });\n }\n\n function pause(ms: number): Promise<boolean> {\n if (cancelled) return Promise.resolve(false);\n return new Promise<boolean>((resolve) => {\n let id = 0;\n const abort = (): void => {\n win.clearTimeout(id);\n resolve(false);\n };\n id = win.setTimeout(() => {\n open.delete(abort);\n resolve(true);\n }, ms);\n open.add(abort);\n });\n }\n\n function cancel(): void {\n if (cancelled) return;\n cancelled = true;\n for (const type of IDLE_INPUT_EVENTS) doc.removeEventListener(type, onInput, LISTEN);\n for (const abort of [...open]) abort();\n open.clear();\n }\n\n return { wait, pause, cancel };\n}\n\nexport type IdleStep = (gate: IdleGate) => void | Promise<void>;\n\nexport interface IdleStepsOptions extends IdleGateOptions {\n /** Pause after one step has finished before the next waits for the gate. */\n gapMs?: number;\n}\n\n/**\n * Run `steps` in order, each once the operator is idle and only after the\n * previous one has settled (plus `gapMs`). A step receives the gate so it can\n * wait again between its own pieces of work. A step that throws or rejects is\n * skipped, never fatal. Returns a cancel that stops every step not yet started\n * and every wait a running step is parked on.\n */\nexport function runIdleSteps(steps: readonly IdleStep[], options: IdleStepsOptions = {}): () => void {\n const gate = createIdleGate(options);\n const gapMs = options.gapMs ?? IDLE_STEP_GAP_MS;\n void (async () => {\n for (const [index, step] of steps.entries()) {\n if (index > 0 && gapMs > 0 && !(await gate.pause(gapMs))) return;\n if (!(await gate.wait())) return;\n try {\n await step(gate);\n } catch {\n // Warm-up only: a step that fails costs the operator a skeleton later, nothing more.\n }\n }\n gate.cancel();\n })();\n return gate.cancel;\n}\n","/**\n * routes/verse/shell/warmup.ts — what the shell warms after first paint, in\n * what order, and when (unit C1; review 3.10.1).\n *\n * 1. the overlay chunks, one at a time, so the first ⌘K / ⌘J / ⌘/ never\n * waits on the network;\n * 2. each rail surface not yet open, in rail order — its chunk (VerseApp's\n * one-per-tab load, so the first visit mounts it directly) and then the\n * reads it opens with (shell/surface-prefetch.ts, one read at a time).\n * A first visit then paints from cache instead of a skeleton.\n *\n * WHEN: every chunk and every read waits for the idle gate\n * (shell/idle-prefetch.ts): window shown, no operator input for a quiet\n * period, and NOTHING in the query cache's gate — no read of the operator's\n * running or queued. The warm-up therefore holds at most one of the gate's\n * four slots, never while the operator's own reads wait, and never in front\n * of the chat's first actions: a click or ⌘N restarts the quiet period, and\n * the reads it causes are waited out before the next warm-up read starts.\n *\n * LAZY ONLY. VerseApp loads this module with import() from a mount effect,\n * so neither the scheduler nor the surface table costs chat first-paint\n * bytes; the surface table is a further import() from here, at the first\n * surface step (VerseApp.first-paint.test.ts pins both).\n */\nimport { getVerseUiState, RAIL_SECTIONS, type VerseSectionId } from '../verse-ui-store.js';\nimport { runIdleSteps, type IdleGate, type IdleStep, type IdleStepsOptions } from './idle-prefetch.js';\n\nexport type WarmupOptions = IdleStepsOptions;\n\nexport interface WarmupDeps {\n /** VerseApp's one load per section (its lazy component shares it). */\n loadSection: (id: VerseSectionId) => Promise<unknown>;\n /** The overlay chunks, in the order they are worth having. */\n overlays: ReadonlyArray<() => Promise<unknown>>;\n /**\n * True while any read is running or queued in the query cache's gate\n * (VerseApp reads `queryGateStats`). Injected rather than imported: a\n * static data/cache.ts import from this chunk made the bundler split the\n * cache out of its shared first-paint chunk (+1.2 KB of chat critical JS,\n * more than moving the scheduler out saved).\n */\n readsInFlight: () => boolean;\n}\n\nconst importSurfacePrefetch = () => import('./surface-prefetch.js');\n\n/** Start the warm-up. Returns a cancel (VerseApp calls it on unmount). */\nexport function warmUpAfterFirstPaint(deps: WarmupDeps, options: WarmupOptions = {}): () => void {\n const overlay = (load: () => Promise<unknown>): IdleStep => async () => {\n await load();\n };\n const surface = (id: VerseSectionId): IdleStep => async (gate: IdleGate) => {\n // Already open: its reads are live, and its chunk is in.\n if (getVerseUiState().mounted.includes(id)) return;\n await deps.loadSection(id);\n const { prefetchSurfaceData } = await importSurfacePrefetch();\n await prefetchSurfaceData(id, { beforeEach: () => gate.wait() });\n };\n return runIdleSteps([...deps.overlays.map(overlay), ...RAIL_SECTIONS.map((s) => surface(s.id))], {\n busy: deps.readsInFlight,\n ...options,\n });\n}\n"],"file":"warmup-AsqwWCUi.js"}
|
|
1
|
+
{"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/idle-prefetch.ts","../../../../../../src/web-ui/routes/verse/shell/warmup.ts"],"sourcesContent":["/**\n * routes/verse/shell/idle-prefetch.ts — run warm-up work in the gaps the\n * operator leaves, never in front of them (unit C1; review 3.10.1).\n *\n * createIdleGate() \"is the operator idle?\" as a promise: the window\n * is shown, no input for `quietMs`, none of the\n * operator's reads in flight (`busy`), and — where\n * the browser can tell — an idle callback;\n * runIdleSteps(steps) the steps one at a time: each waits for the gate,\n * and the next starts only after the previous one\n * has FINISHED (its promise settled) plus `gapMs`.\n *\n * WHY A GATE AND NOT A TIMER. WebKit — so the desktop app's WKWebView — has\n * no requestIdleCallback. 3.10.1 first fell back to fixed timers there (1.5 s,\n * then a step every 400 ms counted from each step's kickoff, not its end), so\n * the warm-up started ~9 reads in about a second whatever the operator was\n * doing, and a chat opened two seconds after launch queued behind the 90-day\n * history and the reasoning digest. The gate instead measures the two things\n * that matter: the operator's hands (pointer, keys, wheel, touch — observed\n * in the capture phase, passively, never delayed) and the operator's reads\n * (the caller's `busy`, which the shell wires to the query cache's gate).\n * Every wait re-checks both, so warm-up work yields the moment the operator\n * does something and resumes only after a fresh quiet period.\n *\n * A HIDDEN document runs nothing: a wait parks on `visibilitychange`, and\n * coming back counts as input (a fresh quiet period — the operator is about\n * to act). Cancel stops everything still pending — timers, idle callbacks,\n * the visibility and input listeners — and resolves every open wait `false`;\n * a step already running finishes on its own. The runner cancels its gate\n * when the last step is done, so a finished warm-up listens to nothing.\n *\n * LAZY ONLY. Framework- and dependency-free, and never imported statically by\n * VerseApp: shell/warmup.ts (itself loaded with import()) is its only user,\n * so none of this costs chat first-paint bytes (VerseApp.first-paint.test.ts).\n */\n\ntype IdleWindow = Pick<Window, 'setTimeout' | 'clearTimeout'> & {\n requestIdleCallback?: (cb: () => void, options?: { timeout: number }) => number;\n cancelIdleCallback?: (id: number) => void;\n};\n\ntype GateDocument = Pick<Document, 'visibilityState' | 'addEventListener' | 'removeEventListener'>;\n\nexport interface IdleGateOptions {\n /** No operator input for this long before anything runs. */\n quietMs?: number;\n /** How often a wait re-checks `busy` once the quiet period is met. */\n pollMs?: number;\n /** True while the operator's own work is in flight (the shell: the query cache's gate). */\n busy?: () => boolean;\n /** requestIdleCallback's deadline, where it exists. */\n timeoutMs?: number;\n /** Test seams. */\n win?: IdleWindow;\n doc?: GateDocument;\n now?: () => number;\n}\n\nexport interface IdleGate {\n /** Resolves true once the operator is idle; false if the gate is (or gets) cancelled first. */\n wait(): Promise<boolean>;\n /** A plain pause that cancel also ends (false). */\n pause(ms: number): Promise<boolean>;\n cancel(): void;\n}\n\nexport const IDLE_QUIET_MS = 2_000;\nexport const IDLE_POLL_MS = 250;\nexport const IDLE_TIMEOUT_MS = 3_000;\nexport const IDLE_STEP_GAP_MS = 400;\n\n/** What counts as the operator doing something. */\nexport const IDLE_INPUT_EVENTS = ['pointerdown', 'keydown', 'wheel', 'touchstart'] as const;\n\nconst LISTEN = { capture: true, passive: true } as const;\n\nexport function createIdleGate(options: IdleGateOptions = {}): IdleGate {\n const win = options.win ?? (window as IdleWindow);\n const doc = options.doc ?? document;\n const now = options.now ?? (() => Date.now());\n const quietMs = options.quietMs ?? IDLE_QUIET_MS;\n const pollMs = Math.max(1, options.pollMs ?? IDLE_POLL_MS);\n const busy = options.busy ?? (() => false);\n const timeoutMs = options.timeoutMs ?? IDLE_TIMEOUT_MS;\n\n let cancelled = false;\n // The gate is created at first paint: the quiet period counts from there.\n let lastInput = now();\n /** One abort per open wait / pause: disarms what it armed and settles it `false`. */\n const open = new Set<() => void>();\n\n const onInput = (): void => {\n lastInput = now();\n };\n for (const type of IDLE_INPUT_EVENTS) doc.addEventListener(type, onInput, LISTEN);\n\n const quietLeft = (): number => lastInput + quietMs - now();\n const idleNow = (): boolean => doc.visibilityState !== 'hidden' && quietLeft() <= 0 && !busy();\n\n function wait(): Promise<boolean> {\n if (cancelled) return Promise.resolve(false);\n return new Promise<boolean>((resolve) => {\n let disarm = (): void => undefined;\n const abort = (): void => {\n disarm();\n resolve(false);\n };\n const done = (): void => {\n open.delete(abort);\n resolve(true);\n };\n open.add(abort);\n\n const check = (): void => {\n disarm = () => undefined;\n if (doc.visibilityState === 'hidden') {\n const onShown = (): void => {\n if (doc.visibilityState === 'hidden') return;\n doc.removeEventListener('visibilitychange', onShown);\n lastInput = now();\n check();\n };\n doc.addEventListener('visibilitychange', onShown);\n disarm = () => doc.removeEventListener('visibilitychange', onShown);\n return;\n }\n const left = quietLeft();\n if (left > 0 || busy()) {\n const id = win.setTimeout(check, left > 0 ? left : pollMs);\n disarm = () => win.clearTimeout(id);\n return;\n }\n if (typeof win.requestIdleCallback === 'function') {\n // Input or a read may have started while the browser was busy: re-check on the way out.\n const id = win.requestIdleCallback(() => (idleNow() ? done() : check()), { timeout: timeoutMs });\n disarm = () => win.cancelIdleCallback?.(id);\n return;\n }\n done();\n };\n check();\n });\n }\n\n function pause(ms: number): Promise<boolean> {\n if (cancelled) return Promise.resolve(false);\n return new Promise<boolean>((resolve) => {\n let id = 0;\n const abort = (): void => {\n win.clearTimeout(id);\n resolve(false);\n };\n id = win.setTimeout(() => {\n open.delete(abort);\n resolve(true);\n }, ms);\n open.add(abort);\n });\n }\n\n function cancel(): void {\n if (cancelled) return;\n cancelled = true;\n for (const type of IDLE_INPUT_EVENTS) doc.removeEventListener(type, onInput, LISTEN);\n for (const abort of [...open]) abort();\n open.clear();\n }\n\n return { wait, pause, cancel };\n}\n\nexport type IdleStep = (gate: IdleGate) => void | Promise<void>;\n\nexport interface IdleStepsOptions extends IdleGateOptions {\n /** Pause after one step has finished before the next waits for the gate. */\n gapMs?: number;\n}\n\n/**\n * Run `steps` in order, each once the operator is idle and only after the\n * previous one has settled (plus `gapMs`). A step receives the gate so it can\n * wait again between its own pieces of work. A step that throws or rejects is\n * skipped, never fatal. Returns a cancel that stops every step not yet started\n * and every wait a running step is parked on.\n */\nexport function runIdleSteps(steps: readonly IdleStep[], options: IdleStepsOptions = {}): () => void {\n const gate = createIdleGate(options);\n const gapMs = options.gapMs ?? IDLE_STEP_GAP_MS;\n void (async () => {\n for (const [index, step] of steps.entries()) {\n if (index > 0 && gapMs > 0 && !(await gate.pause(gapMs))) return;\n if (!(await gate.wait())) return;\n try {\n await step(gate);\n } catch {\n // Warm-up only: a step that fails costs the operator a skeleton later, nothing more.\n }\n }\n gate.cancel();\n })();\n return gate.cancel;\n}\n","/**\n * routes/verse/shell/warmup.ts — what the shell warms after first paint, in\n * what order, and when (unit C1; review 3.10.1).\n *\n * 1. the overlay chunks, one at a time, so the first ⌘K / ⌘J / ⌘/ never\n * waits on the network;\n * 2. each rail surface not yet open, in rail order — its chunk (VerseApp's\n * one-per-tab load, so the first visit mounts it directly) and then the\n * reads it opens with (shell/surface-prefetch.ts, one read at a time).\n * A first visit then paints from cache instead of a skeleton.\n *\n * WHEN: every chunk and every read waits for the idle gate\n * (shell/idle-prefetch.ts): window shown, no operator input for a quiet\n * period, and NOTHING in the query cache's gate — no read of the operator's\n * running or queued. The warm-up therefore holds at most one of the gate's\n * four slots, never while the operator's own reads wait, and never in front\n * of the chat's first actions: a click or ⌘N restarts the quiet period, and\n * the reads it causes are waited out before the next warm-up read starts.\n *\n * LAZY ONLY. VerseApp loads this module with import() from a mount effect,\n * so neither the scheduler nor the surface table costs chat first-paint\n * bytes; the surface table is a further import() from here, at the first\n * surface step (VerseApp.first-paint.test.ts pins both).\n */\nimport { getVerseUiState, RAIL_SECTIONS, type VerseSectionId } from '../verse-ui-store.js';\nimport { runIdleSteps, type IdleGate, type IdleStep, type IdleStepsOptions } from './idle-prefetch.js';\n\nexport type WarmupOptions = IdleStepsOptions;\n\nexport interface WarmupDeps {\n /** VerseApp's one load per section (its lazy component shares it). */\n loadSection: (id: VerseSectionId) => Promise<unknown>;\n /** The overlay chunks, in the order they are worth having. */\n overlays: ReadonlyArray<() => Promise<unknown>>;\n /**\n * True while any read is running or queued in the query cache's gate\n * (VerseApp reads `queryGateStats`). Injected rather than imported: a\n * static data/cache.ts import from this chunk made the bundler split the\n * cache out of its shared first-paint chunk (+1.2 KB of chat critical JS,\n * more than moving the scheduler out saved).\n */\n readsInFlight: () => boolean;\n}\n\nconst importSurfacePrefetch = () => import('./surface-prefetch.js');\n\n/** Start the warm-up. Returns a cancel (VerseApp calls it on unmount). */\nexport function warmUpAfterFirstPaint(deps: WarmupDeps, options: WarmupOptions = {}): () => void {\n const overlay = (load: () => Promise<unknown>): IdleStep => async () => {\n await load();\n };\n const surface = (id: VerseSectionId): IdleStep => async (gate: IdleGate) => {\n // Already open: its reads are live, and its chunk is in.\n if (getVerseUiState().mounted.includes(id)) return;\n await deps.loadSection(id);\n const { prefetchSurfaceData } = await importSurfacePrefetch();\n await prefetchSurfaceData(id, { beforeEach: () => gate.wait() });\n };\n return runIdleSteps([...deps.overlays.map(overlay), ...RAIL_SECTIONS.map((s) => surface(s.id))], {\n busy: deps.readsInFlight,\n ...options,\n });\n}\n"],"file":"warmup-HG5vYbsN.js"}
|
package/dist/core/web/public/next/assets/{workspace-model-CXorJr0G.js → workspace-model-CbhdPhei.js}
RENAMED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import{d as e}from"./verse-model-
|
|
2
|
-
//# sourceMappingURL=workspace-model-
|
|
1
|
+
import{d as e}from"./verse-model-DyCwZF-M.js";function t(e){if(e.git===null)return null;let t=[e.git.branch];return t.push(e.git.dirty===0?`clean`:`${e.git.dirty} changed`),e.git.ahead>0&&t.push(`${e.git.ahead} ahead`),e.git.behind>0&&t.push(`${e.git.behind} behind`),t.join(` · `)}function n(e){return e.exists?e.reachable?e.primary?`primary`:`extra`:`unreachable`:`missing`}function r(e){return e.exists?e.reachable?e.enrolled?null:`not enrolled — autonomous lane refuses it`:`this engine cannot reach it`:`missing on disk`}var i={critical:`Critical`,high:`High`,normal:`Normal`,low:`Low`},a=[`critical`,`high`,`normal`,`low`],o=`Priority orders the repositories the fleet already has. It never adds one — a repository that is not enrolled stays out of reach at every priority.`;function s(e,t){return t?.[e]??`normal`}function c(t,n){let r=t.trim();if(r.length===0)return{ok:!1,error:`Pick a primary folder.`,roots:[]};if(!e(r))return{ok:!1,error:`The primary folder must be an absolute path on this machine.`,roots:[]};let i=[r];for(let t of n){let n=t.trim();if(n.length!==0){if(!e(n))return{ok:!1,error:`Not an absolute path: ${n}`,roots:[]};i.includes(n)||i.push(n)}}return i.length>8?{ok:!1,error:`A workspace holds at most 8 folders.`,roots:[]}:{ok:!0,error:null,roots:i}}function l(e){return(e.roots.find(e=>e.primary)??e.roots[0])?.path??null}function u(e){return e.roots.length-1<=0?`1 folder`:`${e.roots.length} folders`}function d(e){let t=e.roots.find(e=>e.primary);return t?[t,...e.roots.filter(e=>e!==t)]:[...e.roots]}function f(e){return d(e).map(e=>e.path)}function p(e){return e==null||e===`claude`||e===`codex`||e===`local`}var m=`This seat’s CLI takes no additional-directory flag, so it will reach only the primary folder. The other folders will be unreachable — pick a Claude, Codex or local seat to use more than one.`;function h(e,t){return t<=1||p(e)?null:m}function g(e,t){return t<=1?null:h(e,t)??`The agent can read and write these folders for the life of this chat. Enrolment is separate — an unenrolled folder stays out of reach of the autonomous lane.`}var _=`Claude, Codex and local seats reach every folder here. A Grok seat reaches only the primary one.`;function v(e){let t=e.trim().replace(/[/\\]+$/,``),n=t.split(/[/\\]/).pop()??``;return n.length>0?n:t}function y(e,t){let[n=``,...r]=t,i=c(n,r);if(!i.ok)return{ok:!1,error:i.error,name:``,roots:[]};let a=e.trim(),o=a.length>0?a:v(i.roots[0]);return o.length===0?{ok:!1,error:`Give this project a name.`,name:``,roots:[]}:{ok:!0,error:null,name:o,roots:i.roots}}function b(e,t,n){let r=[...e],i=n===`up`?t-1:t+1;if(t<0||t>=r.length||i<0||i>=r.length)return r;let a=r[t];return r[t]=r[i],r[i]=a,r}function x(e){return e===0?`Primary folder`:`Folder ${e+1}`}export{f as _,v as a,b as c,t as d,x as f,l as g,y as h,a as i,s as l,c as m,i as n,h as o,n as p,o as r,g as s,_ as t,r as u,u as v};
|
|
2
|
+
//# sourceMappingURL=workspace-model-CbhdPhei.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"workspace-model-CXorJr0G.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/workspace-model.ts"],"sourcesContent":["/**\n * routes/verse/workspace-model.ts — pure helpers for multi-root sessions.\n * No React, no I/O, so every rule below is testable without a DOM.\n *\n * The honesty rules these encode, and why each exists:\n *\n * - A root with no git repo shows \"not a git repo\", never a blank space where\n * a branch would be. An empty slot reads as \"clean on the default branch\".\n * - `dirty` is a COUNT of changed entries, so it is rendered as a count.\n * \"modified\" alone hides whether that is one file or forty.\n * - An unenrolled root says the autonomous lane refuses it, rather than\n * showing a warning that could be read as \"this chat cannot use it\" — it\n * can, and does.\n * - An unreachable root (a Grok seat, which has no additional-directory flag)\n * is listed and marked, never hidden. Hiding it would misrepresent the\n * workspace the operator chose.\n */\nimport type {\n VerseEngine,\n VerseRootPriority,\n VerseRootStatus,\n VerseSession,\n VerseWorkspace,\n VerseWorkspaceRoot,\n} from '../../data/api-types.js';\nimport { isAbsolutePath } from './verse-model.js';\n\n/** Hard cap, mirroring VERSE_MAX_WORKSPACE_ROOTS on the server. */\nexport const MAX_WORKSPACE_ROOTS = 8;\n\n/** Every root a session can reach, primary first. Mirrors `verseSessionRoots`. */\nexport function sessionRootPaths(session: Pick<VerseSession, 'projectPath' | 'extraRoots'>): string[] {\n const out = [session.projectPath];\n for (const root of session.extraRoots ?? []) {\n if (typeof root === 'string' && root.length > 0 && !out.includes(root)) out.push(root);\n }\n return out;\n}\n\n/** True when this session reaches more than its primary folder. */\nexport function isMultiRoot(session: Pick<VerseSession, 'projectPath' | 'extraRoots'>): boolean {\n return sessionRootPaths(session).length > 1;\n}\n\n/**\n * Short label for a session's folder scope: the primary's name, plus how many\n * more it carries. Used where only one line fits (a sidebar row, a pill).\n */\nexport function rootScopeLabel(\n session: Pick<VerseSession, 'projectPath' | 'extraRoots'>,\n primaryName: string,\n): string {\n const extra = sessionRootPaths(session).length - 1;\n return extra > 0 ? `${primaryName} +${extra}` : primaryName;\n}\n\n/**\n * One line of git identity for a root.\n *\n * Returns null when the root is not a repo, so the caller renders the \"not a\n * git repo\" wording ONCE rather than each caller inventing its own.\n */\nexport function rootGitLine(root: VerseRootStatus): string | null {\n if (root.git === null) return null;\n const parts = [root.git.branch];\n parts.push(root.git.dirty === 0 ? 'clean' : `${root.git.dirty} changed`);\n if (root.git.ahead > 0) parts.push(`${root.git.ahead} ahead`);\n if (root.git.behind > 0) parts.push(`${root.git.behind} behind`);\n return parts.join(' · ');\n}\n\nexport type RootTone = 'primary' | 'extra' | 'unreachable' | 'missing';\n\n/** Which visual treatment a root row gets. Missing beats unreachable. */\nexport function rootTone(root: VerseRootStatus): RootTone {\n if (!root.exists) return 'missing';\n if (!root.reachable) return 'unreachable';\n return root.primary ? 'primary' : 'extra';\n}\n\n/**\n * The plain-language caveat for one root, or null when there is nothing to\n * say. Word, never colour alone (DESIGN-V2 §6).\n */\nexport function rootCaveat(root: VerseRootStatus): string | null {\n if (!root.exists) return 'missing on disk';\n if (!root.reachable) return 'this engine cannot reach it';\n if (!root.enrolled) return 'not enrolled — autonomous lane refuses it';\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Priority\n// ---------------------------------------------------------------------------\n\nexport const ROOT_PRIORITY_LABEL: Record<VerseRootPriority, string> = {\n critical: 'Critical',\n high: 'High',\n normal: 'Normal',\n low: 'Low',\n};\n\nexport const ROOT_PRIORITY_ORDER: readonly VerseRootPriority[] =\n ['critical', 'high', 'normal', 'low'];\n\n/**\n * How a priority must be explained wherever it is offered.\n *\n * Priority orders what the autonomous lane already reaches. It is NOT a grant,\n * and the copy has to say so at the point of the choice — otherwise ranking a\n * repo `critical` reads as turning it on.\n */\nexport const ROOT_PRIORITY_NOTE =\n 'Priority orders the repositories the fleet already has. It never adds one — a repository that is not enrolled stays out of reach at every priority.';\n\n/**\n * Sort weight; lower sorts first. Mirrors `VERSE_ROOT_PRIORITY_RANK` on the\n * server so the list the operator re-ranks here and the list the autonomous\n * lane walks cannot be ordered differently.\n */\nexport const ROOT_PRIORITY_RANK: Record<VerseRootPriority, number> = {\n critical: 0,\n high: 1,\n normal: 2,\n low: 3,\n};\n\n/** A path's priority, treating an absent key as `normal` (as the server does). */\nexport function priorityOf(\n path: string,\n priorities: Readonly<Record<string, VerseRootPriority>> | undefined,\n): VerseRootPriority {\n return priorities?.[path] ?? 'normal';\n}\n\n/**\n * Paths most-important-first.\n *\n * STABLE: two paths at the same priority keep the order they were given, so\n * re-ranking one repo never silently shuffles the rest. Ordering only — this\n * neither adds nor removes a path.\n */\nexport function rankPathsByPriority(\n paths: readonly string[],\n priorities: Readonly<Record<string, VerseRootPriority>> | undefined,\n): string[] {\n return paths\n .map((path, index) => ({ path, index, rank: ROOT_PRIORITY_RANK[priorityOf(path, priorities)] }))\n .sort((a, b) => a.rank - b.rank || a.index - b.index)\n .map((entry) => entry.path);\n}\n\n// ---------------------------------------------------------------------------\n// Root-set editing (the new-chat dialog and the workspace editor share this)\n// ---------------------------------------------------------------------------\n\nexport interface RootSetValidation {\n ok: boolean;\n /** One message, or null when the set is usable. */\n error: string | null;\n /** The set as it would be sent: trimmed, de-duplicated, primary first. */\n roots: string[];\n}\n\n/**\n * Validate a root set typed by hand.\n *\n * COURTESY ONLY. The server re-checks every path against the same deny roots\n * the enrollment registry uses, and it is the authority — this cannot know the\n * real home directory behind a `~`, and it must not pretend to.\n */\nexport function validateRootSet(primary: string, extras: readonly string[]): RootSetValidation {\n const trimmedPrimary = primary.trim();\n if (trimmedPrimary.length === 0) {\n return { ok: false, error: 'Pick a primary folder.', roots: [] };\n }\n if (!isAbsolutePath(trimmedPrimary)) {\n return { ok: false, error: 'The primary folder must be an absolute path on this machine.', roots: [] };\n }\n const roots = [trimmedPrimary];\n for (const raw of extras) {\n const root = raw.trim();\n if (root.length === 0) continue;\n if (!isAbsolutePath(root)) {\n return { ok: false, error: `Not an absolute path: ${root}`, roots: [] };\n }\n if (roots.includes(root)) continue;\n roots.push(root);\n }\n if (roots.length > MAX_WORKSPACE_ROOTS) {\n return { ok: false, error: `A workspace holds at most ${MAX_WORKSPACE_ROOTS} folders.`, roots: [] };\n }\n return { ok: true, error: null, roots };\n}\n\n/** The primary root of a stored workspace (the one a session uses as its cwd). */\nexport function workspacePrimary(workspace: VerseWorkspace): string | null {\n return (workspace.roots.find((r) => r.primary) ?? workspace.roots[0])?.path ?? null;\n}\n\n/** \"service +2 folders\" — how a workspace reads in a picker. */\nexport function workspaceSummary(workspace: VerseWorkspace): string {\n const extra = workspace.roots.length - 1;\n if (extra <= 0) return '1 folder';\n return `${workspace.roots.length} folders`;\n}\n\n/**\n * A workspace's roots in SEND order: the primary first, then the rest as\n * stored.\n *\n * `VerseWorkspace.roots` is documented primary-first, but the flag is the\n * authority and an update replaces the set wholesale with \"first entry is\n * primary\". Normalising here means a reorder can never accidentally demote\n * the primary because a stored record listed it second.\n */\nexport function orderedWorkspaceRoots(workspace: VerseWorkspace): VerseWorkspaceRoot[] {\n const primary = workspace.roots.find((r) => r.primary);\n if (!primary) return [...workspace.roots];\n return [primary, ...workspace.roots.filter((r) => r !== primary)];\n}\n\n/** The same order, as the bare paths `updateVerseWorkspace` takes. */\nexport function workspaceRootPaths(workspace: VerseWorkspace): string[] {\n return orderedWorkspaceRoots(workspace).map((r) => r.path);\n}\n\n// ---------------------------------------------------------------------------\n// Which engines reach more than the primary folder\n// ---------------------------------------------------------------------------\n\n/**\n * Whether this engine's CLI takes an additional-directory flag.\n *\n * Mirrors `engineSupportsExtraRoots` in src/core/verse/workspaces.ts. Grok\n * exposes no such flag at all (checked on grok 0.2.118), so a Grok seat gets\n * its primary root and nothing else — and the UI has to SAY that at the point\n * the seat is chosen rather than let the operator discover it from a diff that\n * never applies.\n *\n * `null` (no seat picked yet) reaches everything: there is nothing to warn\n * about until a seat exists.\n */\nexport function engineReachesExtraRoots(engine: VerseEngine | null | undefined): boolean {\n if (engine === null || engine === undefined) return true;\n return engine === 'claude' || engine === 'codex' || engine === 'local';\n}\n\nexport const EXTRA_ROOTS_REACHABLE_NOTE =\n 'The agent can read and write these folders for the life of this chat. Enrolment is separate — an unenrolled folder stays out of reach of the autonomous lane.';\n\nexport const EXTRA_ROOTS_UNREACHABLE_NOTE =\n 'This seat’s CLI takes no additional-directory flag, so it will reach only the primary folder. The other folders will be unreachable — pick a Claude, Codex or local seat to use more than one.';\n\n/**\n * The caveat for handing `rootCount` folders to a seat, or null when there is\n * nothing to warn about. Only ever the BAD news, so a caller can render it as\n * a warning without having to decide which sentence it got.\n */\nexport function extraRootsCaveat(\n engine: VerseEngine | null | undefined,\n rootCount: number,\n): string | null {\n if (rootCount <= 1) return null;\n return engineReachesExtraRoots(engine) ? null : EXTRA_ROOTS_UNREACHABLE_NOTE;\n}\n\n/** The full note for a multi-folder set: the caveat when there is one, the\n * enrolment reminder otherwise. Null when only one folder is in play. */\nexport function extraRootsNote(\n engine: VerseEngine | null | undefined,\n rootCount: number,\n): string | null {\n if (rootCount <= 1) return null;\n return extraRootsCaveat(engine, rootCount) ?? EXTRA_ROOTS_REACHABLE_NOTE;\n}\n\n/** Said once wherever a multi-folder project is DEFINED, where no seat is\n * chosen yet and so no per-seat caveat can be given. */\nexport const MULTI_ROOT_ENGINE_NOTE =\n 'Claude, Codex and local seats reach every folder here. A Grok seat reaches only the primary one.';\n\n// ---------------------------------------------------------------------------\n// Saved projects (the create/edit form behind the workspace routes)\n// ---------------------------------------------------------------------------\n\n/** The folder's own name, used when the operator names nothing. */\nexport function defaultWorkspaceName(primaryPath: string): string {\n const trimmed = primaryPath.trim().replace(/[/\\\\]+$/, '');\n const base = trimmed.split(/[/\\\\]/).pop() ?? '';\n return base.length > 0 ? base : trimmed;\n}\n\nexport interface WorkspaceDraftValidation {\n ok: boolean;\n /** One message, or null when the draft is sendable. */\n error: string | null;\n /** The name as it would be sent — never empty when `ok`. */\n name: string;\n /** Trimmed, de-duplicated, primary first. */\n roots: string[];\n}\n\n/**\n * Validate a saved project before it is sent.\n *\n * COURTESY ONLY, exactly like `validateRootSet`: the server re-checks every\n * path against the enrollment registry's deny roots and is the authority.\n */\nexport function validateWorkspaceDraft(\n name: string,\n roots: readonly string[],\n): WorkspaceDraftValidation {\n const [primary = '', ...extras] = roots;\n const set = validateRootSet(primary, extras);\n if (!set.ok) return { ok: false, error: set.error, name: '', roots: [] };\n const trimmed = name.trim();\n const resolved = trimmed.length > 0 ? trimmed : defaultWorkspaceName(set.roots[0]!);\n if (resolved.length === 0) {\n return { ok: false, error: 'Give this project a name.', name: '', roots: [] };\n }\n return { ok: true, error: null, name: resolved, roots: set.roots };\n}\n\n/**\n * Move one entry up or down by one place.\n *\n * Returns a NEW array, and returns the order unchanged when the move would\n * fall off either end — so a caller can wire it to a button that is disabled\n * at the ends without the two disagreeing.\n */\nexport function moveRoot<T>(roots: readonly T[], index: number, direction: 'up' | 'down'): T[] {\n const next = [...roots];\n const target = direction === 'up' ? index - 1 : index + 1;\n if (index < 0 || index >= next.length || target < 0 || target >= next.length) return next;\n const moved = next[index]!;\n next[index] = next[target]!;\n next[target] = moved;\n return next;\n}\n\n/**\n * How the first row must be described. The first root IS the primary — it is\n * the session's cwd and the only folder a Grok seat reaches — so the reorder\n * control is not cosmetic and the label has to say what it does.\n */\nexport function rootRowLabel(index: number): string {\n return index === 0 ? 'Primary folder' : `Folder ${index + 1}`;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"workspace-model-CbhdPhei.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/workspace-model.ts"],"sourcesContent":["/**\n * routes/verse/workspace-model.ts — pure helpers for multi-root sessions.\n * No React, no I/O, so every rule below is testable without a DOM.\n *\n * The honesty rules these encode, and why each exists:\n *\n * - A root with no git repo shows \"not a git repo\", never a blank space where\n * a branch would be. An empty slot reads as \"clean on the default branch\".\n * - `dirty` is a COUNT of changed entries, so it is rendered as a count.\n * \"modified\" alone hides whether that is one file or forty.\n * - An unenrolled root says the autonomous lane refuses it, rather than\n * showing a warning that could be read as \"this chat cannot use it\" — it\n * can, and does.\n * - An unreachable root (a Grok seat, which has no additional-directory flag)\n * is listed and marked, never hidden. Hiding it would misrepresent the\n * workspace the operator chose.\n */\nimport type {\n VerseEngine,\n VerseRootPriority,\n VerseRootStatus,\n VerseSession,\n VerseWorkspace,\n VerseWorkspaceRoot,\n} from '../../data/api-types.js';\nimport { isAbsolutePath } from './verse-model.js';\n\n/** Hard cap, mirroring VERSE_MAX_WORKSPACE_ROOTS on the server. */\nexport const MAX_WORKSPACE_ROOTS = 8;\n\n/** Every root a session can reach, primary first. Mirrors `verseSessionRoots`. */\nexport function sessionRootPaths(session: Pick<VerseSession, 'projectPath' | 'extraRoots'>): string[] {\n const out = [session.projectPath];\n for (const root of session.extraRoots ?? []) {\n if (typeof root === 'string' && root.length > 0 && !out.includes(root)) out.push(root);\n }\n return out;\n}\n\n/** True when this session reaches more than its primary folder. */\nexport function isMultiRoot(session: Pick<VerseSession, 'projectPath' | 'extraRoots'>): boolean {\n return sessionRootPaths(session).length > 1;\n}\n\n/**\n * Short label for a session's folder scope: the primary's name, plus how many\n * more it carries. Used where only one line fits (a sidebar row, a pill).\n */\nexport function rootScopeLabel(\n session: Pick<VerseSession, 'projectPath' | 'extraRoots'>,\n primaryName: string,\n): string {\n const extra = sessionRootPaths(session).length - 1;\n return extra > 0 ? `${primaryName} +${extra}` : primaryName;\n}\n\n/**\n * One line of git identity for a root.\n *\n * Returns null when the root is not a repo, so the caller renders the \"not a\n * git repo\" wording ONCE rather than each caller inventing its own.\n */\nexport function rootGitLine(root: VerseRootStatus): string | null {\n if (root.git === null) return null;\n const parts = [root.git.branch];\n parts.push(root.git.dirty === 0 ? 'clean' : `${root.git.dirty} changed`);\n if (root.git.ahead > 0) parts.push(`${root.git.ahead} ahead`);\n if (root.git.behind > 0) parts.push(`${root.git.behind} behind`);\n return parts.join(' · ');\n}\n\nexport type RootTone = 'primary' | 'extra' | 'unreachable' | 'missing';\n\n/** Which visual treatment a root row gets. Missing beats unreachable. */\nexport function rootTone(root: VerseRootStatus): RootTone {\n if (!root.exists) return 'missing';\n if (!root.reachable) return 'unreachable';\n return root.primary ? 'primary' : 'extra';\n}\n\n/**\n * The plain-language caveat for one root, or null when there is nothing to\n * say. Word, never colour alone (DESIGN-V2 §6).\n */\nexport function rootCaveat(root: VerseRootStatus): string | null {\n if (!root.exists) return 'missing on disk';\n if (!root.reachable) return 'this engine cannot reach it';\n if (!root.enrolled) return 'not enrolled — autonomous lane refuses it';\n return null;\n}\n\n// ---------------------------------------------------------------------------\n// Priority\n// ---------------------------------------------------------------------------\n\nexport const ROOT_PRIORITY_LABEL: Record<VerseRootPriority, string> = {\n critical: 'Critical',\n high: 'High',\n normal: 'Normal',\n low: 'Low',\n};\n\nexport const ROOT_PRIORITY_ORDER: readonly VerseRootPriority[] =\n ['critical', 'high', 'normal', 'low'];\n\n/**\n * How a priority must be explained wherever it is offered.\n *\n * Priority orders what the autonomous lane already reaches. It is NOT a grant,\n * and the copy has to say so at the point of the choice — otherwise ranking a\n * repo `critical` reads as turning it on.\n */\nexport const ROOT_PRIORITY_NOTE =\n 'Priority orders the repositories the fleet already has. It never adds one — a repository that is not enrolled stays out of reach at every priority.';\n\n/**\n * Sort weight; lower sorts first. Mirrors `VERSE_ROOT_PRIORITY_RANK` on the\n * server so the list the operator re-ranks here and the list the autonomous\n * lane walks cannot be ordered differently.\n */\nexport const ROOT_PRIORITY_RANK: Record<VerseRootPriority, number> = {\n critical: 0,\n high: 1,\n normal: 2,\n low: 3,\n};\n\n/** A path's priority, treating an absent key as `normal` (as the server does). */\nexport function priorityOf(\n path: string,\n priorities: Readonly<Record<string, VerseRootPriority>> | undefined,\n): VerseRootPriority {\n return priorities?.[path] ?? 'normal';\n}\n\n/**\n * Paths most-important-first.\n *\n * STABLE: two paths at the same priority keep the order they were given, so\n * re-ranking one repo never silently shuffles the rest. Ordering only — this\n * neither adds nor removes a path.\n */\nexport function rankPathsByPriority(\n paths: readonly string[],\n priorities: Readonly<Record<string, VerseRootPriority>> | undefined,\n): string[] {\n return paths\n .map((path, index) => ({ path, index, rank: ROOT_PRIORITY_RANK[priorityOf(path, priorities)] }))\n .sort((a, b) => a.rank - b.rank || a.index - b.index)\n .map((entry) => entry.path);\n}\n\n// ---------------------------------------------------------------------------\n// Root-set editing (the new-chat dialog and the workspace editor share this)\n// ---------------------------------------------------------------------------\n\nexport interface RootSetValidation {\n ok: boolean;\n /** One message, or null when the set is usable. */\n error: string | null;\n /** The set as it would be sent: trimmed, de-duplicated, primary first. */\n roots: string[];\n}\n\n/**\n * Validate a root set typed by hand.\n *\n * COURTESY ONLY. The server re-checks every path against the same deny roots\n * the enrollment registry uses, and it is the authority — this cannot know the\n * real home directory behind a `~`, and it must not pretend to.\n */\nexport function validateRootSet(primary: string, extras: readonly string[]): RootSetValidation {\n const trimmedPrimary = primary.trim();\n if (trimmedPrimary.length === 0) {\n return { ok: false, error: 'Pick a primary folder.', roots: [] };\n }\n if (!isAbsolutePath(trimmedPrimary)) {\n return { ok: false, error: 'The primary folder must be an absolute path on this machine.', roots: [] };\n }\n const roots = [trimmedPrimary];\n for (const raw of extras) {\n const root = raw.trim();\n if (root.length === 0) continue;\n if (!isAbsolutePath(root)) {\n return { ok: false, error: `Not an absolute path: ${root}`, roots: [] };\n }\n if (roots.includes(root)) continue;\n roots.push(root);\n }\n if (roots.length > MAX_WORKSPACE_ROOTS) {\n return { ok: false, error: `A workspace holds at most ${MAX_WORKSPACE_ROOTS} folders.`, roots: [] };\n }\n return { ok: true, error: null, roots };\n}\n\n/** The primary root of a stored workspace (the one a session uses as its cwd). */\nexport function workspacePrimary(workspace: VerseWorkspace): string | null {\n return (workspace.roots.find((r) => r.primary) ?? workspace.roots[0])?.path ?? null;\n}\n\n/** \"service +2 folders\" — how a workspace reads in a picker. */\nexport function workspaceSummary(workspace: VerseWorkspace): string {\n const extra = workspace.roots.length - 1;\n if (extra <= 0) return '1 folder';\n return `${workspace.roots.length} folders`;\n}\n\n/**\n * A workspace's roots in SEND order: the primary first, then the rest as\n * stored.\n *\n * `VerseWorkspace.roots` is documented primary-first, but the flag is the\n * authority and an update replaces the set wholesale with \"first entry is\n * primary\". Normalising here means a reorder can never accidentally demote\n * the primary because a stored record listed it second.\n */\nexport function orderedWorkspaceRoots(workspace: VerseWorkspace): VerseWorkspaceRoot[] {\n const primary = workspace.roots.find((r) => r.primary);\n if (!primary) return [...workspace.roots];\n return [primary, ...workspace.roots.filter((r) => r !== primary)];\n}\n\n/** The same order, as the bare paths `updateVerseWorkspace` takes. */\nexport function workspaceRootPaths(workspace: VerseWorkspace): string[] {\n return orderedWorkspaceRoots(workspace).map((r) => r.path);\n}\n\n// ---------------------------------------------------------------------------\n// Which engines reach more than the primary folder\n// ---------------------------------------------------------------------------\n\n/**\n * Whether this engine's CLI takes an additional-directory flag.\n *\n * Mirrors `engineSupportsExtraRoots` in src/core/verse/workspaces.ts. Grok\n * exposes no such flag at all (checked on grok 0.2.118), so a Grok seat gets\n * its primary root and nothing else — and the UI has to SAY that at the point\n * the seat is chosen rather than let the operator discover it from a diff that\n * never applies.\n *\n * `null` (no seat picked yet) reaches everything: there is nothing to warn\n * about until a seat exists.\n */\nexport function engineReachesExtraRoots(engine: VerseEngine | null | undefined): boolean {\n if (engine === null || engine === undefined) return true;\n return engine === 'claude' || engine === 'codex' || engine === 'local';\n}\n\nexport const EXTRA_ROOTS_REACHABLE_NOTE =\n 'The agent can read and write these folders for the life of this chat. Enrolment is separate — an unenrolled folder stays out of reach of the autonomous lane.';\n\nexport const EXTRA_ROOTS_UNREACHABLE_NOTE =\n 'This seat’s CLI takes no additional-directory flag, so it will reach only the primary folder. The other folders will be unreachable — pick a Claude, Codex or local seat to use more than one.';\n\n/**\n * The caveat for handing `rootCount` folders to a seat, or null when there is\n * nothing to warn about. Only ever the BAD news, so a caller can render it as\n * a warning without having to decide which sentence it got.\n */\nexport function extraRootsCaveat(\n engine: VerseEngine | null | undefined,\n rootCount: number,\n): string | null {\n if (rootCount <= 1) return null;\n return engineReachesExtraRoots(engine) ? null : EXTRA_ROOTS_UNREACHABLE_NOTE;\n}\n\n/** The full note for a multi-folder set: the caveat when there is one, the\n * enrolment reminder otherwise. Null when only one folder is in play. */\nexport function extraRootsNote(\n engine: VerseEngine | null | undefined,\n rootCount: number,\n): string | null {\n if (rootCount <= 1) return null;\n return extraRootsCaveat(engine, rootCount) ?? EXTRA_ROOTS_REACHABLE_NOTE;\n}\n\n/** Said once wherever a multi-folder project is DEFINED, where no seat is\n * chosen yet and so no per-seat caveat can be given. */\nexport const MULTI_ROOT_ENGINE_NOTE =\n 'Claude, Codex and local seats reach every folder here. A Grok seat reaches only the primary one.';\n\n// ---------------------------------------------------------------------------\n// Saved projects (the create/edit form behind the workspace routes)\n// ---------------------------------------------------------------------------\n\n/** The folder's own name, used when the operator names nothing. */\nexport function defaultWorkspaceName(primaryPath: string): string {\n const trimmed = primaryPath.trim().replace(/[/\\\\]+$/, '');\n const base = trimmed.split(/[/\\\\]/).pop() ?? '';\n return base.length > 0 ? base : trimmed;\n}\n\nexport interface WorkspaceDraftValidation {\n ok: boolean;\n /** One message, or null when the draft is sendable. */\n error: string | null;\n /** The name as it would be sent — never empty when `ok`. */\n name: string;\n /** Trimmed, de-duplicated, primary first. */\n roots: string[];\n}\n\n/**\n * Validate a saved project before it is sent.\n *\n * COURTESY ONLY, exactly like `validateRootSet`: the server re-checks every\n * path against the enrollment registry's deny roots and is the authority.\n */\nexport function validateWorkspaceDraft(\n name: string,\n roots: readonly string[],\n): WorkspaceDraftValidation {\n const [primary = '', ...extras] = roots;\n const set = validateRootSet(primary, extras);\n if (!set.ok) return { ok: false, error: set.error, name: '', roots: [] };\n const trimmed = name.trim();\n const resolved = trimmed.length > 0 ? trimmed : defaultWorkspaceName(set.roots[0]!);\n if (resolved.length === 0) {\n return { ok: false, error: 'Give this project a name.', name: '', roots: [] };\n }\n return { ok: true, error: null, name: resolved, roots: set.roots };\n}\n\n/**\n * Move one entry up or down by one place.\n *\n * Returns a NEW array, and returns the order unchanged when the move would\n * fall off either end — so a caller can wire it to a button that is disabled\n * at the ends without the two disagreeing.\n */\nexport function moveRoot<T>(roots: readonly T[], index: number, direction: 'up' | 'down'): T[] {\n const next = [...roots];\n const target = direction === 'up' ? index - 1 : index + 1;\n if (index < 0 || index >= next.length || target < 0 || target >= next.length) return next;\n const moved = next[index]!;\n next[index] = next[target]!;\n next[target] = moved;\n return next;\n}\n\n/**\n * How the first row must be described. The first root IS the primary — it is\n * the session's cwd and the only folder a Grok seat reaches — so the reorder\n * control is not cosmetic and the label has to say what it does.\n */\nexport function rootRowLabel(index: number): string {\n return index === 0 ? 'Primary folder' : `Folder ${index + 1}`;\n}\n"],"mappings":"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"}
|
|
@@ -6,7 +6,7 @@
|
|
|
6
6
|
<meta name="color-scheme" content="light dark" />
|
|
7
7
|
<title>Ashlrverse — operator console</title>
|
|
8
8
|
<meta name="referrer" content="no-referrer" />
|
|
9
|
-
<script type="module" crossorigin src="/next/assets/index-
|
|
9
|
+
<script type="module" crossorigin src="/next/assets/index-BVxOlseC.js"></script>
|
|
10
10
|
</head>
|
|
11
11
|
<body>
|
|
12
12
|
<div id="root"></div>
|