@ashlr/hub 3.11.0 → 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.
Files changed (403) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/dist/authority-surface.json +12 -7
  3. package/dist/build-identity.json +2 -2
  4. package/dist/core/universe/builtins/preparation/manifest.json +1 -1
  5. package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +5 -4
  6. package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +4 -3
  7. package/dist/core/universe/campaign.js +9 -1
  8. package/dist/core/universe/campaign.js.map +1 -1
  9. package/dist/core/universe/runner.d.ts +3 -0
  10. package/dist/core/universe/runner.js +7 -3
  11. package/dist/core/universe/runner.js.map +1 -1
  12. package/dist/core/verse/compaction-point.d.ts +55 -0
  13. package/dist/core/verse/compaction-point.js +75 -0
  14. package/dist/core/verse/compaction-point.js.map +1 -0
  15. package/dist/core/verse/context-math.d.ts +1 -38
  16. package/dist/core/verse/context-math.js +5 -59
  17. package/dist/core/verse/context-math.js.map +1 -1
  18. package/dist/core/web/public/next/assets/{ActionMenu-CQvNJvHY.js → ActionMenu-FxXeRbPx.js} +2 -2
  19. package/dist/core/web/public/next/assets/{ActionMenu-CQvNJvHY.js.map → ActionMenu-FxXeRbPx.js.map} +1 -1
  20. package/dist/core/web/public/next/assets/Advanced-D_eS4472.js +2 -0
  21. package/dist/core/web/public/next/assets/{Advanced-DEM93sKI.js.map → Advanced-D_eS4472.js.map} +1 -1
  22. package/dist/core/web/public/next/assets/App-Cj4zKbG3.js +7 -0
  23. package/dist/core/web/public/next/assets/{App-CimXmK0L.js.map → App-Cj4zKbG3.js.map} +1 -1
  24. package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js +2 -0
  25. package/dist/core/web/public/next/assets/{AppsSection-D6U-dSj6.js.map → AppsSection-Ddu_RCQE.js.map} +1 -1
  26. package/dist/core/web/public/next/assets/{AreaTrend-LD9lCPkT.js → AreaTrend-CDxrQU4b.js} +2 -2
  27. package/dist/core/web/public/next/assets/{AreaTrend-LD9lCPkT.js.map → AreaTrend-CDxrQU4b.js.map} +1 -1
  28. package/dist/core/web/public/next/assets/AutonomySection-DuQkHGD_.js +2 -0
  29. package/dist/core/web/public/next/assets/{AutonomySection-3V9pUyxm.js.map → AutonomySection-DuQkHGD_.js.map} +1 -1
  30. package/dist/core/web/public/next/assets/BranchBar-CLsvOcyK.js +2 -0
  31. package/dist/core/web/public/next/assets/{BranchBar-U8UdpfEB.js.map → BranchBar-CLsvOcyK.js.map} +1 -1
  32. package/dist/core/web/public/next/assets/{BudgetControl-DOTlMSmW.js → BudgetControl-TL3FeZ1D.js} +2 -2
  33. package/dist/core/web/public/next/assets/{BudgetControl-DOTlMSmW.js.map → BudgetControl-TL3FeZ1D.js.map} +1 -1
  34. package/dist/core/web/public/next/assets/{BurnDown-x4PWH9JF.js → BurnDown-sFXkUGdB.js} +2 -2
  35. package/dist/core/web/public/next/assets/{BurnDown-x4PWH9JF.js.map → BurnDown-sFXkUGdB.js.map} +1 -1
  36. package/dist/core/web/public/next/assets/{Button-DYv_KKxr.js → Button-HHXgoXGr.js} +2 -2
  37. package/dist/core/web/public/next/assets/{Button-DYv_KKxr.js.map → Button-HHXgoXGr.js.map} +1 -1
  38. package/dist/core/web/public/next/assets/CapacityStrip-qReu0RaF.js +2 -0
  39. package/dist/core/web/public/next/assets/CapacityStrip-qReu0RaF.js.map +1 -0
  40. package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js +3 -0
  41. package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js.map +1 -0
  42. package/dist/core/web/public/next/assets/{CloudBudgetForm-DJeJvBEu.js → CloudBudgetForm-DJbiT1wi.js} +2 -2
  43. package/dist/core/web/public/next/assets/{CloudBudgetForm-DJeJvBEu.js.map → CloudBudgetForm-DJbiT1wi.js.map} +1 -1
  44. package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js +2 -0
  45. package/dist/core/web/public/next/assets/{CommandPalette-FiD4N8XD.js.map → CommandPalette-zYLFZRnj.js.map} +1 -1
  46. package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js +2 -0
  47. package/dist/core/web/public/next/assets/{CommandSection-DN8KwH-X.js.map → CommandSection-rIeMK5Ch.js.map} +1 -1
  48. package/dist/core/web/public/next/assets/ConfirmDialog-DLrLKM0c.js +2 -0
  49. package/dist/core/web/public/next/assets/ConfirmDialog-DLrLKM0c.js.map +1 -0
  50. package/dist/core/web/public/next/assets/ConfirmDialog-Dx15x0Ho.css +1 -0
  51. package/dist/core/web/public/next/assets/Dialog-BS9Dxi3G.js +2 -0
  52. package/dist/core/web/public/next/assets/Dialog-BS9Dxi3G.js.map +1 -0
  53. package/dist/core/web/public/next/assets/Dialog-tQ8kFulD.css +1 -0
  54. package/dist/core/web/public/next/assets/{DiffPane-DLJ3gGGK.js → DiffPane-TOmUf3b2.js} +2 -2
  55. package/dist/core/web/public/next/assets/{DiffPane-DLJ3gGGK.js.map → DiffPane-TOmUf3b2.js.map} +1 -1
  56. package/dist/core/web/public/next/assets/{DiffViewer-B7NWPjIO.js → DiffViewer-BpH56302.js} +2 -2
  57. package/dist/core/web/public/next/assets/{DiffViewer-B7NWPjIO.js.map → DiffViewer-BpH56302.js.map} +1 -1
  58. package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js +2 -0
  59. package/dist/core/web/public/next/assets/{DockHost-DvR-hPhZ.js.map → DockHost-DzkzR-HD.js.map} +1 -1
  60. package/dist/core/web/public/next/assets/{EmptyState-DhNgDDrF.js → EmptyState-BqR5YAmf.js} +2 -2
  61. package/dist/core/web/public/next/assets/{EmptyState-DhNgDDrF.js.map → EmptyState-BqR5YAmf.js.map} +1 -1
  62. package/dist/core/web/public/next/assets/{Epistemic-uARPnx9x.js → Epistemic-dhvDTwAZ.js} +2 -2
  63. package/dist/core/web/public/next/assets/{Epistemic-uARPnx9x.js.map → Epistemic-dhvDTwAZ.js.map} +1 -1
  64. package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js +3 -0
  65. package/dist/core/web/public/next/assets/{FleetSection-D_zRBCub.js.map → FleetSection-ViAb549H.js.map} +1 -1
  66. package/dist/core/web/public/next/assets/{Funnel-CL8uHONq.js → Funnel-D2u7Wlzc.js} +2 -2
  67. package/dist/core/web/public/next/assets/{Funnel-CL8uHONq.js.map → Funnel-D2u7Wlzc.js.map} +1 -1
  68. package/dist/core/web/public/next/assets/GearTray-Cb2npoxM.js +2 -0
  69. package/dist/core/web/public/next/assets/{GearTray-C7k4l_BW.js.map → GearTray-Cb2npoxM.js.map} +1 -1
  70. package/dist/core/web/public/next/assets/{GrowthSection-DwdNSGj8.js → GrowthSection-C5aDPs8B.js} +2 -2
  71. package/dist/core/web/public/next/assets/{GrowthSection-DwdNSGj8.js.map → GrowthSection-C5aDPs8B.js.map} +1 -1
  72. package/dist/core/web/public/next/assets/HandoffDialog-BF3AYg-X.js +2 -0
  73. package/dist/core/web/public/next/assets/{HandoffDialog-FPVOqOMN.js.map → HandoffDialog-BF3AYg-X.js.map} +1 -1
  74. package/dist/core/web/public/next/assets/{Input-B9-VLcHS.js → Input-B5dmGLZx.js} +2 -2
  75. package/dist/core/web/public/next/assets/{Input-B9-VLcHS.js.map → Input-B5dmGLZx.js.map} +1 -1
  76. package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js +2 -0
  77. package/dist/core/web/public/next/assets/{LeaderCard-4R0BhDzT.js.map → LeaderCard-DZrmjDbI.js.map} +1 -1
  78. package/dist/core/web/public/next/assets/{MatrixHeatmap-DiuushcS.js → MatrixHeatmap-BgEUs2Eu.js} +2 -2
  79. package/dist/core/web/public/next/assets/{MatrixHeatmap-DiuushcS.js.map → MatrixHeatmap-BgEUs2Eu.js.map} +1 -1
  80. package/dist/core/web/public/next/assets/McpSection-DZkiOuoq.js +2 -0
  81. package/dist/core/web/public/next/assets/{McpSection-CJ__OJKl.js.map → McpSection-DZkiOuoq.js.map} +1 -1
  82. package/dist/core/web/public/next/assets/{MessageMarkdown-qWKyJvAQ.js → MessageMarkdown-BauY8ZTY.js} +3 -3
  83. package/dist/core/web/public/next/assets/{MessageMarkdown-qWKyJvAQ.js.map → MessageMarkdown-BauY8ZTY.js.map} +1 -1
  84. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-x05TrsrW.js → MessageMarkdownRenderer-DLBNLfsn.js} +2 -2
  85. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-x05TrsrW.js.map → MessageMarkdownRenderer-DLBNLfsn.js.map} +1 -1
  86. package/dist/core/web/public/next/assets/{Meter-D-hncpkO.js → Meter-DNeocJnD.js} +2 -2
  87. package/dist/core/web/public/next/assets/{Meter-D-hncpkO.js.map → Meter-DNeocJnD.js.map} +1 -1
  88. package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js +2 -0
  89. package/dist/core/web/public/next/assets/{MindSection-BjXHkQPS.js.map → MindSection-BvJXFjyX.js.map} +1 -1
  90. package/dist/core/web/public/next/assets/MutationTokenDialog-CrfJ0PdD.css +1 -0
  91. package/dist/core/web/public/next/assets/MutationTokenDialog-mxrw0Yvy.js +2 -0
  92. package/dist/core/web/public/next/assets/MutationTokenDialog-mxrw0Yvy.js.map +1 -0
  93. package/dist/core/web/public/next/assets/NeedsYouDrawer-CO-Balfp.js +2 -0
  94. package/dist/core/web/public/next/assets/{NeedsYouDrawer-rSd1ZHAR.js.map → NeedsYouDrawer-CO-Balfp.js.map} +1 -1
  95. package/dist/core/web/public/next/assets/{NeedsYouList-CG-nB1tr.js → NeedsYouList-CzDZbzRD.js} +2 -2
  96. package/dist/core/web/public/next/assets/{NeedsYouList-CG-nB1tr.js.map → NeedsYouList-CzDZbzRD.js.map} +1 -1
  97. package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js +3 -0
  98. package/dist/core/web/public/next/assets/{NewChatDialog-BeDQ1eW3.js.map → NewChatDialog-B8eJjlFf.js.map} +1 -1
  99. package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js +2 -0
  100. package/dist/core/web/public/next/assets/{OnboardingFlow-CkTZtt-m.js.map → OnboardingFlow-Cij6KWat.js.map} +1 -1
  101. package/dist/core/web/public/next/assets/PreviewPane-BS-CleCd.js +2 -0
  102. package/dist/core/web/public/next/assets/{PreviewPane-kzbbSK4u.js.map → PreviewPane-BS-CleCd.js.map} +1 -1
  103. package/dist/core/web/public/next/assets/ProviderLogo-C5mBg8i0.js +2 -0
  104. package/dist/core/web/public/next/assets/ProviderLogo-C5mBg8i0.js.map +1 -0
  105. package/dist/core/web/public/next/assets/{RailStatus-D-t2gPae.js → RailStatus-cPRyOmrk.js} +2 -2
  106. package/dist/core/web/public/next/assets/{RailStatus-D-t2gPae.js.map → RailStatus-cPRyOmrk.js.map} +1 -1
  107. package/dist/core/web/public/next/assets/{RefreshIndicator-BLnr9IOM.js → RefreshIndicator-CMwSCiz5.js} +2 -2
  108. package/dist/core/web/public/next/assets/{RefreshIndicator-BLnr9IOM.js.map → RefreshIndicator-CMwSCiz5.js.map} +1 -1
  109. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BeG0gBif.js → ResourcePoolConsoleApp-BFi1opsC.js} +5 -5
  110. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BeG0gBif.js.map → ResourcePoolConsoleApp-BFi1opsC.js.map} +1 -1
  111. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-CM_8pJs6.css → ResourcePoolConsoleApp-BX9JLkT4.css} +1 -1
  112. package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js +3 -0
  113. package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js.map +1 -0
  114. package/dist/core/web/public/next/assets/ResourcesChrome-uZEqC2EM.css +1 -0
  115. package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js +2 -0
  116. package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js.map +1 -0
  117. package/dist/core/web/public/next/assets/RouteErrorBoundary-DYtwc2ja.js +2 -0
  118. package/dist/core/web/public/next/assets/RouteErrorBoundary-DYtwc2ja.js.map +1 -0
  119. package/dist/core/web/public/next/assets/RouteErrorBoundary-DdxhTdZ6.css +1 -0
  120. package/dist/core/web/public/next/assets/{RunInCloudAction-C3LBp7C4.js → RunInCloudAction-BEGEEM8O.js} +2 -2
  121. package/dist/core/web/public/next/assets/{RunInCloudAction-C3LBp7C4.js.map → RunInCloudAction-BEGEEM8O.js.map} +1 -1
  122. package/dist/core/web/public/next/assets/SeatSelector-CYHRR7Wp.js +3 -0
  123. package/dist/core/web/public/next/assets/{SeatSelector-DpvvbjNm.js.map → SeatSelector-CYHRR7Wp.js.map} +1 -1
  124. package/dist/core/web/public/next/assets/{Segmented-BL40udoO.js → Segmented-BE53BenI.js} +2 -2
  125. package/dist/core/web/public/next/assets/{Segmented-BL40udoO.js.map → Segmented-BE53BenI.js.map} +1 -1
  126. package/dist/core/web/public/next/assets/{Select-FWLnAw_j.js → Select-BwSGkHCS.js} +2 -2
  127. package/dist/core/web/public/next/assets/{Select-FWLnAw_j.js.map → Select-BwSGkHCS.js.map} +1 -1
  128. package/dist/core/web/public/next/assets/SessionGate-DvMpXNpJ.css +1 -0
  129. package/dist/core/web/public/next/assets/SessionGate-e0dFJm9d.js +2 -0
  130. package/dist/core/web/public/next/assets/SessionGate-e0dFJm9d.js.map +1 -0
  131. package/dist/core/web/public/next/assets/SessionInsightChip-CxlSyueJ.js +2 -0
  132. package/dist/core/web/public/next/assets/{SessionInsightChip-CWye87Ju.js.map → SessionInsightChip-CxlSyueJ.js.map} +1 -1
  133. package/dist/core/web/public/next/assets/{SessionSearch-YvCHFUuN.js → SessionSearch-_yp7S2TP.js} +2 -2
  134. package/dist/core/web/public/next/assets/{SessionSearch-YvCHFUuN.js.map → SessionSearch-_yp7S2TP.js.map} +1 -1
  135. package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js +2 -0
  136. package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js.map +1 -0
  137. package/dist/core/web/public/next/assets/Sheet-DVP2Mgy6.js +2 -0
  138. package/dist/core/web/public/next/assets/{Sheet-DZKcQXQg.js.map → Sheet-DVP2Mgy6.js.map} +1 -1
  139. package/dist/core/web/public/next/assets/ShortcutsOverlay-BcIcoClX.js +2 -0
  140. package/dist/core/web/public/next/assets/{ShortcutsOverlay-BpDimdPq.js.map → ShortcutsOverlay-BcIcoClX.js.map} +1 -1
  141. package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js +3 -0
  142. package/dist/core/web/public/next/assets/{Sidebar-BoBzBEFX.js.map → Sidebar-DjQOqPbm.js.map} +1 -1
  143. package/dist/core/web/public/next/assets/{Slider-DUMo9HDD.js → Slider-BypUWjpH.js} +2 -2
  144. package/dist/core/web/public/next/assets/{Slider-DUMo9HDD.js.map → Slider-BypUWjpH.js.map} +1 -1
  145. package/dist/core/web/public/next/assets/{StatusBadge-BwnBNFQr.js → StatusBadge-HCZp416_.js} +2 -2
  146. package/dist/core/web/public/next/assets/{StatusBadge-BwnBNFQr.js.map → StatusBadge-HCZp416_.js.map} +1 -1
  147. package/dist/core/web/public/next/assets/{StepBand-PDXMIlRk.js → StepBand-Duz1PUes.js} +2 -2
  148. package/dist/core/web/public/next/assets/{StepBand-PDXMIlRk.js.map → StepBand-Duz1PUes.js.map} +1 -1
  149. package/dist/core/web/public/next/assets/{Surface-B3TZVoER.js → Surface-B75lVfzm.js} +2 -2
  150. package/dist/core/web/public/next/assets/{Surface-B3TZVoER.js.map → Surface-B75lVfzm.js.map} +1 -1
  151. package/dist/core/web/public/next/assets/{Swimlane-DR4OgON_.js → Swimlane-DGcIcnNA.js} +2 -2
  152. package/dist/core/web/public/next/assets/{Swimlane-DR4OgON_.js.map → Swimlane-DGcIcnNA.js.map} +1 -1
  153. package/dist/core/web/public/next/assets/{Switch-CcR5Llk5.js → Switch-iveI-8NY.js} +2 -2
  154. package/dist/core/web/public/next/assets/{Switch-CcR5Llk5.js.map → Switch-iveI-8NY.js.map} +1 -1
  155. package/dist/core/web/public/next/assets/{Tag-_-K1h7Hk.js → Tag-DH15CUJp.js} +2 -2
  156. package/dist/core/web/public/next/assets/{Tag-_-K1h7Hk.js.map → Tag-DH15CUJp.js.map} +1 -1
  157. package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js +7 -0
  158. package/dist/core/web/public/next/assets/{TerminalPane-_1aH4ndN.js.map → TerminalPane-MQT-veKZ.js.map} +1 -1
  159. package/dist/core/web/public/next/assets/UniverseConsoleApp-C8yQ0AaR.js +2 -0
  160. package/dist/core/web/public/next/assets/{UniverseConsoleApp-BUsq-inZ.js.map → UniverseConsoleApp-C8yQ0AaR.js.map} +1 -1
  161. package/dist/core/web/public/next/assets/{UniverseConsoleApp-Dh7A-hLD.css → UniverseConsoleApp-DfuT-wFw.css} +1 -1
  162. package/dist/core/web/public/next/assets/{UniverseView-Dogy_dsB.js → UniverseView-_nPURPqe.js} +4 -4
  163. package/dist/core/web/public/next/assets/{UniverseView-Dogy_dsB.js.map → UniverseView-_nPURPqe.js.map} +1 -1
  164. package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js +2 -0
  165. package/dist/core/web/public/next/assets/{UsageSection-DiX_dTyo.js.map → UsageSection-CqxRGJ40.js.map} +1 -1
  166. package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js +3 -0
  167. package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js.map +1 -0
  168. package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js +10 -0
  169. package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js.map +1 -0
  170. package/dist/core/web/public/next/assets/Workspace-Dwri2jFJ.css +1 -0
  171. package/dist/core/web/public/next/assets/actions-tWevL9HV.js +2 -0
  172. package/dist/core/web/public/next/assets/{actions-s2lfm_5k.js.map → actions-tWevL9HV.js.map} +1 -1
  173. package/dist/core/web/public/next/assets/budget-queries-V3wcJVK_.js +2 -0
  174. package/dist/core/web/public/next/assets/{budget-queries-wUshcovN.js.map → budget-queries-V3wcJVK_.js.map} +1 -1
  175. package/dist/core/web/public/next/assets/{capacity-strip-model-Bj_9ztzs.js → capacity-strip-model-BDbmQ3e3.js} +2 -2
  176. package/dist/core/web/public/next/assets/{capacity-strip-model-Bj_9ztzs.js.map → capacity-strip-model-BDbmQ3e3.js.map} +1 -1
  177. package/dist/core/web/public/next/assets/{charts-CMSgAUKn.js → charts-CfAjuKMv.js} +2 -2
  178. package/dist/core/web/public/next/assets/{charts-CMSgAUKn.js.map → charts-CfAjuKMv.js.map} +1 -1
  179. package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js +2 -0
  180. package/dist/core/web/public/next/assets/{cloud-queries-CnV1yaNG.js.map → cloud-queries-Br_r0UAz.js.map} +1 -1
  181. package/dist/core/web/public/next/assets/{cloud.module-CiwatLj3.js → cloud.module-ascz58c3.js} +2 -2
  182. package/dist/core/web/public/next/assets/{cloud.module-CiwatLj3.js.map → cloud.module-ascz58c3.js.map} +1 -1
  183. package/dist/core/web/public/next/assets/{command-bus-DqimKCUY.js → command-bus-xYZoK9nQ.js} +2 -2
  184. package/dist/core/web/public/next/assets/{command-bus-DqimKCUY.js.map → command-bus-xYZoK9nQ.js.map} +1 -1
  185. package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js +2 -0
  186. package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js.map +1 -0
  187. package/dist/core/web/public/next/assets/compaction-point-VL9oegWS.js +2 -0
  188. package/dist/core/web/public/next/assets/compaction-point-VL9oegWS.js.map +1 -0
  189. package/dist/core/web/public/next/assets/{composer-keys-DBRymxQn.js → composer-keys-su0g1h9o.js} +2 -2
  190. package/dist/core/web/public/next/assets/{composer-keys-DBRymxQn.js.map → composer-keys-su0g1h9o.js.map} +1 -1
  191. package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js +2 -0
  192. package/dist/core/web/public/next/assets/{context-model-Dwd49-dp.js.map → context-model-BC-HOmPo.js.map} +1 -1
  193. package/dist/core/web/public/next/assets/context-model-CIBmSugV.js +2 -0
  194. package/dist/core/web/public/next/assets/{context-model-MT17V86_.js.map → context-model-CIBmSugV.js.map} +1 -1
  195. package/dist/core/web/public/next/assets/context-queries-CrPcHWTz.js +2 -0
  196. package/dist/core/web/public/next/assets/{context-queries-xVKIeynP.js.map → context-queries-CrPcHWTz.js.map} +1 -1
  197. package/dist/core/web/public/next/assets/control-queries-CmgBgKV7.js +2 -0
  198. package/dist/core/web/public/next/assets/{control-queries-DOZR-D8G.js.map → control-queries-CmgBgKV7.js.map} +1 -1
  199. package/dist/core/web/public/next/assets/{dock-icons-8EtARwUm.js → dock-icons-CUh8dOxJ.js} +2 -2
  200. package/dist/core/web/public/next/assets/{dock-icons-8EtARwUm.js.map → dock-icons-CUh8dOxJ.js.map} +1 -1
  201. package/dist/core/web/public/next/assets/{dock-store-BA1cHOYA.js → dock-store-B2vlxqPu.js} +2 -2
  202. package/dist/core/web/public/next/assets/{dock-store-BA1cHOYA.js.map → dock-store-B2vlxqPu.js.map} +1 -1
  203. package/dist/core/web/public/next/assets/{fleet-model-CNe8Wh-s.js → fleet-model-7i-FbzKI.js} +2 -2
  204. package/dist/core/web/public/next/assets/{fleet-model-CNe8Wh-s.js.map → fleet-model-7i-FbzKI.js.map} +1 -1
  205. package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js +2 -0
  206. package/dist/core/web/public/next/assets/{fleet-queries-BSdRlUwJ.js.map → fleet-queries-DzGoqq8X.js.map} +1 -1
  207. package/dist/core/web/public/next/assets/focus-trap-HtcoXeEq.js +2 -0
  208. package/dist/core/web/public/next/assets/focus-trap-HtcoXeEq.js.map +1 -0
  209. package/dist/core/web/public/next/assets/{format-B8DAVcn2.js → format-BkWdOQDL.js} +2 -2
  210. package/dist/core/web/public/next/assets/{format-B8DAVcn2.js.map → format-BkWdOQDL.js.map} +1 -1
  211. package/dist/core/web/public/next/assets/git-model-bk_RXh3y.js +5 -0
  212. package/dist/core/web/public/next/assets/{git-model-CivuBY_D.js.map → git-model-bk_RXh3y.js.map} +1 -1
  213. package/dist/core/web/public/next/assets/global-BlI2BYa1.css +1 -0
  214. package/dist/core/web/public/next/assets/global-oEl9Qj8u.js +2 -0
  215. package/dist/core/web/public/next/assets/global-oEl9Qj8u.js.map +1 -0
  216. package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js +3 -0
  217. package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js.map +1 -0
  218. package/dist/core/web/public/next/assets/guarded-runners-LHLXmXIk.js +2 -0
  219. package/dist/core/web/public/next/assets/guarded-runners-LHLXmXIk.js.map +1 -0
  220. package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js +2 -0
  221. package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js.map +1 -0
  222. package/dist/core/web/public/next/assets/icons-DEQa2rTx.js +2 -0
  223. package/dist/core/web/public/next/assets/icons-DEQa2rTx.js.map +1 -0
  224. package/dist/core/web/public/next/assets/{index-oAAq8XJa.js → index-BVxOlseC.js} +3 -3
  225. package/dist/core/web/public/next/assets/{index-oAAq8XJa.js.map → index-BVxOlseC.js.map} +1 -1
  226. package/dist/core/web/public/next/assets/{live-model-DCw_IFRI.js → live-model-bmsJgnYD.js} +2 -2
  227. package/dist/core/web/public/next/assets/{live-model-DCw_IFRI.js.map → live-model-bmsJgnYD.js.map} +1 -1
  228. package/dist/core/web/public/next/assets/{mind.module-vnuJcwvD.js → mind.module-gTGAuJt1.js} +2 -2
  229. package/dist/core/web/public/next/assets/{mind.module-vnuJcwvD.js.map → mind.module-gTGAuJt1.js.map} +1 -1
  230. package/dist/core/web/public/next/assets/mutations-C5S7okTW.js +2 -0
  231. package/dist/core/web/public/next/assets/{mutations-Dpsql5t7.js.map → mutations-C5S7okTW.js.map} +1 -1
  232. package/dist/core/web/public/next/assets/nav-NVtnuG7A.js +2 -0
  233. package/dist/core/web/public/next/assets/nav-NVtnuG7A.js.map +1 -0
  234. package/dist/core/web/public/next/assets/overnight-queries-DGm3qL1b.js +2 -0
  235. package/dist/core/web/public/next/assets/{overnight-queries-X-44Gsw5.js.map → overnight-queries-DGm3qL1b.js.map} +1 -1
  236. package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js +2 -0
  237. package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js.map +1 -0
  238. package/dist/core/web/public/next/assets/primitives-DyCKYSBG.js +1 -0
  239. package/dist/core/web/public/next/assets/{queries-BA4rNGD-.js → queries-CYisSAAB.js} +2 -2
  240. package/dist/core/web/public/next/assets/{queries-BA4rNGD-.js.map → queries-CYisSAAB.js.map} +1 -1
  241. package/dist/core/web/public/next/assets/reasoning-pref-BUcFF_5G.js +2 -0
  242. package/dist/core/web/public/next/assets/{reasoning-pref-B9-DJUXP.js.map → reasoning-pref-BUcFF_5G.js.map} +1 -1
  243. package/dist/core/web/public/next/assets/reveal-anchor-D-tV8xau.js +2 -0
  244. package/dist/core/web/public/next/assets/reveal-anchor-D-tV8xau.js.map +1 -0
  245. package/dist/core/web/public/next/assets/seat-subscription-B-f9ViU2.js +2 -0
  246. package/dist/core/web/public/next/assets/{seat-subscription-CH6fW4fJ.js.map → seat-subscription-B-f9ViU2.js.map} +1 -1
  247. package/dist/core/web/public/next/assets/{section-visibility-qFqc_d4Z.js → section-visibility-Yctxu-if.js} +2 -2
  248. package/dist/core/web/public/next/assets/{section-visibility-qFqc_d4Z.js.map → section-visibility-Yctxu-if.js.map} +1 -1
  249. package/dist/core/web/public/next/assets/{sidebar-model-M1GaQU5l.js → sidebar-model-DQ-FyBHW.js} +2 -2
  250. package/dist/core/web/public/next/assets/{sidebar-model-M1GaQU5l.js.map → sidebar-model-DQ-FyBHW.js.map} +1 -1
  251. package/dist/core/web/public/next/assets/slots-BhP8b8tf.js +3 -0
  252. package/dist/core/web/public/next/assets/{slots-Ds9ZIqUL.js.map → slots-BhP8b8tf.js.map} +1 -1
  253. package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js +2 -0
  254. package/dist/core/web/public/next/assets/{surface-data-J52iIGMD.js.map → surface-data-DTI7LjvH.js.map} +1 -1
  255. package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js +2 -0
  256. package/dist/core/web/public/next/assets/{surface-prefetch-CgZ-LEJK.js.map → surface-prefetch-CdUEBFrl.js.map} +1 -1
  257. package/dist/core/web/public/next/assets/{tasks-model-ent8f0jZ.js → tasks-model-BKDNqmmt.js} +2 -2
  258. package/dist/core/web/public/next/assets/{tasks-model-ent8f0jZ.js.map → tasks-model-BKDNqmmt.js.map} +1 -1
  259. package/dist/core/web/public/next/assets/{terminal-icons-DJTK7QpR.js → terminal-icons-D2xe-aM1.js} +2 -2
  260. package/dist/core/web/public/next/assets/{terminal-icons-DJTK7QpR.js.map → terminal-icons-D2xe-aM1.js.map} +1 -1
  261. package/dist/core/web/public/next/assets/{usage-queries-Bn8ccqyN.js → usage-queries-BZuAANlI.js} +2 -2
  262. package/dist/core/web/public/next/assets/{usage-queries-Bn8ccqyN.js.map → usage-queries-BZuAANlI.js.map} +1 -1
  263. package/dist/core/web/public/next/assets/use-guarded-action-Cf4MeNBa.js +2 -0
  264. package/dist/core/web/public/next/assets/{use-guarded-action-C2HlSzkz.js.map → use-guarded-action-Cf4MeNBa.js.map} +1 -1
  265. package/dist/core/web/public/next/assets/{use-ticker-BNc1H4ZC.js → use-ticker-D9yi49my.js} +2 -2
  266. package/dist/core/web/public/next/assets/{use-ticker-BNc1H4ZC.js.map → use-ticker-D9yi49my.js.map} +1 -1
  267. package/dist/core/web/public/next/assets/use-token-gate-DqrSXdX6.js +2 -0
  268. package/dist/core/web/public/next/assets/{use-token-gate-B3IJL6bf.js.map → use-token-gate-DqrSXdX6.js.map} +1 -1
  269. package/dist/core/web/public/next/assets/useChartWidth-BW6SwYIK.css +1 -0
  270. package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js +2 -0
  271. package/dist/core/web/public/next/assets/{useChartWidth-lZ9PrQn0.js.map → useChartWidth-owwodNVz.js.map} +1 -1
  272. package/dist/core/web/public/next/assets/{useSeatsRefresh-CG4jczeL.js → useSeatsRefresh-DgFy-Ph4.js} +2 -2
  273. package/dist/core/web/public/next/assets/{useSeatsRefresh-CG4jczeL.js.map → useSeatsRefresh-DgFy-Ph4.js.map} +1 -1
  274. package/dist/core/web/public/next/assets/useVerseTranscript-CDYrrWOO.js +2 -0
  275. package/dist/core/web/public/next/assets/useVerseTranscript-CDYrrWOO.js.map +1 -0
  276. package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js +2 -0
  277. package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js.map +1 -0
  278. package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js +2 -0
  279. package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js.map +1 -0
  280. package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js +3 -0
  281. package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js.map +1 -0
  282. package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js +3 -0
  283. package/dist/core/web/public/next/assets/{verse-ui-store-zafyzXKD.js.map → verse-ui-store-62DxpVHS.js.map} +1 -1
  284. package/dist/core/web/public/next/assets/{viewport-BEqGUoTA.js → viewport-nTubFCwf.js} +2 -2
  285. package/dist/core/web/public/next/assets/{viewport-BEqGUoTA.js.map → viewport-nTubFCwf.js.map} +1 -1
  286. package/dist/core/web/public/next/assets/warmup-HG5vYbsN.js +3 -0
  287. package/dist/core/web/public/next/assets/{warmup-BR6pxAKs.js.map → warmup-HG5vYbsN.js.map} +1 -1
  288. package/dist/core/web/public/next/assets/{workspace-model-D_tWD5Wt.js → workspace-model-CbhdPhei.js} +2 -2
  289. package/dist/core/web/public/next/assets/{workspace-model-D_tWD5Wt.js.map → workspace-model-CbhdPhei.js.map} +1 -1
  290. package/dist/core/web/public/next/index.html +1 -1
  291. package/dist/release-dependency-inventory.json +1 -1
  292. package/package.json +5 -2
  293. package/dist/cli/activation.d.ts +0 -41
  294. package/dist/cli/activation.js +0 -485
  295. package/dist/cli/activation.js.map +0 -1
  296. package/dist/core/fleet/generated-repair-resolution.d.ts +0 -36
  297. package/dist/core/fleet/generated-repair-resolution.js +0 -245
  298. package/dist/core/fleet/generated-repair-resolution.js.map +0 -1
  299. package/dist/core/local-runtime/llama/port.d.ts +0 -17
  300. package/dist/core/local-runtime/llama/port.js +0 -47
  301. package/dist/core/local-runtime/llama/port.js.map +0 -1
  302. package/dist/core/local-runtime/llama/proxy-host.d.ts +0 -54
  303. package/dist/core/local-runtime/llama/proxy-host.js +0 -159
  304. package/dist/core/local-runtime/llama/proxy-host.js.map +0 -1
  305. package/dist/core/local-runtime/llama/proxy-process.d.ts +0 -148
  306. package/dist/core/local-runtime/llama/proxy-process.js +0 -250
  307. package/dist/core/local-runtime/llama/proxy-process.js.map +0 -1
  308. package/dist/core/local-runtime/llama/proxy-record.d.ts +0 -40
  309. package/dist/core/local-runtime/llama/proxy-record.js +0 -133
  310. package/dist/core/local-runtime/llama/proxy-record.js.map +0 -1
  311. package/dist/core/local-runtime/llama/proxy-supervisor.d.ts +0 -118
  312. package/dist/core/local-runtime/llama/proxy-supervisor.js +0 -511
  313. package/dist/core/local-runtime/llama/proxy-supervisor.js.map +0 -1
  314. package/dist/core/web/public/next/assets/Advanced-DEM93sKI.js +0 -2
  315. package/dist/core/web/public/next/assets/App-CimXmK0L.js +0 -7
  316. package/dist/core/web/public/next/assets/AppsSection-D6U-dSj6.js +0 -2
  317. package/dist/core/web/public/next/assets/AutonomySection-3V9pUyxm.js +0 -2
  318. package/dist/core/web/public/next/assets/BranchBar-U8UdpfEB.js +0 -2
  319. package/dist/core/web/public/next/assets/CapacityStrip-C667yQe8.js +0 -2
  320. package/dist/core/web/public/next/assets/CapacityStrip-C667yQe8.js.map +0 -1
  321. package/dist/core/web/public/next/assets/ChatSection-CCcIPpOq.js +0 -3
  322. package/dist/core/web/public/next/assets/ChatSection-CCcIPpOq.js.map +0 -1
  323. package/dist/core/web/public/next/assets/CommandPalette-FiD4N8XD.js +0 -2
  324. package/dist/core/web/public/next/assets/CommandSection-DN8KwH-X.js +0 -2
  325. package/dist/core/web/public/next/assets/DockHost-DvR-hPhZ.js +0 -2
  326. package/dist/core/web/public/next/assets/FleetSection-D_zRBCub.js +0 -3
  327. package/dist/core/web/public/next/assets/GearTray-C7k4l_BW.js +0 -2
  328. package/dist/core/web/public/next/assets/HandoffDialog-FPVOqOMN.js +0 -2
  329. package/dist/core/web/public/next/assets/LeaderCard-4R0BhDzT.js +0 -2
  330. package/dist/core/web/public/next/assets/McpSection-CJ__OJKl.js +0 -2
  331. package/dist/core/web/public/next/assets/MindSection-BjXHkQPS.js +0 -2
  332. package/dist/core/web/public/next/assets/MutationTokenDialog-Cum_DqQZ.css +0 -1
  333. package/dist/core/web/public/next/assets/MutationTokenDialog-SkRxqV_I.js +0 -2
  334. package/dist/core/web/public/next/assets/MutationTokenDialog-SkRxqV_I.js.map +0 -1
  335. package/dist/core/web/public/next/assets/NeedsYouDrawer-rSd1ZHAR.js +0 -2
  336. package/dist/core/web/public/next/assets/NewChatDialog-BeDQ1eW3.js +0 -3
  337. package/dist/core/web/public/next/assets/OnboardingFlow-CkTZtt-m.js +0 -2
  338. package/dist/core/web/public/next/assets/PreviewPane-kzbbSK4u.js +0 -2
  339. package/dist/core/web/public/next/assets/ResourcesChrome-B3Z3O98t.css +0 -1
  340. package/dist/core/web/public/next/assets/ResourcesChrome-BzV6bkIa.js +0 -3
  341. package/dist/core/web/public/next/assets/ResourcesChrome-BzV6bkIa.js.map +0 -1
  342. package/dist/core/web/public/next/assets/ResourcesDrawer-o4ILHdep.js +0 -2
  343. package/dist/core/web/public/next/assets/ResourcesDrawer-o4ILHdep.js.map +0 -1
  344. package/dist/core/web/public/next/assets/RouteErrorBoundary-6RMd_aZg.css +0 -1
  345. package/dist/core/web/public/next/assets/RouteErrorBoundary-C5SxA2Dg.js +0 -2
  346. package/dist/core/web/public/next/assets/RouteErrorBoundary-C5SxA2Dg.js.map +0 -1
  347. package/dist/core/web/public/next/assets/SeatSelector-DpvvbjNm.js +0 -3
  348. package/dist/core/web/public/next/assets/SessionInsightChip-CWye87Ju.js +0 -2
  349. package/dist/core/web/public/next/assets/SettingsSection-Dr18upeE.js +0 -2
  350. package/dist/core/web/public/next/assets/SettingsSection-Dr18upeE.js.map +0 -1
  351. package/dist/core/web/public/next/assets/Sheet-DZKcQXQg.js +0 -2
  352. package/dist/core/web/public/next/assets/ShortcutsOverlay-BpDimdPq.js +0 -2
  353. package/dist/core/web/public/next/assets/Sidebar-BoBzBEFX.js +0 -3
  354. package/dist/core/web/public/next/assets/TerminalPane-_1aH4ndN.js +0 -7
  355. package/dist/core/web/public/next/assets/UniverseConsoleApp-BUsq-inZ.js +0 -2
  356. package/dist/core/web/public/next/assets/UsageSection-DiX_dTyo.js +0 -2
  357. package/dist/core/web/public/next/assets/VerseConsoleApp-WVeyJnW7.js +0 -3
  358. package/dist/core/web/public/next/assets/VerseConsoleApp-WVeyJnW7.js.map +0 -1
  359. package/dist/core/web/public/next/assets/Workspace-BYW9dm90.css +0 -1
  360. package/dist/core/web/public/next/assets/Workspace-BbxZHwQd.js +0 -10
  361. package/dist/core/web/public/next/assets/Workspace-BbxZHwQd.js.map +0 -1
  362. package/dist/core/web/public/next/assets/actions-s2lfm_5k.js +0 -2
  363. package/dist/core/web/public/next/assets/budget-queries-wUshcovN.js +0 -2
  364. package/dist/core/web/public/next/assets/cloud-queries-CnV1yaNG.js +0 -2
  365. package/dist/core/web/public/next/assets/command-catalog-BdtDH93o.js +0 -2
  366. package/dist/core/web/public/next/assets/command-catalog-BdtDH93o.js.map +0 -1
  367. package/dist/core/web/public/next/assets/context-model-Dwd49-dp.js +0 -2
  368. package/dist/core/web/public/next/assets/context-model-MT17V86_.js +0 -2
  369. package/dist/core/web/public/next/assets/context-queries-xVKIeynP.js +0 -2
  370. package/dist/core/web/public/next/assets/control-queries-DOZR-D8G.js +0 -2
  371. package/dist/core/web/public/next/assets/dock-panes-UKS-mXhr.js +0 -2
  372. package/dist/core/web/public/next/assets/dock-panes-UKS-mXhr.js.map +0 -1
  373. package/dist/core/web/public/next/assets/fleet-queries-BSdRlUwJ.js +0 -2
  374. package/dist/core/web/public/next/assets/git-model-CivuBY_D.js +0 -5
  375. package/dist/core/web/public/next/assets/global-Di2PUgj4.js +0 -2
  376. package/dist/core/web/public/next/assets/global-Di2PUgj4.js.map +0 -1
  377. package/dist/core/web/public/next/assets/global-_tOCFt9y.css +0 -1
  378. package/dist/core/web/public/next/assets/guarded-action-CvOHcqyH.js +0 -2
  379. package/dist/core/web/public/next/assets/guarded-action-CvOHcqyH.js.map +0 -1
  380. package/dist/core/web/public/next/assets/icons-B_yuAgdN.js +0 -2
  381. package/dist/core/web/public/next/assets/icons-B_yuAgdN.js.map +0 -1
  382. package/dist/core/web/public/next/assets/mutations-Dpsql5t7.js +0 -2
  383. package/dist/core/web/public/next/assets/overnight-queries-X-44Gsw5.js +0 -2
  384. package/dist/core/web/public/next/assets/primitives-BDIcUvob.js +0 -1
  385. package/dist/core/web/public/next/assets/reasoning-pref-B9-DJUXP.js +0 -2
  386. package/dist/core/web/public/next/assets/seat-subscription-CH6fW4fJ.js +0 -2
  387. package/dist/core/web/public/next/assets/slots-Ds9ZIqUL.js +0 -3
  388. package/dist/core/web/public/next/assets/surface-data-J52iIGMD.js +0 -2
  389. package/dist/core/web/public/next/assets/surface-prefetch-CgZ-LEJK.js +0 -2
  390. package/dist/core/web/public/next/assets/use-guarded-action-C2HlSzkz.js +0 -2
  391. package/dist/core/web/public/next/assets/use-token-gate-B3IJL6bf.js +0 -2
  392. package/dist/core/web/public/next/assets/useActivity-Bk3XgXjL.js +0 -2
  393. package/dist/core/web/public/next/assets/useActivity-Bk3XgXjL.js.map +0 -1
  394. package/dist/core/web/public/next/assets/useChartWidth-BAtVgn2n.css +0 -1
  395. package/dist/core/web/public/next/assets/useChartWidth-lZ9PrQn0.js +0 -2
  396. package/dist/core/web/public/next/assets/verse-model-D7NZQFAR.js +0 -2
  397. package/dist/core/web/public/next/assets/verse-model-D7NZQFAR.js.map +0 -1
  398. package/dist/core/web/public/next/assets/verse-queries-DvIJcn6Z.js +0 -2
  399. package/dist/core/web/public/next/assets/verse-queries-DvIJcn6Z.js.map +0 -1
  400. package/dist/core/web/public/next/assets/verse-store-DjBWj04q.js +0 -3
  401. package/dist/core/web/public/next/assets/verse-store-DjBWj04q.js.map +0 -1
  402. package/dist/core/web/public/next/assets/verse-ui-store-zafyzXKD.js +0 -3
  403. package/dist/core/web/public/next/assets/warmup-BR6pxAKs.js +0 -3
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useVerseTranscript-CDYrrWOO.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/dock/dock-panes.ts","../../../../../../src/web-ui/routes/verse/verse-transcript.ts","../../../../../../src/web-ui/routes/verse/useVerseTranscript.ts"],"sourcesContent":["/**\n * routes/verse/dock/dock-panes.ts — which dock panes exist in this build,\n * and their names (unit C2).\n *\n * Split out of Dock.tsx so the header's pane toggles can ask without pulling\n * the dock itself into the chat's first-paint chunk: the dock is lazy (it\n * starts closed), the toggles are not.\n */\nimport { DOCK_PANES, type DockPaneId } from '../shell/dock-catalog.js';\nimport { isSlotAvailable, type SlotId } from '../shell/slots.js';\n\nconst SLOT_FOR: Readonly<Partial<Record<DockPaneId, SlotId>>> = Object.fromEntries(\n DOCK_PANES.filter((p) => p.slot !== null).map((p) => [p.id, p.slot]),\n);\n\n/** A pane exists in this build: C2's always, a slot pane once its unit's file landed. */\nexport function isPaneAvailable(pane: DockPaneId): boolean {\n const slot = SLOT_FOR[pane];\n return slot === undefined || isSlotAvailable(slot);\n}\n\nexport const DOCK_PANE_LABEL: Readonly<Record<DockPaneId, string>> = Object.fromEntries(\n DOCK_PANES.map((p) => [p.id, p.label]),\n) as Record<DockPaneId, string>;\n","/**\n * routes/verse/verse-transcript.ts — what the transcript renders, derived\n * from a session's raw event log (moved out of verse-store.ts).\n *\n * WHY A SEPARATE MODULE: verse-store is on the chat first-paint path (the\n * Chat section opens the selected chat's stream as it mounts), but nothing\n * reads a DERIVED transcript until the workspace or the dock — both lazy\n * chunks — renders one. Keeping the derivation here keeps ~5 KB of it out of\n * the chat first-paint critical JS (SPEC-310A §1, scripts/check-first-paint-\n * budget.mjs). verse-store must never import this module back as a value.\n *\n * `buildTranscript()` derives what the transcript renders from the raw\n * events: streamed `text-delta`s accumulate into a provisional assistant\n * bubble until the matching `assistant-message` arrives and replaces it;\n * `tool-use` and `tool-result` pair up by toolUseId into one card.\n * `getVerseTranscript()` memoizes it per session against the store's event\n * log, rebuilding only the turn segments that changed.\n */\nimport type { VerseEvent, VerseUsage } from '../../data/api-types.js';\nimport type { VerseRecoveryHow, VerseThinkingKind } from '../../../core/verse/types.js';\nimport { getVerseSessionState, getVerseThinkingStats, subscribeVerseStoreLifecycle, type VerseThinkingStat } from './verse-store.js';\n\n// ---------------------------------------------------------------------------\n// Per-session memo over the store\n// ---------------------------------------------------------------------------\n\nconst transcriptMemo = new Map<string, { events: readonly VerseEvent[]; transcript: Transcript; cache: TranscriptCache }>();\n\n// The store tells us when a chat is forgotten or everything is reset\n// (logout, tests), exactly when it used to clear this memo itself.\nsubscribeVerseStoreLifecycle((event) => {\n if (event.kind === 'reset') transcriptMemo.clear();\n else transcriptMemo.delete(event.sessionId);\n});\n\nconst EMPTY_TRANSCRIPT: Transcript = { items: [], live: false, usage: null, segments: [] };\n\n/**\n * The derived transcript, rebuilt only when the event log changed and then\n * only for the turn segments that changed (see buildTranscript's cache).\n */\nexport function getVerseTranscript(sessionId: string | null): Transcript {\n if (!sessionId) return EMPTY_TRANSCRIPT;\n const entry = getVerseSessionState(sessionId);\n const memo = transcriptMemo.get(sessionId);\n if (memo && memo.events === entry.events) return memo.transcript;\n const cache = memo?.cache ?? createTranscriptCache();\n const transcript = buildTranscript(entry.events, { cache, thinkingStats: getVerseThinkingStats(sessionId) });\n transcriptMemo.set(sessionId, { events: entry.events, transcript, cache });\n return transcript;\n}\n\n// ---------------------------------------------------------------------------\n// Transcript derivation\n// ---------------------------------------------------------------------------\n\nexport type TranscriptItem =\n | { kind: 'user'; key: string; turnId: string; at: string; text: string }\n | { kind: 'assistant'; key: string; turnId: string; at: string; text: string; streaming: boolean }\n | {\n kind: 'thinking';\n key: string;\n turnId: string;\n at: string;\n text: string;\n /** V3.10: the CLI sent a signature-only / redacted block — the model thought, the text is withheld. */\n redacted: boolean;\n /** Streaming wall time: the event's own figure, else what this tab measured; null = unknown. */\n durationMs: number | null;\n /** The CLI's reasoning-token estimate this tab saw while it streamed; null = unknown. */\n estimatedTokens: number | null;\n thinkingKind: VerseThinkingKind | null;\n }\n | {\n kind: 'tool';\n key: string;\n turnId: string;\n at: string;\n toolUseId: string;\n name: string;\n input: unknown;\n result: { output: string; isError: boolean } | null;\n /** tool-use → tool-result wall time; null while pending or unstamped. */\n durationMs: number | null;\n }\n | { kind: 'error'; key: string; turnId: string | null; at: string; message: string; code: string | null }\n | {\n /** V3.9: the CLI compacted its own context. Counts are null when the CLI does not report them (codex). */\n kind: 'compaction';\n key: string;\n turnId: string | null;\n at: string;\n trigger: 'auto' | 'manual';\n preTokens: number | null;\n postTokens: number | null;\n durationMs: number | null;\n }\n | { kind: 'cancelled'; key: string; turnId: string; at: string }\n | { kind: 'turn-done'; key: string; turnId: string; at: string; ok: boolean; durationMs: number }\n /** V3.10: the engine restored a lost native conversation. */\n | { kind: 'recovered'; key: string; turnId: string | null; at: string; how: VerseRecoveryHow; message: string }\n /** V3.10: the log hit its cap and dropped everything before `droppedBefore` (at a turn boundary). */\n | { kind: 'truncated'; key: string; turnId: null; at: string; droppedBefore: number };\n\n/**\n * One turn's worth of items — the log cut at each `user-message`. Unchanged\n * segments come back as the SAME object from a cached build, which is what\n * lets the renderer skip every finished turn while one is streaming.\n */\nexport interface TranscriptSegment {\n key: string;\n items: TranscriptItem[];\n}\n\nexport interface Transcript {\n items: TranscriptItem[];\n /** True while a turn is open (started and not yet done/cancelled). */\n live: boolean;\n /** Most recent usage frame seen in the log, if any. */\n usage: VerseUsage | null;\n /** `items`, cut into turn segments. Absent on a hand-built transcript (treated as one segment). */\n segments?: TranscriptSegment[];\n}\n\n/** Wall time between two ISO stamps; null when either is unparseable. */\nfunction spanMs(from: string, to: string): number | null {\n const a = Date.parse(from);\n const b = Date.parse(to);\n return Number.isFinite(a) && Number.isFinite(b) ? Math.max(0, b - a) : null;\n}\n\ninterface PendingText {\n turnId: string;\n at: string;\n text: string;\n key: string;\n}\n\ninterface SegmentBuild {\n /** Items without the trailing streamed text, which depends on whether the WHOLE log is live. */\n items: TranscriptItem[];\n pending: PendingText | null;\n /** The last live-flag change in this segment: true (started), false (ended) or null (none). */\n liveEffect: boolean | null;\n usage: VerseUsage | null;\n /** tool-results in this segment whose tool-use is not in it. */\n orphanResults: string[];\n toolUseIds: string[];\n}\n\ninterface CachedSegment {\n firstSeq: number;\n lastSeq: number;\n count: number;\n build: SegmentBuild;\n /** The finished segment per trailing-streaming flag it was finalized with. */\n finalized: { streaming: boolean; segment: TranscriptSegment } | null;\n}\n\nexport interface TranscriptCache {\n segments: Map<string, CachedSegment>;\n}\n\nexport function createTranscriptCache(): TranscriptCache {\n return { segments: new Map() };\n}\n\nexport interface BuildTranscriptOptions {\n /** Reuse segments from a previous build of the same session's log. */\n cache?: TranscriptCache;\n /** Measured figures for reasoning blocks this tab watched stream, by the persisted event's seq. */\n thinkingStats?: ReadonlyMap<number, VerseThinkingStat>;\n}\n\n/**\n * The original single-pass derivation over `events[from, to)`. A whole log\n * run through it in one range is exactly the pre-3.10 buildTranscript; cut\n * at `user-message` boundaries (where it flushes anyway) the pieces\n * concatenate to the same items.\n */\nfunction buildSegment(\n events: readonly VerseEvent[],\n from: number,\n to: number,\n stats: ReadonlyMap<number, VerseThinkingStat> | undefined,\n): SegmentBuild {\n const items: TranscriptItem[] = [];\n const toolIndex = new Map<string, number>();\n const orphanResults: string[] = [];\n const toolUseIds: string[] = [];\n let pending: PendingText | null = null;\n let liveEffect: boolean | null = null;\n let usage: VerseUsage | null = null;\n\n const flushPending = () => {\n if (!pending) return;\n items.push({ kind: 'assistant', key: pending.key, turnId: pending.turnId, at: pending.at, text: pending.text, streaming: false });\n pending = null;\n };\n\n for (let i = from; i < to; i += 1) {\n const e = events[i]!;\n switch (e.type) {\n case 'user-message':\n flushPending();\n items.push({ kind: 'user', key: `u-${e.seq}`, turnId: e.turnId, at: e.at, text: e.text });\n break;\n case 'turn-started':\n liveEffect = true;\n break;\n case 'text-delta':\n if (pending && pending.turnId !== e.turnId) flushPending();\n if (!pending) pending = { turnId: e.turnId, at: e.at, text: '', key: `d-${e.seq}` };\n pending.text += e.text;\n break;\n case 'assistant-message':\n // The complete message supersedes whatever deltas streamed before it.\n pending = null;\n items.push({ kind: 'assistant', key: `a-${e.seq}`, turnId: e.turnId, at: e.at, text: e.text, streaming: false });\n break;\n case 'thinking': {\n flushPending();\n const measured = stats?.get(e.seq);\n items.push({\n kind: 'thinking',\n key: `t-${e.seq}`,\n turnId: e.turnId,\n at: e.at,\n text: e.text,\n redacted: e.redacted === true,\n durationMs: typeof e.durationMs === 'number' && Number.isFinite(e.durationMs) && e.durationMs >= 0\n ? e.durationMs\n : measured?.durationMs ?? null,\n estimatedTokens: measured?.estimatedTokens ?? null,\n thinkingKind: e.kind ?? null,\n });\n break;\n }\n case 'tool-use':\n flushPending();\n toolIndex.set(e.toolUseId, items.length);\n toolUseIds.push(e.toolUseId);\n items.push({\n kind: 'tool',\n key: `tu-${e.seq}`,\n turnId: e.turnId,\n at: e.at,\n toolUseId: e.toolUseId,\n name: e.name,\n input: e.input,\n result: null,\n durationMs: null,\n });\n break;\n case 'tool-result': {\n const idx = toolIndex.get(e.toolUseId);\n const existing = idx === undefined ? undefined : items[idx];\n if (existing && existing.kind === 'tool') {\n items[idx!] = { ...existing, result: { output: e.output, isError: e.isError }, durationMs: spanMs(existing.at, e.at) };\n } else {\n orphanResults.push(e.toolUseId);\n items.push({\n kind: 'tool',\n key: `tr-${e.seq}`,\n turnId: e.turnId,\n at: e.at,\n toolUseId: e.toolUseId,\n name: 'tool',\n input: null,\n result: { output: e.output, isError: e.isError },\n durationMs: null,\n });\n }\n break;\n }\n case 'usage':\n usage = e.usage;\n break;\n case 'compaction':\n // Deliberately NO flushPending: CLIs compact between model calls, and\n // flushing a streamed bubble here would leave it in the list when the\n // complete `assistant-message` arrives — the same reply twice.\n items.push({\n kind: 'compaction',\n key: `k-${e.seq}`,\n turnId: e.turnId,\n at: e.at,\n trigger: e.trigger,\n preTokens: e.preTokens,\n postTokens: e.postTokens,\n durationMs: e.durationMs,\n });\n break;\n case 'error':\n flushPending();\n items.push({ kind: 'error', key: `e-${e.seq}`, turnId: e.turnId, at: e.at, message: e.message, code: typeof e.code === 'string' && e.code ? e.code : null });\n break;\n case 'cancelled':\n flushPending();\n liveEffect = false;\n items.push({ kind: 'cancelled', key: `c-${e.seq}`, turnId: e.turnId, at: e.at });\n break;\n case 'turn-done':\n flushPending();\n liveEffect = false;\n items.push({ kind: 'turn-done', key: `td-${e.seq}`, turnId: e.turnId, at: e.at, ok: e.ok, durationMs: e.durationMs });\n break;\n case 'recovered':\n // Like compaction, no flush: recovery happens before the new native\n // session produces anything, never in the middle of a reply.\n items.push({ kind: 'recovered', key: `r-${e.seq}`, turnId: e.turnId, at: e.at, how: e.how, message: e.message });\n break;\n case 'history-truncated':\n items.push({ kind: 'truncated', key: `h-${e.seq}`, turnId: null, at: e.at, droppedBefore: e.droppedBefore });\n break;\n default:\n break;\n }\n }\n return { items, pending, liveEffect, usage, orphanResults, toolUseIds };\n}\n\nfunction finalizeSegment(key: string, build: SegmentBuild, streaming: boolean): TranscriptSegment {\n const p = build.pending;\n if (!p) return { key, items: build.items };\n return {\n key,\n items: [...build.items, { kind: 'assistant', key: p.key, turnId: p.turnId, at: p.at, text: p.text, streaming }],\n };\n}\n\n// `VerseEvent[]` (not readonly) is the published signature: callers type\n// their fixture arrays as `Parameters<typeof buildTranscript>[0]` and push.\nexport function buildTranscript(events: VerseEvent[], options: BuildTranscriptOptions = {}): Transcript {\n const { cache, thinkingStats: stats } = options;\n if (events.length === 0) return { items: [], live: false, usage: null, segments: [] };\n\n // Cut at every user-message: a new ask always opens a new turn, and the\n // derivation flushes its streamed text there, so nothing spans the cut.\n const starts: number[] = [0];\n for (let i = 1; i < events.length; i += 1) if (events[i]!.type === 'user-message') starts.push(i);\n\n const builds: Array<{ key: string; build: SegmentBuild; cached: CachedSegment | null }> = [];\n const seenKeys = new Set<string>();\n for (let s = 0; s < starts.length; s += 1) {\n const from = starts[s]!;\n const to = s + 1 < starts.length ? starts[s + 1]! : events.length;\n const firstSeq = events[from]!.seq;\n const lastSeq = events[to - 1]!.seq;\n const count = to - from;\n const key = `s-${firstSeq}`;\n seenKeys.add(key);\n const hit = cache?.segments.get(key);\n if (hit && hit.firstSeq === firstSeq && hit.lastSeq === lastSeq && hit.count === count) {\n builds.push({ key, build: hit.build, cached: hit });\n continue;\n }\n const build = buildSegment(events, from, to, stats);\n const entry: CachedSegment = { firstSeq, lastSeq, count, build, finalized: null };\n cache?.segments.set(key, entry);\n builds.push({ key, build, cached: entry });\n }\n if (cache) for (const key of [...cache.segments.keys()]) if (!seenKeys.has(key)) cache.segments.delete(key);\n\n // A tool-result whose tool-use sits in an EARLIER segment would have\n // updated that earlier card in the single-pass derivation. It never\n // happens in a real log (a result follows its call inside one turn); if it\n // does, derive the whole log in one pass rather than render it differently.\n if (builds.length > 1) {\n const earlier = new Set<string>();\n for (const b of builds) {\n if (b.build.orphanResults.some((id) => earlier.has(id))) return singlePass(events, stats);\n for (const id of b.build.toolUseIds) earlier.add(id);\n }\n }\n\n let live = false;\n let usage: VerseUsage | null = null;\n for (const b of builds) {\n if (b.build.liveEffect !== null) live = b.build.liveEffect;\n if (b.build.usage !== null) usage = b.build.usage;\n }\n\n const segments: TranscriptSegment[] = [];\n const items: TranscriptItem[] = [];\n for (let s = 0; s < builds.length; s += 1) {\n const b = builds[s]!;\n // Deltas still arriving for an open turn render as a streaming bubble;\n // every earlier segment's trailing text was flushed by the next ask.\n const streaming = s === builds.length - 1 ? live : false;\n let segment: TranscriptSegment;\n if (b.cached?.finalized && b.cached.finalized.streaming === streaming) {\n segment = b.cached.finalized.segment;\n } else {\n segment = finalizeSegment(b.key, b.build, streaming);\n if (b.cached) b.cached.finalized = { streaming, segment };\n }\n segments.push(segment);\n for (const item of segment.items) items.push(item);\n }\n return { items, live, usage, segments };\n}\n\nfunction singlePass(events: readonly VerseEvent[], stats: ReadonlyMap<number, VerseThinkingStat> | undefined): Transcript {\n const build = buildSegment(events, 0, events.length, stats);\n const live = build.liveEffect ?? false;\n const segment = finalizeSegment(`s-${events[0]!.seq}`, build, live);\n return { items: segment.items, live, usage: build.usage, segments: [segment] };\n}\n\n// ---------------------------------------------------------------------------\n// Render-time grouping\n// ---------------------------------------------------------------------------\n\nexport type ToolGroupMember = Extract<TranscriptItem, { kind: 'tool' | 'thinking' }>;\n\nexport interface ToolGroupItem {\n kind: 'toolGroup';\n key: string;\n turnId: string;\n at: string;\n items: ToolGroupMember[];\n /** Tool calls only (thinking blocks are not counted). */\n toolCount: number;\n /** \"Read ×6, Edit ×4\" — names in first-seen order. */\n summary: string;\n errorCount: number;\n /** A member is still waiting for its result. */\n pending: boolean;\n /** Wall time between the first and last member, when both have parseable timestamps. */\n spanMs: number | null;\n}\n\nexport type TranscriptRenderItem = TranscriptItem | ToolGroupItem;\n\n/**\n * Fold runs of consecutive tool calls from the same turn that hold two or\n * more calls into one `toolGroup`, so an agentic turn reads as \"N tool calls\"\n * with a single disclosure instead of a wall of cards. A single call (with\n * whatever reasoning surrounds it) stays as it is.\n * Pure over buildTranscript()'s output (the index-based tool-result pairing\n * there is untouched).\n *\n * Reasoning INTERLEAVED between tool calls folds with them (it explains the\n * next call). Reasoning that ENDS a run — the model's last thought before it\n * answers or before the next ask — is lifted out and rendered on its own, so\n * the part worth reading is never two disclosures deep. A run of reasoning\n * alone never folds.\n */\nexport function groupTranscriptItems(items: readonly TranscriptItem[]): TranscriptRenderItem[] {\n const out: TranscriptRenderItem[] = [];\n let run: ToolGroupMember[] = [];\n\n const flush = () => {\n if (run.length === 0) return;\n let end = run.length;\n while (end > 0 && run[end - 1]!.kind === 'thinking') end -= 1;\n const folded = run.slice(0, end);\n const trailing = run.slice(end);\n // Only a run with two or more CALLS is worth a disclosure: \"1 tool\" hiding\n // a single call plus the reasoning before it is a click for nothing.\n if (folded.filter((m) => m.kind === 'tool').length >= 2) out.push(makeToolGroup(folded));\n else for (const member of folded) out.push(member);\n for (const thought of trailing) out.push(thought);\n run = [];\n };\n\n for (const item of items) {\n if ((item.kind === 'tool' || item.kind === 'thinking') && (run.length === 0 || run[0]!.turnId === item.turnId)) {\n run.push(item);\n continue;\n }\n flush();\n if (item.kind === 'tool' || item.kind === 'thinking') run.push(item);\n else out.push(item);\n }\n flush();\n return out;\n}\n\nfunction makeToolGroup(members: ToolGroupMember[]): ToolGroupItem {\n const counts = new Map<string, number>();\n let errorCount = 0;\n let pending = false;\n for (const m of members) {\n if (m.kind !== 'tool') continue;\n counts.set(m.name, (counts.get(m.name) ?? 0) + 1);\n if (m.result === null) pending = true;\n else if (m.result.isError) errorCount += 1;\n }\n const toolCount = [...counts.values()].reduce((a, b) => a + b, 0);\n const summary = [...counts.entries()].map(([name, n]) => (n > 1 ? `${name} ×${n}` : name)).join(', ');\n const span = spanMs(members[0]!.at, members[members.length - 1]!.at);\n return {\n kind: 'toolGroup',\n key: `g-${members[0]!.key}`,\n turnId: members[0]!.turnId,\n at: members[0]!.at,\n items: members,\n toolCount,\n summary,\n errorCount,\n pending,\n spanMs: span,\n };\n}\n","/**\n * routes/verse/useVerseTranscript.ts — the React glue over the derived\n * transcript (verse-transcript.ts).\n *\n * Not in useVerseSession.ts because that module is on the chat first-paint\n * path (the Chat section opens the chat through it) while the transcript is\n * rendered only by lazy chunks (the workspace, the dock). Importing the\n * derivation from there would put it back in the first-paint critical JS.\n */\nimport { useSyncExternalStore } from 'react';\nimport { useSessionSubscription } from './useVerseSession.js';\nimport { getVerseTranscript, type Transcript } from './verse-transcript.js';\n\n/** The transcript of one chat, rebuilt only for the turn that changed. */\nexport function useVerseTranscript(sessionId: string | null): Transcript {\n const subscribe = useSessionSubscription(sessionId);\n return useSyncExternalStore(\n subscribe,\n () => getVerseTranscript(sessionId),\n () => getVerseTranscript(sessionId),\n );\n}\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{n as e}from"./index-BVxOlseC.js";import{O as t}from"./VerseConsoleApp-DTjDpGCd.js";import{_ as n,a as r,h as i,i as a}from"./icons-DEQa2rTx.js";var o=e(),s=n,c=i,l=a,u=r;function d(e){return(0,o.jsxs)(t,{...e,children:[(0,o.jsx)(`rect`,{x:`2.5`,y:`3`,width:`11`,height:`10`,rx:`1.5`}),(0,o.jsx)(`path`,{d:`M10 3v10`})]})}function f(e){return(0,o.jsxs)(t,{...e,children:[(0,o.jsx)(`rect`,{x:`2.5`,y:`3`,width:`11`,height:`10`,rx:`1.5`}),(0,o.jsx)(`path`,{d:`M6 3v10`})]})}function p(e){return(0,o.jsxs)(t,{width:`1em`,height:`1em`,style:{display:`inline-block`,verticalAlign:`-0.125em`},...e,children:[(0,o.jsx)(`path`,{d:`M13 3.5v5a2 2 0 0 1-2 2H3.5`}),(0,o.jsx)(`path`,{d:`M6 8 3.5 10.5 6 13`})]})}export{p as a,c as i,u as n,s as o,d as r,f as s,l as t};
2
+ //# sourceMappingURL=verse-icons-F9VwX07_.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verse-icons-F9VwX07_.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/verse-icons.tsx"],"sourcesContent":["/**\n * routes/verse/verse-icons.tsx — the icons the shell rail and the chat chrome\n * use, under the names the Verse surfaces already import.\n *\n * Owner A's `components/primitives/icons.tsx` is now the drawing authority:\n * one geometry (16px box, 1.5px stroke, round caps/joins, currentColor), one\n * stroke weight, one accessibility convention. Everything below that has an\n * equivalent there is an ALIAS of it, so the rail and the inbox cannot drift\n * to two different chat glyphs.\n *\n * 3.10 adds the workbench surfaces (Command, Fleet, Growth, Mind), the gear\n * tray and Apps. They are drawn here, not in the shared set, because they\n * name Verse surfaces — a console page borrowing \"Fleet\" would be a lie.\n *\n * Five icons stay drawn here because the shared set has no equivalent and\n * they are Verse-specific chrome, not general console vocabulary:\n * `PanelIcon` / `SidebarIcon` (the two pane toggles, which must read as\n * mirror images of each other), `RailToggleIcon` (the rail's own expand /\n * collapse control, which has to read as the same family as those two),\n * `VerseMark` (the brand mark in the rail head, which is 32px and never takes\n * a color state; drawn in rail-icons.tsx with the other rail glyphs) and `McpIcon` (a plug — the shared set has no connector\n * glyph, and every candidate in it already means another rail section).\n */\nimport {\n IconChevronDown,\n IconChevronRight,\n IconCpu,\n IconInbox,\n IconMoon,\n IconPlus,\n IconSearch,\n IconTrash,\n type IconProps,\n} from '../../components/primitives/icons.js';\nimport { Icon } from './rail-icons.js';\n\nexport type { IconProps };\n// The rail's icons (the section glyphs, the gear, the mark) live in\n// rail-icons.tsx so the shell's first paint does not pull this module and the\n// shared icon set in with them; re-exported so the names stay importable here.\nexport {\n AppsIcon,\n ChatIcon,\n CommandIcon,\n FleetIcon,\n GearIcon,\n GrowthIcon,\n MindIcon,\n NeedsYouIcon,\n SECTION_ICON,\n SettingsIcon,\n UsageIcon,\n VerseMark,\n} from './rail-icons.js';\n\n/**\n * Aliases onto the shared set. The names are the ones the Verse rail, sidebar\n * and composer already import — keeping them means this reconciliation\n * touched no call site.\n */\nexport const AutonomyIcon = IconCpu;\nexport const ApprovalsIcon = IconInbox;\nexport const SearchIcon = IconSearch;\nexport const PlusIcon = IconPlus;\nexport const TrashIcon = IconTrash;\nexport const ArrowDownIcon = IconChevronDown;\nexport const ChevronIcon = IconChevronRight;\n/** The rail's theme quick-toggle. One glyph for the control, not per-theme. */\nexport const ThemeIcon = IconMoon;\n\nexport function PanelIcon(props: IconProps) {\n return <Icon {...props}><rect x=\"2.5\" y=\"3\" width=\"11\" height=\"10\" rx=\"1.5\" /><path d=\"M10 3v10\" /></Icon>;\n}\n\nexport function SidebarIcon(props: IconProps) {\n return <Icon {...props}><rect x=\"2.5\" y=\"3\" width=\"11\" height=\"10\" rx=\"1.5\" /><path d=\"M6 3v10\" /></Icon>;\n}\n\n/**\n * The Return key (↩) as a key-legend glyph, 1em and inline so it sits in a\n * <kbd> like the letters around it. WHY drawn: of the fonts the console\n * serves, only the 230 KB full Plex face has U+21A9, so typing it into the\n * palette's or the drawer's key legend fetched that face each time one opened\n * (3.10 first-paint review; global.css scopes the full faces).\n */\nexport function ReturnKeyIcon(props: IconProps) {\n return (\n <Icon width=\"1em\" height=\"1em\" style={{ display: 'inline-block', verticalAlign: '-0.125em' }} {...props}>\n <path d=\"M13 3.5v5a2 2 0 0 1-2 2H3.5\" /><path d=\"M6 8 3.5 10.5 6 13\" />\n </Icon>\n );\n}\n\n/**\n * The rail's own expand/collapse control: the same framed panel as the two\n * pane toggles above, plus a chevron saying which way it is about to move.\n * ONE glyph that rotates rather than two drawings, so the control reads as a\n * single thing in two states — and so the state is carried by direction, the\n * one property a user can read without having memorised the other icon.\n */\nexport function RailToggleIcon({ expanded = false, ...props }: IconProps & { expanded?: boolean }) {\n return (\n <Icon {...props}>\n <rect x=\"2.5\" y=\"3\" width=\"11\" height=\"10\" rx=\"1.5\" />\n <path d=\"M6 3v10\" />\n {expanded ? <path d=\"M11.2 6.4 9.6 8l1.6 1.6\" /> : <path d=\"M9.4 6.4 11 8l-1.6 1.6\" />}\n </Icon>\n );\n}\n\n/**\n * MCP — a plug in a socket. Drawn here rather than aliased: the shared set's\n * nearest candidates (`IconCpu`, `IconSliders`, `IconKey`) are already the\n * Autonomy, Settings and credential glyphs, and two rail items that read as\n * the same picture is worse than one more 16px drawing.\n */\nexport function McpIcon(props: IconProps) {\n return (\n <Icon {...props}>\n <path d=\"M6 1.8v3.2M10 1.8v3.2\" />\n <path d=\"M3.8 5h8.4v2.6a4.2 4.2 0 0 1-4.2 4.2 4.2 4.2 0 0 1-4.2-4.2V5Z\" />\n <path d=\"M8 11.8v2.4\" />\n </Icon>\n );\n}\n"],"mappings":"iKA8Da,EAAa,EACb,EAAW,EAEX,EAAgB,EAChB,EAAc,EAI3B,SAAgB,EAAU,EAAkB,CAC1C,OAAO,EAAA,EAAA,KAAA,CAAC,EAAD,CAAM,GAAI,EAAV,SAAA,EAAiB,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,MAAM,EAAE,IAAI,MAAM,KAAK,OAAO,KAAK,GAAG,KAAO,CAAA,GAAC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,UAAY,CAAA,CAAO,GAC3G,CAEA,SAAgB,EAAY,EAAkB,CAC5C,OAAO,EAAA,EAAA,KAAA,CAAC,EAAD,CAAM,GAAI,EAAV,SAAA,EAAiB,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,MAAM,EAAE,IAAI,MAAM,KAAK,OAAO,KAAK,GAAG,KAAO,CAAA,GAAC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,SAAW,CAAA,CAAO,GAC1G,CASA,SAAgB,EAAc,EAAkB,CAC9C,OACE,EAAA,EAAA,KAAA,CAAC,EAAD,CAAM,MAAM,MAAM,OAAO,MAAM,MAAO,CAAE,QAAS,eAAgB,cAAe,UAAW,EAAG,GAAI,EAAlG,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,6BAA+B,CAAA,GAAC,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,oBAAsB,CAAA,CAClE,GAEV"}
@@ -0,0 +1,2 @@
1
+ import{o as e}from"./index-BVxOlseC.js";import{E as t}from"./VerseConsoleApp-DTjDpGCd.js";import{i as n,n as r,r as i,t as a}from"./compaction-point-VL9oegWS.js";var o=4e5,s=36e5,c={claude:25e3,codex:15e3,grok:2e4,local:15e3},l=25e3;function u(e){return e?c[e]??25e3:l}c.local+8e3+r+a;var d={"claude-opus-5.5":`claude-opus-5-5`};function f(e){return d[e]??e}function p(e,t){if(!e)return null;if(t===`expansive`)return e.expansive??null;let n=i(e.contextWindow);return n===null?null:{contextWindow:n,autoCompactAt:i(e.autoCompactAt??null)}}function m(e){let t=p(e,`standard`),n=p(e,`expansive`);return n?!t||(n.autoCompactAt??n.contextWindow)>(t.autoCompactAt??t.contextWindow):!1}function h(e,t){if(t===`expansive`)return null;let n=i(e?.contextWindow??null);return n!==null&&n>4e5&&m(e)?o:null}var ee=.8,g=.95;function _(e){let t=Math.max(0,Math.floor(e.contextTokens||0)),n=i(e.contextWindow),r=i(e.autoCompactAt??null),a=n===null?null:t/n,o=r===null?null:t/r,s=o??a,c=e.contextTokensExact!==!1,l=`unknown`;return!c&&s!==null&&s>=1?l=`unknown`:n!==null&&t>n?l=`over`:s!==null&&(l=s>=.95?`danger`:s>=.8?`warn`:`ok`),{tokens:t,window:n,autoCompactAt:r,ofWindow:a,ofCompaction:o,untilCompaction:r===null?null:Math.max(0,r-t),tone:l,exact:c}}function te(e){let t=e.inputTokens+e.cacheReadTokens+e.cacheCreationTokens;return t>0?e.cacheReadTokens/t:null}function v(e){return Math.ceil(Math.max(0,e)/4)}function y(e,t,n=l){let r=p(t,`standard`);if(!r)return null;let i=Math.max(0,e)+Math.max(0,n),a=r.autoCompactAt??r.contextWindow;if(i<=a*.6)return`fits`;if(i<=a)return`tight`;let o=p(t,`expansive`);return o&&i<=(o.autoCompactAt??o.contextWindow)?`expansive`:`split`}function b(e){return e>=1e6?`${(e/1e6).toFixed(e%1e6==0?0:1)}M`:e>=1e3?`${Math.round(e/1e3)}k`:String(e)}function x(e){let t=_(e.usage),n=[],r=`none`,i=e=>{(e===`urge`||e===`suggest`&&r===`none`)&&(r=e)};t.exact&&(t.tone===`over`?(i(`urge`),n.push(`Context (${b(t.tokens)}) is past the ${b(t.window??0)} window.`)):t.ofCompaction!==null&&t.ofCompaction>=.8&&(i(`suggest`),n.push(`About ${b(t.untilCompaction??0)} tokens left before the CLI auto-compacts.`)));let a=e.compactionCount??0;if(a>=2&&(i(`suggest`),n.push(`Compacted ${a} times — early turns now survive only as summaries.`)),e.lastActivityAt){let r=e.now-Date.parse(e.lastActivityAt);t.exact&&Number.isFinite(r)&&r>=36e5&&t.tokens>=1e5&&(i(`suggest`),n.push(`Idle over an hour: the prompt cache has likely expired, so the next turn re-reads ~${b(t.tokens)} tokens at full cost.`))}return{level:r,reasons:n}}function S(e){if((e.session.contextMode??`standard`)!==`standard`||!m(e.option))return{suggest:!1,reason:null};let t=e.session.compactionCount??0;return t>=2?{suggest:!0,reason:`This session has compacted ${t} times; expansive mode keeps more of it in view.`}:typeof e.workingSetTokens==`number`&&y(e.workingSetTokens,e.option)===`expansive`?{suggest:!0,reason:`The reachable code (~${b(e.workingSetTokens)} tokens) only fits the expansive budget.`}:{suggest:!1,reason:null}}function C(e){return e===`claude`||e===`codex`}var w=e({CODEX_EXPANSIVE_METERING_NOTE:()=>L,ENGINE_LABEL:()=>E,ENGINE_ORDER:()=>T,SEAT_CAPACITY_WORD:()=>B,WINDOW_SOURCE_TEXT:()=>F,firstRunnableModel:()=>R,formatDuration:()=>q,formatElapsed:()=>K,formatRelative:()=>J,groupSeats:()=>W,groupSessions:()=>G,isAbsolutePath:()=>Q,isVerseEngine:()=>D,modelLabel:()=>j,modelOptionFor:()=>M,prettyJson:()=>Z,projectName:()=>O,seatById:()=>k,seatCapacity:()=>U,seatLabel:()=>A,seatPillLabel:()=>$,seatUnavailableReason:()=>z,seatWindowLabel:()=>H,sessionContextBudget:()=>P,summarizeToolInput:()=>Y,truncate:()=>X,windowSourceText:()=>I}),T=[`claude`,`codex`,`grok`,`local`],E={claude:`Claude`,codex:`Codex`,grok:`Grok`,local:`Local`};function D(e){return T.includes(e)}function O(e,t=[]){let n=t.find(t=>t.path===e);return n?n.name:e.split(/[\\/]/).filter(Boolean).at(-1)??e}function k(e,t){return e.find(e=>e.id===t)}function A(e,t){return k(e,t.seatId)?.label??E[t.engine]}function j(e,t){return k(e,t.seatId)?.models.find(e=>e.id===t.model)?.label??t.model}function M(e,t){let n=k(e,t.seatId);if(!n)return null;let r=n.models.find(e=>e.id===t.model);if(r)return r;let i=f(t.model);return n.models.find(e=>f(e.id)===i)??null}function N(e){return typeof e==`number`&&Number.isFinite(e)&&e>0?e:null}function P(e,t){let r=t.usage,i=t.contextMode??`standard`,a=M(e,t),o={contextTokens:typeof r.contextTokens==`number`&&Number.isFinite(r.contextTokens)?Math.max(0,r.contextTokens):0,exact:r.contextTokensExact!==!1,mode:i,option:a},s=p(a,i),c=N(r.contextWindow);if(c!==null&&(t.engine===`local`||r.contextWindowSource===`runtime`)){let e=N(r.autoCompactAt??null)??n({engine:t.engine,runtimeWindow:c,budget:t.engine===`local`?null:s,autocompactWindow:t.engine===`claude`?h(a,i):null,maxOutputTokens:a?.maxOutputTokens??null}),l=t.engine===`local`?r.contextWindowSource??null:`runtime`;return{...o,contextWindow:c,autoCompactAt:e,source:l}}if(s)return{...o,contextWindow:s.contextWindow,autoCompactAt:s.autoCompactAt,source:a?.windowSource??`fallback`};if(c!==null)return{...o,contextWindow:c,autoCompactAt:N(r.autoCompactAt??null),source:r.contextWindowSource??null};let l=N(k(e,t.seatId)?.contextWindow??null);return{...o,contextWindow:l,autoCompactAt:null,source:l===null?null:`fallback`}}var F={runtime:`reported by the CLI on the last turn`,"provider-catalog":`from this seat's own model catalog`,"cli-catalog":`from the pinned CLI's built-in model table`,documented:`from the provider's published model table`,fallback:`a default estimate — the CLI has not reported the real window yet`};function I(e,t){return t===`local`?`${e===`runtime`?`measured from the local model server`:e===`fallback`?`a default estimate — the model server did not report one`:F[e]}; Verse passes this window to Claude Code for this chat`:F[e]}var L=`OpenAI reportedly also counts requests above 272k tokens at about 2× against plan limits, so a turn near the expansive limit may cost roughly twice that.`;function R(e){return e.models.find(e=>!e.unavailableReason)??null}function z(e){return e.health.state===`unavailable`?e.health.summary??`seat unavailable`:null}var B={ready:`usable`,tight:`tight`,blocked:`blocked`,unread:`no reading`},V=85;function H(e){let t={five_hour:`5-hour window`,seven_day:`weekly window`,codex:`weekly window`};if(t[e])return t[e];let n=/^seven_day_(.+)$/.exec(e);return n?`weekly ${n[1].replace(/_/g,` `)} window`:`${e.replace(/_/g,` `)} window`}function U(e){let n=z(e);if(n!==null)return{cls:`blocked`,usedPercent:null,text:n};let r=e.health.windows.filter(e=>typeof e.usedPercent==`number`&&Number.isFinite(e.usedPercent));if(r.length===0)return{cls:`unread`,usedPercent:null,text:`no capacity reading`};let i=r.reduce((e,t)=>t.usedPercent>e.usedPercent?t:e),a=Math.max(0,Math.min(100,i.usedPercent)),o=H(i.id);return a>=100?{cls:`blocked`,usedPercent:null,text:`${o} limit reached`}:{cls:a>=V?`tight`:`ready`,usedPercent:a,text:`${t(a)} of ${o} used`}}function W(e){return T.map(t=>({engine:t,seats:e.filter(e=>e.engine===t)})).filter(e=>e.seats.length>0)}function G(e,t,n=``){let r=n.trim().toLowerCase(),i=r?e.filter(e=>e.title.toLowerCase().includes(r)||e.projectPath.toLowerCase().includes(r)||e.model.toLowerCase().includes(r)||e.seatId.toLowerCase().includes(r)):[...e],a=new Map;for(let e of i){let t=a.get(e.projectPath)??[];t.push(e),a.set(e.projectPath,t)}let o=[];for(let[e,n]of a)n.sort((e,t)=>t.updatedAt.localeCompare(e.updatedAt)),o.push({projectPath:e,name:O(e,t),enrolled:t.find(t=>t.path===e)?.enrolled??!1,sessions:n});return o.sort((e,t)=>t.sessions[0].updatedAt.localeCompare(e.sessions[0].updatedAt)),o}function K(e){if(!Number.isFinite(e)||e<0)return`0s`;let t=Math.floor(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60);return n<60?`${n}m ${t%60}s`:`${Math.floor(n/60)}h ${n%60}m`}function q(e){return!Number.isFinite(e)||e<0?`—`:e<1e3?`${Math.round(e)}ms`:e<6e4?`${(e/1e3).toFixed(1)}s`:K(e)}function J(e,t=Date.now()){let n=Date.parse(e);if(!Number.isFinite(n))return``;let r=Math.round((t-n)/1e3);if(r<0||r<60)return`now`;let i=Math.floor(r/60);if(i<60)return`${i}m`;let a=Math.floor(i/60);if(a<24)return`${a}h`;let o=Math.floor(a/24);return o<7?`${o}d`:new Date(n).toLocaleDateString([],{month:`short`,day:`numeric`})}function Y(e){if(e==null)return``;if(typeof e==`string`)return X(e,96);if(typeof e!=`object`)return X(String(e),96);let t=e;for(let e of[`command`,`cmd`,`file_path`,`path`,`pattern`,`query`,`url`,`description`,`prompt`,`text`]){let n=t[e];if(typeof n==`string`&&n.trim())return X(n.trim().replace(/\s+/g,` `),96)}let n=Object.keys(t);if(n.length===0)return``;let r=t[n[0]],i=typeof r==`string`?r:JSON.stringify(r);return X(`${n[0]}: ${i??``}`.replace(/\s+/g,` `),96)}function X(e,t){return e.length>t?`${e.slice(0,t-1)}…`:e}function Z(e){if(typeof e==`string`)return e;try{return JSON.stringify(e,null,2)??``}catch{return String(e)}}function Q(e){return/^(?:\/|~(?:\/|$)|[a-zA-Z]:[\\/]|\\\\)/.test(e)&&![...e].some(e=>e.charCodeAt(0)<32||e.charCodeAt(0)>=127&&e.charCodeAt(0)<=159)}function $(e,t){let n=A(e,t),r=j(e,t);return!r||n.toLowerCase().includes(r.toLowerCase())?n:`${n} · ${r}`}export{te as A,Y as C,g as D,s as E,y as F,x as I,m as L,C as M,v as N,ee as O,S as P,_ as R,P as S,I as T,k as _,R as a,z as b,J as c,Q as d,D as f,O as g,Z as h,F as i,f as j,p as k,W as l,M as m,E as n,q as o,j as p,B as r,K as s,L as t,G as u,U as v,w,H as x,$ as y,u as z};
2
+ //# sourceMappingURL=verse-model-DyCwZF-M.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verse-model-DyCwZF-M.js","names":[],"sources":["../../../../../../src/core/verse/context-math.ts","../../../../../../src/web-ui/routes/verse/verse-model.ts"],"sourcesContent":["/**\n * Ashlr Verse — context arithmetic shared by the server and the browser.\n *\n * PURE and BROWSER-SAFE: no node imports, no I/O. The seat catalog, the\n * session engine, the adapters and the UI all compute thresholds through this\n * one module, so \"compacts at 367k\" can never mean two different numbers in\n * two places. docs/VERSE-CONTEXT.md is the prose authority for every constant.\n *\n * Where each formula comes from (all read from the CLIs themselves, 2026-09-23):\n *\n * Claude Code (2.1.257 and 2.1.280 binaries): the auto-compaction window is\n * `min(--autocompact | autoCompactWindow | auto, model window)`. From it the\n * CLI reserves `min(max output, 20_000)` for the reply and compacts a\n * further 13_000 below that. On a 1M model at `auto` that is 967_000 — the\n * `pre_tokens` observed on real compactions (967_391).\n * Codex (0.136 – 0.155 rollouts): the window the CLI measures against is\n * `context_window × effective_context_window_percent / 100` = 258_400 for\n * every 272k model; auto-compaction triggers at 90% of the RAW window\n * (244_800). The largest uncompacted call across 62,104 was 243_204.\n * Grok (0.2.118 catalog): compacts at `auto_compact_threshold_percent` (80)\n * of `context_window` (500_000) = 400_000.\n * Local seats run the Claude Code binary against Ollama, so they compact by\n * the Claude formula over the window Verse passes in\n * `CLAUDE_CODE_MAX_CONTEXT_TOKENS`.\n */\n\nimport type {\n VerseContextBudget,\n VerseContextMode,\n VerseEngine,\n VerseFitVerdict,\n VerseModelOption,\n VerseSession,\n VerseUsage,\n} from './types.js';\nimport {\n CLAUDE_COMPACT_BUFFER,\n CLAUDE_OUTPUT_RESERVE_CAP,\n CODEX_EFFECTIVE_WINDOW_PERCENT,\n positiveInt,\n} from './compaction-point.js';\n\n// The runtime compaction-point formulas live in compaction-point.ts (the\n// browser's chat first-paint path needs them without the rest of this\n// module); re-exported so every existing importer keeps one entry point.\nexport {\n CLAUDE_COMPACT_BUFFER,\n CLAUDE_OUTPUT_RESERVE_CAP,\n CODEX_AUTO_COMPACT_FRACTION,\n CODEX_EFFECTIVE_WINDOW_PERCENT,\n claudeAutoCompactAt,\n codexAutoCompactAt,\n reconcileAutoCompactAt,\n} from './compaction-point.js';\n\n// ---------------------------------------------------------------------------\n// Constants\n// ---------------------------------------------------------------------------\n\n/**\n * Standard-mode compaction window for 1M-context Claude models.\n *\n * WHY 400k and not the CLI's ~967k: every turn re-sends the whole prefix, so a\n * session held near 900k costs ~2.3× per call what one held under 400k does,\n * and long-context recall degrades with length on every published benchmark\n * (docs/VERSE-CONTEXT.md §2). 400k keeps a large working set — far above the\n * 150k Anthropic's own API compacts at by default — while leaving the full\n * window one click away in `expansive` mode. Grok's native budget is also\n * 400k, so the two frontier engines share one standard ceiling.\n */\nexport const CLAUDE_STANDARD_AUTOCOMPACT_WINDOW = 400_000;\n\n/** Claude Code clamps `--autocompact` to [100k, 1M]. */\nexport const CLAUDE_AUTOCOMPACT_MIN = 100_000;\nexport const CLAUDE_AUTOCOMPACT_MAX = 1_000_000;\n\n/** Grok: `auto_compact_threshold_percent` in the 0.2.118 catalog. */\nexport const GROK_AUTO_COMPACT_PERCENT = 80;\n\n/**\n * How long a provider keeps a conversation's prompt cache warm while idle.\n * Claude Code on a subscription: 1h (5 min without it). Past this, the next\n * turn re-reads the whole context at full price — the single most expensive\n * thing an idle long session can do.\n */\nexport const CACHE_IDLE_TTL_MS = 60 * 60 * 1000;\n\n/**\n * Fixed prompt overhead (system prompt + tool definitions) a FRESH session\n * already occupies before any work, per engine.\n *\n * local 15k — measured: two real turns through Claude Code 2.1.280 against\n * Ollama with `--exclude-dynamic-system-prompt-sections`\n * reported 14,695 and 14,942 context tokens for a one-word reply.\n * claude 25k — the same CLI without that flag measured 17.8k–23.3k on local\n * seats; rounded up. An ESTIMATE, never shown as a measurement.\n * codex 15k / grok 20k — estimates; neither CLI reports its base prompt.\n *\n * Only used by the fit verdicts, which are labelled as estimates in the UI.\n */\nexport const SESSION_BASE_OVERHEAD_BY_ENGINE: Readonly<Record<VerseEngine, number>> = {\n claude: 25_000,\n codex: 15_000,\n grok: 20_000,\n local: 15_000,\n};\n\n/** Fallback overhead when the engine is unknown (the largest estimate). */\nexport const SESSION_BASE_OVERHEAD_TOKENS = 25_000;\n\nexport function sessionOverheadTokens(engine: VerseEngine | null | undefined): number {\n return engine ? SESSION_BASE_OVERHEAD_BY_ENGINE[engine] ?? SESSION_BASE_OVERHEAD_TOKENS : SESSION_BASE_OVERHEAD_TOKENS;\n}\n\n/**\n * Smallest local window worth offering as a seat. Local turns run Claude Code\n * with `CLAUDE_CODE_MAX_CONTEXT_TOKENS=<window>`, which compacts at\n * `window − 20k − 13k`; below this the compaction point leaves under 8k of\n * working room above the ~15k base prompt, so every turn would compact.\n */\nexport const LOCAL_MIN_WORKING_TOKENS = 8_000;\nexport const LOCAL_MIN_USABLE_WINDOW =\n SESSION_BASE_OVERHEAD_BY_ENGINE.local + LOCAL_MIN_WORKING_TOKENS + CLAUDE_OUTPUT_RESERVE_CAP + CLAUDE_COMPACT_BUFFER;\n\n/** True when a local window leaves real working room under Claude Code's compaction rule. */\nexport function localWindowUsable(window: number | null | undefined): boolean {\n return typeof window === 'number' && Number.isFinite(window) && window >= LOCAL_MIN_USABLE_WINDOW;\n}\n\n/** chars → tokens estimator used everywhere a count is estimated rather than measured. */\nexport const CHARS_PER_TOKEN = 4;\n\n// ---------------------------------------------------------------------------\n// Per-engine formulas\n// ---------------------------------------------------------------------------\n\n/** Codex: the window the CLI measures occupancy against. */\nexport function codexEffectiveWindow(rawWindow: number, percent: number | null = null): number {\n const pct = positiveInt(percent) !== null && (percent as number) <= 100 ? (percent as number) : CODEX_EFFECTIVE_WINDOW_PERCENT;\n return Math.floor((rawWindow * pct) / 100);\n}\n\n/** Grok: where auto-compaction fires. */\nexport function grokAutoCompactAt(window: number, percent: number | null = null): number {\n const pct = positiveInt(percent) !== null && (percent as number) <= 100 ? (percent as number) : GROK_AUTO_COMPACT_PERCENT;\n return Math.floor((window * pct) / 100);\n}\n\n// ---------------------------------------------------------------------------\n// Model ids\n// ---------------------------------------------------------------------------\n\n/**\n * Ids Verse once shipped that the CLI does NOT resolve to the model the label\n * promised. `claude-opus-5.5` is parsed by Claude Code as a fuzzy match for\n * `claude-opus-5` (its normaliser rejects the `.5` suffix and falls back to\n * `includes('claude-opus-5')`), so every \"Opus 5.5\" turn actually ran Opus 5.\n * Old session records keep their stored id; adapters send the canonical one.\n */\nexport const VERSE_MODEL_ID_ALIASES: Readonly<Record<string, string>> = {\n 'claude-opus-5.5': 'claude-opus-5-5',\n};\n\nexport function canonicalModelId(id: string): string {\n return VERSE_MODEL_ID_ALIASES[id] ?? id;\n}\n\n// ---------------------------------------------------------------------------\n// Budgets and occupancy\n// ---------------------------------------------------------------------------\n\n/** The budget a model runs with in a mode, or null when that mode does not exist for it. */\nexport function budgetFor(option: VerseModelOption | null | undefined, mode: VerseContextMode): VerseContextBudget | null {\n if (!option) return null;\n if (mode === 'expansive') return option.expansive ?? null;\n const window = positiveInt(option.contextWindow);\n if (window === null) return null;\n return { contextWindow: window, autoCompactAt: positiveInt(option.autoCompactAt ?? null) };\n}\n\n/** True when this model has a genuine expansive budget larger than its standard one. */\nexport function hasExpansiveMode(option: VerseModelOption | null | undefined): boolean {\n const standard = budgetFor(option, 'standard');\n const expansive = budgetFor(option, 'expansive');\n if (!expansive) return false;\n if (!standard) return true;\n return (expansive.autoCompactAt ?? expansive.contextWindow) > (standard.autoCompactAt ?? standard.contextWindow);\n}\n\n/**\n * The `--autocompact` value Verse passes to Claude Code for a model in a mode,\n * or null for \"let the CLI use `auto`\". Only 1M-native models are capped in\n * standard mode; a 200k model already compacts near 167k natively.\n */\nexport function claudeAutocompactFlag(option: VerseModelOption | null | undefined, mode: VerseContextMode): number | null {\n if (mode === 'expansive') return null;\n const window = positiveInt(option?.contextWindow ?? null);\n return window !== null && window > CLAUDE_STANDARD_AUTOCOMPACT_WINDOW && hasExpansiveMode(option)\n ? CLAUDE_STANDARD_AUTOCOMPACT_WINDOW\n : null;\n}\n\nexport type VerseOccupancyTone = 'unknown' | 'ok' | 'warn' | 'danger' | 'over';\n\nexport interface VerseOccupancy {\n tokens: number;\n window: number | null;\n autoCompactAt: number | null;\n /** tokens / window, unclamped; null when the window is unknown. */\n ofWindow: number | null;\n /** tokens / autoCompactAt, unclamped; null when the compaction point is unknown. */\n ofCompaction: number | null;\n /** Tokens left before auto-compaction (≥ 0), null when unknown. */\n untilCompaction: number | null;\n tone: VerseOccupancyTone;\n /** False when `tokens` is an upper bound (codex before its rollout is readable). */\n exact: boolean;\n}\n\n/** Warn at 80% of the compaction point, danger from 95% — BEFORE the CLI compacts, not after. */\nexport const OCCUPANCY_WARN = 0.8;\nexport const OCCUPANCY_DANGER = 0.95;\n\nexport function occupancy(usage: Pick<VerseUsage, 'contextTokens' | 'contextWindow' | 'autoCompactAt' | 'contextTokensExact'>): VerseOccupancy {\n const tokens = Math.max(0, Math.floor(usage.contextTokens || 0));\n const window = positiveInt(usage.contextWindow);\n const compactAt = positiveInt(usage.autoCompactAt ?? null);\n const ofWindow = window !== null ? tokens / window : null;\n const ofCompaction = compactAt !== null ? tokens / compactAt : null;\n const gauge = ofCompaction ?? ofWindow;\n const exact = usage.contextTokensExact !== false;\n let tone: VerseOccupancyTone = 'unknown';\n if (!exact && gauge !== null && gauge >= 1) {\n // An UPPER BOUND past the compaction point says nothing about the real\n // prompt: codex's turn total sums every model call (median 29× the last\n // one). Claiming \"over the window\" from it would be invented precision.\n tone = 'unknown';\n } else if (window !== null && tokens > window) tone = 'over';\n else if (gauge !== null) tone = gauge >= OCCUPANCY_DANGER ? 'danger' : gauge >= OCCUPANCY_WARN ? 'warn' : 'ok';\n return {\n tokens,\n window,\n autoCompactAt: compactAt,\n ofWindow,\n ofCompaction,\n untilCompaction: compactAt !== null ? Math.max(0, compactAt - tokens) : null,\n tone,\n exact,\n };\n}\n\n// ---------------------------------------------------------------------------\n// Efficiency\n// ---------------------------------------------------------------------------\n\n/**\n * Share of prompt tokens served from cache: cacheRead / (input + cacheRead +\n * cacheCreation). Adapters already report `inputTokens` EXCLUDING cached\n * tokens (codex's turn total is split by its adapter), so the buckets are\n * disjoint. Null when nothing has been read yet.\n */\nexport function cacheHitRatio(usage: Pick<VerseUsage, 'inputTokens' | 'cacheReadTokens' | 'cacheCreationTokens'>): number | null {\n const denominator = usage.inputTokens + usage.cacheReadTokens + usage.cacheCreationTokens;\n return denominator > 0 ? usage.cacheReadTokens / denominator : null;\n}\n\nexport function estimateTokensFromChars(chars: number): number {\n return Math.ceil(Math.max(0, chars) / CHARS_PER_TOKEN);\n}\n\n// ---------------------------------------------------------------------------\n// Advice (pure; the UI decides how to show it, nothing here spends)\n// ---------------------------------------------------------------------------\n\n/**\n * Would this working set fit one context on this model?\n *\n * fits — working set + fixed overhead ≤ 60% of the standard compaction point\n * tight — ≤ 100% of it: it fits, but the session will compact soon\n * expansive — only the expansive budget holds it\n * split — no single context holds it; fan the work out instead\n *\n * Null when the model's budget is unknown (never guessed). Pass the engine's\n * `sessionOverheadTokens(engine)`; the default is the largest estimate.\n */\nexport function fitVerdict(\n workingSetTokens: number,\n option: VerseModelOption | null | undefined,\n overheadTokens: number = SESSION_BASE_OVERHEAD_TOKENS,\n): VerseFitVerdict | null {\n const standard = budgetFor(option, 'standard');\n if (!standard) return null;\n const need = Math.max(0, workingSetTokens) + Math.max(0, overheadTokens);\n const standardCap = standard.autoCompactAt ?? standard.contextWindow;\n if (need <= standardCap * 0.6) return 'fits';\n if (need <= standardCap) return 'tight';\n const expansive = budgetFor(option, 'expansive');\n if (expansive && need <= (expansive.autoCompactAt ?? expansive.contextWindow)) return 'expansive';\n return 'split';\n}\n\nexport type VerseAdviceLevel = 'none' | 'suggest' | 'urge';\n\nexport interface VerseHandoffAdvice {\n level: VerseAdviceLevel;\n /** Plain sentences, most important first. Empty when level is 'none'. */\n reasons: string[];\n}\n\n/** Compactions after which early-turn detail is mostly summaries. */\nexport const HANDOFF_COMPACTION_THRESHOLD = 2;\n/** Below this, an expired cache is cheap to re-read and not worth a handoff. */\nexport const HANDOFF_IDLE_MIN_TOKENS = 100_000;\n\nfunction compactTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(n % 1_000_000 === 0 ? 0 : 1)}M`;\n if (n >= 1_000) return `${Math.round(n / 1_000)}k`;\n return String(n);\n}\n\n/**\n * Should the operator continue in a fresh session? Pure: `now` and\n * `lastActivityAt` are passed in, so the verdict is reproducible in tests.\n */\nexport function handoffAdvice(input: {\n usage: VerseUsage;\n compactionCount?: number;\n lastActivityAt?: string | null;\n now: number;\n}): VerseHandoffAdvice {\n const occ = occupancy(input.usage);\n const reasons: string[] = [];\n let level: VerseAdviceLevel = 'none';\n const bump = (to: VerseAdviceLevel): void => {\n // (level only ever rises)\n if (to === 'urge' || (to === 'suggest' && level === 'none')) level = to;\n };\n\n if (!occ.exact) {\n // An upper bound cannot justify \"you are near compaction\"; wait for a reading.\n } else if (occ.tone === 'over') {\n bump('urge');\n reasons.push(`Context (${compactTokens(occ.tokens)}) is past the ${compactTokens(occ.window ?? 0)} window.`);\n } else if (occ.ofCompaction !== null && occ.ofCompaction >= OCCUPANCY_WARN) {\n bump('suggest');\n reasons.push(`About ${compactTokens(occ.untilCompaction ?? 0)} tokens left before the CLI auto-compacts.`);\n }\n\n const compactions = input.compactionCount ?? 0;\n if (compactions >= HANDOFF_COMPACTION_THRESHOLD) {\n bump('suggest');\n reasons.push(`Compacted ${compactions} times — early turns now survive only as summaries.`);\n }\n\n if (input.lastActivityAt) {\n const idle = input.now - Date.parse(input.lastActivityAt);\n if (occ.exact && Number.isFinite(idle) && idle >= CACHE_IDLE_TTL_MS && occ.tokens >= HANDOFF_IDLE_MIN_TOKENS) {\n bump('suggest');\n reasons.push(`Idle over an hour: the prompt cache has likely expired, so the next turn re-reads ~${compactTokens(occ.tokens)} tokens at full cost.`);\n }\n }\n return { level, reasons };\n}\n\nexport interface VerseExpansiveAdvice {\n suggest: boolean;\n reason: string | null;\n}\n\n/**\n * Suggest — never switch on — expansive mode. Only for a session in standard\n * mode whose model has a real expansive budget, and only on evidence: it has\n * already compacted repeatedly, or its working set only fits expansive.\n */\nexport function expansiveAdvice(input: {\n session: Pick<VerseSession, 'contextMode' | 'compactionCount'>;\n option: VerseModelOption | null | undefined;\n workingSetTokens?: number | null;\n}): VerseExpansiveAdvice {\n if ((input.session.contextMode ?? 'standard') !== 'standard' || !hasExpansiveMode(input.option)) {\n return { suggest: false, reason: null };\n }\n const compactions = input.session.compactionCount ?? 0;\n if (compactions >= HANDOFF_COMPACTION_THRESHOLD) {\n return { suggest: true, reason: `This session has compacted ${compactions} times; expansive mode keeps more of it in view.` };\n }\n if (typeof input.workingSetTokens === 'number' && fitVerdict(input.workingSetTokens, input.option) === 'expansive') {\n return { suggest: true, reason: `The reachable code (~${compactTokens(input.workingSetTokens)} tokens) only fits the expansive budget.` };\n }\n return { suggest: false, reason: null };\n}\n\n/** Engines whose CLIs can be told a compaction budget per invocation. */\nexport function engineSupportsModes(engine: VerseEngine): boolean {\n return engine === 'claude' || engine === 'codex';\n}\n","/**\n * routes/verse/verse-model.ts — small pure helpers shared by the Verse\n * components (labels, grouping, health → tone). No React, no I/O.\n */\nimport type { VerseEngine, VerseModelOption, VerseProject, VerseSeat, VerseSeatHealth, VerseSession } from '../../data/api-types.js';\nimport type { VerseContextMode, VerseWindowSource } from '../../../core/verse/types.js';\nimport type { Tone } from '../../components/primitives/StatusBadge.js';\n// context-math is PURE and browser-safe by contract (its only import is\n// type-only), so a value import here does not drag node into the bundle.\nimport { budgetFor, canonicalModelId, claudeAutocompactFlag, reconcileAutoCompactAt } from '../../../core/verse/context-math.js';\nimport { usedPercentText } from './percent-text.js';\n\nexport const ENGINE_ORDER: readonly VerseEngine[] = ['claude', 'codex', 'grok', 'local'];\n\nexport const ENGINE_LABEL: Record<VerseEngine, string> = {\n claude: 'Claude',\n codex: 'Codex',\n grok: 'Grok',\n local: 'Local',\n};\n\nexport function isVerseEngine(value: string): value is VerseEngine {\n return (ENGINE_ORDER as readonly string[]).includes(value);\n}\n\nexport function projectName(path: string, projects: readonly VerseProject[] = []): string {\n const known = projects.find((p) => p.path === path);\n if (known) return known.name;\n return path.split(/[\\\\/]/).filter(Boolean).at(-1) ?? path;\n}\n\nexport function seatById(seats: readonly VerseSeat[], seatId: string): VerseSeat | undefined {\n return seats.find((s) => s.id === seatId);\n}\n\nexport function seatLabel(seats: readonly VerseSeat[], session: Pick<VerseSession, 'seatId' | 'engine'>): string {\n return seatById(seats, session.seatId)?.label ?? ENGINE_LABEL[session.engine];\n}\n\nexport function modelLabel(seats: readonly VerseSeat[], session: Pick<VerseSession, 'seatId' | 'model'>): string {\n const seat = seatById(seats, session.seatId);\n return seat?.models.find((m) => m.id === session.model)?.label ?? session.model;\n}\n\n/**\n * The seat's catalog entry for a session's model. Exact id first; then the\n * canonical form, because a session created before the alias fix stores\n * `claude-opus-5.5` while today's catalog lists `claude-opus-5-5` (context-math\n * `VERSE_MODEL_ID_ALIASES`) — the record keeps its id, the lookup must not miss.\n */\nexport function modelOptionFor(seats: readonly VerseSeat[], session: Pick<VerseSession, 'seatId' | 'model'>): VerseModelOption | null {\n const seat = seatById(seats, session.seatId);\n if (!seat) return null;\n const exact = seat.models.find((m) => m.id === session.model);\n if (exact) return exact;\n const canonical = canonicalModelId(session.model);\n return seat.models.find((m) => canonicalModelId(m.id) === canonical) ?? null;\n}\n\n/** Everything the meter, the composer's cost hint and the advice banners read. */\nexport interface SessionContextBudget {\n /** Live occupancy as stored — UNCLAMPED; only the drawing clamps. */\n contextTokens: number;\n contextWindow: number | null;\n autoCompactAt: number | null;\n /** False when `contextTokens` is an upper bound (codex before its rollout is read). */\n exact: boolean;\n /** Where `contextWindow` came from; null when nothing on the record says. */\n source: VerseWindowSource | null;\n mode: VerseContextMode;\n /** The catalog option the session's model maps to on its seat, when listed. */\n option: VerseModelOption | null;\n}\n\nfunction positive(value: number | null | undefined): number | null {\n return typeof value === 'number' && Number.isFinite(value) && value > 0 ? value : null;\n}\n\n/**\n * The window a session is measured against, and where it compacts.\n *\n * Precedence (docs/VERSE-CONTEXT.md, \"honesty rules\"):\n *\n * 0. LOCAL — the window STORED on the record, whatever its source. Verse\n * SETS a local seat's window: the claude adapter passes the stored\n * `usage.contextWindow` as `CLAUDE_CODE_MAX_CONTEXT_TOKENS`, and the\n * engine refreshes that stored value from live discovery before each\n * turn. The seat's CURRENT option can differ (another dispatch lane,\n * another resident num_ctx), and drawing it measured the chat against a\n * window the CLI was never told — \"past the 66k window\" for a chat the\n * CLI compacts at 229k. The meter and the CLI must quote one number.\n * 1. RUNTIME — the CLI reported the window for this session's last turn\n * (`usage.contextWindowSource === 'runtime'`). Nothing outranks what the\n * CLI said it is actually running with (e.g. Claude Code clamping a 1M\n * model to 200k when long-context credit runs out).\n * 2. CATALOG — the seat's CURRENT option for the session's model, in the\n * session's mode. Current rather than stored so a corrected catalog (a\n * fixed window table, a mode switch) shows up without waiting for a turn.\n * 3. STORED — whatever the record carries (every pre-3.9 session).\n * 4. The seat's default window, marked `fallback`.\n *\n * A compaction point is only ever DERIVED from a window it belongs to: a\n * runtime window without a stored point is reconciled with context-math's\n * per-engine formula, never paired with a catalog point for another window.\n */\nexport function sessionContextBudget(\n seats: readonly VerseSeat[],\n session: Pick<VerseSession, 'seatId' | 'model' | 'usage' | 'engine' | 'contextMode'>,\n): SessionContextBudget {\n const usage = session.usage;\n // No UI-side legacy rule: the engine materialises a pre-3.9 Claude\n // record's mode (and its budget) on startup and on every touch, so every\n // record reaching the browser already names the mode it runs in.\n const mode: VerseContextMode = session.contextMode ?? 'standard';\n const option = modelOptionFor(seats, session);\n const base = {\n contextTokens: typeof usage.contextTokens === 'number' && Number.isFinite(usage.contextTokens) ? Math.max(0, usage.contextTokens) : 0,\n exact: usage.contextTokensExact !== false,\n mode,\n option,\n };\n const catalog = budgetFor(option, mode);\n\n const stored = positive(usage.contextWindow);\n if (stored !== null && (session.engine === 'local' || usage.contextWindowSource === 'runtime')) {\n const storedPoint = positive(usage.autoCompactAt ?? null);\n const autoCompactAt = storedPoint ?? reconcileAutoCompactAt({\n engine: session.engine,\n runtimeWindow: stored,\n // A local window is the whole budget (no --autocompact); pairing it\n // with the seat's current option would borrow another window's point.\n budget: session.engine === 'local' ? null : catalog,\n autocompactWindow: session.engine === 'claude' ? claudeAutocompactFlag(option, mode) : null,\n maxOutputTokens: option?.maxOutputTokens ?? null,\n });\n const source = session.engine === 'local' ? usage.contextWindowSource ?? null : 'runtime';\n return { ...base, contextWindow: stored, autoCompactAt, source };\n }\n if (catalog) {\n return { ...base, contextWindow: catalog.contextWindow, autoCompactAt: catalog.autoCompactAt, source: option?.windowSource ?? 'fallback' };\n }\n if (stored !== null) {\n return { ...base, contextWindow: stored, autoCompactAt: positive(usage.autoCompactAt ?? null), source: usage.contextWindowSource ?? null };\n }\n const seatWindow = positive(seatById(seats, session.seatId)?.contextWindow ?? null);\n return { ...base, contextWindow: seatWindow, autoCompactAt: null, source: seatWindow !== null ? 'fallback' : null };\n}\n\n/** Context window for a session — see {@link sessionContextBudget} for the precedence. */\nexport function contextWindowFor(\n seats: readonly VerseSeat[],\n session: Pick<VerseSession, 'seatId' | 'model' | 'usage' | 'engine' | 'contextMode'>,\n): number | null {\n return sessionContextBudget(seats, session).contextWindow;\n}\n\n/** Plain words for a window's provenance — the meter's tooltip and the resources panel share them. */\nexport const WINDOW_SOURCE_TEXT: Record<VerseWindowSource, string> = {\n runtime: 'reported by the CLI on the last turn',\n 'provider-catalog': \"from this seat's own model catalog\",\n 'cli-catalog': \"from the pinned CLI's built-in model table\",\n documented: \"from the provider's published model table\",\n fallback: 'a default estimate — the CLI has not reported the real window yet',\n};\n\n/**\n * The same provenance, per engine. On a LOCAL seat nothing is \"reported by\n * the CLI\": Verse measures the window from the model server (llama-server\n * slot, Ollama residency/defaults) and TELLS Claude Code to use it, so the\n * sentence names both halves.\n */\nexport function windowSourceText(source: VerseWindowSource, engine: VerseEngine | null | undefined): string {\n if (engine !== 'local') return WINDOW_SOURCE_TEXT[source];\n const from = source === 'runtime' ? 'measured from the local model server'\n : source === 'fallback' ? 'a default estimate — the model server did not report one'\n : WINDOW_SOURCE_TEXT[source];\n return `${from}; Verse passes this window to Claude Code for this chat`;\n}\n\n/**\n * The one sentence about Codex's surcharge above its standard window, for\n * every surface that prices Expansive on codex (the mode menu, the\n * \"Expansive could help\" chip, the new-chat mode selector, the handoff\n * dialog). Worded as REPORTED because that is all it is: the sources\n * docs/VERSE-CONTEXT.md §2.3 cites say GPT-5.6-class requests above 272k\n * count about 2× against plan limits, and Verse has no reading of its own\n * that confirms the multiplier. It multiplies the size ratio the copy quotes\n * (the ratio of the two compaction points), which is why it says \"twice that\".\n */\nexport const CODEX_EXPANSIVE_METERING_NOTE =\n 'OpenAI reportedly also counts requests above 272k tokens at about 2× against plan limits, so a turn near the expansive limit may cost roughly twice that.';\n\n/** The first model on a seat that can actually run (skips ones listed with an `unavailableReason`). */\nexport function firstRunnableModel(seat: VerseSeat): VerseModelOption | null {\n return seat.models.find((m) => !m.unavailableReason) ?? null;\n}\n\nexport function healthTone(state: VerseSeatHealth['state']): Tone {\n switch (state) {\n case 'ready':\n return 'success';\n case 'degraded':\n return 'warning';\n case 'unavailable':\n return 'danger';\n default:\n return 'unknown';\n }\n}\n\nexport function seatUnavailableReason(seat: VerseSeat): string | null {\n if (seat.health.state !== 'unavailable') return null;\n return seat.health.summary ?? 'seat unavailable';\n}\n\n// ---------------------------------------------------------------------------\n// Seat capacity — \"which account can I actually use right now\", at the point\n// the choice is made\n// ---------------------------------------------------------------------------\n\n/**\n * The four answers a picker needs. Same vocabulary as the Usage section's\n * `CapacityClass` so the two surfaces never use different words for one state.\n */\nexport type SeatCapacityClass = 'ready' | 'tight' | 'blocked' | 'unread';\n\n/** Word, never colour alone (DESIGN-V2 §6). */\nexport const SEAT_CAPACITY_WORD: Record<SeatCapacityClass, string> = {\n ready: 'usable',\n tight: 'tight',\n blocked: 'blocked',\n unread: 'no reading',\n};\n\n/** Above this share of the binding window a seat is worth flagging. */\nconst TIGHT_PERCENT = 85;\n\nexport interface SeatCapacityNote {\n cls: SeatCapacityClass;\n /**\n * The binding window's percent when it is a real measurement. Null for an\n * unread seat AND at the 100 ceiling, where the upstream value may be the\n * provider's \"limit reached\" sentinel rather than a reading\n * (docs/VERSE-TELEMETRY-V2.md) — and \"limit reached\" is true under either.\n */\n usedPercent: number | null;\n /** One short phrase for an option label, a pill title, a menu row. */\n text: string;\n}\n\n/** `seven_day_fable` → `weekly (fable)`; `five_hour` → `5-hour`. */\nexport function seatWindowLabel(id: string): string {\n const known: Record<string, string> = {\n five_hour: '5-hour window',\n seven_day: 'weekly window',\n codex: 'weekly window',\n };\n if (known[id]) return known[id];\n const perModel = /^seven_day_(.+)$/.exec(id);\n if (perModel) return `weekly ${perModel[1]!.replace(/_/g, ' ')} window`;\n return `${id.replace(/_/g, ' ')} window`;\n}\n\n/**\n * What a seat's own health says about whether a turn sent to it will land.\n *\n * This exists because the seat picker showed NOTHING: it annotated an option\n * only when `health.state === 'unavailable'`, and Claude's `health` is\n * `unknown` by construction (docs/VERSE-TELEMETRY-V2.md). So a Claude seat\n * whose binding weekly window reads 100% used appeared as an ordinary,\n * enabled, unannotated choice, and the exhaustion was discovered at turn time\n * — exactly the failure the Usage section was built to prevent.\n *\n * A `blocked` seat is MARKED, never disabled: a used-up window can coexist\n * with a spendable credit balance, so refusing the choice would be a stronger\n * claim than the data supports.\n */\nexport function seatCapacity(seat: VerseSeat): SeatCapacityNote {\n const reason = seatUnavailableReason(seat);\n if (reason !== null) return { cls: 'blocked', usedPercent: null, text: reason };\n\n const measured = seat.health.windows.filter(\n (w): w is { id: string; usedPercent: number; resetsAt: string | null } =>\n typeof w.usedPercent === 'number' && Number.isFinite(w.usedPercent),\n );\n // No window reported a number. That is an unanswered question, not a zero —\n // an empty meter would read \"plenty left\".\n if (measured.length === 0) return { cls: 'unread', usedPercent: null, text: 'no capacity reading' };\n\n const binding = measured.reduce((a, b) => (b.usedPercent > a.usedPercent ? b : a));\n const pct = Math.max(0, Math.min(100, binding.usedPercent));\n const where = seatWindowLabel(binding.id);\n if (pct >= 100) return { cls: 'blocked', usedPercent: null, text: `${where} limit reached` };\n return {\n cls: pct >= TIGHT_PERCENT ? 'tight' : 'ready',\n usedPercent: pct,\n text: `${usedPercentText(pct)} of ${where} used`,\n };\n}\n\n/** Seats grouped in the fixed engine order; empty engines are omitted. */\nexport function groupSeats(seats: readonly VerseSeat[]): Array<{ engine: VerseEngine; seats: VerseSeat[] }> {\n return ENGINE_ORDER.map((engine) => ({ engine, seats: seats.filter((s) => s.engine === engine) })).filter((g) => g.seats.length > 0);\n}\n\nexport interface SessionGroup {\n projectPath: string;\n name: string;\n enrolled: boolean;\n sessions: VerseSession[];\n}\n\n/** Sidebar grouping: by project, most recently touched project first, sessions newest first. */\nexport function groupSessions(sessions: readonly VerseSession[], projects: readonly VerseProject[], query = ''): SessionGroup[] {\n const q = query.trim().toLowerCase();\n const filtered = q\n ? sessions.filter((s) =>\n s.title.toLowerCase().includes(q) ||\n s.projectPath.toLowerCase().includes(q) ||\n s.model.toLowerCase().includes(q) ||\n s.seatId.toLowerCase().includes(q))\n : [...sessions];\n const byProject = new Map<string, VerseSession[]>();\n for (const s of filtered) {\n const list = byProject.get(s.projectPath) ?? [];\n list.push(s);\n byProject.set(s.projectPath, list);\n }\n const groups: SessionGroup[] = [];\n for (const [projectPath, list] of byProject) {\n list.sort((a, b) => b.updatedAt.localeCompare(a.updatedAt));\n groups.push({\n projectPath,\n name: projectName(projectPath, projects),\n enrolled: projects.find((p) => p.path === projectPath)?.enrolled ?? false,\n sessions: list,\n });\n }\n groups.sort((a, b) => b.sessions[0]!.updatedAt.localeCompare(a.sessions[0]!.updatedAt));\n return groups;\n}\n\nexport function formatElapsed(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '0s';\n const s = Math.floor(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${s % 60}s`;\n const h = Math.floor(m / 60);\n return `${h}h ${m % 60}m`;\n}\n\nexport function formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '—';\n if (ms < 1000) return `${Math.round(ms)}ms`;\n if (ms < 60_000) return `${(ms / 1000).toFixed(1)}s`;\n return formatElapsed(ms);\n}\n\n/**\n * Sidebar rows carry a right-aligned relative time. Short by design — the\n * row has ~5ch for it — and it degrades to a date rather than \"412d\".\n * `now` is injectable so the format is testable without faking the clock.\n */\nexport function formatRelative(iso: string, now: number = Date.now()): string {\n const then = Date.parse(iso);\n if (!Number.isFinite(then)) return '';\n const seconds = Math.round((now - then) / 1000);\n if (seconds < 0) return 'now';\n if (seconds < 60) return 'now';\n const minutes = Math.floor(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.floor(minutes / 60);\n if (hours < 24) return `${hours}h`;\n const days = Math.floor(hours / 24);\n if (days < 7) return `${days}d`;\n return new Date(then).toLocaleDateString([], { month: 'short', day: 'numeric' });\n}\n\nexport function formatClock(iso: string): string {\n const d = new Date(iso);\n if (Number.isNaN(d.getTime())) return '';\n return d.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });\n}\n\n/** One-line description of a tool call for a collapsed card header. */\nexport function summarizeToolInput(input: unknown): string {\n if (input === null || input === undefined) return '';\n if (typeof input === 'string') return truncate(input, 96);\n if (typeof input !== 'object') return truncate(String(input), 96);\n const record = input as Record<string, unknown>;\n const preferred = ['command', 'cmd', 'file_path', 'path', 'pattern', 'query', 'url', 'description', 'prompt', 'text'];\n for (const key of preferred) {\n const v = record[key];\n if (typeof v === 'string' && v.trim()) return truncate(v.trim().replace(/\\s+/g, ' '), 96);\n }\n const keys = Object.keys(record);\n if (keys.length === 0) return '';\n const first = record[keys[0]!];\n const rendered = typeof first === 'string' ? first : JSON.stringify(first);\n return truncate(`${keys[0]}: ${rendered ?? ''}`.replace(/\\s+/g, ' '), 96);\n}\n\nexport function truncate(value: string, max: number): string {\n return value.length > max ? `${value.slice(0, max - 1)}…` : value;\n}\n\n/** Pretty JSON for tool cards; falls back to String() for non-serializable input. */\nexport function prettyJson(value: unknown): string {\n if (typeof value === 'string') return value;\n try {\n return JSON.stringify(value, null, 2) ?? '';\n } catch {\n return String(value);\n }\n}\n\n/**\n * Accepts POSIX/Windows absolute paths and `~/...`. The server rewrites the\n * home directory as `~` in every outbound payload (sanitizePublicJson) and\n * expands it again on the way in, so a `~/` project from bootstrap is valid.\n */\nexport function isAbsolutePath(value: string): boolean {\n return /^(?:\\/|~(?:\\/|$)|[a-zA-Z]:[\\\\/]|\\\\\\\\)/.test(value) &&\n ![...value].some((c) => c.charCodeAt(0) < 32 || (c.charCodeAt(0) >= 127 && c.charCodeAt(0) <= 159));\n}\n\n/**\n * Seat pill text: \"<seat> · <model>\", collapsing to just the seat when the\n * model label is already contained in it (local seats expose one model whose\n * name is the seat name), so the pill never reads \"Qwen3-Coder · Qwen3-Coder\".\n */\nexport function seatPillLabel(seats: readonly VerseSeat[], ref: Pick<VerseSession, 'seatId' | 'engine' | 'model'>): string {\n const seat = seatLabel(seats, ref);\n const model = modelLabel(seats, ref);\n if (!model || seat.toLowerCase().includes(model.toLowerCase())) return seat;\n return `${seat} · ${model}`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import{i as e}from"./compaction-point-VL9oegWS.js";var t=[`minimal`,`low`,`medium`,`high`,`xhigh`,`max`],n=new Set([`thinking-delta`,`thinking-progress`,`progress`,`status`]);function r(e){return n.has(e.type)}var i=65536,a=12e3,o=[`This conversation is about to continue in a fresh session that has none of its context.`,`Write the handoff note that new session should start from. Do not edit files or run commands for this — only write the note.`,``,`Cover, concretely:`,`- The goal, and what "done" looks like.`,`- Decisions made so far, each with the reason it was made.`,`- Current state: what is finished, what is half-done, what is untested.`,`- Files changed and anything not yet committed.`,`- How to verify the work (exact commands).`,`- Open questions, risks, and approaches already tried that did not work.`,``,`Keep it under 600 words. Prefer file paths and commands over prose.`].join(`
2
+ `),s=65536,c=139264,l=6144,u={turnId:null,startedAt:null,progress:null,thinking:null,notice:null,settledTurnId:null},d={session:null,events:[],lastSeq:0,loaded:!1,loadError:null,stream:`idle`,live:u},f=new Map,p=new Map,m=new Map,h=new Set,g=new Map,_=new Set;function v(e){if(e!==null){let t=g.get(e);if(t)for(let e of[...t])e()}else for(let e of[...g.values()])for(let t of[...e])t();for(let e of[...h])e()}function y(e){return h.add(e),()=>h.delete(e)}function b(e,t){let n=g.get(e);return n||(n=new Set,g.set(e,n)),n.add(t),()=>{let n=g.get(e);n&&(n.delete(t),n.size===0&&g.delete(e))}}function x(e){return _.add(e),()=>_.delete(e)}function S(e){return{sessionId:e.sessionId,session:e.session,events:e.events,lastSeq:e.lastSeq,loaded:e.loaded,loadError:e.loadError,stream:e.stream}}function C(e){let t=f.get(e);return t||(t={sessionId:e,...d},f.set(e,t),p.set(e,S(t))),t}function w(e,t,n){f.set(e,t);let r=p.get(e);(!r||n||r.session!==t.session||r.loaded!==t.loaded||r.loadError!==t.loadError||r.stream!==t.stream)&&p.set(e,S(t))}function T(e,t,n=!1){w(e,{...C(e),...t},n),v(e)}var E={sessionId:``,...d},D=S(E);function O(e){return e?C(e):E}function k(e){return e?(C(e),p.get(e)):D}function A(e){return e?C(e).live:u}function j(e){return m.get(e)}function M(e,t,n){let r=C(e),i=$(r.events,n),a=I(t,i),o=r.session&&te(r.session,a)?r.session:a,s=i!==r.events,c=s||o!==r.session?W(r.live,i,o):r.live;(s||o!==r.session||!r.loaded||r.loadError!==null||c!==r.live)&&(w(e,{...r,session:o,events:i,lastSeq:i.length?Math.max(r.lastSeq,i[i.length-1].seq):r.lastSeq,loaded:!0,loadError:null,live:c},s),v(e))}function N(e,t){T(e,{loadError:t,loaded:!0})}function P(e,t){C(e).stream!==t&&T(e,{stream:t})}function F(e,t,n){T(e,{session:I(t,C(e).events,n)})}function I(e,t,n){if(e.status!==`running`)return e;let r=-1,i=n??null;if(!n){for(let e of t)(e.type===`user-message`||e.type===`turn-started`)&&(r=e.seq,i=e.turnId);if(i===null)return e}let a=null,o=null;for(let e of t)e.seq<=r||(e.type===`error`&&e.turnId===i&&(o=e.message),(e.type===`turn-done`||e.type===`cancelled`)&&e.turnId===i&&(a=e));if(!a)return e;let s=a.type===`turn-done`&&!a.ok&&o!==null;return{...e,status:s?`error`:`idle`,lastError:s?o:null,updatedAt:a.at>e.updatedAt?a.at:e.updatedAt}}function L(e,t){let n=C(e);n.session&&n.session.status!==t&&T(e,{session:{...n.session,status:t}})}function R(e,t){let n=C(e),i=n.events,a=!1,o=n.lastSeq,s=n.session,c=n.live,l=0,u=!1,d=!1,f=!1,p=Date.now();for(let n of t){if(r(n)){let e=H(c,n,p);e!==c&&(c=e,f=!0);continue}if(!Number.isFinite(n.seq))continue;let t=i.length>0?i[i.length-1].seq:-1/0;if(n.seq>t)a||=(i=i.slice(),!0),i.push(n);else{let e=Z(i,n.seq);if(e.found)continue;a||=(i=i.slice(),!0),i.splice(e.index,0,n)}l+=1,o=Math.max(o,n.seq),n.type!==`text-delta`&&(d=!0),(n.type===`turn-done`||n.type===`cancelled`||n.type===`error`)&&(u=!0),s&&=z(s,n);let m=U(c,n,p,e);m!==c&&(c=m)}return l===0&&!f?{applied:0,settled:!1,liveChanged:!1}:(w(e,{...n,events:i,lastSeq:o,session:s,live:c},d),v(e),{applied:l,settled:u,liveChanged:f})}function z(e,t){switch(t.type){case`turn-started`:return{...e,status:`running`,lastError:null,updatedAt:t.at};case`usage`:return{...e,usage:G(e,t.usage),updatedAt:t.at};case`context`:return{...e,usage:J(e,t),updatedAt:t.at};case`compaction`:return{...e,compactionCount:(e.compactionCount??0)+1,updatedAt:t.at};case`turn-done`:return{...e,status:t.ok?`idle`:e.lastError?`error`:`idle`,turnCount:e.turnCount+1,nativeSessionId:t.nativeSessionId??e.nativeSessionId,updatedAt:t.at};case`error`:return{...e,status:`error`,lastError:t.message,updatedAt:t.at};case`cancelled`:return{...e,status:`idle`,updatedAt:t.at};default:return e}}function B(e,t){let n=Date.parse(e);return Number.isFinite(n)?n:t}function V(e,t,n){return e.turnId===t?e:{...u,turnId:t,startedAt:n,settledTurnId:e.settledTurnId}}function H(e,t,n){if(t.turnId!==null&&t.turnId===e.settledTurnId)return e;let r=t.turnId===null?e:V(e,t.turnId,n);switch(t.type){case`thinking-delta`:{if(t.text.length===0)return r;let e=r.thinking&&r.thinking.turnId===t.turnId?{...r.thinking,text:r.thinking.text+t.text}:{turnId:t.turnId,text:t.text,startedAt:n,estimatedTokens:null};return{...r,thinking:e,notice:null}}case`thinking-progress`:{let e=r.thinking&&r.thinking.turnId===t.turnId?{...r.thinking,estimatedTokens:t.estimatedTokens}:{turnId:t.turnId,text:``,startedAt:n,estimatedTokens:t.estimatedTokens};return{...r,thinking:e}}case`progress`:return{...r,progress:{phase:t.phase,tool:typeof t.tool==`string`&&t.tool.length>0?t.tool:null,elapsedMs:t.elapsedMs,outTokens:t.outTokens??null,tokPerSec:t.tokPerSec??null,receivedAt:n}};case`status`:return{...r,notice:{kind:t.kind,message:t.message,at:t.at,receivedAt:n}};default:return r}}function U(e,t,n,r){switch(t.type){case`turn-started`:return t.turnId===e.settledTurnId?e:e.turnId===t.turnId?{...e,startedAt:B(t.at,e.startedAt??n)}:{...u,turnId:t.turnId,startedAt:B(t.at,n),settledTurnId:e.settledTurnId};case`thinking`:{let i=e.thinking&&e.thinking.turnId===t.turnId?e.thinking:null;if(i){let e=m.get(r);e||(e=new Map,m.set(r,e)),e.set(t.seq,{durationMs:typeof t.durationMs==`number`?t.durationMs:Math.max(0,n-i.startedAt),estimatedTokens:i.estimatedTokens})}return i||e.notice?{...e,thinking:i?null:e.thinking,notice:null}:e}case`text-delta`:case`assistant-message`:case`tool-use`:case`tool-result`:return e.notice&&(t.turnId===e.turnId||e.turnId===null)?{...e,notice:null}:e;case`turn-done`:case`cancelled`:return{...u,settledTurnId:t.turnId};default:return e}}function W(e,t,n){let r=null,i=e.settledTurnId;for(let e=t.length-1;e>=0;--e){let n=t[e];if(n.type===`turn-done`||n.type===`cancelled`){i=n.turnId;break}if(n.type===`turn-started`){r=n;break}}return r?n&&n.status!==`running`?e.turnId===null?e:{...u,settledTurnId:e.settledTurnId}:e.turnId===r.turnId?e:{...u,turnId:r.turnId,startedAt:B(r.at,Date.now()),settledTurnId:e.settledTurnId}:e.turnId!==null&&e.turnId===i?{...u,settledTurnId:i}:e.settledTurnId===i?e:{...e,settledTurnId:i}}function G(e,t){let n=e.usage,r={...n,inputTokens:n.inputTokens+t.inputTokens,outputTokens:n.outputTokens+t.outputTokens,cacheReadTokens:n.cacheReadTokens+t.cacheReadTokens,cacheCreationTokens:n.cacheCreationTokens+t.cacheCreationTokens,contextTokens:t.contextTokens},i=typeof t.contextWindow==`number`&&t.contextWindow>0?t.contextWindow:null,a=t.contextWindowSource!==void 0||e.engine!==`local`;return i!==null&&a&&(r.contextWindow=i),t.contextWindowSource!==void 0&&(r.contextWindowSource=t.contextWindowSource),t.autoCompactAt!==void 0&&(r.autoCompactAt=t.autoCompactAt),t.contextTokensExact===!1?r.contextTokensExact=!1:t.contextWindowSource!==void 0&&delete r.contextTokensExact,r}var K=new Set([`runtime`,`provider-catalog`,`cli-catalog`,`documented`,`fallback`]);function q(e){return typeof e==`string`&&K.has(e)?e:null}function J(t,n){let r=t.usage,i={...r,contextTokens:Math.max(0,Math.floor(n.contextTokens)),contextTokensExact:n.exact},a=typeof n.contextWindow==`number`&&n.contextWindow>0?n.contextWindow:null,o=q(n.contextWindowSource);return a===null||t.engine===`local`&&o===null?(n.autoCompactAt!==void 0&&n.autoCompactAt!==null&&(i.autoCompactAt=n.autoCompactAt),i):(i.contextWindow=a,i.contextWindowSource=o??`runtime`,n.autoCompactAt===void 0?a!==r.contextWindow&&(i.autoCompactAt=e({engine:t.engine,runtimeWindow:a,budget:r.contextWindow?{contextWindow:r.contextWindow,autoCompactAt:r.autoCompactAt??null}:null})):i.autoCompactAt=n.autoCompactAt,i)}function Y(e){let t=null;for(let n of e)(n.type===`usage`||n.type===`turn-done`||n.type===`cancelled`||n.type===`context`&&n.turnId!==null)&&typeof n.at==`string`&&(t===null||n.at>t)&&(t=n.at);return t}function X(e){let t=f.delete(e);p.delete(e),m.delete(e);for(let t of[..._])t({kind:`forget`,sessionId:e});t&&v(e)}function Z(e,t){let n=0,r=e.length;for(;n<r;){let i=n+r>>>1,a=e[i].seq;if(a===t)return{found:!0,index:i};a<t?n=i+1:r=i}return{found:!1,index:n}}function Q(e){let t=!0;for(let n=0;n<e.length;n+=1){let r=e[n].seq;if(!Number.isFinite(r)||n>0&&r<=e[n-1].seq){t=!1;break}}if(t)return e.slice();let n=new Map;for(let t of e)Number.isFinite(t.seq)&&!n.has(t.seq)&&n.set(t.seq,t);return[...n.values()].sort((e,t)=>e.seq-t.seq)}function $(e,t){if(t.length===0)return e;let n=Q(t);if(n.length===0)return e;if(e.length===0)return n;if(n[0].seq>e[e.length-1].seq)return e.concat(n);let r=[],i=0,a=0,o=0;for(;a<e.length||o<n.length;){let t=e[a],s=n[o];s===void 0||t!==void 0&&t.seq<s.seq?(r.push(t),a+=1):t===void 0||s.seq<t.seq?(r.push(s),i+=1,o+=1):(r.push(t),a+=1,o+=1)}return i===0?e:r}function ee(e,t){if(Object.is(e,t))return!0;if(!e||!t||typeof e!=`object`||typeof t!=`object`||Array.isArray(e)!==Array.isArray(t))return!1;let n=Object.keys(e),r=Object.keys(t);if(n.length!==r.length)return!1;for(let r of n)if(!Object.is(e[r],t[r]))return!1;return!0}function te(e,t){if(e===t)return!0;let n=Object.keys(e);return n.length===Object.keys(t).length&&n.every(n=>ee(e[n],t[n]))}function ne(e){return e==null||!Number.isFinite(e)?`—`:Math.round(e)<1e3?String(Math.round(e)):Math.round(e/1e3)<1e3?`${Math.round(e/1e3)}k`:`${(e/1e6).toFixed(1).replace(/\.0$/,``)}M`}export{s as C,c as S,t as _,k as a,i as b,Y as c,F as d,L as f,x as g,y as h,A as i,M as l,b as m,X as n,O as o,P as p,ne as r,j as s,R as t,N as u,a as v,l as x,o as y};
3
+ //# sourceMappingURL=verse-store-b_Lek_c5.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"verse-store-b_Lek_c5.js","names":[],"sources":["../../../../../../src/core/verse/types.ts","../../../../../../src/web-ui/routes/verse/verse-store.ts"],"sourcesContent":["/**\n * Ashlr Verse — interactive multi-turn session contract (V1).\n *\n * A Verse session binds one project directory to one execution seat\n * (engine + account + model). Each user turn spawns ONE vendor CLI process\n * that resumes the vendor-native conversation by id, streams normalized\n * events, and exits. No long-lived stdin is held between turns.\n *\n * Seats:\n * claude -> `claude -p ... --output-format stream-json` via a native-profile launcher (account pinned by CLAUDE_CONFIG_DIR)\n * local -> the plain `claude` binary with ANTHROPIC_BASE_URL pointed at Ollama (Anthropic-compatible API); model = Ollama tag\n * codex -> `codex exec --json` / `codex exec resume <threadId> --json` via a native-profile launcher (CODEX_HOME pinned)\n * grok -> `grok -p ... --output-format streaming-messages-json` via a native-profile launcher (GROK_HOME pinned)\n *\n * Nothing in this module reads secrets. Account identity is pinned by the\n * launcher command recorded in ~/.ashlr/account-connections/connections.json.\n */\n\nexport type VerseEngine = 'claude' | 'codex' | 'grok' | 'local';\n\nexport type VerseSessionStatus = 'idle' | 'running' | 'error';\n\n/** One selectable execution seat shown in the model/account picker. */\nexport interface VerseSeat {\n /** Stable id, e.g. `claude`, `codex-personal`, `grok`, `local:qwen3-coder-next:ctx64k`. */\n id: string;\n engine: VerseEngine;\n /** Human label, e.g. \"Claude Code\", \"Personal Codex\", \"Grok\", \"Qwen3-Coder-Next (local)\". */\n label: string;\n /** Account id from connections.json for native seats; `local` for Ollama seats. */\n accountId: string;\n /** Models this seat can run. First entry is the default. */\n models: VerseModelOption[];\n /** Best-known context window in tokens for the default model (null when unknown). */\n contextWindow: number | null;\n /** Latest health/usage evidence, if any. Never an admission input in V1. */\n health: VerseSeatHealth;\n /**\n * V2.1 ADDITIVE. The subscription capacity behind this seat, so the seat\n * list can render a meter without a second request.\n *\n * Absent (`undefined`) for LOCAL seats: an Ollama tag has no subscription\n * and no provider window. Its real constraint is machine memory, which is\n * reported by `VerseBootstrap.localRuntime`, not by a quota. Absent on a\n * native seat means the server could not build a record for that account\n * at all — `health.state` says what it does know.\n */\n capacity?: VerseSeatCapacity;\n /**\n * V3.9 ADDITIVE. The version of the CLI binary this seat is PINNED to (its\n * native-profile launcher execs one exact file). Absent when unknown and on\n * local seats. A pinned binary never updates itself, so a model that needs a\n * newer CLI is listed with `unavailableReason` rather than silently failing.\n */\n cliVersion?: string;\n /**\n * V3.9 ADDITIVE. Plain-language facts about this seat's context setup the UI\n * must show rather than imply (binary skew, catalog not yet fetched, …).\n * Absent when there is nothing to say, so ordinary seats keep their shape.\n */\n notes?: string[];\n}\n\n/**\n * Where a context-window figure came from, so nothing on screen implies more\n * certainty than it has (docs/VERSE-CONTEXT.md §1).\n *\n * - `runtime` — the CLI reported it for THIS turn (claude/grok\n * `result.modelUsage.<m>.contextWindow`, codex rollout\n * `token_count.info.model_context_window`, Ollama\n * `/api/ps`). Wins over everything else.\n * - `provider-catalog` — the seat's own served catalog on disk (codex/grok\n * `native-state/models_cache.json`).\n * - `cli-catalog` — read out of the pinned CLI binary's embedded catalog\n * and recorded here with the version it was read from.\n * - `documented` — the provider's published model table.\n * - `fallback` — a named default; the UI marks it as an estimate.\n */\nexport type VerseWindowSource = 'runtime' | 'provider-catalog' | 'cli-catalog' | 'documented' | 'fallback';\n\n/**\n * How much context a session is allowed to accumulate before the CLI compacts.\n *\n * - `standard` — the default. Evidence-based budget per engine: Claude 1M\n * models compact near 400k instead of ~967k; Codex, Grok and\n * local run their native windows.\n * - `expansive` — opt-in. Claude runs its full native window (CLI `auto`),\n * Codex raises `model_context_window` to the model's catalog\n * maximum (872k on GPT-6 / GPT-5.6). Costs more usage per turn,\n * buys simultaneous visibility for coupled, cross-cutting work.\n *\n * A mode that does not exist for a model (Grok, local, 200k Claude models,\n * GPT-5.5) is simply absent from that model's option — never faked.\n */\nexport type VerseContextMode = 'standard' | 'expansive';\n\nexport const VERSE_CONTEXT_MODES: readonly VerseContextMode[] = ['standard', 'expansive'];\n\n/** One mode's budget for a model on a seat. */\nexport interface VerseContextBudget {\n /** The window the CLI measures against in this mode (the meter's denominator). */\n contextWindow: number;\n /** Token count at which the CLI auto-compacts in this mode; null when unknown. */\n autoCompactAt: number | null;\n /**\n * The RAW window value the CLI must be TOLD to reach this budget, when that\n * differs from `contextWindow` — codex measures against 95% of the window it\n * is configured with, so expansive GPT-6 is `providerWindow: 872_000`\n * (`-c model_context_window=872000`) but `contextWindow: 828_400`.\n */\n providerWindow?: number | null;\n}\n\nexport interface VerseModelOption {\n id: string;\n label: string;\n /** Standard-mode window the CLI measures against (codex: the 95% effective window). */\n contextWindow: number | null;\n /**\n * V3.9 ADDITIVE — every field below is optional so records and fixtures\n * written before it keep validating. Absent means \"not known\", never zero.\n */\n /** Standard-mode auto-compaction point. */\n autoCompactAt?: number | null;\n /** Present ONLY when this model on this seat has a real expansive mode. */\n expansive?: VerseContextBudget | null;\n /** The CLI's default max output for this model, when known. */\n maxOutputTokens?: number | null;\n windowSource?: VerseWindowSource;\n /** Minimum CLI version that knows this model id (e.g. '2.1.280'); null when any. */\n minCliVersion?: string | null;\n /**\n * Why this model cannot run on this seat right now, in plain language (e.g.\n * \"needs Claude Code 2.1.280; this seat runs 2.1.257\"). Null/absent = runnable.\n * Listed rather than hidden so the operator learns WHY a model is missing.\n */\n unavailableReason?: string | null;\n}\n\nexport interface VerseSeatHealth {\n state: 'ready' | 'degraded' | 'unavailable' | 'unknown';\n /** e.g. \"5h window 72% used, resets 14:00\" — plain text, already sanitized. */\n summary: string | null;\n windows: Array<{ id: string; usedPercent: number | null; resetsAt: string | null }>;\n observedAt: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Seat capacity (V2.1, additive) — see docs/VERSE-TELEMETRY-V2.md, which is\n// the authority for every honesty rule encoded in these shapes.\n//\n// This file is imported by the BROWSER bundle, so it may not import\n// `core/verse/accounts.ts` (node:fs). The shapes below therefore restate the\n// provider-record shapes structurally. `seats.ts` assigns the account record's\n// values straight into them, so a divergence in `core/verse/accounts.ts` stops\n// `seats.ts` compiling — that assignment is the drift guard.\n// ---------------------------------------------------------------------------\n\n/** One provider-reported quota window, as carried on a seat. */\nexport interface VerseSeatWindow {\n id: string;\n /** Provider-reported percent, or null for NO SIGNAL — which is not zero. */\n usedPercent: number | null;\n /**\n * Machine-readable reset instant. STRUCTURALLY ALWAYS NULL for Claude: that\n * provider publishes only a sentence, which lives in `resetDescription` and\n * is rendered verbatim. The server never synthesizes an instant from it.\n * (3.10.1: the Command burn-down chart may place the reset on its time axis\n * via `resetInstantFromWords` in web-ui command-model, but only for the\n * collector's exact \"Mon D at H:MMam (Area/Zone)\" form and only when the\n * result lands within one window of now; anything else stays words.)\n */\n resetsAt: string | null;\n /** The provider's own reset wording, verbatim (\"resets Sep 25 at 7pm (America/New_York)\"). */\n resetDescription: string | null;\n /**\n * TRUE only when the provider explicitly FLAGGED the limit. Such a window's\n * `usedPercent` is the SENTINEL 100 — a denial, not a measurement — and must\n * be labelled \"limit reached\", never \"100% used\".\n */\n limitReached: boolean;\n /** False when `usedPercent` is a flagged sentinel rather than a reading. */\n measured: boolean;\n}\n\n/**\n * Codex credits, INDEPENDENT of the window: a fully used weekly window with a\n * spendable balance is not blocked. `null` is \"no signal\", never \"no credits\".\n */\nexport interface VerseSeatCredits {\n hasCredits: boolean;\n unlimited: boolean;\n /** Provider-reported decimal string, kept verbatim — never rounded. */\n balance: string | null;\n}\n\n/**\n * The coarse \"can I use this seat right now\" verdict. Deliberately coarse: the\n * exact numbers are in `windows`, and a verdict that pretended to more\n * precision than the providers give would be a lie.\n *\n * - `ready` — a reading exists and the binding window has headroom.\n * - `tight` — the binding window is at/above the warn threshold, OR it is\n * spent while Codex credits remain spendable (not blocked).\n * - `exhausted` — the binding window is spent and nothing else is left.\n * - `signed-out` — the account is not authenticated; reconnect it.\n * - `unknown` — NO window carried a percent. Not zero, not healthy.\n */\nexport type VerseSeatUsability = 'ready' | 'tight' | 'exhausted' | 'signed-out' | 'unknown';\n\n/**\n * Where a seat's windows came from, so nothing implies freshness it lacks.\n * Mirrors `VerseEvidenceSource` in `core/verse/accounts.ts`.\n */\nexport type VerseSeatEvidenceSource = 'collector' | 'shared-evidence' | 'baseline' | 'none';\n\n/** Everything the seat list needs to draw a capacity meter honestly. */\nexport interface VerseSeatCapacity {\n /** e.g. \"max\", \"pro\", \"SuperGrok\". Null when the provider gave none. */\n planType: string | null;\n /**\n * THE CONSTRAINT THAT ACTUALLY BLOCKS WORK: the window with the highest\n * `usedPercent`. Null when no window carried a percent at all.\n */\n binding: VerseSeatWindow | null;\n /** Every window the provider reported, in provider order. */\n windows: VerseSeatWindow[];\n /** Codex only; null for every other provider and when no signal exists. */\n credits: VerseSeatCredits | null;\n usability: VerseSeatUsability;\n observedAt: string | null;\n evidenceSource: VerseSeatEvidenceSource;\n /** Plain-language provider facts the UI must show instead of implying a fault. */\n notes: string[];\n}\n\nexport interface VerseProject {\n path: string;\n name: string;\n /** From ~/.ashlr/enrollment.json when present. */\n enrolled: boolean;\n}\n\n// ---------------------------------------------------------------------------\n// Workspaces (V2.2, ADDITIVE) — see docs/VERSE-WORKSPACES.md §1.\n//\n// A session bound to ONE directory cannot express \"this service plus the\n// shared library it depends on\", which is most real work. A workspace is a\n// NAMED set of roots with exactly one marked primary.\n//\n// `VerseSession.projectPath` keeps its meaning — it IS the primary root — so\n// every session record, adapter and test written before workspaces existed\n// still loads and still runs. Nothing rewrites saved chat history.\n//\n// ENROLLMENT IS NOT PART OF THIS SHAPE ON PURPOSE. A workspace says what a\n// session may REACH; `~/.ashlr/enrollment.json` says what the AUTONOMOUS lane\n// may mutate, and the two are deliberately separate registries. Membership in\n// a workspace grants no enrollment: `enrolled` below is READ from the\n// registry per root and is never written by anything in this feature.\n// ---------------------------------------------------------------------------\n\n/** One directory in a workspace. Exactly one root in a workspace is primary. */\nexport interface VerseWorkspaceRoot {\n /** Absolute, physically resolved path (symlinks followed). */\n path: string;\n /** Display name; defaults to the basename. */\n name: string;\n /**\n * The session's cwd and the value `projectPath` carries. Exactly one root\n * per workspace has this set.\n */\n primary: boolean;\n}\n\n/**\n * A named set of roots.\n *\n * ONE TYPE, TWO USES, DELIBERATELY. An interactive session binds to a\n * workspace to decide what it can reach; the autonomous lane reads the same\n * workspace as a SECTION — \"these repositories collaborate, work on them\n * together\" — when `section` is true. They were not split because the thing\n * being named is identical in both: a set of directories that belong to one\n * piece of work. Two registries of named repo groups would drift.\n *\n * What is NOT on this type is priority. A repo may belong to several\n * workspaces, so a per-membership rank would give one repo several\n * contradictory ranks. Priority is therefore an attribute OF THE REPO, held\n * once per path in the same registry — see `VerseRootPriority`.\n */\nexport interface VerseWorkspace {\n id: string;\n name: string;\n /** Primary first, then the extras in the order they were added. */\n roots: VerseWorkspaceRoot[];\n /**\n * Offer this workspace to the autonomous lane as a section.\n *\n * GRANTS NOTHING. The fleet still reaches only what\n * `~/.ashlr/enrollment.json` permits; a section can group and order those\n * repos and nothing else. A member that is not enrolled stays unreachable.\n */\n section: boolean;\n createdAt: string;\n updatedAt: string;\n}\n\n/**\n * Relative standing of one repository in the autonomous lane's attention.\n *\n * ORDERING ONLY, NEVER ADMISSION. `critical` on an unenrolled repo is still\n * refused by `assertMayMutate`; `low` on an enrolled one is still permitted.\n * An ordinal rather than a number because the operator's judgement here is\n * \"this matters more than that\", and a 0-100 score would invent a precision\n * nobody holds.\n *\n * Absent means `normal`, which is how every repo already behaves — so a\n * registry with no priorities at all reproduces today's flat list exactly.\n */\nexport type VerseRootPriority = 'critical' | 'high' | 'normal' | 'low';\n\nexport const VERSE_ROOT_PRIORITIES: readonly VerseRootPriority[] =\n ['critical', 'high', 'normal', 'low'];\n\nexport const VERSE_DEFAULT_ROOT_PRIORITY: VerseRootPriority = 'normal';\n\n/** Sort weight; lower sorts first. Never a budget, never a multiplier. */\nexport const VERSE_ROOT_PRIORITY_RANK: Record<VerseRootPriority, number> = {\n critical: 0,\n high: 1,\n normal: 2,\n low: 3,\n};\n\n/** One enrolled repository as the autonomy scope view ranks it. */\nexport interface VerseAutonomyScopeEntry {\n path: string;\n name: string;\n priority: VerseRootPriority;\n /** Sections (workspaces with `section: true`) this repo belongs to. */\n sections: Array<{ id: string; name: string }>;\n /** True when a focus section is set and this repo is outside it. */\n outsideFocus: boolean;\n}\n\n/**\n * The autonomous lane's scope, ORDERED.\n *\n * Built by INTERSECTING section membership with the enrollment registry, so\n * it can only ever be a subset of what enrollment already allows. Sections\n * add ordering and grouping; they never add reach.\n */\nexport interface VerseAutonomyScopeView {\n focusSectionId: string | null;\n focusSectionName: string | null;\n /** Enrolled repos, most important first. */\n entries: VerseAutonomyScopeEntry[];\n /**\n * Paths a section names that are NOT enrolled. Listed so the blast radius\n * is legible in both directions — these are exactly the repos a section\n * does NOT give the fleet.\n */\n unenrolledSectionRoots: string[];\n}\n\n/**\n * Per-root git identity. A turn that edits two repos produces two diffs, so\n * the transcript has to be able to attribute each file to the right one.\n *\n * `remote` is the canonical `owner/repo` for a GitHub origin and null for\n * anything else — deliberately NOT the raw remote URL, which can carry a\n * token in its userinfo and would then reach an API response.\n */\nexport interface VerseRootGit {\n branch: string;\n /** Count of porcelain entries; 0 is clean. */\n dirty: number;\n ahead: number;\n behind: number;\n remote: string | null;\n}\n\n/** A root as the client sees it: identity, reachability and honest scope. */\nexport interface VerseRootStatus {\n path: string;\n name: string;\n primary: boolean;\n exists: boolean;\n /**\n * Read live from the enrollment registry. FALSE means the interactive lane\n * still works on this root while the autonomous lane refuses it — being in\n * a workspace never changes this.\n */\n enrolled: boolean;\n /** Null when the root is not a git repository, or git is unavailable. */\n git: VerseRootGit | null;\n /**\n * False when the session's engine has no way to be granted this root (Grok's\n * CLI exposes `--cwd` and nothing else). The root is still listed, because\n * hiding it would misrepresent what the workspace is.\n */\n reachable: boolean;\n}\n\n/** GET /api/verse/sessions/:id/roots */\nexport interface VerseSessionRootsResponse {\n sessionId: string;\n workspaceId: string | null;\n workspaceName: string | null;\n roots: VerseRootStatus[];\n /**\n * Plain-language facts the UI must show rather than imply: an unreachable\n * root on a Grok seat, or a root the autonomous lane will refuse.\n */\n notes: string[];\n}\n\n/** GET /api/verse/workspaces */\nexport interface VerseWorkspacesResponse {\n workspaces: VerseWorkspace[];\n /** Live per-root facts, keyed by workspace id, so one read draws the list. */\n status: Record<string, VerseRootStatus[]>;\n /** Per-repo priority, keyed by canonical path. Absent key means `normal`. */\n priorities: Record<string, VerseRootPriority>;\n focusSectionId: string | null;\n}\n\n/** POST /api/verse/workspaces */\nexport interface VerseWorkspaceCreateRequest {\n name: string;\n /** Absolute paths. The first is the primary. */\n roots: string[];\n /** Also offer this set to the autonomous lane as a section. Default false. */\n section?: boolean;\n}\n\n/** POST /api/verse/workspaces/:id/update */\nexport interface VerseWorkspaceUpdateRequest {\n name?: string;\n /** When present, replaces the root set wholesale. First entry is primary. */\n roots?: string[];\n section?: boolean;\n}\n\n/** POST /api/verse/workspaces/priority */\nexport interface VerseRootPriorityRequest {\n path: string;\n priority: VerseRootPriority;\n}\n\n/** POST /api/verse/workspaces/focus — `sectionId: null` clears the focus. */\nexport interface VerseFocusSectionRequest {\n sectionId: string | null;\n}\n\n/** Hard cap on roots per workspace — a blast radius, not a UI limit. */\nexport const VERSE_MAX_WORKSPACE_ROOTS = 8;\n\n/**\n * Every root a session can reach, primary first.\n *\n * Pure and total: a record written before workspaces existed has no\n * `extraRoots` and yields exactly `[projectPath]`, which is what every caller\n * assumed before this existed.\n */\nexport function verseSessionRoots(\n session: Pick<VerseSession, 'projectPath' | 'extraRoots'>,\n): 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\nexport interface VerseUsage {\n inputTokens: number;\n outputTokens: number;\n cacheReadTokens: number;\n cacheCreationTokens: number;\n /**\n * Prompt size of the most recent assistant call = live context occupancy.\n * Stored UNCLAMPED: a reading above the window is information (the CLI is\n * about to compact or overflow), and only the UI decides how to draw it.\n */\n contextTokens: number;\n contextWindow: number | null;\n /** V3.9 ADDITIVE. Where `contextWindow` came from; absent on old records. */\n contextWindowSource?: VerseWindowSource;\n /** V3.9 ADDITIVE. Auto-compaction point for the session's current mode. */\n autoCompactAt?: number | null;\n /**\n * V3.9 ADDITIVE. False when `contextTokens` is an UPPER BOUND rather than a\n * measurement (codex before its rollout is readable: the turn total sums\n * every model call). Absent means exact.\n */\n contextTokensExact?: boolean;\n}\n\nexport interface VerseSession {\n id: string;\n title: string;\n /**\n * The PRIMARY root: the process cwd and the folder every pre-workspace\n * client already reads. Unchanged in meaning, which is why no session\n * record ever has to be rewritten.\n */\n projectPath: string;\n /**\n * V2.2 ADDITIVE. Roots BEYOND the primary, pinned at creation time.\n *\n * Absent on every record written before workspaces existed, and absent on\n * a single-root session today — so the on-disk shape of an ordinary chat\n * does not change at all.\n *\n * PINNED, not referenced: a session keeps the roots it was created with\n * even if the named workspace is later edited or deleted, for the same\n * reason `launch.anthropicBaseUrl` is pinned — a conversation must not\n * silently gain reach because config moved underneath it.\n */\n extraRoots?: string[];\n /** V2.2 ADDITIVE. Provenance of the pinned roots; absent for an ad-hoc set. */\n workspaceId?: string;\n workspaceName?: string;\n engine: VerseEngine;\n accountId: string;\n seatId: string;\n model: string;\n /** Vendor conversation id used for resume (claude/grok: our uuid; codex: thread id from output). */\n nativeSessionId: string | null;\n createdAt: string;\n updatedAt: string;\n status: VerseSessionStatus;\n turnCount: number;\n usage: VerseUsage;\n lastError: string | null;\n /**\n * V3.9 ADDITIVE. The session's context budget. Every record written by 3.9+\n * carries it explicitly, so ABSENT means a pre-3.9 record: the engine\n * materializes it on first touch — `expansive` for a Claude 1M model (that\n * is the native ~967k compaction those chats always ran with, so upgrading\n * never forces a paid compaction), `standard` otherwise (= native).\n * Changeable mid-session (POST /sessions/:id/context-mode): it changes CLI\n * flags, not prompt content — but switching DOWN below the current\n * occupancy makes the CLI compact on its next turn.\n */\n contextMode?: VerseContextMode;\n /** V3.9 ADDITIVE. Native compactions observed so far (claude/grok compact_boundary, codex rollout `compacted`). */\n compactionCount?: number;\n /** V3.9 ADDITIVE. Set when this session was started as a handoff from another. */\n handoffFrom?: { sessionId: string; title: string };\n /**\n * V3.9 ADDITIVE. Shared project memory was offered to this session's CLI at\n * creation. Pinned, like the roots: a conversation must not silently gain a\n * writable directory because a preference moved underneath it.\n */\n memoryEnabled?: boolean;\n /**\n * V3.10 ADDITIVE (contract: unit C0; written by C3's engine). The operator's\n * per-chat effort and permission choices, applied from the NEXT turn — a\n * running turn keeps the argv it was launched with. Absent (every record\n * before 3.10, and any key never set) = the engine default: permission mode\n * `accept-edits`, effort = the CLI's own default.\n *\n * A MODEL change is deliberately NOT stored here: it rewrites `model` above,\n * which every launch already reads — one field, one truth.\n */\n controls?: VerseSessionControls;\n}\n\n/**\n * V3.10. Permission modes a chat can run in (SPEC-310C §0.6), in picker order.\n * - `plan` — the CLI plans and edits nothing.\n * - `accept-edits` — the default: edits applied without asking.\n * - `auto` — the CLI's own auto mode.\n * - `bypass` — every check skipped. Shown red and confirmed PER CHAT:\n * never a default, never inherited by a new chat.\n * Adapters map these to each CLI's spelling (claude `acceptEdits` /\n * `bypassPermissions`, grok `dontAsk`, …). An engine that cannot honour one\n * reports it unavailable WITH a reason rather than approximating it. The\n * in-page \"Ask\" mode (answering permission prompts in the UI) is 3.11.\n */\nexport const VERSE_PERMISSION_MODES = ['plan', 'accept-edits', 'auto', 'bypass'] as const;\nexport type VersePermissionMode = (typeof VERSE_PERMISSION_MODES)[number];\nexport const VERSE_DEFAULT_PERMISSION_MODE: VersePermissionMode = 'accept-edits';\n\n/**\n * V3.10. Reasoning effort, the union across engines — claude `--effort`\n * (low · medium · high · xhigh · max) and codex `model_reasoning_effort`\n * (minimal · low · medium · high · xhigh). Each seat offers only the subset\n * its CLI accepts; the rest come back unavailable with a reason.\n */\nexport const VERSE_EFFORTS = ['minimal', 'low', 'medium', 'high', 'xhigh', 'max'] as const;\nexport type VerseEffort = (typeof VERSE_EFFORTS)[number];\n\n/** V3.10. `VerseSession.controls` — absent key = engine default (see there). */\nexport interface VerseSessionControls {\n effort?: VerseEffort;\n permissionMode?: VersePermissionMode;\n}\n\n/** Normalized event stream. `seq` is monotonic per session and is the SSE id. */\nexport type VerseEvent =\n | { seq: number; at: string; type: 'user-message'; turnId: string; text: string }\n | { seq: number; at: string; type: 'turn-started'; turnId: string; pid: number | null }\n | { seq: number; at: string; type: 'text-delta'; turnId: string; text: string }\n | { seq: number; at: string; type: 'assistant-message'; turnId: string; text: string }\n /**\n * Reasoning the CLI chose to show. V3.10 ADDITIVE optional fields (absent on\n * older records = unknown, never \"false\"/\"0\"):\n * - `redacted` the CLI sent a signature-only / redacted block, so `text` is\n * empty but the model DID think (the UI says \"Thought 12s\").\n * - `durationMs` wall time the block took to stream, when measured.\n * - `kind` see VerseThinkingKind.\n */\n | {\n seq: number;\n at: string;\n type: 'thinking';\n turnId: string;\n text: string;\n redacted?: boolean;\n durationMs?: number;\n kind?: VerseThinkingKind;\n }\n | { seq: number; at: string; type: 'tool-use'; turnId: string; toolUseId: string; name: string; input: unknown }\n | { seq: number; at: string; type: 'tool-result'; turnId: string; toolUseId: string; output: string; isError: boolean }\n | { seq: number; at: string; type: 'usage'; turnId: string; usage: VerseUsage }\n | { seq: number; at: string; type: 'turn-done'; turnId: string; ok: boolean; nativeSessionId: string | null; durationMs: number }\n /**\n * `code` (V3.10 ADDITIVE, optional) is a stable machine key for errors the UI\n * or engine acts on — see VERSE_ERROR_CODES. Absent = uncategorised.\n */\n | { seq: number; at: string; type: 'error'; turnId: string | null; message: string; code?: string }\n | { seq: number; at: string; type: 'cancelled'; turnId: string }\n /**\n * V3.9. The CLI compacted its own conversation. Token counts are the CLI's\n * own (`compact_metadata.pre_tokens/post_tokens` on claude/grok). Codex\n * rollouts mark only THAT a compaction happened, so its counts are the last\n * `token_count` reading before the marker and the first one after it —\n * measured, but by Verse, not stated by the CLI; its `durationMs` is null.\n * Any count may be null when no reading brackets the compaction.\n */\n | {\n seq: number;\n at: string;\n type: 'compaction';\n turnId: string | null;\n trigger: 'auto' | 'manual';\n preTokens: number | null;\n postTokens: number | null;\n durationMs: number | null;\n }\n /**\n * V3.9. A context-occupancy READING that is not a usage delta — e.g. codex's\n * rollout `token_count` (exact last-call prompt size and the window the CLI\n * measured it against), polled mid-turn and read again after it. Replaces\n * the session's `contextTokens`; never summed. The engine fills\n * `autoCompactAt` for the window in force.\n */\n | {\n seq: number;\n at: string;\n type: 'context';\n turnId: string | null;\n contextTokens: number;\n contextWindow: number | null;\n exact: boolean;\n autoCompactAt?: number | null;\n /**\n * Where `contextWindow` came from. A CLI reading is `runtime`; the event\n * the engine writes after a MODE SWITCH carries the new budget's catalog\n * source, so a client never relabels a catalog figure as a measurement.\n * Absent on events from before this field existed (treat as `runtime`).\n */\n contextWindowSource?: VerseWindowSource;\n }\n // ── V3.10 TRANSIENT events ────────────────────────────────────────────────\n // Never written to the session log; fanned out to live SSE listeners only\n // (see VERSE_TRANSIENT_EVENT_TYPES for the wire rules). A reload therefore\n // never shows them — everything they convey is either ephemeral (a spinner)\n // or re-stated by a persisted event at turn end (`thinking`, `usage`).\n /** A chunk of streamed reasoning text for the in-flight thinking block. */\n | { seq: number; at: string; type: 'thinking-delta'; turnId: string; text: string }\n /**\n * The CLI reports reasoning volume without text (claude\n * `system/thinking_tokens`). An ESTIMATE, rate-limited by the adapter.\n */\n | { seq: number; at: string; type: 'thinking-progress'; turnId: string; estimatedTokens: number }\n /**\n * What the running turn is doing right now. `tool` names the running tool\n * when phase is `tool`. `outTokens`/`tokPerSec` are absent when unmeasured.\n */\n | {\n seq: number;\n at: string;\n type: 'progress';\n turnId: string;\n phase: VerseProgressPhase;\n tool?: string;\n elapsedMs: number;\n outTokens?: number;\n tokPerSec?: number;\n }\n /** A human-readable notice about the turn's plumbing (API retry, preflight, no-output watchdog). */\n | { seq: number; at: string; type: 'status'; turnId: string | null; kind: VerseStatusKind; message: string }\n // ── V3.10 PERSISTED events ────────────────────────────────────────────────\n /**\n * The engine recovered from a lost native conversation (e.g. the vendor\n * thread vanished) by starting a new native session seeded with the handoff\n * note (`how: 'handoff'`) or a bare new session (`new-native-session`).\n */\n | { seq: number; at: string; type: 'recovered'; turnId: string | null; how: VerseRecoveryHow; message: string }\n /**\n * The log hit its cap and events with `seq < droppedBefore` were dropped at\n * a TURN boundary (never mid-turn). `turnId` is always null — it is present\n * only so code reading `event.turnId` across the union keeps typechecking.\n */\n | { seq: number; at: string; type: 'history-truncated'; turnId: null; droppedBefore: number };\n\nexport type VerseEventType = VerseEvent['type'];\n\n/** V3.10. `summary` = vendor-summarised reasoning, `raw` = verbatim, `progress` = a heading/placeholder only. */\nexport type VerseThinkingKind = 'summary' | 'raw' | 'progress';\n\n/** V3.10. Phase of a running turn, carried by the transient `progress` event. */\nexport type VerseProgressPhase = 'thinking' | 'tool' | 'writing' | 'waiting';\n\n/** V3.10. What a transient `status` notice is about. */\nexport type VerseStatusKind = 'retry' | 'preflight' | 'watchdog';\n\n/** V3.10. How a `recovered` event restored the conversation. */\nexport type VerseRecoveryHow = 'new-native-session' | 'handoff';\n\n/**\n * V3.10. Known `error.code` values. `code` stays `string` on the wire so an\n * older client never rejects a newer code; these are the ones Verse acts on.\n * - `native-thread-missing` — the vendor conversation to resume no longer exists.\n * - `session-in-use` — the CLI refused because the native session id is locked.\n */\nexport const VERSE_ERROR_CODES = ['native-thread-missing', 'session-in-use'] as const;\nexport type VerseErrorCode = (typeof VERSE_ERROR_CODES)[number];\n\n/**\n * V3.10. Event types that are NEVER persisted — emitted to live SSE listeners\n * only. Wire rules (A5 server, A6 client):\n * - a transient event carries `seq` = the session's LAST PERSISTED seq (the\n * counter does not advance), so the stored log stays gap-free and a server\n * restart can never reissue a seq a client already saw;\n * - its SSE frame has NO `id:` line, so the browser's Last-Event-ID resume\n * cursor only ever points at persisted events;\n * - clients must not dedupe, store or resume by a transient event's seq.\n * Browser-safe (plain Set), imported by the web bundle.\n */\nconst TRANSIENT_EVENT_TYPE_LIST = [\n 'thinking-delta',\n 'thinking-progress',\n 'progress',\n 'status',\n] as const satisfies readonly VerseEventType[];\n\nexport const VERSE_TRANSIENT_EVENT_TYPES: ReadonlySet<VerseEventType> = new Set<VerseEventType>(TRANSIENT_EVENT_TYPE_LIST);\n\nexport type VerseTransientEventType = (typeof TRANSIENT_EVENT_TYPE_LIST)[number];\nexport type VerseTransientEvent = Extract<VerseEvent, { type: VerseTransientEventType }>;\nexport type VersePersistedEvent = Exclude<VerseEvent, { type: VerseTransientEventType }>;\n\n/** V3.10. Type guard over VERSE_TRANSIENT_EVENT_TYPES. */\nexport function isTransientVerseEvent(event: VerseEvent): event is VerseTransientEvent {\n return VERSE_TRANSIENT_EVENT_TYPES.has(event.type);\n}\n\n/**\n * Which endpoint a LOCAL seat sends its turns to.\n *\n * - `ollama` — the historical lane: the plain `claude` binary with\n * ANTHROPIC_BASE_URL pointed straight at Ollama's\n * Anthropic-compatible endpoint on :11434. Ollama\n * serialises this model architecture, so a fleet of local\n * agents on this lane is a queue (docs/LOCAL-FLEET.md).\n * - `llama-server` — the same binary pointed at the local Anthropic\n * normalising proxy that fronts llama-server. That proxy\n * is the ONLY way to reach llama-server's parallel slots\n * and the prompt-cache fix, because Qwen3.8's chat\n * template rejects Claude Code's request shape unless the\n * proxy rewrites it on the way through.\n *\n * DISPATCH ONLY. Model DISCOVERY stays on Ollama in both lanes — llama-server\n * implements neither `/api/tags` nor `/api/show`, which is where every local\n * seat's identity, context window and `tools` capability comes from.\n */\nexport type VerseLocalDispatch = 'ollama' | 'llama-server';\n\n/** What a client is told about this machine's local serving situation. */\nexport interface VerseLocalRuntimeSummary {\n /** Ollama reachable? Drives the local seats and an inline hint when false. */\n ollama: { reachable: boolean; baseUrl: string; models: string[] };\n /**\n * Where local seats DISPATCH turns, reported only when that is NOT the\n * default Ollama lane.\n *\n * Absent means `ollama`, i.e. exactly what every existing client already\n * assumes — so opting in is visible on the wire and NOT opting in changes no\n * payload at all.\n */\n dispatch?: { lane: VerseLocalDispatch; baseUrl: string };\n}\n\n/** GET /api/verse/bootstrap */\nexport interface VerseBootstrap {\n seats: VerseSeat[];\n projects: VerseProject[];\n sessions: VerseSession[];\n /** Whether POST routes are enabled on this server (`ashlr serve --allow-dispatch` / `ashlr verse`). */\n dispatchEnabled: boolean;\n localRuntime: VerseLocalRuntimeSummary;\n}\n\n/**\n * GET /api/verse/seats (V2.1)\n *\n * WHY THIS ROUTE EXISTS: `bootstrap` is a MOUNT-TIME snapshot. A client that\n * opened the app before the collector's first cycle finished would show\n * \"unknown\" forever. This is the same seat list, cheap enough to poll, and it\n * always reflects the collector's CURRENT state rather than a cached one.\n */\nexport interface VerseSeatsResponse {\n /** When this body was built. */\n sampledAt: string;\n seats: VerseSeat[];\n localRuntime: VerseBootstrap['localRuntime'];\n}\n\n/**\n * POST /api/verse/sessions\n *\n * Two spellings, never mixed (the API rejects the mix rather than silently\n * preferring one):\n * - `workspaceId` alone — the named workspace supplies primary and extras.\n * - `projectPath` (+ optional `extraRoots`) — an ad-hoc set, which is also\n * exactly the pre-workspace request shape.\n */\nexport interface VerseCreateSessionRequest {\n projectPath: string;\n seatId: string;\n model?: string;\n title?: string;\n /** V2.2 ADDITIVE. Absolute paths beyond the primary. */\n extraRoots?: string[];\n /** V2.2 ADDITIVE. Bind to a named workspace instead of naming paths. */\n workspaceId?: string;\n /**\n * SERVER-FILLED. The API resolves this from the registry once `workspaceId`\n * is validated, and never reads it off the request body — so a session can\n * not be labelled with a workspace name that is not the one it was built\n * from.\n */\n workspaceName?: string;\n /**\n * V3.9 ADDITIVE. Absent → the seat's preferred mode (preferences.json), else\n * `standard`. `expansive` on a model with no expansive budget is rejected.\n */\n contextMode?: VerseContextMode;\n /**\n * V3.9 ADDITIVE. Start this session as a handoff from an existing one. The\n * server resolves the source's title itself (never from the body) and pins\n * `handoffFrom`; the handoff TEXT is sent by the client as turn 1, after the\n * operator has read it — nothing is spent on their behalf.\n */\n handoffFromSessionId?: string;\n}\n\n/** POST /api/verse/sessions/:id/turns */\nexport interface VerseTurnRequest {\n text: string;\n}\nexport interface VerseTurnResponse {\n turnId: string;\n session: VerseSession;\n}\n\n/** GET /api/verse/sessions/:id */\nexport interface VerseSessionDetail {\n session: VerseSession;\n events: VerseEvent[];\n}\n\n/** Adapter input: how to launch one turn. Pure data, produced by the engine, consumed by the spawner. */\nexport interface VerseTurnLaunch {\n argv: string[];\n cwd: string;\n /** Extra env layered over a minimal base (PATH/HOME/TMPDIR/LANG). Never contains secrets. */\n env: Record<string, string>;\n /** Text written to stdin (codex); null when the prompt is in argv. */\n stdin: string | null;\n}\n\nexport const VERSE_MAX_TURN_TEXT_BYTES = 64 * 1024;\nexport const VERSE_MAX_EVENTS_PER_SESSION = 20_000;\nexport const VERSE_TURN_TIMEOUT_MS = 30 * 60 * 1000;\n/**\n * LAST-RESORT fallbacks, used only when neither the runtime, the seat's own\n * catalog, nor the verified per-model table (core/verse/model-windows.ts) knows\n * the model. Each mirrors what the CLI ITSELF assumes for an unknown id, so the\n * meter never claims more than the CLI will allow:\n *\n * - claude 200_000 — Claude Code's `Mg()` default for an unrecognized model.\n * Every KNOWN Claude id carries its real window (1M for the 5.x family,\n * Opus 4.8 and Sonnet 5) in the per-model table instead.\n * - codex 258_400 — 272_000 × the 95% `effective_context_window_percent`\n * every codex catalog entry carries; the figure codex's own rollouts report\n * as `model_context_window` (65,440 of 65,440 observed events).\n * - grok 500_000 — `context_window` for every grok-4.x id in the seat catalog.\n * - local 65_536 — the num_ctx the default local tag pins.\n */\nexport const VERSE_DEFAULT_CONTEXT_WINDOWS: Record<string, number> = {\n claude: 200_000,\n codex: 258_400,\n grok: 500_000,\n local: 65_536,\n};\n\n// ---------------------------------------------------------------------------\n// V3.9 context orchestration — request/response shapes (docs/VERSE-CONTEXT.md)\n// ---------------------------------------------------------------------------\n\n/** GET /api/verse/preferences — the operator's standing context choices. */\nexport interface VersePreferences {\n version: 1;\n /** Per-seat default context mode for NEW sessions. Absent = `standard`. */\n seats: Record<string, { contextMode?: VerseContextMode }>;\n /** Shared project memory. On by default; listed canonical paths opt out. */\n memory: { enabled: boolean; disabledProjects: string[] };\n /**\n * V3.10 ADDITIVE. Stream vendor-summarised reasoning on non-local seats\n * (claude `--thinking-display summarized`). Absent = on (Mason's default).\n */\n thinkingDisplay?: boolean;\n}\n\n/**\n * POST /api/verse/preferences — exactly ONE of the three forms per request, so\n * a body can never change more than the operator clicked.\n */\nexport type VersePreferencesUpdate =\n | { seatId: string; contextMode: VerseContextMode }\n | { memoryEnabled: boolean }\n | { projectPath: string; memoryEnabled: boolean };\n\n/** POST /api/verse/sessions/:id/context-mode */\nexport interface VerseContextModeRequest {\n mode: VerseContextMode;\n}\n\n/** POST /api/verse/sessions/:id/handoff-preview */\nexport interface VerseHandoffPreviewRequest {\n /**\n * Include the latest assistant message verbatim (capped) as the agent's own\n * summary — used after \"Ask this seat to summarize\" produced one.\n */\n includeLastAssistant?: boolean;\n /** Optional operator focus line, e.g. \"finish the migration of X\". ≤ 500 chars. */\n focus?: string;\n}\n\n/** Deterministic, zero-spend handoff note built from the session's event log. */\nexport interface VerseHandoffPreview {\n sourceSessionId: string;\n sourceTitle: string;\n /** The exact text to send as turn 1 of the new session. ≤ VERSE_HANDOFF_MAX_CHARS. */\n text: string;\n stats: {\n chars: number;\n /** chars / 4, rounded up — the same estimator the fit badges use. */\n estTokens: number;\n turnsCovered: number;\n filesTouched: number;\n /** Sections dropped to respect the cap, by name; empty when nothing was cut. */\n truncated: string[];\n };\n}\n\nexport const VERSE_HANDOFF_MAX_CHARS = 12_000;\n\n/**\n * The canned turn behind \"Ask this seat to summarize first\". Shared by the UI\n * (which sends it as an ordinary turn through the normal spend chokepoint) and\n * the handoff builder (which must NOT carry it into the new session as the\n * operator's \"latest ask\" — the new chat would otherwise be told to write a\n * handoff note instead of continuing the work).\n *\n * Written so the reply is useful as turn 1 of a session that has NONE of this\n * context. It asks for no tool use on purpose: a summary that starts editing\n * files is not a summary, and a read-only turn is also the cheapest one.\n */\nexport const VERSE_HANDOFF_SUMMARY_REQUEST = [\n 'This conversation is about to continue in a fresh session that has none of its context.',\n 'Write the handoff note that new session should start from. Do not edit files or run commands for this — only write the note.',\n '',\n 'Cover, concretely:',\n '- The goal, and what \"done\" looks like.',\n '- Decisions made so far, each with the reason it was made.',\n '- Current state: what is finished, what is half-done, what is untested.',\n '- Files changed and anything not yet committed.',\n '- How to verify the work (exact commands).',\n '- Open questions, risks, and approaches already tried that did not work.',\n '',\n 'Keep it under 600 words. Prefer file paths and commands over prose.',\n].join('\\n');\n\n/** GET /api/verse/context-fit — how big the reachable code is, in tokens. */\nexport interface VerseContextFitRoot {\n path: string;\n /** Tracked text files counted (git ls-files, binaries and >1 MB files skipped). */\n files: number;\n bytes: number;\n estTokens: number;\n /** True when the scan hit its file or time cap; estTokens is then a floor. */\n truncated: boolean;\n}\n\nexport interface VerseContextFit {\n roots: VerseContextFitRoot[];\n totalEstTokens: number;\n /** Always 'bytes/4' today; named so a better estimator can be introduced honestly. */\n estimator: 'bytes/4';\n sampledAt: string;\n}\n\n/**\n * Per-model verdict for a working set (see context-math.ts `fitVerdict`):\n * fits in standard, tight in standard, fits only in expansive, or too big for\n * any single context (split the work).\n */\nexport type VerseFitVerdict = 'fits' | 'tight' | 'expansive' | 'split';\n\n/** GET /api/verse/search?q=&limit= — keyword search over past sessions. Zero spend. */\nexport interface VerseSearchHit {\n sessionId: string;\n title: string;\n projectPath: string;\n engine: VerseEngine;\n seq: number;\n at: string;\n kind: 'user' | 'assistant';\n /** ≤ 240 chars around the first match, whitespace-collapsed. */\n snippet: string;\n score: number;\n}\n\nexport interface VerseSearchResponse {\n query: string;\n hits: VerseSearchHit[];\n /** Sessions actually scanned (the scan is bounded; see session-search.ts). */\n scannedSessions: number;\n truncated: boolean;\n}\n\n/** GET/POST /api/verse/memory — shared project memory for one project. */\nexport interface VerseProjectMemory {\n projectPath: string;\n enabled: boolean;\n /** Contents of MEMORY.md ('' when absent). */\n content: string;\n bytes: number;\n updatedAt: string | null;\n /** Other files the agents created in the memory directory (names only). */\n files: string[];\n /**\n * Present (true) only when `content` as SENT differs from the bytes on disk:\n * the public-JSON sanitizer rewrote the home path to `~` or replaced a\n * secret-looking value with `[REDACTED]`. The file itself is untouched; a\n * save that would write placeholders over real values is refused (409\n * VERSE_MEMORY_REDACTED), so the editor must say so before the operator types.\n */\n contentSanitized?: boolean;\n}\n\n/** POST /api/verse/memory */\nexport interface VerseProjectMemoryWrite {\n projectPath: string;\n content: string;\n}\n\nexport const VERSE_MEMORY_MAX_BYTES = 64 * 1024;\n\n/**\n * POST /api/verse/memory's own JSON body cap: JSON escaping can double the\n * content (every newline becomes `\\\\n`), plus room for the other fields. Every\n * other route keeps the 64 KiB default. Shared so the browser's pre-check can\n * never refuse a save the server would accept.\n */\nexport const VERSE_MEMORY_BODY_MAX_BYTES = 2 * VERSE_MEMORY_MAX_BYTES + 8 * 1024;\n\n/** Cap on the memory block appended to each session's system prompt. */\nexport const VERSE_MEMORY_BLOCK_MAX_BYTES = 6 * 1024;\n","/**\n * routes/verse/verse-store.ts — per-session transcript state for the Verse\n * console. Framework-free (useSyncExternalStore glue lives in\n * useVerseSession.ts, the live stream in session-stream.ts), same split as\n * data/cache.ts + data/hooks.ts.\n *\n * One entry per session id holds the ordered, seq-deduplicated event log,\n * the latest session record we know of, the stream connection state, and —\n * V3.10 — the LIVE state of a running turn (reasoning streaming in, what the\n * turn is doing, retry/watchdog notices), which is fed by transient events\n * that are never persisted and never enter the event log.\n * Snapshots are replaced wholesale on every change (Object.is semantics —\n * see DESIGN.md §3 for the bug that rule prevents).\n *\n * V3.10 DATA PATH. The previous store merged every event with a Map + spread\n * + sort and told every subscriber about it: replaying 5k events took 2.45 s\n * and 10k took 17 s, and every streamed token re-rendered the whole Chat\n * section. Now:\n *\n * - `applyVerseEvents` applies a BATCH: an event past the newest seq is a\n * plain append (one array copy per batch, not per event), an older one\n * is binary-searched (duplicate → dropped, gap → inserted in place);\n * - subscribers are per session (`subscribeVerseSession`) and read one of\n * three snapshots that change independently:\n * · the HEAD (`getVerseSessionHead`) — session record, stream state\n * and the event log as of the last STRUCTURAL event. A text-delta\n * alone does not republish it, so the sidebar, header and resources\n * panel do not re-render per token;\n * · the TRANSCRIPT (`getVerseTranscript`, verse-transcript.ts) —\n * derived lazily, per turn segment, with unchanged turns returned as\n * the same objects so the renderer can skip them;\n * · the LIVE state (`getVerseLive`) — transient signals only.\n * - the stream (session-stream.ts) calls `applyVerseEvents` once per\n * animation frame, so a burst of frames costs one render.\n *\n * The transcript derivation (`buildTranscript`, `getVerseTranscript`,\n * `groupTranscriptItems`) lives in verse-transcript.ts: this store is on the\n * chat first-paint path and the derivation is not (only lazy chunks render a\n * transcript). Its types are re-exported below so type imports keep working;\n * never re-export a VALUE from there, or the derivation rides along again.\n */\nimport type { VerseEvent, VerseSession, VerseUsage } from '../../data/api-types.js';\nimport {\n isTransientVerseEvent,\n type VerseProgressPhase,\n type VerseStatusKind,\n type VerseTransientEvent,\n type VerseWindowSource,\n} from '../../../core/verse/types.js';\n// compaction-point, not context-math: this store is on the chat first-paint\n// path and needs only this formula (context-math re-exports it).\nimport { reconcileAutoCompactAt } from '../../../core/verse/compaction-point.js';\n\nexport type {\n BuildTranscriptOptions,\n ToolGroupItem,\n ToolGroupMember,\n Transcript,\n TranscriptCache,\n TranscriptItem,\n TranscriptRenderItem,\n TranscriptSegment,\n} from './verse-transcript.js';\n\nexport type VerseStreamState = 'idle' | 'connecting' | 'open' | 'reconnecting' | 'closed';\n\n// ---------------------------------------------------------------------------\n// Live (transient) state\n// ---------------------------------------------------------------------------\n\n/** The reasoning block currently streaming in (`thinking-delta` / `thinking-progress`). */\nexport interface VerseLiveThinking {\n turnId: string;\n /** Streamed text so far; empty when the CLI reports only a token estimate. */\n text: string;\n /** Client clock (ms) when this block's first signal arrived. */\n startedAt: number;\n /** Latest `thinking-progress` estimate; null when the CLI sent none (unknown, never 0). */\n estimatedTokens: number | null;\n}\n\nexport interface VerseLiveProgress {\n phase: VerseProgressPhase;\n tool: string | null;\n /** Server-measured turn wall time when the frame was sent. */\n elapsedMs: number;\n outTokens: number | null;\n tokPerSec: number | null;\n /** Client clock (ms) the frame arrived, so elapsed can keep counting between frames. */\n receivedAt: number;\n}\n\nexport interface VerseLiveNotice {\n kind: VerseStatusKind;\n message: string;\n at: string;\n receivedAt: number;\n}\n\nexport interface VerseLiveState {\n /** The running turn these signals belong to; null when none is running. */\n turnId: string | null;\n /** Client clock (ms) the running turn started, from its `turn-started` stamp when parseable. */\n startedAt: number | null;\n progress: VerseLiveProgress | null;\n thinking: VerseLiveThinking | null;\n /** The latest plumbing notice (API retry, preflight, no-output watchdog); cleared when output resumes. */\n notice: VerseLiveNotice | null;\n /** Last turn that settled, so a late transient frame for it cannot resurrect the live line. */\n settledTurnId: string | null;\n}\n\n/** What this tab measured about a reasoning block while it streamed — keyed by the persisted `thinking` event's seq. */\nexport interface VerseThinkingStat {\n durationMs: number | null;\n estimatedTokens: number | null;\n}\n\nconst EMPTY_LIVE: VerseLiveState = {\n turnId: null,\n startedAt: null,\n progress: null,\n thinking: null,\n notice: null,\n settledTurnId: null,\n};\n\n// ---------------------------------------------------------------------------\n// Entries, heads and subscriptions\n// ---------------------------------------------------------------------------\n\nexport interface VerseSessionState {\n sessionId: string;\n session: VerseSession | null;\n events: VerseEvent[];\n /** Highest PERSISTED seq held — the resume cursor. Transient frames never move it. */\n lastSeq: number;\n loaded: boolean;\n loadError: string | null;\n stream: VerseStreamState;\n /** V3.10 transient signals of the running turn. */\n live: VerseLiveState;\n}\n\n/**\n * Everything about a session EXCEPT its live signals, republished only on\n * structural change. `events` is the log as of the last non-`text-delta`\n * event: streamed tokens reach the transcript through its own subscription,\n * so a consumer of the head (session record, meters, activity stats) never\n * re-renders per token. Code that needs every delta reads\n * `getVerseSessionState` or `getVerseTranscript` instead.\n */\nexport type VerseSessionHead = Omit<VerseSessionState, 'live'>;\n\nconst EMPTY: Omit<VerseSessionState, 'sessionId'> = {\n session: null,\n events: [],\n lastSeq: 0,\n loaded: false,\n loadError: null,\n stream: 'idle',\n live: EMPTY_LIVE,\n};\n\nconst sessions = new Map<string, VerseSessionState>();\nconst heads = new Map<string, VerseSessionHead>();\nconst thinkingStats = new Map<string, Map<number, VerseThinkingStat>>();\nconst listeners = new Set<() => void>();\nconst sessionListeners = new Map<string, Set<() => void>>();\n\nexport type VerseStoreLifecycle = { kind: 'reset' } | { kind: 'forget'; sessionId: string };\nconst lifecycleListeners = new Set<(event: VerseStoreLifecycle) => void>();\n\nfunction notify(sessionId: string | null): void {\n if (sessionId !== null) {\n const scoped = sessionListeners.get(sessionId);\n if (scoped) for (const l of [...scoped]) l();\n } else {\n for (const set of [...sessionListeners.values()]) for (const l of [...set]) l();\n }\n for (const l of [...listeners]) l();\n}\n\n/** Every change to every session. Prefer `subscribeVerseSession` in components. */\nexport function subscribeVerseStore(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\n/** Changes to ONE session only — what a component showing that session subscribes to. */\nexport function subscribeVerseSession(sessionId: string, listener: () => void): () => void {\n let set = sessionListeners.get(sessionId);\n if (!set) {\n set = new Set();\n sessionListeners.set(sessionId, set);\n }\n set.add(listener);\n return () => {\n const current = sessionListeners.get(sessionId);\n if (!current) return;\n current.delete(listener);\n if (current.size === 0) sessionListeners.delete(sessionId);\n };\n}\n\n/**\n * Reset / forget notifications, so the live-stream registry can close the\n * connection of a chat that was deleted or of a store that was cleared on\n * logout (and so tests never inherit a previous test's stream).\n */\nexport function subscribeVerseStoreLifecycle(listener: (event: VerseStoreLifecycle) => void): () => void {\n lifecycleListeners.add(listener);\n return () => lifecycleListeners.delete(listener);\n}\n\nfunction headOf(state: VerseSessionState): VerseSessionHead {\n return {\n sessionId: state.sessionId,\n session: state.session,\n events: state.events,\n lastSeq: state.lastSeq,\n loaded: state.loaded,\n loadError: state.loadError,\n stream: state.stream,\n };\n}\n\nfunction entryFor(sessionId: string): VerseSessionState {\n let e = sessions.get(sessionId);\n if (!e) {\n e = { sessionId, ...EMPTY };\n sessions.set(sessionId, e);\n heads.set(sessionId, headOf(e));\n }\n return e;\n}\n\n/**\n * Store `next` and republish the head when anything it carries changed.\n * `structural` = the event log gained something other than a text-delta.\n */\nfunction commit(sessionId: string, next: VerseSessionState, structural: boolean): void {\n sessions.set(sessionId, next);\n const head = heads.get(sessionId);\n if (\n !head || structural || head.session !== next.session || head.loaded !== next.loaded ||\n head.loadError !== next.loadError || head.stream !== next.stream\n ) {\n heads.set(sessionId, headOf(next));\n }\n}\n\nfunction patch(sessionId: string, delta: Partial<VerseSessionState>, structural = false): void {\n const current = entryFor(sessionId);\n commit(sessionId, { ...current, ...delta }, structural);\n notify(sessionId);\n}\n\nconst NONE: VerseSessionState = { sessionId: '', ...EMPTY };\nconst NONE_HEAD: VerseSessionHead = headOf(NONE);\n\n/** Stable reference until the entry changes, so useSyncExternalStore is happy. */\nexport function getVerseSessionState(sessionId: string | null): VerseSessionState {\n if (!sessionId) return NONE;\n return entryFor(sessionId);\n}\n\n/** The head snapshot (see VerseSessionHead) — stable across text-deltas. */\nexport function getVerseSessionHead(sessionId: string | null): VerseSessionHead {\n if (!sessionId) return NONE_HEAD;\n entryFor(sessionId);\n return heads.get(sessionId)!;\n}\n\n/** Live signals of the running turn; the same object until one of them changes. */\nexport function getVerseLive(sessionId: string | null): VerseLiveState {\n if (!sessionId) return EMPTY_LIVE;\n return entryFor(sessionId).live;\n}\n\n/**\n * What this tab measured about the session's reasoning blocks while they\n * streamed (read by verse-transcript.ts when it derives the transcript).\n */\nexport function getVerseThinkingStats(sessionId: string): ReadonlyMap<number, VerseThinkingStat> | undefined {\n return thinkingStats.get(sessionId);\n}\n\n/** Merge a fetched detail (session + full event log) into the entry. Events\n * already known (same seq) are kept once; the union stays sorted by seq. The\n * detail fetch can race a live stream, so a `turn-done` that streamed in\n * meanwhile wins over the older `running` snapshot. A refetch that brings\n * nothing new changes nothing — no re-render. */\nexport function seedVerseSession(sessionId: string, session: VerseSession, events: readonly VerseEvent[]): void {\n const current = entryFor(sessionId);\n const merged = mergeEvents(current.events, events);\n const settled = settledStatus(session, merged);\n const nextSession = current.session && sameSession(current.session, settled) ? current.session : settled;\n const eventsChanged = merged !== current.events;\n const live = eventsChanged || nextSession !== current.session ? liveFromLog(current.live, merged, nextSession) : current.live;\n if (!eventsChanged && nextSession === current.session && current.loaded && current.loadError === null && live === current.live) return;\n commit(sessionId, {\n ...current,\n session: nextSession,\n events: merged,\n lastSeq: merged.length ? Math.max(current.lastSeq, merged[merged.length - 1]!.seq) : current.lastSeq,\n loaded: true,\n loadError: null,\n live,\n }, eventsChanged);\n notify(sessionId);\n}\n\nexport function setVerseLoadError(sessionId: string, message: string): void {\n patch(sessionId, { loadError: message, loaded: true });\n}\n\nexport function setVerseStreamState(sessionId: string, stream: VerseStreamState): void {\n if (entryFor(sessionId).stream === stream) return;\n patch(sessionId, { stream });\n}\n\n/**\n * Replace the session record (after a turn POST / rename / list refresh).\n * `turnId` is the turn the snapshot claims is running (POST …/turns returns\n * it): when the log already holds that turn's `turn-done`/`cancelled` — a\n * spawn failure settles in the same tick as the 202 — the snapshot is stale\n * and must not drag the composer back to running.\n */\nexport function setVerseSession(sessionId: string, session: VerseSession, turnId?: string): void {\n const current = entryFor(sessionId);\n patch(sessionId, { session: settledStatus(session, current.events, turnId) });\n}\n\n/**\n * Reconcile a `running` snapshot against the event log. Without a `turnId`\n * the running turn is the last `user-message`/`turn-started` in the log; a\n * later `turn-done`/`cancelled` means the server already settled it. With a\n * `turnId`, only that turn's terminal event counts (its `user-message` may\n * not have streamed in yet, so a previous turn's `turn-done` proves nothing).\n * Status follows the same rules applyVerseEvent uses: cancelled → idle,\n * `turn-done ok:false` → error only when an `error` event was logged for it.\n */\nexport function settledStatus(session: VerseSession, events: readonly VerseEvent[], turnId?: string): VerseSession {\n if (session.status !== 'running') return session;\n let anchorSeq = -1;\n let anchorTurn: string | null = turnId ?? null;\n if (!turnId) {\n for (const e of events) {\n if (e.type === 'user-message' || e.type === 'turn-started') {\n anchorSeq = e.seq;\n anchorTurn = e.turnId;\n }\n }\n if (anchorTurn === null) return session;\n }\n let terminal: Extract<VerseEvent, { type: 'turn-done' | 'cancelled' }> | null = null;\n let lastError: string | null = null;\n for (const e of events) {\n if (e.seq <= anchorSeq) continue;\n if (e.type === 'error' && e.turnId === anchorTurn) lastError = e.message;\n if ((e.type === 'turn-done' || e.type === 'cancelled') && e.turnId === anchorTurn) terminal = e;\n }\n if (!terminal) return session;\n const failed = terminal.type === 'turn-done' && !terminal.ok && lastError !== null;\n return {\n ...session,\n status: failed ? 'error' : 'idle',\n lastError: failed ? lastError : null,\n updatedAt: terminal.at > session.updatedAt ? terminal.at : session.updatedAt,\n };\n}\n\n/** Optimistic status flip (e.g. right after POST …/turns returns 202). */\nexport function setVerseSessionStatus(sessionId: string, status: VerseSession['status']): void {\n const current = entryFor(sessionId);\n if (!current.session || current.session.status === status) return;\n patch(sessionId, { session: { ...current.session, status } });\n}\n\nexport interface VerseApplyResult {\n /** Persisted events newly added to the log (duplicates excluded). */\n applied: number;\n /** A newly added event settled a turn (`turn-done` / `cancelled` / `error`) — the lists may be stale. */\n settled: boolean;\n /** A transient frame changed the live state. */\n liveChanged: boolean;\n}\n\n/**\n * Apply a BATCH of live events in arrival order, then notify once.\n *\n * Persisted events: duplicates (a stream that replays from the start, or a\n * resume that overlaps the detail fetch) are dropped by seq; an event past\n * the newest seq is appended; an older unseen one is inserted in place.\n * Session-level side effects: `usage` and `context` update the live context\n * meter, `compaction` counts a native compaction, `turn-started` flips\n * status to running, `turn-done`/`cancelled`/`error` settle it, and a codex\n * `turn-done.nativeSessionId` is captured.\n *\n * Transient events (VERSE_TRANSIENT_EVENT_TYPES) never enter the log and\n * never move `lastSeq`: they carry the last PERSISTED seq, so deduping them\n * by seq would drop every one of them. They only update `live`.\n */\nexport function applyVerseEvents(sessionId: string, incoming: readonly VerseEvent[]): VerseApplyResult {\n const current = entryFor(sessionId);\n let events: VerseEvent[] = current.events;\n let copied = false;\n let lastSeq = current.lastSeq;\n let session = current.session;\n let live = current.live;\n let applied = 0;\n let settled = false;\n let structural = false;\n let liveChanged = false;\n const now = Date.now();\n\n for (const event of incoming) {\n if (isTransientVerseEvent(event)) {\n const next = applyTransient(live, event, now);\n if (next !== live) {\n live = next;\n liveChanged = true;\n }\n continue;\n }\n if (!Number.isFinite(event.seq)) continue;\n const tail = events.length > 0 ? events[events.length - 1]!.seq : -Infinity;\n if (event.seq > tail) {\n if (!copied) {\n events = events.slice();\n copied = true;\n }\n events.push(event);\n } else {\n const at = seqIndex(events, event.seq);\n if (at.found) continue;\n if (!copied) {\n events = events.slice();\n copied = true;\n }\n events.splice(at.index, 0, event);\n }\n applied += 1;\n lastSeq = Math.max(lastSeq, event.seq);\n if (event.type !== 'text-delta') structural = true;\n if (event.type === 'turn-done' || event.type === 'cancelled' || event.type === 'error') settled = true;\n if (session) session = sessionAfter(session, event);\n const nextLive = livePersisted(live, event, now, sessionId);\n if (nextLive !== live) live = nextLive;\n }\n\n if (applied === 0 && !liveChanged) return { applied: 0, settled: false, liveChanged: false };\n commit(sessionId, { ...current, events, lastSeq, session, live }, structural);\n notify(sessionId);\n return { applied, settled, liveChanged };\n}\n\n/**\n * Apply one live event (the single-event form of applyVerseEvents). Returns\n * true when the log gained the event, or — for a transient frame — when the\n * live state changed.\n */\nexport function applyVerseEvent(sessionId: string, event: VerseEvent): boolean {\n const result = applyVerseEvents(sessionId, [event]);\n return result.applied > 0 || result.liveChanged;\n}\n\n/** A persisted event's effect on the session record (the old applyVerseEvent switch). */\nfunction sessionAfter(session: VerseSession, event: VerseEvent): VerseSession {\n switch (event.type) {\n case 'turn-started':\n return { ...session, status: 'running', lastError: null, updatedAt: event.at };\n case 'usage':\n return { ...session, usage: applyUsageFrame(session, event.usage), updatedAt: event.at };\n case 'context':\n return { ...session, usage: applyContextReading(session, event), updatedAt: event.at };\n case 'compaction':\n // Counted exactly as the server counts it (session-engine), so a reload\n // shows the same number the live stream did. Occupancy is NOT touched\n // here: the next `usage`/`context` reading is the measurement.\n return { ...session, compactionCount: (session.compactionCount ?? 0) + 1, updatedAt: event.at };\n case 'turn-done':\n return {\n ...session,\n status: event.ok ? 'idle' : session.lastError ? 'error' : 'idle',\n turnCount: session.turnCount + 1,\n nativeSessionId: event.nativeSessionId ?? session.nativeSessionId,\n updatedAt: event.at,\n };\n case 'error':\n return { ...session, status: 'error', lastError: event.message, updatedAt: event.at };\n case 'cancelled':\n return { ...session, status: 'idle', updatedAt: event.at };\n default:\n return session;\n }\n}\n\nfunction stampMs(at: string, fallback: number): number {\n const parsed = Date.parse(at);\n return Number.isFinite(parsed) ? parsed : fallback;\n}\n\n/** Enter (or stay in) the live context of `turnId`. */\nfunction liveForTurn(live: VerseLiveState, turnId: string, startedAt: number): VerseLiveState {\n if (live.turnId === turnId) return live;\n return { ...EMPTY_LIVE, turnId, startedAt, settledTurnId: live.settledTurnId };\n}\n\nfunction applyTransient(live: VerseLiveState, event: VerseTransientEvent, now: number): VerseLiveState {\n // A frame for a turn that already settled (late delivery after turn-done)\n // must not bring the live line back.\n if (event.turnId !== null && event.turnId === live.settledTurnId) return live;\n const base = event.turnId !== null ? liveForTurn(live, event.turnId, now) : live;\n switch (event.type) {\n case 'thinking-delta': {\n if (event.text.length === 0) return base;\n const block = base.thinking && base.thinking.turnId === event.turnId\n ? { ...base.thinking, text: base.thinking.text + event.text }\n : { turnId: event.turnId, text: event.text, startedAt: now, estimatedTokens: null };\n return { ...base, thinking: block, notice: null };\n }\n case 'thinking-progress': {\n const block = base.thinking && base.thinking.turnId === event.turnId\n ? { ...base.thinking, estimatedTokens: event.estimatedTokens }\n : { turnId: event.turnId, text: '', startedAt: now, estimatedTokens: event.estimatedTokens };\n return { ...base, thinking: block };\n }\n case 'progress':\n return {\n ...base,\n progress: {\n phase: event.phase,\n tool: typeof event.tool === 'string' && event.tool.length > 0 ? event.tool : null,\n elapsedMs: event.elapsedMs,\n outTokens: event.outTokens ?? null,\n tokPerSec: event.tokPerSec ?? null,\n receivedAt: now,\n },\n };\n case 'status':\n return { ...base, notice: { kind: event.kind, message: event.message, at: event.at, receivedAt: now } };\n default:\n return base;\n }\n}\n\n/** A persisted event's effect on the live state. */\nfunction livePersisted(live: VerseLiveState, event: VerseEvent, now: number, sessionId: string): VerseLiveState {\n switch (event.type) {\n case 'turn-started':\n if (event.turnId === live.settledTurnId) return live;\n return live.turnId === event.turnId\n ? { ...live, startedAt: stampMs(event.at, live.startedAt ?? now) }\n : { ...EMPTY_LIVE, turnId: event.turnId, startedAt: stampMs(event.at, now), settledTurnId: live.settledTurnId };\n case 'thinking': {\n // The persisted block supersedes the streamed one. What this tab\n // measured while it streamed (duration, the CLI's token estimate) is\n // kept beside the log, by seq, so the finished block can still say\n // \"Thought 12s · ~1.8k tok\" — the event itself is immutable.\n const streamed = live.thinking && live.thinking.turnId === event.turnId ? live.thinking : null;\n if (streamed) {\n let stats = thinkingStats.get(sessionId);\n if (!stats) {\n stats = new Map();\n thinkingStats.set(sessionId, stats);\n }\n stats.set(event.seq, {\n durationMs: typeof event.durationMs === 'number' ? event.durationMs : Math.max(0, now - streamed.startedAt),\n estimatedTokens: streamed.estimatedTokens,\n });\n }\n return streamed || live.notice ? { ...live, thinking: streamed ? null : live.thinking, notice: null } : live;\n }\n case 'text-delta':\n case 'assistant-message':\n case 'tool-use':\n case 'tool-result':\n // Output resumed: a retry went through, the watchdog's silence ended.\n return live.notice && (event.turnId === live.turnId || live.turnId === null) ? { ...live, notice: null } : live;\n case 'turn-done':\n case 'cancelled':\n return { ...EMPTY_LIVE, settledTurnId: event.turnId };\n default:\n return live;\n }\n}\n\n/**\n * Live state implied by a freshly merged log: a chat opened (or reloaded)\n * mid-turn still shows its live line, timed from the turn's own stamp; a\n * log whose last turn is settled shows none.\n */\nfunction liveFromLog(live: VerseLiveState, events: readonly VerseEvent[], session: VerseSession | null): VerseLiveState {\n let openTurn: Extract<VerseEvent, { type: 'turn-started' }> | null = null;\n let settledTurnId: string | null = live.settledTurnId;\n for (let i = events.length - 1; i >= 0; i -= 1) {\n const e = events[i]!;\n if (e.type === 'turn-done' || e.type === 'cancelled') {\n settledTurnId = e.turnId;\n break;\n }\n if (e.type === 'turn-started') {\n openTurn = e;\n break;\n }\n }\n if (!openTurn) {\n if (live.turnId !== null && live.turnId === settledTurnId) return { ...EMPTY_LIVE, settledTurnId };\n // No turn-started in the log yet (the POST just went out): keep whatever\n // the stream already told us; nothing in the log contradicts it.\n return live.settledTurnId === settledTurnId ? live : { ...live, settledTurnId };\n }\n if (session && session.status !== 'running') return live.turnId === null ? live : { ...EMPTY_LIVE, settledTurnId: live.settledTurnId };\n if (live.turnId === openTurn.turnId) return live;\n return { ...EMPTY_LIVE, turnId: openTurn.turnId, startedAt: stampMs(openTurn.at, Date.now()), settledTurnId: live.settledTurnId };\n}\n\n/**\n * Fold one `usage` frame into the session record. The frame carries THIS\n * turn's counts; the record keeps the session totals (server: session-engine\n * applyUsage). Occupancy and the window are live values, not sums.\n *\n * V3.9 fields are adopted only when the frame carries them (spread-when-\n * present), so a pre-3.9 server's frames leave the record's shape unchanged.\n * The one exception is a local seat: Verse SETS that window\n * (`CLAUDE_CODE_MAX_CONTEXT_TOKENS`), so a window a frame reports without\n * provenance is not allowed to replace it — the server ignores runtime\n * windows on local for the same reason.\n */\nexport function applyUsageFrame(session: VerseSession, frame: VerseUsage): VerseUsage {\n const prev = session.usage;\n const next: VerseUsage = {\n ...prev,\n inputTokens: prev.inputTokens + frame.inputTokens,\n outputTokens: prev.outputTokens + frame.outputTokens,\n cacheReadTokens: prev.cacheReadTokens + frame.cacheReadTokens,\n cacheCreationTokens: prev.cacheCreationTokens + frame.cacheCreationTokens,\n contextTokens: frame.contextTokens,\n };\n const frameWindow = typeof frame.contextWindow === 'number' && frame.contextWindow > 0 ? frame.contextWindow : null;\n const trusted = frame.contextWindowSource !== undefined || session.engine !== 'local';\n if (frameWindow !== null && trusted) next.contextWindow = frameWindow;\n if (frame.contextWindowSource !== undefined) next.contextWindowSource = frame.contextWindowSource;\n if (frame.autoCompactAt !== undefined) next.autoCompactAt = frame.autoCompactAt;\n // The server marks an EXACT reading by OMITTING the key (it only writes\n // `false`), so a resolved frame without it must clear an earlier \"≤\" — a\n // frame from a pre-3.9 server (no V3.9 fields at all) leaves it alone.\n if (frame.contextTokensExact === false) next.contextTokensExact = false;\n else if (frame.contextWindowSource !== undefined) delete next.contextTokensExact;\n return next;\n}\n\n/** The provenance values a frame may carry; anything else is ignored, never stored. */\nconst WINDOW_SOURCES: ReadonlySet<string> = new Set<VerseWindowSource>(['runtime', 'provider-catalog', 'cli-catalog', 'documented', 'fallback']);\n\nfunction frameWindowSource(value: unknown): VerseWindowSource | null {\n return typeof value === 'string' && WINDOW_SOURCES.has(value) ? (value as VerseWindowSource) : null;\n}\n\n/**\n * Apply a `context` reading: it REPLACES occupancy (never summed). When it\n * names a window, the window's provenance is the one the EVENT states\n * (`contextWindowSource`, V3.9): the engine also emits a `context` event\n * after a MODE SWITCH, carrying the new mode's CATALOG budget, and stamping\n * that 'runtime' made the tooltip say \"reported by the CLI on the last turn\"\n * for a number no CLI reported — and pinned it ahead of later catalog\n * corrections (sessionContextBudget precedence 1). Only an event from a\n * server that predates the field (no source at all) is taken as a runtime\n * reading, which is what every such event was.\n *\n * The engine fills `autoCompactAt` for the window in force; a frame without\n * it (an older server) is reconciled from the previous budget rather than\n * left pointing at a compaction point that belonged to a different window.\n */\nexport function applyContextReading(\n session: VerseSession,\n event: Extract<VerseEvent, { type: 'context' }>,\n): VerseUsage {\n const prev = session.usage;\n const next: VerseUsage = {\n ...prev,\n contextTokens: Math.max(0, Math.floor(event.contextTokens)),\n contextTokensExact: event.exact,\n };\n const window = typeof event.contextWindow === 'number' && event.contextWindow > 0 ? event.contextWindow : null;\n const stated = frameWindowSource(event.contextWindowSource);\n // Local windows are SET by Verse (CLAUDE_CODE_MAX_CONTEXT_TOKENS), not\n // measured: a window without provenance is not allowed to move one (see\n // applyUsageFrame). A V3.9 event that states its source is the engine's\n // own record of the window it just launched with, so it is adopted.\n if (window === null || (session.engine === 'local' && stated === null)) {\n if (event.autoCompactAt !== undefined && event.autoCompactAt !== null) next.autoCompactAt = event.autoCompactAt;\n return next;\n }\n next.contextWindow = window;\n next.contextWindowSource = stated ?? 'runtime';\n if (event.autoCompactAt !== undefined) {\n next.autoCompactAt = event.autoCompactAt;\n } else if (window !== prev.contextWindow) {\n next.autoCompactAt = reconcileAutoCompactAt({\n engine: session.engine,\n runtimeWindow: window,\n budget: prev.contextWindow ? { contextWindow: prev.contextWindow, autoCompactAt: prev.autoCompactAt ?? null } : null,\n });\n }\n return next;\n}\n\n/**\n * When this chat last talked to its provider — the newest `usage`,\n * `turn-done`, `cancelled` or TURN-attributed `context` event — or null when\n * the log holds none (no turn yet, or the log is not loaded).\n *\n * WHY NOT `session.updatedAt`: the idle-cache advice (\"the prompt cache has\n * likely expired\") asks how long the PROVIDER has gone without a request,\n * and `updatedAt` moves on things that never reach a provider: a rename, a\n * context-mode switch (whose `context` event has `turnId: null`), a reload's\n * record save. Measured from `updatedAt`, one rename silenced the warning\n * for another hour while the cache stayed cold.\n */\nexport function lastTurnActivityAt(events: readonly VerseEvent[]): string | null {\n let latest: string | null = null;\n for (const e of events) {\n const turnActivity = e.type === 'usage' || e.type === 'turn-done' || e.type === 'cancelled' ||\n (e.type === 'context' && e.turnId !== null);\n if (turnActivity && typeof e.at === 'string' && (latest === null || e.at > latest)) latest = e.at;\n }\n return latest;\n}\n\nexport function forgetVerseSession(sessionId: string): void {\n const existed = sessions.delete(sessionId);\n heads.delete(sessionId);\n thinkingStats.delete(sessionId);\n for (const l of [...lifecycleListeners]) l({ kind: 'forget', sessionId });\n if (existed) notify(sessionId);\n}\n\n/** Test/logout hygiene. */\nexport function resetVerseStore(): void {\n sessions.clear();\n heads.clear();\n thinkingStats.clear();\n for (const l of [...lifecycleListeners]) l({ kind: 'reset' });\n notify(null);\n}\n\n/** Position of `seq` in a seq-sorted log (binary search). */\nfunction seqIndex(events: readonly VerseEvent[], seq: number): { found: boolean; index: number } {\n let lo = 0;\n let hi = events.length;\n while (lo < hi) {\n const mid = (lo + hi) >>> 1;\n const s = events[mid]!.seq;\n if (s === seq) return { found: true, index: mid };\n if (s < seq) lo = mid + 1;\n else hi = mid;\n }\n return { found: false, index: lo };\n}\n\n/** Sorted by seq, one event per seq (first occurrence wins), non-finite seqs dropped. */\nfunction normalizeEvents(events: readonly VerseEvent[]): VerseEvent[] {\n let ascending = true;\n for (let i = 0; i < events.length; i += 1) {\n const seq = events[i]!.seq;\n if (!Number.isFinite(seq) || (i > 0 && seq <= events[i - 1]!.seq)) {\n ascending = false;\n break;\n }\n }\n if (ascending) return events.slice();\n const bySeq = new Map<number, VerseEvent>();\n for (const e of events) if (Number.isFinite(e.seq) && !bySeq.has(e.seq)) bySeq.set(e.seq, e);\n return [...bySeq.values()].sort((a, b) => a.seq - b.seq);\n}\n\n/**\n * Union of two logs by seq, existing events winning. Returns `existing`\n * itself when `incoming` adds nothing, so a refetch that brought no news is\n * not a change. Linear in the two lengths (both are seq-sorted).\n */\nfunction mergeEvents(existing: VerseEvent[], incomingRaw: readonly VerseEvent[]): VerseEvent[] {\n if (incomingRaw.length === 0) return existing;\n const incoming = normalizeEvents(incomingRaw);\n if (incoming.length === 0) return existing;\n if (existing.length === 0) return incoming;\n if (incoming[0]!.seq > existing[existing.length - 1]!.seq) return existing.concat(incoming);\n const out: VerseEvent[] = [];\n let added = 0;\n let i = 0;\n let j = 0;\n while (i < existing.length || j < incoming.length) {\n const a = existing[i];\n const b = incoming[j];\n if (b === undefined || (a !== undefined && a.seq < b.seq)) {\n out.push(a!);\n i += 1;\n } else if (a === undefined || b.seq < a.seq) {\n out.push(b);\n added += 1;\n j += 1;\n } else {\n out.push(a);\n i += 1;\n j += 1;\n }\n }\n return added === 0 ? existing : out;\n}\n\nfunction shallowEqualValue(a: unknown, b: unknown): boolean {\n if (Object.is(a, b)) return true;\n if (!a || !b || typeof a !== 'object' || typeof b !== 'object' || Array.isArray(a) !== Array.isArray(b)) return false;\n const ka = Object.keys(a as object);\n const kb = Object.keys(b as object);\n if (ka.length !== kb.length) return false;\n for (const k of ka) {\n if (!Object.is((a as Record<string, unknown>)[k], (b as Record<string, unknown>)[k])) return false;\n }\n return true;\n}\n\n/** Same record, one level deep — a refetched but unchanged session must not re-render its chat. */\nfunction sameSession(a: VerseSession, b: VerseSession): boolean {\n if (a === b) return true;\n const ka = Object.keys(a) as Array<keyof VerseSession>;\n if (ka.length !== Object.keys(b).length) return false;\n return ka.every((k) => shallowEqualValue(a[k], b[k]));\n}\n\n\n/**\n * \"123k\" / \"1.2M\" — compact token counts for the meter and usage rows.\n *\n * The unit is chosen AFTER rounding: choosing it first printed 999,500–\n * 999,999 as \"1000k\" (and 999.5–999.9 as \"1000\"), a band a 1M Claude chat in\n * Expansive can actually reach.\n */\nexport function formatTokens(n: number | null | undefined): string {\n if (n === null || n === undefined || !Number.isFinite(n)) return '—';\n if (Math.round(n) < 1000) return String(Math.round(n));\n if (Math.round(n / 1000) < 1000) return `${Math.round(n / 1000)}k`;\n return `${(n / 1_000_000).toFixed(1).replace(/\\.0$/, '')}M`;\n}\n"],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/AppsSection-Ddu_RCQE.js","assets/index-BVxOlseC.js","assets/global-oEl9Qj8u.js","assets/global-BlI2BYa1.css","assets/Dialog-BS9Dxi3G.js","assets/focus-trap-HtcoXeEq.js","assets/Dialog-tQ8kFulD.css","assets/MutationTokenDialog-mxrw0Yvy.js","assets/MutationTokenDialog-CrfJ0PdD.css","assets/workbench-types-DzN-5trg.js","assets/dock-store-B2vlxqPu.js","assets/viewport-nTubFCwf.js","assets/section-visibility-Yctxu-if.js","assets/VerseConsoleApp-DTjDpGCd.js","assets/RouteErrorBoundary-DYtwc2ja.js","assets/RouteErrorBoundary-DdxhTdZ6.css","assets/command-catalog-Bb_PxC5w.js","assets/guarded-action-OzqcPjmh.js","assets/preloaded-Cwf9rsnZ.js","assets/composer-keys-su0g1h9o.js","assets/command-bus-xYZoK9nQ.js","assets/icon-base-DvM1eI5V.js","assets/VerseConsoleApp-Cxqr-3qc.css","assets/CapacityStrip-qReu0RaF.js","assets/ProviderLogo-C5mBg8i0.js","assets/format-BkWdOQDL.js","assets/format-DKrNjdwD.js","assets/verse-model-DyCwZF-M.js","assets/compaction-point-VL9oegWS.js","assets/Tag-DH15CUJp.js","assets/Tag-D0rAEciH.css","assets/budget-queries-V3wcJVK_.js","assets/useSeatsRefresh-DgFy-Ph4.js","assets/capacity-strip-model-BDbmQ3e3.js","assets/seat-subscription-B-f9ViU2.js","assets/context-model-BC-HOmPo.js","assets/verse-store-b_Lek_c5.js","assets/CapacityStrip-Cc28CyWk.css","assets/Button-HHXgoXGr.js","assets/Button-DrnKsvnQ.css","assets/icons-DEQa2rTx.js","assets/use-token-gate-DqrSXdX6.js","assets/slots-BhP8b8tf.js","assets/EmptyState-BqR5YAmf.js","assets/EmptyState-B3YUPGaa.css","assets/Switch-iveI-8NY.js","assets/Switch-CU044EaE.css","assets/BudgetControl-TL3FeZ1D.js","assets/Segmented-BE53BenI.js","assets/Segmented-BnjHbKzH.css","assets/Slider-BypUWjpH.js","assets/Slider-AgAdMFpo.css","assets/BudgetControl-CmG1JOWK.css","assets/Select-BwSGkHCS.js","assets/Select-DSu5ghId.css","assets/Input-B5dmGLZx.js","assets/Input-BQ3PR065.css","assets/Sheet-DVP2Mgy6.js","assets/Sheet-ChxlNivX.css","assets/apps-model-CDFvmsQV.js","assets/AppsSection-D88QlDpG.css","assets/AutonomySection-DuQkHGD_.js","assets/Advanced-D_eS4472.js","assets/Epistemic-dhvDTwAZ.js","assets/Epistemic-OaGnEJkn.css","assets/StatusBadge-HCZp416_.js","assets/StatusBadge-BVi0IBb9.css","assets/ConfirmDialog-DLrLKM0c.js","assets/ConfirmDialog-Dx15x0Ho.css","assets/RefreshIndicator-CMwSCiz5.js","assets/RefreshIndicator-CVv22U_j.css","assets/workspace-model-CbhdPhei.js","assets/Meter-DNeocJnD.js","assets/Meter-CYt9KpM0.css","assets/control-queries-CmgBgKV7.js","assets/mutations-C5S7okTW.js","assets/use-ticker-D9yi49my.js","assets/fleet-model-7i-FbzKI.js","assets/fleet-queries-DzGoqq8X.js","assets/overnight-queries-DGm3qL1b.js","assets/use-guarded-action-Cf4MeNBa.js","assets/Advanced-Bywv_iYR.css","assets/ChatSection-DZuZfTaC.js","assets/ChatSection-C9obUsLL.css","assets/CommandSection-rIeMK5Ch.js","assets/useChartWidth-owwodNVz.js","assets/colors-BZ3a9wFf.js","assets/useChartWidth-BW6SwYIK.css","assets/Swimlane-DGcIcnNA.js","assets/Swimlane-o6_Zsrnr.css","assets/BurnDown-sFXkUGdB.js","assets/BurnDown-BuLMsJMx.css","assets/types-D5XOdyw8.js","assets/cloud.module-ascz58c3.js","assets/cloud-C1KPNRHC.css","assets/cloud-queries-Br_r0UAz.js","assets/nav-NVtnuG7A.js","assets/surface-data-DTI7LjvH.js","assets/actions-tWevL9HV.js","assets/actions-Ddfg2iLl.css","assets/dark-since-DOMvtB_G.js","assets/Surface-B75lVfzm.js","assets/Surface-DMca0gAe.css","assets/live-model-bmsJgnYD.js","assets/LeaderCard-DZrmjDbI.js","assets/NeedsYouList-CzDZbzRD.js","assets/NeedsYouList-CruOt4JT.css","assets/CloudBudgetForm-DJbiT1wi.js","assets/FleetSection-ViAb549H.js","assets/Funnel-D2u7Wlzc.js","assets/FleetSection-CFiWeOEs.css","assets/GrowthSection-C5aDPs8B.js","assets/queries-CYisSAAB.js","assets/AreaTrend-CDxrQU4b.js","assets/StepBand-Duz1PUes.js","assets/StepBand-Dz_9Kryb.css","assets/calendar-day-BxBYHfX1.js","assets/McpSection-DZkiOuoq.js","assets/MindSection-BvJXFjyX.js","assets/MatrixHeatmap-BgEUs2Eu.js","assets/MatrixHeatmap-Bmnvo1l1.css","assets/mind.module-gTGAuJt1.js","assets/mind-B9PzLcl0.css","assets/SettingsSection-wGnpWeGW.js","assets/reasoning-pref-BUcFF_5G.js","assets/primitives-DyCKYSBG.js","assets/ShortcutsOverlay-BcIcoClX.js","assets/ShortcutsOverlay-QSjxmW0a.css","assets/SettingsSection-B8yD34ZM.css","assets/UsageSection-CqxRGJ40.js","assets/charts-CfAjuKMv.js","assets/charts-uSX6xVYN.css","assets/context-model-CIBmSugV.js","assets/usage-queries-BZuAANlI.js","assets/local-model-DFyjKX0b.js","assets/UsageSection-DsB-Jqyl.css"])))=>i.map(i=>d[i]);
2
+ import{t as e}from"./index-BVxOlseC.js";import{r as t,x as n}from"./workbench-types-DzN-5trg.js";import{f as r,i,v as a,y as o}from"./dock-store-B2vlxqPu.js";Object.freeze({entries:Object.freeze([]),index:-1});function s(e,t){return!!e&&e.section===t.section&&(e.section!==`chat`||e.sessionId===t.sessionId)}function c(e,t){let n={section:t.section,sessionId:t.section===`chat`?t.sessionId:null},r=e.entries[e.index];if(s(r,n))return e;if(r&&r.section===`chat`&&r.sessionId===null&&n.section===`chat`){let t=[...e.entries.slice(0,e.index),n];return{entries:t,index:t.length-1}}let i=[...e.entries.slice(0,e.index+1),n].slice(-50);return{entries:i,index:i.length-1}}function l(e,t){let n=e.index+t,r=e.entries[n];return r?{history:{entries:e.entries,index:n},entry:r}:null}var u=1500;function d(e,t,n,r,i=u){let a=!t||r-t.at>i,o=a?e:t.order;if(o.length<2)return null;let s=((a?0:t.position)+n+o.length)%o.length;return{sessionId:o[s],cycle:{order:o,position:s,at:r}}}function f(e,t,n=10){return[t,...e.filter(e=>e!==t)].slice(0,n)}var p=Object.fromEntries(Object.entries(Object.assign({"../sections/AppsSection.tsx":()=>e(()=>import(`./AppsSection-Ddu_RCQE.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,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60])),"../sections/AutonomySection.tsx":()=>e(()=>import(`./AutonomySection-DuQkHGD_.js`),__vite__mapDeps([61,1,62,2,3,63,64,65,66,7,4,5,6,8,67,68,69,70,13,14,15,16,9,17,18,11,19,20,12,21,22,48,49,25,26,27,28,71,72,73,53,40,54,74,75,76,77,78,79,80,81])),"../sections/ChatSection.tsx":()=>e(()=>import(`./ChatSection-DZuZfTaC.js`).then(e=>e.t),__vite__mapDeps([82,1,2,3,14,15,16,18,10,11,20,12,13,9,17,19,21,22,36,28,38,39,83])),"../sections/CommandSection.tsx":()=>e(()=>import(`./CommandSection-rIeMK5Ch.js`),__vite__mapDeps([84,1,2,3,5,4,6,65,66,69,70,85,86,26,24,87,88,89,90,91,16,11,12,13,14,15,9,17,18,19,20,21,22,27,28,48,49,25,29,30,31,38,39,40,72,73,45,46,47,7,8,33,34,35,36,41,50,51,52,92,93,94,95,76,80,74,75,96,97,55,56,57,58,98,99,100,101,102,103,104,105,106,107])),"../sections/FleetSection.tsx":()=>e(()=>import(`./FleetSection-ViAb549H.js`),__vite__mapDeps([108,1,2,3,69,70,88,85,86,26,24,87,89,109,11,12,25,13,14,15,16,9,17,18,19,20,21,22,27,28,29,30,31,38,39,40,93,35,36,92,94,95,76,79,74,75,96,97,98,4,5,6,7,8,80,99,100,101,102,103,110])),"../sections/GrowthSection.tsx":()=>e(()=>import(`./GrowthSection-C5aDPs8B.js`),__vite__mapDeps([111,1,2,3,112,69,70,86,26,113,85,24,87,109,114,115,12,76,97,13,14,15,16,9,17,18,11,19,20,21,22,74,75,116,100,101,102])),"../sections/McpSection.tsx":()=>e(()=>import(`./McpSection-DZkiOuoq.js`),__vite__mapDeps([117,1,0,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,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60])),"../sections/MindSection.tsx":()=>e(()=>import(`./MindSection-BvJXFjyX.js`),__vite__mapDeps([118,1,2,3,69,70,113,85,86,26,24,87,119,120,11,12,13,14,15,16,9,17,18,19,20,21,22,25,27,28,96,97,74,75,121,71,116,122,98,4,5,6,7,8,38,39,80,99,101,102,104,76])),"../sections/SettingsSection.tsx":()=>e(()=>import(`./SettingsSection-wGnpWeGW.js`),__vite__mapDeps([123,1,2,3,4,5,6,65,66,7,8,14,15,16,13,9,17,18,11,19,20,12,21,22,48,49,36,28,29,30,35,27,25,26,38,39,40,124,41,72,73,50,51,45,46,53,54,55,56,125,63,64,69,70,43,44,57,58,126,127,128])),"../sections/UsageSection.tsx":()=>e(()=>import(`./UsageSection-CqxRGJ40.js`),__vite__mapDeps([129,1,2,3,63,64,65,66,112,85,86,26,24,87,130,88,89,90,91,113,109,114,115,119,120,131,12,13,14,15,16,9,17,18,11,19,20,21,22,27,28,36,25,132,23,29,30,31,32,33,34,35,37,40,72,73,92,93,94,95,77,116,133,134,98,4,5,6,7,8,38,39,80,74,75,99,107,45,46,55,56,135]))})).map(([e,t])=>[e.replace(/^\.\.\//,`./`),t]));function m(e,t=p){return t[`./sections/${e}.tsx`]}var h=[{id:`command`,label:`Command`,module:`CommandSection`,placement:`rail`,blurb:`What the fleet did, what needs you, and the autonomy switch — the morning read.`},{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.`},{id:`growth`,label:`Growth`,module:`GrowthSection`,placement:`rail`,blurb:`Is the fleet getting better? Merges, cost per merge and the experiments behind them.`},{id:`mind`,label:`Mind`,module:`MindSection`,placement:`rail`,blurb:`The Leader's memos, what came of each move, and what the reasoning shows.`},{id:`chat`,label:`Chat`,module:`ChatSection`,placement:`rail`,blurb:`Talk to a seat. Chats are grouped by project and resume where they stopped.`},{id:`settings`,label:`Settings`,module:`SettingsSection`,placement:`tray`,blurb:`Theme, chat, desktop and keyboard — and this tour again.`},{id:`apps`,label:`Apps & Accounts`,module:`AppsSection`,placement:`tray`,blurb:`Seats, terminal agents, local models and MCP servers in one list.`},{id:`usage`,label:`Usage`,module:`UsageSection`,placement:`tray`,blurb:`Which account you can actually use right now, and what it costs.`}],g=h.filter(e=>e.placement===`rail`);h.filter(e=>e.placement===`tray`);var _=new Set(h.map(e=>e.id));function v(e){return h.find(t=>t.id===e)}function y(e,t=e=>m(e)!==void 0){let n=v(e);for(let e of[n.module,...n.fallbackModules??[]])if(t(e))return e;return null}var b=[`all`,...t],x={min:240,max:360,def:264},S={min:260,max:480,def:320},C={section:`chat`,railExpanded:!1,sidebarWidth:x.def,sidebarCollapsed:!1,resourcesOpen:!0,resourcesWidth:S.def,recentActions:[],recentChats:[],mounted:[`chat`],overlay:null,needsYouSplit:`all`,needsYouFocus:null,history:{entries:[{section:`chat`,sessionId:null}],index:0},activeSessionId:null,command:null,announceChatMoved:!1};function w(e,t){let n=Number(e);return!Number.isFinite(n)||n<=0?t.def:Math.max(t.min,Math.min(t.max,Math.round(n)))}function ee(e){let t=new Date(e),n=e=>String(e).padStart(2,`0`);return`${t.getFullYear()}-${n(t.getMonth()+1)}-${n(t.getDate())}`}function te(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function T(e,t,n){if(!Array.isArray(e))return[];let r=[];for(let i of e)if(typeof i==`string`&&n.test(i)&&!r.includes(i)&&r.push(i),r.length>=t)break;return r}function E(e){try{let t=localStorage.getItem(e);if(!t)return null;let n=JSON.parse(t);return te(n)?n:null}catch{return null}}var D=null,O=!1;function k(e={}){let t=e.now??Date.now(),r=e.landed??(e=>m(e)!==void 0),i=E(a),s=i?null:E(o),c=i??s??{},l=C.section,u=null,d=n(c.section);d&&_.has(d.section)&&(l=d.section,d.openNeedsYou&&!i&&(u=`needs-you`)),D=i&&typeof i.lastLaunchDay==`string`?i.lastLaunchDay:null,O=i?i.chatMovedAnnounced===!0:!1;let f=ee(t);return D!==f&&y(`command`,r)!==null&&(l=`command`),D=f,{...C,section:l,railExpanded:c.railExpanded===!0,sidebarWidth:w(c.sidebarWidth,x),sidebarCollapsed:c.sidebarCollapsed===!0,resourcesOpen:c.resourcesOpen!==!1,resourcesWidth:w(c.resourcesWidth,S),recentActions:T(c.recentActions,5,/^[a-z][a-z0-9.-]{0,63}$/),recentChats:T(c.recentChats,10,/^[\w.-]{1,200}$/),mounted:[l],overlay:u,history:{entries:[{section:l,sessionId:null}],index:0},announceChatMoved:s!==null&&!O}}var A=C,j=0,M=null,N=new Set;function P(e){let t={version:3,section:e.section,railExpanded:e.railExpanded,sidebarWidth:e.sidebarWidth,sidebarCollapsed:e.sidebarCollapsed,resourcesOpen:e.resourcesOpen,resourcesWidth:e.resourcesWidth,recentActions:[...e.recentActions],recentChats:[...e.recentChats],lastLaunchDay:D,chatMovedAnnounced:O,dock:i()};try{localStorage.setItem(a,JSON.stringify(t))}catch{}}var ne=[`section`,`railExpanded`,`sidebarWidth`,`sidebarCollapsed`,`resourcesOpen`,`resourcesWidth`,`recentActions`,`recentChats`];function F(e){let t={...A,...e};if(Object.keys(e).every(e=>Object.is(A[e],t[e])))return;let n=ne.some(e=>!Object.is(A[e],t[e]));A=t,n&&P(t);for(let e of[...N])e()}function I(){A=k(),P(A)}I();var L=``;r(()=>{let e=``;try{e=JSON.stringify(i())}catch{e=``}e!==L&&(L=e,P(A))});function R(e){return N.add(e),()=>N.delete(e)}function re(){return A}function ie(e,t){let n=t===`chat`||e.includes(`chat`),r=e.filter(e=>e!==`chat`&&e!==t),i=(t===`chat`?r:[t,...r]).slice(0,3),a=t===`chat`?[`chat`,...i]:i;return n&&!a.includes(`chat`)&&a.push(`chat`),a}function z(e,t){if(!_.has(e))return;let n=t.history?c(A.history,{section:e,sessionId:e===`chat`?A.activeSessionId:null}):A.history;F({section:e,mounted:ie(A.mounted,e),history:n})}var B=`ashlr:verse-anchor`;function V(e,t=null){if(z(e,{history:!0}),!t||typeof window>`u`)return;let n={section:e,anchor:t};window.dispatchEvent(new CustomEvent(B,{detail:n}))}function H(e){let t=l(A.history,e);if(!t)return!1;F({history:t.history}),z(t.entry.section,{history:!1});let n=t.entry.sessionId;return t.entry.section===`chat`&&n&&n!==A.activeSessionId&&(K(`open-session`,{sessionId:n},!1),F({activeSessionId:n,recentChats:f(A.recentChats,n)})),!0}function U(e){e!==A.activeSessionId&&F({activeSessionId:e,recentChats:e?f(A.recentChats,e):A.recentChats,history:e&&A.section===`chat`?c(A.history,{section:`chat`,sessionId:e}):A.history})}function W(e,t=Date.now()){let n=d(A.activeSessionId?f(A.recentChats,A.activeSessionId):[...A.recentChats],M,e,t);return n?(M=n.cycle,J(n.sessionId),n.sessionId):null}var G=`ashlr.verse.selected.v1`;function K(e,t,n){j+=1;let r={name:e,nonce:j,...t};n&&A.section!==`chat`&&z(`chat`,{history:!0}),F({command:r})}function q(e,t={}){K(e,t,!0)}function J(e){if(/^[\w.-]{1,200}$/.test(e)){if(!A.mounted.includes(`chat`))try{localStorage.setItem(G,e)}catch{}K(`open-session`,{sessionId:e},!0),U(e)}}function ae(){F({command:null})}function oe(e){F({overlay:e})}function se(){F({overlay:null,needsYouFocus:null})}function ce(e){F({overlay:A.overlay===e?null:e,needsYouFocus:null})}function le(e={}){F({overlay:`needs-you`,needsYouSplit:e.split??A.needsYouSplit,needsYouFocus:e.focusId??null})}function ue(e){b.includes(e)&&F({needsYouSplit:e})}function de(){F({railExpanded:!A.railExpanded})}function fe(e){F({sidebarCollapsed:e})}function Y(e){/^[a-z][a-z0-9.-]{0,63}$/.test(e)&&F({recentActions:[e,...A.recentActions.filter(t=>t!==e)].slice(0,5)})}function pe(){O=!0,A.announceChatMoved&&F({announceChatMoved:!1}),P(A)}var X=`ashlr.verse.seats.v1`,me=50,Z=null;function Q(){if(Z)return Z;let e={};try{let t=localStorage.getItem(X),n=t?JSON.parse(t):null;if(n&&typeof n==`object`&&!Array.isArray(n))for(let[t,r]of Object.entries(n)){if(!r||typeof r!=`object`||Array.isArray(r))continue;let{seatId:n,model:i}=r;typeof n==`string`&&n.length!==0&&typeof i==`string`&&i.length!==0&&(e[t]={seatId:n,model:i})}}catch{}return Z=e,e}function he(e){let t=Q();if(e){let n=t[e];if(n)return n}let n=Object.keys(t),r=n[n.length-1];return r?t[r]??null:null}function ge(e,t){if(!e||!t.seatId||!t.model)return;let n=Q();delete n[e],n[e]={seatId:t.seatId,model:t.model};let r=Object.keys(n);for(let e of r.slice(0,Math.max(0,r.length-me)))delete n[e];try{localStorage.setItem(X,JSON.stringify(n))}catch{}}var $=new Map,_e=50;function ve(e,t){if(!e||!t)return;let n=$.get(e)??new Set;n.add(t),$.delete(e),$.set(e,n);for(let e of[...$.keys()].slice(0,Math.max(0,$.size-_e)))$.delete(e)}function ye(e,t){return $.get(e)?.has(t)??!1}export{m as A,V as C,ce as D,R as E,de as O,ue as S,H as T,Y as _,pe as a,v as b,W as c,ye as d,y as f,J as g,oe as h,h as i,p as k,ve as l,le as m,g as n,ae as o,he as p,B as r,se as s,b as t,re as u,ge as v,fe as w,U as x,q as y};
3
+ //# sourceMappingURL=verse-ui-store-62DxpVHS.js.map