@ashlr/hub 3.22.0 → 3.22.1

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 (929) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/README.md +5 -5
  3. package/dist/authority-surface.json +16 -11
  4. package/dist/build-identity.json +2 -2
  5. package/dist/cli/verify-safety-sources.d.ts +4 -0
  6. package/dist/cli/verify-safety-sources.js +41 -0
  7. package/dist/cli/verify-safety-sources.js.map +1 -0
  8. package/dist/cli/verify-safety.js +16 -1
  9. package/dist/cli/verify-safety.js.map +1 -1
  10. package/dist/core/decide/needs-you.d.ts +3 -1
  11. package/dist/core/decide/needs-you.js +52 -28
  12. package/dist/core/decide/needs-you.js.map +1 -1
  13. package/dist/core/fleet/fleet-control-model.d.ts +2 -1
  14. package/dist/core/fleet/fleet-control-model.js +5 -0
  15. package/dist/core/fleet/fleet-control-model.js.map +1 -1
  16. package/dist/core/fleet/fleet-control-types.d.ts +11 -1
  17. package/dist/core/fleet/fleet-control.d.ts +4 -0
  18. package/dist/core/fleet/fleet-control.js +23 -1
  19. package/dist/core/fleet/fleet-control.js.map +1 -1
  20. package/dist/core/fleet/quota.js +1 -1
  21. package/dist/core/fleet/quota.js.map +1 -1
  22. package/dist/core/universe/builtins/preparation/manifest.json +1 -1
  23. package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +4 -2
  24. package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +3 -1
  25. package/dist/core/web/public/next/assets/ActionMenu-Z14OhnFI.js +2 -0
  26. package/dist/core/web/public/next/assets/ActionMenu-Z14OhnFI.js.map +1 -0
  27. package/dist/core/web/public/next/assets/Advanced-fUyq-fpH.js +2 -0
  28. package/dist/core/web/public/next/assets/Advanced-fUyq-fpH.js.map +1 -0
  29. package/dist/core/web/public/next/assets/AgentDetailScreen-C8h--Nah.js +2 -0
  30. package/dist/core/web/public/next/assets/AgentDetailScreen-C8h--Nah.js.map +1 -0
  31. package/dist/core/web/public/next/assets/AgentToolsSheet-BP3h-UbZ.js +2 -0
  32. package/dist/core/web/public/next/assets/AgentToolsSheet-BP3h-UbZ.js.map +1 -0
  33. package/dist/core/web/public/next/assets/AgentToolsStrip--hf18knJ.js +2 -0
  34. package/dist/core/web/public/next/assets/AgentToolsStrip--hf18knJ.js.map +1 -0
  35. package/dist/core/web/public/next/assets/AgentsScreen-BR-j0Fzd.js +2 -0
  36. package/dist/core/web/public/next/assets/AgentsScreen-BR-j0Fzd.js.map +1 -0
  37. package/dist/core/web/public/next/assets/AgentsSection-OKKOuYed.js +3 -0
  38. package/dist/core/web/public/next/assets/AgentsSection-OKKOuYed.js.map +1 -0
  39. package/dist/core/web/public/next/assets/App-ttVrZYp5.js +8 -0
  40. package/dist/core/web/public/next/assets/App-ttVrZYp5.js.map +1 -0
  41. package/dist/core/web/public/next/assets/AppsSection-sqsXqENO.js +2 -0
  42. package/dist/core/web/public/next/assets/AppsSection-sqsXqENO.js.map +1 -0
  43. package/dist/core/web/public/next/assets/AreaTrend-LVgaB49b.js +2 -0
  44. package/dist/core/web/public/next/assets/AreaTrend-LVgaB49b.js.map +1 -0
  45. package/dist/core/web/public/next/assets/AutomationsSection-BITmxjuB.js +2 -0
  46. package/dist/core/web/public/next/assets/AutomationsSection-BITmxjuB.js.map +1 -0
  47. package/dist/core/web/public/next/assets/AutonomyOffState-nO9lIcCv.js +3 -0
  48. package/dist/core/web/public/next/assets/AutonomyOffState-nO9lIcCv.js.map +1 -0
  49. package/dist/core/web/public/next/assets/AutonomySection-DWYUPDP6.js +2 -0
  50. package/dist/core/web/public/next/assets/AutonomySection-DWYUPDP6.js.map +1 -0
  51. package/dist/core/web/public/next/assets/AutonomyStatus-C4Yp1JTY.js +2 -0
  52. package/dist/core/web/public/next/assets/AutonomyStatus-C4Yp1JTY.js.map +1 -0
  53. package/dist/core/web/public/next/assets/BranchBar-CkiZSNqB.js +2 -0
  54. package/dist/core/web/public/next/assets/BranchBar-CkiZSNqB.js.map +1 -0
  55. package/dist/core/web/public/next/assets/BrowserPanel-CECVGJBS.js +7 -0
  56. package/dist/core/web/public/next/assets/BrowserPanel-CECVGJBS.js.map +1 -0
  57. package/dist/core/web/public/next/assets/BudgetControl-De1TPzvX.js +2 -0
  58. package/dist/core/web/public/next/assets/BudgetControl-De1TPzvX.js.map +1 -0
  59. package/dist/core/web/public/next/assets/Button-CstSJwha.js +2 -0
  60. package/dist/core/web/public/next/assets/Button-CstSJwha.js.map +1 -0
  61. package/dist/core/web/public/next/assets/CapacityStrip-nIJcB_lA.js +2 -0
  62. package/dist/core/web/public/next/assets/CapacityStrip-nIJcB_lA.js.map +1 -0
  63. package/dist/core/web/public/next/assets/ChangesPaneHost-Bnj_NcRa.js +16 -0
  64. package/dist/core/web/public/next/assets/ChangesPaneHost-Bnj_NcRa.js.map +1 -0
  65. package/dist/core/web/public/next/assets/ChartFrame-Dljee9y6.js +2 -0
  66. package/dist/core/web/public/next/assets/ChartFrame-Dljee9y6.js.map +1 -0
  67. package/dist/core/web/public/next/assets/ChatPanes-x_ySUIyR.js +2 -0
  68. package/dist/core/web/public/next/assets/ChatPanes-x_ySUIyR.js.map +1 -0
  69. package/dist/core/web/public/next/assets/ChatSection-CXJa8QOi.js +3 -0
  70. package/dist/core/web/public/next/assets/ChatSection-CXJa8QOi.js.map +1 -0
  71. package/dist/core/web/public/next/assets/ChecksPanel-D9r8koxq.js +5 -0
  72. package/dist/core/web/public/next/assets/ChecksPanel-D9r8koxq.js.map +1 -0
  73. package/dist/core/web/public/next/assets/CloudBudgetForm-D5ajpoMe.js +2 -0
  74. package/dist/core/web/public/next/assets/CloudBudgetForm-D5ajpoMe.js.map +1 -0
  75. package/dist/core/web/public/next/assets/CommandPalette-ONyqYZzt.js +3 -0
  76. package/dist/core/web/public/next/assets/CommandPalette-ONyqYZzt.js.map +1 -0
  77. package/dist/core/web/public/next/assets/CommandSection-DxNIibnI.js +3 -0
  78. package/dist/core/web/public/next/assets/CommandSection-DxNIibnI.js.map +1 -0
  79. package/dist/core/web/public/next/assets/CommandWorkflowForm-Bz3PuZXH.js +9 -0
  80. package/dist/core/web/public/next/assets/CommandWorkflowForm-Bz3PuZXH.js.map +1 -0
  81. package/dist/core/web/public/next/assets/CommandWorkflowPicker-COVyeer0.js +3 -0
  82. package/dist/core/web/public/next/assets/CommandWorkflowPicker-COVyeer0.js.map +1 -0
  83. package/dist/core/web/public/next/assets/CompareDialog-PVqv0Tx9.js +4 -0
  84. package/dist/core/web/public/next/assets/CompareDialog-PVqv0Tx9.js.map +1 -0
  85. package/dist/core/web/public/next/assets/ComputerControl-DkSIUrYm.js +2 -0
  86. package/dist/core/web/public/next/assets/ComputerControl-DkSIUrYm.js.map +1 -0
  87. package/dist/core/web/public/next/assets/ConfirmDialog-CdCzzk0I.js +2 -0
  88. package/dist/core/web/public/next/assets/ConfirmDialog-CdCzzk0I.js.map +1 -0
  89. package/dist/core/web/public/next/assets/DeleteChatDialog-BTzOgqho.js +2 -0
  90. package/dist/core/web/public/next/assets/DeleteChatDialog-BTzOgqho.js.map +1 -0
  91. package/dist/core/web/public/next/assets/DevinStopDialog-CGsDqfan.js +2 -0
  92. package/dist/core/web/public/next/assets/DevinStopDialog-CGsDqfan.js.map +1 -0
  93. package/dist/core/web/public/next/assets/Dialog-DDHg9cuT.js +2 -0
  94. package/dist/core/web/public/next/assets/Dialog-DDHg9cuT.js.map +1 -0
  95. package/dist/core/web/public/next/assets/DiffPane-BR3HU7pC.js +2 -0
  96. package/dist/core/web/public/next/assets/DiffPane-BR3HU7pC.js.map +1 -0
  97. package/dist/core/web/public/next/assets/DiffViewer-hJK75qko.js +2 -0
  98. package/dist/core/web/public/next/assets/DiffViewer-hJK75qko.js.map +1 -0
  99. package/dist/core/web/public/next/assets/DockHost-DhOosHbo.js +2 -0
  100. package/dist/core/web/public/next/assets/DockHost-DhOosHbo.js.map +1 -0
  101. package/dist/core/web/public/next/assets/EmptyState-CGVr0VO2.js +2 -0
  102. package/dist/core/web/public/next/assets/EmptyState-CGVr0VO2.js.map +1 -0
  103. package/dist/core/web/public/next/assets/Epistemic-tp0ZNAKZ.js +2 -0
  104. package/dist/core/web/public/next/assets/Epistemic-tp0ZNAKZ.js.map +1 -0
  105. package/dist/core/web/public/next/assets/EvidenceTimeline-YmKIoxNx.js +2 -0
  106. package/dist/core/web/public/next/assets/EvidenceTimeline-YmKIoxNx.js.map +1 -0
  107. package/dist/core/web/public/next/assets/FilesPane-CoNjfkPP.js +2 -0
  108. package/dist/core/web/public/next/assets/FilesPane-CoNjfkPP.js.map +1 -0
  109. package/dist/core/web/public/next/assets/FleetScreen-CstwycnB.js +2 -0
  110. package/dist/core/web/public/next/assets/FleetScreen-CstwycnB.js.map +1 -0
  111. package/dist/core/web/public/next/assets/FleetSection-D0xk0s5J.js +5 -0
  112. package/dist/core/web/public/next/assets/FleetSection-D0xk0s5J.js.map +1 -0
  113. package/dist/core/web/public/next/assets/Funnel-UPrk7fcy.js +2 -0
  114. package/dist/core/web/public/next/assets/Funnel-UPrk7fcy.js.map +1 -0
  115. package/dist/core/web/public/next/assets/GearTray-BSjga1J_.js +2 -0
  116. package/dist/core/web/public/next/assets/GearTray-BSjga1J_.js.map +1 -0
  117. package/dist/core/web/public/next/assets/GitDialogs-ekwzxl76.js +2 -0
  118. package/dist/core/web/public/next/assets/GitDialogs-ekwzxl76.js.map +1 -0
  119. package/dist/core/web/public/next/assets/GrowthSection-Dh-gnkgc.js +3 -0
  120. package/dist/core/web/public/next/assets/GrowthSection-Dh-gnkgc.js.map +1 -0
  121. package/dist/core/web/public/next/assets/HandoffDialog-BDiyA3u-.js +2 -0
  122. package/dist/core/web/public/next/assets/HandoffDialog-BDiyA3u-.js.map +1 -0
  123. package/dist/core/web/public/next/assets/HomeBody-Ce3HBIEb.js +3 -0
  124. package/dist/core/web/public/next/assets/HomeBody-Ce3HBIEb.js.map +1 -0
  125. package/dist/core/web/public/next/assets/HomeSeats-BFLCWCFp.js +2 -0
  126. package/dist/core/web/public/next/assets/HomeSeats-BFLCWCFp.js.map +1 -0
  127. package/dist/core/web/public/next/assets/Input-Cpn9uYj2.js +2 -0
  128. package/dist/core/web/public/next/assets/Input-Cpn9uYj2.js.map +1 -0
  129. package/dist/core/web/public/next/assets/LaunchDialog-CrPEf652.js +9 -0
  130. package/dist/core/web/public/next/assets/LaunchDialog-CrPEf652.js.map +1 -0
  131. package/dist/core/web/public/next/assets/LeaderCard-Dhq-w_Mf.js +2 -0
  132. package/dist/core/web/public/next/assets/LeaderCard-Dhq-w_Mf.js.map +1 -0
  133. package/dist/core/web/public/next/assets/LeaderConversation-CiWqhsoa.js +3 -0
  134. package/dist/core/web/public/next/assets/LeaderConversation-CiWqhsoa.js.map +1 -0
  135. package/dist/core/web/public/next/assets/LeaderScreen-Z5KPjxBV.js +2 -0
  136. package/dist/core/web/public/next/assets/LeaderScreen-Z5KPjxBV.js.map +1 -0
  137. package/dist/core/web/public/next/assets/LessonsPanel-B6XVKAPE.js +2 -0
  138. package/dist/core/web/public/next/assets/LessonsPanel-B6XVKAPE.js.map +1 -0
  139. package/dist/core/web/public/next/assets/LiveTimer-B8t2iX5h.js +2 -0
  140. package/dist/core/web/public/next/assets/LiveTimer-B8t2iX5h.js.map +1 -0
  141. package/dist/core/web/public/next/assets/LocalSeatBadge-HMxIrMiL.js +2 -0
  142. package/dist/core/web/public/next/assets/LocalSeatBadge-HMxIrMiL.js.map +1 -0
  143. package/dist/core/web/public/next/assets/MatrixHeatmap-BlFI5oao.js +2 -0
  144. package/dist/core/web/public/next/assets/MatrixHeatmap-BlFI5oao.js.map +1 -0
  145. package/dist/core/web/public/next/assets/McpSection-snZNKexW.js +2 -0
  146. package/dist/core/web/public/next/assets/McpSection-snZNKexW.js.map +1 -0
  147. package/dist/core/web/public/next/assets/MessageMarkdown-CS0mAtSs.js +3 -0
  148. package/dist/core/web/public/next/assets/MessageMarkdown-CS0mAtSs.js.map +1 -0
  149. package/dist/core/web/public/next/assets/MessageMarkdownRenderer-D5R-zr-W.js +72 -0
  150. package/dist/core/web/public/next/assets/MessageMarkdownRenderer-D5R-zr-W.js.map +1 -0
  151. package/dist/core/web/public/next/assets/Meter-VXI75VNe.js +2 -0
  152. package/dist/core/web/public/next/assets/Meter-VXI75VNe.js.map +1 -0
  153. package/dist/core/web/public/next/assets/MicButton-DORAXsUU.js +2 -0
  154. package/dist/core/web/public/next/assets/MicButton-DORAXsUU.js.map +1 -0
  155. package/dist/core/web/public/next/assets/MindSection-DZLHz29Q.js +3 -0
  156. package/dist/core/web/public/next/assets/MindSection-DZLHz29Q.js.map +1 -0
  157. package/dist/core/web/public/next/assets/MobileComposer-B8nWsIJO.js +2 -0
  158. package/dist/core/web/public/next/assets/MobileComposer-B8nWsIJO.js.map +1 -0
  159. package/dist/core/web/public/next/assets/MobileGuardSheet-BRwOfD9o.js +2 -0
  160. package/dist/core/web/public/next/assets/MobileGuardSheet-BRwOfD9o.js.map +1 -0
  161. package/dist/core/web/public/next/assets/MobileRuntime-kMob_MjB.js +3 -0
  162. package/dist/core/web/public/next/assets/MobileRuntime-kMob_MjB.js.map +1 -0
  163. package/dist/core/web/public/next/assets/MoreScreen-92dC6Bj7.js +2 -0
  164. package/dist/core/web/public/next/assets/MoreScreen-92dC6Bj7.js.map +1 -0
  165. package/dist/core/web/public/next/assets/MultiModelBar-BhAUUQOq.js +7 -0
  166. package/dist/core/web/public/next/assets/MultiModelBar-BhAUUQOq.js.map +1 -0
  167. package/dist/core/web/public/next/assets/MutationTokenDialog-DlY2VLVh.js +2 -0
  168. package/dist/core/web/public/next/assets/MutationTokenDialog-DlY2VLVh.js.map +1 -0
  169. package/dist/core/web/public/next/assets/NeedsYouDrawer-BH0ffbht.js +3 -0
  170. package/dist/core/web/public/next/assets/NeedsYouDrawer-BH0ffbht.js.map +1 -0
  171. package/dist/core/web/public/next/assets/NeedsYouList-CI_Dy-hi.js +2 -0
  172. package/dist/core/web/public/next/assets/NeedsYouList-CI_Dy-hi.js.map +1 -0
  173. package/dist/core/web/public/next/assets/NeedsYouScreen-CvDiEphJ.js +2 -0
  174. package/dist/core/web/public/next/assets/NeedsYouScreen-CvDiEphJ.js.map +1 -0
  175. package/dist/core/web/public/next/assets/NewAgentScreen-BpTRKp9z.js +2 -0
  176. package/dist/core/web/public/next/assets/NewAgentScreen-BpTRKp9z.js.map +1 -0
  177. package/dist/core/web/public/next/assets/NewChatDialog-O1LwwBc4.js +4 -0
  178. package/dist/core/web/public/next/assets/NewChatDialog-O1LwwBc4.js.map +1 -0
  179. package/dist/core/web/public/next/assets/OnboardingFlow-uMNBVHvK.js +3 -0
  180. package/dist/core/web/public/next/assets/OnboardingFlow-uMNBVHvK.js.map +1 -0
  181. package/dist/core/web/public/next/assets/OnboardingGate-sdzxSPZF.js +3 -0
  182. package/dist/core/web/public/next/assets/OnboardingGate-sdzxSPZF.js.map +1 -0
  183. package/dist/core/web/public/next/assets/PlaybooksSection-CnWfwZv8.js +9 -0
  184. package/dist/core/web/public/next/assets/PlaybooksSection-CnWfwZv8.js.map +1 -0
  185. package/dist/core/web/public/next/assets/PreviewPane-D1WaefIG.js +2 -0
  186. package/dist/core/web/public/next/assets/PreviewPane-D1WaefIG.js.map +1 -0
  187. package/dist/core/web/public/next/assets/ProviderLogo-g2YWCmNY.js +2 -0
  188. package/dist/core/web/public/next/assets/ProviderLogo-g2YWCmNY.js.map +1 -0
  189. package/dist/core/web/public/next/assets/RailStatus-OrvAuyzs.js +2 -0
  190. package/dist/core/web/public/next/assets/RailStatus-OrvAuyzs.js.map +1 -0
  191. package/dist/core/web/public/next/assets/ReasoningPane-BARDPl4-.js +2 -0
  192. package/dist/core/web/public/next/assets/ReasoningPane-BARDPl4-.js.map +1 -0
  193. package/dist/core/web/public/next/assets/ReasoningSheet-rPTXyt-b.js +2 -0
  194. package/dist/core/web/public/next/assets/ReasoningSheet-rPTXyt-b.js.map +1 -0
  195. package/dist/core/web/public/next/assets/RefreshIndicator-D96C9qiH.js +2 -0
  196. package/dist/core/web/public/next/assets/RefreshIndicator-D96C9qiH.js.map +1 -0
  197. package/dist/core/web/public/next/assets/RemoteMobileApp-DfDjiBTR.js +2 -0
  198. package/dist/core/web/public/next/assets/RemoteMobileApp-DfDjiBTR.js.map +1 -0
  199. package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-CcfULh_p.js +7 -0
  200. package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-CcfULh_p.js.map +1 -0
  201. package/dist/core/web/public/next/assets/ResourcesChrome-DuEa7WOo.css +1 -0
  202. package/dist/core/web/public/next/assets/ResourcesChrome-e9ifgnWf.js +3 -0
  203. package/dist/core/web/public/next/assets/ResourcesChrome-e9ifgnWf.js.map +1 -0
  204. package/dist/core/web/public/next/assets/ResourcesDrawer-DOv_mxpe.js +3 -0
  205. package/dist/core/web/public/next/assets/ResourcesDrawer-DOv_mxpe.js.map +1 -0
  206. package/dist/core/web/public/next/assets/ReviewMenu-Ba3saQlX.js +2 -0
  207. package/dist/core/web/public/next/assets/ReviewMenu-Ba3saQlX.js.map +1 -0
  208. package/dist/core/web/public/next/assets/RouteErrorBoundary-BaJ1ZePy.js +2 -0
  209. package/dist/core/web/public/next/assets/RouteErrorBoundary-BaJ1ZePy.js.map +1 -0
  210. package/dist/core/web/public/next/assets/RunInCloudAction-DRSX84Jy.js +2 -0
  211. package/dist/core/web/public/next/assets/RunInCloudAction-DRSX84Jy.js.map +1 -0
  212. package/dist/core/web/public/next/assets/RunInDevinAction-BMji-YN2.js +2 -0
  213. package/dist/core/web/public/next/assets/RunInDevinAction-BMji-YN2.js.map +1 -0
  214. package/dist/core/web/public/next/assets/SchedulingEvidence-xxjV6HF_.js +2 -0
  215. package/dist/core/web/public/next/assets/SchedulingEvidence-xxjV6HF_.js.map +1 -0
  216. package/dist/core/web/public/next/assets/ScreenHost-Dv6z76Ta.js +3 -0
  217. package/dist/core/web/public/next/assets/ScreenHost-Dv6z76Ta.js.map +1 -0
  218. package/dist/core/web/public/next/assets/SeatSelector-YRNdNpP8.js +3 -0
  219. package/dist/core/web/public/next/assets/SeatSelector-YRNdNpP8.js.map +1 -0
  220. package/dist/core/web/public/next/assets/Segmented-BA8RmKYq.js +2 -0
  221. package/dist/core/web/public/next/assets/Segmented-BA8RmKYq.js.map +1 -0
  222. package/dist/core/web/public/next/assets/Select-B8GqZOX9.js +2 -0
  223. package/dist/core/web/public/next/assets/Select-B8GqZOX9.js.map +1 -0
  224. package/dist/core/web/public/next/assets/SessionGate-CnASHl7g.js +2 -0
  225. package/dist/core/web/public/next/assets/SessionGate-CnASHl7g.js.map +1 -0
  226. package/dist/core/web/public/next/assets/SessionInsightChip-DIKfih6i.js +2 -0
  227. package/dist/core/web/public/next/assets/SessionInsightChip-DIKfih6i.js.map +1 -0
  228. package/dist/core/web/public/next/assets/SessionSearch-K6lvMlji.js +2 -0
  229. package/dist/core/web/public/next/assets/SessionSearch-K6lvMlji.js.map +1 -0
  230. package/dist/core/web/public/next/assets/SettingsSection-C-c3f_6J.js +2 -0
  231. package/dist/core/web/public/next/assets/SettingsSection-C-c3f_6J.js.map +1 -0
  232. package/dist/core/web/public/next/assets/SetupChecklist-DAbAdrX4.js +2 -0
  233. package/dist/core/web/public/next/assets/SetupChecklist-DAbAdrX4.js.map +1 -0
  234. package/dist/core/web/public/next/assets/ShadowDecisions-C41uRSw4.js +3 -0
  235. package/dist/core/web/public/next/assets/ShadowDecisions-C41uRSw4.js.map +1 -0
  236. package/dist/core/web/public/next/assets/Sheet-Bk64-Hlt.js +2 -0
  237. package/dist/core/web/public/next/assets/Sheet-Bk64-Hlt.js.map +1 -0
  238. package/dist/core/web/public/next/assets/ShortcutsOverlay-CcP96zqy.js +2 -0
  239. package/dist/core/web/public/next/assets/ShortcutsOverlay-CcP96zqy.js.map +1 -0
  240. package/dist/core/web/public/next/assets/Sidebar-sSNKd57n.js +3 -0
  241. package/dist/core/web/public/next/assets/Sidebar-sSNKd57n.js.map +1 -0
  242. package/dist/core/web/public/next/assets/SkipToContent-BynsXs9i.js +2 -0
  243. package/dist/core/web/public/next/assets/SkipToContent-BynsXs9i.js.map +1 -0
  244. package/dist/core/web/public/next/assets/Slider-DS5HrVzl.js +2 -0
  245. package/dist/core/web/public/next/assets/Slider-DS5HrVzl.js.map +1 -0
  246. package/dist/core/web/public/next/assets/SourcesPane-QffcyDfA.js +2 -0
  247. package/dist/core/web/public/next/assets/SourcesPane-QffcyDfA.js.map +1 -0
  248. package/dist/core/web/public/next/assets/SourcesPanel-DlttePk7.js +2 -0
  249. package/dist/core/web/public/next/assets/SourcesPanel-DlttePk7.js.map +1 -0
  250. package/dist/core/web/public/next/assets/StatTile-mYm1GPj7.js +2 -0
  251. package/dist/core/web/public/next/assets/StatTile-mYm1GPj7.js.map +1 -0
  252. package/dist/core/web/public/next/assets/StatusBadge-Yz7S3kZ2.js +2 -0
  253. package/dist/core/web/public/next/assets/StatusBadge-Yz7S3kZ2.js.map +1 -0
  254. package/dist/core/web/public/next/assets/StepBand-Bdkv7iGd.js +2 -0
  255. package/dist/core/web/public/next/assets/StepBand-Bdkv7iGd.js.map +1 -0
  256. package/dist/core/web/public/next/assets/Surface-DVOAKl2g.js +2 -0
  257. package/dist/core/web/public/next/assets/Surface-DVOAKl2g.js.map +1 -0
  258. package/dist/core/web/public/next/assets/Swimlane-CeMBD_FC.js +2 -0
  259. package/dist/core/web/public/next/assets/Swimlane-CeMBD_FC.js.map +1 -0
  260. package/dist/core/web/public/next/assets/Switch-Cqc_bSoh.js +2 -0
  261. package/dist/core/web/public/next/assets/Switch-Cqc_bSoh.js.map +1 -0
  262. package/dist/core/web/public/next/assets/Tag-BvOxSxYi.js +2 -0
  263. package/dist/core/web/public/next/assets/Tag-BvOxSxYi.js.map +1 -0
  264. package/dist/core/web/public/next/assets/TerminalPane-D3f02aI4.js +3 -0
  265. package/dist/core/web/public/next/assets/TerminalPane-D3f02aI4.js.map +1 -0
  266. package/dist/core/web/public/next/assets/TerminalPane-XZ5n3Pns.js +26 -0
  267. package/dist/core/web/public/next/assets/TerminalPane-XZ5n3Pns.js.map +1 -0
  268. package/dist/core/web/public/next/assets/ThinkingBlock-DZNlOGaV.js +2 -0
  269. package/dist/core/web/public/next/assets/ThinkingBlock-DZNlOGaV.js.map +1 -0
  270. package/dist/core/web/public/next/assets/UniverseConsoleApp-CzBI6Upl.js +2 -0
  271. package/dist/core/web/public/next/assets/UniverseConsoleApp-CzBI6Upl.js.map +1 -0
  272. package/dist/core/web/public/next/assets/UniverseView-Dsi3Kk8o.js +9 -0
  273. package/dist/core/web/public/next/assets/UniverseView-Dsi3Kk8o.js.map +1 -0
  274. package/dist/core/web/public/next/assets/UsageSection-rVvLat9z.js +3 -0
  275. package/dist/core/web/public/next/assets/UsageSection-rVvLat9z.js.map +1 -0
  276. package/dist/core/web/public/next/assets/UsePlaybookAction-B4XAzSeI.js +2 -0
  277. package/dist/core/web/public/next/assets/UsePlaybookAction-B4XAzSeI.js.map +1 -0
  278. package/dist/core/web/public/next/assets/VerseConsoleApp-BmckthwC.css +1 -0
  279. package/dist/core/web/public/next/assets/VerseConsoleApp-DjPpZLo1.js +3 -0
  280. package/dist/core/web/public/next/assets/VerseConsoleApp-DjPpZLo1.js.map +1 -0
  281. package/dist/core/web/public/next/assets/VerseMobileApp-ePNuVERe.js +3 -0
  282. package/dist/core/web/public/next/assets/VerseMobileApp-ePNuVERe.js.map +1 -0
  283. package/dist/core/web/public/next/assets/VerseShared-Bf-XTHCh.js +2 -0
  284. package/dist/core/web/public/next/assets/VerseShared-Bf-XTHCh.js.map +1 -0
  285. package/dist/core/web/public/next/assets/VoiceHud-BG5FV2h0.js +2 -0
  286. package/dist/core/web/public/next/assets/VoiceHud-BG5FV2h0.js.map +1 -0
  287. package/dist/core/web/public/next/assets/VoiceInput-k3vB_FxV.js +2 -0
  288. package/dist/core/web/public/next/assets/VoiceInput-k3vB_FxV.js.map +1 -0
  289. package/dist/core/web/public/next/assets/WikiSection-DeBKNqd6.js +2 -0
  290. package/dist/core/web/public/next/assets/WikiSection-DeBKNqd6.js.map +1 -0
  291. package/dist/core/web/public/next/assets/Workspace-CvwS2-RN.js +6 -0
  292. package/dist/core/web/public/next/assets/Workspace-CvwS2-RN.js.map +1 -0
  293. package/dist/core/web/public/next/assets/actions-Dg6UJTLn.js +2 -0
  294. package/dist/core/web/public/next/assets/actions-Dg6UJTLn.js.map +1 -0
  295. package/dist/core/web/public/next/assets/agent-tools-client-DmJq7zlr.js +2 -0
  296. package/dist/core/web/public/next/assets/agent-tools-client-DmJq7zlr.js.map +1 -0
  297. package/dist/core/web/public/next/assets/agents-focus-B1LKhUVg.js +2 -0
  298. package/dist/core/web/public/next/assets/agents-focus-B1LKhUVg.js.map +1 -0
  299. package/dist/core/web/public/next/assets/app-version-Cb1z8iCO.js +2 -0
  300. package/dist/core/web/public/next/assets/app-version-Cb1z8iCO.js.map +1 -0
  301. package/dist/core/web/public/next/assets/apps-model-_chbcQeN.js +2 -0
  302. package/dist/core/web/public/next/assets/apps-model-_chbcQeN.js.map +1 -0
  303. package/dist/core/web/public/next/assets/ask-seat-O60AydbV.js +2 -0
  304. package/dist/core/web/public/next/assets/ask-seat-O60AydbV.js.map +1 -0
  305. package/dist/core/web/public/next/assets/authority-model-BeDDHF22.js +2 -0
  306. package/dist/core/web/public/next/assets/authority-model-BeDDHF22.js.map +1 -0
  307. package/dist/core/web/public/next/assets/automations-focus-BXaRZ8nX.js +2 -0
  308. package/dist/core/web/public/next/assets/automations-focus-BXaRZ8nX.js.map +1 -0
  309. package/dist/core/web/public/next/assets/budget-queries-Nvx0H2XE.js +2 -0
  310. package/dist/core/web/public/next/assets/budget-queries-Nvx0H2XE.js.map +1 -0
  311. package/dist/core/web/public/next/assets/capacity-strip-model-CBMJ2U-w.js +2 -0
  312. package/dist/core/web/public/next/assets/capacity-strip-model-CBMJ2U-w.js.map +1 -0
  313. package/dist/core/web/public/next/assets/charts-DT9PYS49.js +2 -0
  314. package/dist/core/web/public/next/assets/charts-DT9PYS49.js.map +1 -0
  315. package/dist/core/web/public/next/assets/chat-pane-data-CfbpeAYX.js +2 -0
  316. package/dist/core/web/public/next/assets/chat-pane-data-CfbpeAYX.js.map +1 -0
  317. package/dist/core/web/public/next/assets/checkpoint-queries-BKD2evmX.js +2 -0
  318. package/dist/core/web/public/next/assets/checkpoint-queries-BKD2evmX.js.map +1 -0
  319. package/dist/core/web/public/next/assets/cloud-queries-CsU54eNn.js +2 -0
  320. package/dist/core/web/public/next/assets/cloud-queries-CsU54eNn.js.map +1 -0
  321. package/dist/core/web/public/next/assets/command-catalog-B0ApAGD0.js +2 -0
  322. package/dist/core/web/public/next/assets/command-catalog-B0ApAGD0.js.map +1 -0
  323. package/dist/core/web/public/next/assets/composer-queries-D1H4E0Ye.js +2 -0
  324. package/dist/core/web/public/next/assets/composer-queries-D1H4E0Ye.js.map +1 -0
  325. package/dist/core/web/public/next/assets/connectivity-xQ0Nh0j3.js +2 -0
  326. package/dist/core/web/public/next/assets/connectivity-xQ0Nh0j3.js.map +1 -0
  327. package/dist/core/web/public/next/assets/context-queries-bnI3P0Wt.js +2 -0
  328. package/dist/core/web/public/next/assets/context-queries-bnI3P0Wt.js.map +1 -0
  329. package/dist/core/web/public/next/assets/control-queries-BG53otwz.js +2 -0
  330. package/dist/core/web/public/next/assets/control-queries-BG53otwz.js.map +1 -0
  331. package/dist/core/web/public/next/assets/copy-setup-COMDnur3.js +2 -0
  332. package/dist/core/web/public/next/assets/copy-setup-COMDnur3.js.map +1 -0
  333. package/dist/core/web/public/next/assets/deep-link-CqOP-JEm.js +2 -0
  334. package/dist/core/web/public/next/assets/deep-link-CqOP-JEm.js.map +1 -0
  335. package/dist/core/web/public/next/assets/device-permissions-DpsJJcUW.js +2 -0
  336. package/dist/core/web/public/next/assets/device-permissions-DpsJJcUW.js.map +1 -0
  337. package/dist/core/web/public/next/assets/devin-queries-BSEOfLuZ.js +2 -0
  338. package/dist/core/web/public/next/assets/devin-queries-BSEOfLuZ.js.map +1 -0
  339. package/dist/core/web/public/next/assets/dock-icons-DK7QcBXJ.js +2 -0
  340. package/dist/core/web/public/next/assets/dock-icons-DK7QcBXJ.js.map +1 -0
  341. package/dist/core/web/public/next/assets/dock-panes-DvQ6t4Nl.js +2 -0
  342. package/dist/core/web/public/next/assets/dock-panes-DvQ6t4Nl.js.map +1 -0
  343. package/dist/core/web/public/next/assets/fleet-control-queries-BL-Vlf85.js +2 -0
  344. package/dist/core/web/public/next/assets/fleet-control-queries-BL-Vlf85.js.map +1 -0
  345. package/dist/core/web/public/next/assets/fleet-queries-eacERnLm.js +2 -0
  346. package/dist/core/web/public/next/assets/fleet-queries-eacERnLm.js.map +1 -0
  347. package/dist/core/web/public/next/assets/fleet-state-DfKcuo4A.js +3 -0
  348. package/dist/core/web/public/next/assets/fleet-state-DfKcuo4A.js.map +1 -0
  349. package/dist/core/web/public/next/assets/focus-trap-BZeH0rVB.js +2 -0
  350. package/dist/core/web/public/next/assets/focus-trap-BZeH0rVB.js.map +1 -0
  351. package/dist/core/web/public/next/assets/git-model-C1I4z_iQ.js +5 -0
  352. package/dist/core/web/public/next/assets/git-model-C1I4z_iQ.js.map +1 -0
  353. package/dist/core/web/public/next/assets/global-w7KDTTi0.js +3 -0
  354. package/dist/core/web/public/next/assets/global-w7KDTTi0.js.map +1 -0
  355. package/dist/core/web/public/next/assets/guarded-action-J9umcJgI.js +3 -0
  356. package/dist/core/web/public/next/assets/guarded-action-J9umcJgI.js.map +1 -0
  357. package/dist/core/web/public/next/assets/guarded-runners-Da5yA9Im.js +2 -0
  358. package/dist/core/web/public/next/assets/guarded-runners-Da5yA9Im.js.map +1 -0
  359. package/dist/core/web/public/next/assets/health-queries-D3HgrdU_.js +2 -0
  360. package/dist/core/web/public/next/assets/health-queries-D3HgrdU_.js.map +1 -0
  361. package/dist/core/web/public/next/assets/icons-C3G-y5j2.js +2 -0
  362. package/dist/core/web/public/next/assets/icons-C3G-y5j2.js.map +1 -0
  363. package/dist/core/web/public/next/assets/index-BC5Uslm5.js +11 -0
  364. package/dist/core/web/public/next/assets/index-BC5Uslm5.js.map +1 -0
  365. package/dist/core/web/public/next/assets/jev-queries-D6JNU-s6.js +2 -0
  366. package/dist/core/web/public/next/assets/jev-queries-D6JNU-s6.js.map +1 -0
  367. package/dist/core/web/public/next/assets/ladder-queries-BnYWjJoi.js +2 -0
  368. package/dist/core/web/public/next/assets/ladder-queries-BnYWjJoi.js.map +1 -0
  369. package/dist/core/web/public/next/assets/leader-focus-C6LVWgYI.js +2 -0
  370. package/dist/core/web/public/next/assets/leader-focus-C6LVWgYI.js.map +1 -0
  371. package/dist/core/web/public/next/assets/live-model-BPyZCTr1.js +2 -0
  372. package/dist/core/web/public/next/assets/live-model-BPyZCTr1.js.map +1 -0
  373. package/dist/core/web/public/next/assets/mobile-actions-avKNGddD.js +2 -0
  374. package/dist/core/web/public/next/assets/mobile-actions-avKNGddD.js.map +1 -0
  375. package/dist/core/web/public/next/assets/mobile-toast-BqSzGmw1.js +2 -0
  376. package/dist/core/web/public/next/assets/mobile-toast-BqSzGmw1.js.map +1 -0
  377. package/dist/core/web/public/next/assets/multimodel-flows-DOHsEKUG.js +7 -0
  378. package/dist/core/web/public/next/assets/multimodel-flows-DOHsEKUG.js.map +1 -0
  379. package/dist/core/web/public/next/assets/multimodel-queries-xmBBUT6n.js +2 -0
  380. package/dist/core/web/public/next/assets/multimodel-queries-xmBBUT6n.js.map +1 -0
  381. package/dist/core/web/public/next/assets/mutations-CdLi0erM.js +2 -0
  382. package/dist/core/web/public/next/assets/mutations-CdLi0erM.js.map +1 -0
  383. package/dist/core/web/public/next/assets/nav-CUXtg-Iw.js +2 -0
  384. package/dist/core/web/public/next/assets/nav-CUXtg-Iw.js.map +1 -0
  385. package/dist/core/web/public/next/assets/needs-you-actions-B2tjWO-0.js +2 -0
  386. package/dist/core/web/public/next/assets/needs-you-actions-B2tjWO-0.js.map +1 -0
  387. package/dist/core/web/public/next/assets/needs-you-model-DL9EEd2L.js +2 -0
  388. package/dist/core/web/public/next/assets/needs-you-model-DL9EEd2L.js.map +1 -0
  389. package/dist/core/web/public/next/assets/open-terminal-BfbxGoYQ.js +2 -0
  390. package/dist/core/web/public/next/assets/open-terminal-BfbxGoYQ.js.map +1 -0
  391. package/dist/core/web/public/next/assets/open-terminal-request-BT1UE0fz.js +2 -0
  392. package/dist/core/web/public/next/assets/open-terminal-request-BT1UE0fz.js.map +1 -0
  393. package/dist/core/web/public/next/assets/overnight-queries-cjjogTzn.js +2 -0
  394. package/dist/core/web/public/next/assets/overnight-queries-cjjogTzn.js.map +1 -0
  395. package/dist/core/web/public/next/assets/palette-handoff-XL2WWc9I.js +2 -0
  396. package/dist/core/web/public/next/assets/palette-handoff-XL2WWc9I.js.map +1 -0
  397. package/dist/core/web/public/next/assets/panes-5GU8cuI9.js +3 -0
  398. package/dist/core/web/public/next/assets/panes-5GU8cuI9.js.map +1 -0
  399. package/dist/core/web/public/next/assets/path-display-ZSzKoo8T.js +2 -0
  400. package/dist/core/web/public/next/assets/path-display-ZSzKoo8T.js.map +1 -0
  401. package/dist/core/web/public/next/assets/playbook-composer-D04tqOmU.js +2 -0
  402. package/dist/core/web/public/next/assets/playbook-composer-D04tqOmU.js.map +1 -0
  403. package/dist/core/web/public/next/assets/playbook-focus-DD1VIfkd.js +2 -0
  404. package/dist/core/web/public/next/assets/playbook-focus-DD1VIfkd.js.map +1 -0
  405. package/dist/core/web/public/next/assets/playbooks-queries-X7NGzpIn.js +2 -0
  406. package/dist/core/web/public/next/assets/playbooks-queries-X7NGzpIn.js.map +1 -0
  407. package/dist/core/web/public/next/assets/preloaded-6hKNGuRp.js +2 -0
  408. package/dist/core/web/public/next/assets/preloaded-6hKNGuRp.js.map +1 -0
  409. package/dist/core/web/public/next/assets/primitives-6nAFZkcg.js +1 -0
  410. package/dist/core/web/public/next/assets/pwa-BzXJXtDt.js +2 -0
  411. package/dist/core/web/public/next/assets/pwa-BzXJXtDt.js.map +1 -0
  412. package/dist/core/web/public/next/assets/queries-PgZlvFqO.js +2 -0
  413. package/dist/core/web/public/next/assets/queries-PgZlvFqO.js.map +1 -0
  414. package/dist/core/web/public/next/assets/reasoning-pref-BS0PSZ8d.js +2 -0
  415. package/dist/core/web/public/next/assets/reasoning-pref-BS0PSZ8d.js.map +1 -0
  416. package/dist/core/web/public/next/assets/remote-session-Bu-dtRcS.js +3 -0
  417. package/dist/core/web/public/next/assets/remote-session-Bu-dtRcS.js.map +1 -0
  418. package/dist/core/web/public/next/assets/resolved-store-UYN2k9My.js +2 -0
  419. package/dist/core/web/public/next/assets/resolved-store-UYN2k9My.js.map +1 -0
  420. package/dist/core/web/public/next/assets/resources-queries-XfQ8w9In.js +2 -0
  421. package/dist/core/web/public/next/assets/resources-queries-XfQ8w9In.js.map +1 -0
  422. package/dist/core/web/public/next/assets/reveal-anchor-3ZUTtB8Q.js +2 -0
  423. package/dist/core/web/public/next/assets/reveal-anchor-3ZUTtB8Q.js.map +1 -0
  424. package/dist/core/web/public/next/assets/sheet-DP8ByDWU.js +2 -0
  425. package/dist/core/web/public/next/assets/sheet-DP8ByDWU.js.map +1 -0
  426. package/dist/core/web/public/next/assets/slots-DWlj_c7i.js +3 -0
  427. package/dist/core/web/public/next/assets/slots-DWlj_c7i.js.map +1 -0
  428. package/dist/core/web/public/next/assets/sources-queries-Cjk1rpDU.js +4 -0
  429. package/dist/core/web/public/next/assets/sources-queries-Cjk1rpDU.js.map +1 -0
  430. package/dist/core/web/public/next/assets/sse-Z3U8XhDI.js +2 -0
  431. package/dist/core/web/public/next/assets/sse-Z3U8XhDI.js.map +1 -0
  432. package/dist/core/web/public/next/assets/surface-data-hufdOfpz.js +2 -0
  433. package/dist/core/web/public/next/assets/surface-data-hufdOfpz.js.map +1 -0
  434. package/dist/core/web/public/next/assets/surface-prefetch-CFtP8imB.js +2 -0
  435. package/dist/core/web/public/next/assets/surface-prefetch-CFtP8imB.js.map +1 -0
  436. package/dist/core/web/public/next/assets/terminal-client-CCSvMeEv.js +2 -0
  437. package/dist/core/web/public/next/assets/terminal-client-CCSvMeEv.js.map +1 -0
  438. package/dist/core/web/public/next/assets/terminal-icons-Dx6neM-J.js +2 -0
  439. package/dist/core/web/public/next/assets/terminal-icons-Dx6neM-J.js.map +1 -0
  440. package/dist/core/web/public/next/assets/terminal-view-BSieiQvi.js +6 -0
  441. package/dist/core/web/public/next/assets/terminal-view-BSieiQvi.js.map +1 -0
  442. package/dist/core/web/public/next/assets/thread-data-Cd2DZffn.js +2 -0
  443. package/dist/core/web/public/next/assets/thread-data-Cd2DZffn.js.map +1 -0
  444. package/dist/core/web/public/next/assets/ui-parts-wvov2ktB.js +2 -0
  445. package/dist/core/web/public/next/assets/ui-parts-wvov2ktB.js.map +1 -0
  446. package/dist/core/web/public/next/assets/usage-queries-nZjJ1aky.js +2 -0
  447. package/dist/core/web/public/next/assets/usage-queries-nZjJ1aky.js.map +1 -0
  448. package/dist/core/web/public/next/assets/use-chat-activity-_tBmEPPN.js +2 -0
  449. package/dist/core/web/public/next/assets/use-chat-activity-_tBmEPPN.js.map +1 -0
  450. package/dist/core/web/public/next/assets/use-guarded-action-DKKjhPKG.js +2 -0
  451. package/dist/core/web/public/next/assets/use-guarded-action-DKKjhPKG.js.map +1 -0
  452. package/dist/core/web/public/next/assets/use-ticker-w1c3SOqK.js +2 -0
  453. package/dist/core/web/public/next/assets/use-ticker-w1c3SOqK.js.map +1 -0
  454. package/dist/core/web/public/next/assets/use-token-gate-h5QAERLT.js +2 -0
  455. package/dist/core/web/public/next/assets/use-token-gate-h5QAERLT.js.map +1 -0
  456. package/dist/core/web/public/next/assets/useAutoSeat-Dpbn0XUv.js +2 -0
  457. package/dist/core/web/public/next/assets/useAutoSeat-Dpbn0XUv.js.map +1 -0
  458. package/dist/core/web/public/next/assets/useOnboarding-VoV1LcuJ.js +2 -0
  459. package/dist/core/web/public/next/assets/useOnboarding-VoV1LcuJ.js.map +1 -0
  460. package/dist/core/web/public/next/assets/useSeatHealth-DuSaKdIs.js +2 -0
  461. package/dist/core/web/public/next/assets/useSeatHealth-DuSaKdIs.js.map +1 -0
  462. package/dist/core/web/public/next/assets/useSeatsRefresh-DFaR1jSz.js +2 -0
  463. package/dist/core/web/public/next/assets/useSeatsRefresh-DFaR1jSz.js.map +1 -0
  464. package/dist/core/web/public/next/assets/useVerseSession-BOsgJzT5.js +2 -0
  465. package/dist/core/web/public/next/assets/useVerseSession-BOsgJzT5.js.map +1 -0
  466. package/dist/core/web/public/next/assets/useVerseTranscript-BN_fMz6x.js +2 -0
  467. package/dist/core/web/public/next/assets/useVerseTranscript-BN_fMz6x.js.map +1 -0
  468. package/dist/core/web/public/next/assets/verse-bootstrap-query-B3vFD9XK.js +2 -0
  469. package/dist/core/web/public/next/assets/verse-bootstrap-query-B3vFD9XK.js.map +1 -0
  470. package/dist/core/web/public/next/assets/verse-icons-vSkflmRB.js +2 -0
  471. package/dist/core/web/public/next/assets/verse-icons-vSkflmRB.js.map +1 -0
  472. package/dist/core/web/public/next/assets/warmup-D9MjYs5S.js +3 -0
  473. package/dist/core/web/public/next/assets/warmup-D9MjYs5S.js.map +1 -0
  474. package/dist/core/web/public/next/assets/wiki-focus-De8-E48Z.js +2 -0
  475. package/dist/core/web/public/next/assets/wiki-focus-De8-E48Z.js.map +1 -0
  476. package/dist/core/web/public/next/index.html +1 -1
  477. package/dist/release-dependency-inventory.json +1 -1
  478. package/package.json +1 -1
  479. package/dist/core/web/public/next/assets/ActionMenu-CebJFKYy.js +0 -2
  480. package/dist/core/web/public/next/assets/ActionMenu-CebJFKYy.js.map +0 -1
  481. package/dist/core/web/public/next/assets/Advanced-Dr9aVbXV.js +0 -2
  482. package/dist/core/web/public/next/assets/Advanced-Dr9aVbXV.js.map +0 -1
  483. package/dist/core/web/public/next/assets/AgentDetailScreen-DCVf81Vo.js +0 -2
  484. package/dist/core/web/public/next/assets/AgentDetailScreen-DCVf81Vo.js.map +0 -1
  485. package/dist/core/web/public/next/assets/AgentToolsSheet-C3SbvEiV.js +0 -2
  486. package/dist/core/web/public/next/assets/AgentToolsSheet-C3SbvEiV.js.map +0 -1
  487. package/dist/core/web/public/next/assets/AgentToolsStrip-CZNxj_Iv.js +0 -2
  488. package/dist/core/web/public/next/assets/AgentToolsStrip-CZNxj_Iv.js.map +0 -1
  489. package/dist/core/web/public/next/assets/AgentsScreen-zLj4gzPR.js +0 -2
  490. package/dist/core/web/public/next/assets/AgentsScreen-zLj4gzPR.js.map +0 -1
  491. package/dist/core/web/public/next/assets/AgentsSection-CIo_nRmi.js +0 -3
  492. package/dist/core/web/public/next/assets/AgentsSection-CIo_nRmi.js.map +0 -1
  493. package/dist/core/web/public/next/assets/App-CPKNuUdC.js +0 -8
  494. package/dist/core/web/public/next/assets/App-CPKNuUdC.js.map +0 -1
  495. package/dist/core/web/public/next/assets/AppsSection-D2F2CM-E.js +0 -2
  496. package/dist/core/web/public/next/assets/AppsSection-D2F2CM-E.js.map +0 -1
  497. package/dist/core/web/public/next/assets/AreaTrend-DiZu8bjc.js +0 -2
  498. package/dist/core/web/public/next/assets/AreaTrend-DiZu8bjc.js.map +0 -1
  499. package/dist/core/web/public/next/assets/AutomationsSection-B4rBNUyo.js +0 -2
  500. package/dist/core/web/public/next/assets/AutomationsSection-B4rBNUyo.js.map +0 -1
  501. package/dist/core/web/public/next/assets/AutonomyOffState-DEznxI-Q.js +0 -3
  502. package/dist/core/web/public/next/assets/AutonomyOffState-DEznxI-Q.js.map +0 -1
  503. package/dist/core/web/public/next/assets/AutonomySection-Dq5n3gs7.js +0 -2
  504. package/dist/core/web/public/next/assets/AutonomySection-Dq5n3gs7.js.map +0 -1
  505. package/dist/core/web/public/next/assets/AutonomyStatus-Uydy6-pZ.js +0 -2
  506. package/dist/core/web/public/next/assets/AutonomyStatus-Uydy6-pZ.js.map +0 -1
  507. package/dist/core/web/public/next/assets/BranchBar-BzUmUM_j.js +0 -2
  508. package/dist/core/web/public/next/assets/BranchBar-BzUmUM_j.js.map +0 -1
  509. package/dist/core/web/public/next/assets/BrowserPanel-C_VI6Awi.js +0 -7
  510. package/dist/core/web/public/next/assets/BrowserPanel-C_VI6Awi.js.map +0 -1
  511. package/dist/core/web/public/next/assets/BudgetControl-B23rNAuC.js +0 -2
  512. package/dist/core/web/public/next/assets/BudgetControl-B23rNAuC.js.map +0 -1
  513. package/dist/core/web/public/next/assets/Button-DJY_Pu5B.js +0 -2
  514. package/dist/core/web/public/next/assets/Button-DJY_Pu5B.js.map +0 -1
  515. package/dist/core/web/public/next/assets/CapacityStrip-B5Yj2PhZ.js +0 -2
  516. package/dist/core/web/public/next/assets/CapacityStrip-B5Yj2PhZ.js.map +0 -1
  517. package/dist/core/web/public/next/assets/ChangesPaneHost-LsUonc7P.js +0 -16
  518. package/dist/core/web/public/next/assets/ChangesPaneHost-LsUonc7P.js.map +0 -1
  519. package/dist/core/web/public/next/assets/ChartFrame-CakjKkPx.js +0 -2
  520. package/dist/core/web/public/next/assets/ChartFrame-CakjKkPx.js.map +0 -1
  521. package/dist/core/web/public/next/assets/ChatPanes-DgKskpXb.js +0 -2
  522. package/dist/core/web/public/next/assets/ChatPanes-DgKskpXb.js.map +0 -1
  523. package/dist/core/web/public/next/assets/ChatSection-DXpzV1NW.js +0 -3
  524. package/dist/core/web/public/next/assets/ChatSection-DXpzV1NW.js.map +0 -1
  525. package/dist/core/web/public/next/assets/ChecksPanel-BeCJVOJC.js +0 -5
  526. package/dist/core/web/public/next/assets/ChecksPanel-BeCJVOJC.js.map +0 -1
  527. package/dist/core/web/public/next/assets/CloudBudgetForm-4SWIGJLs.js +0 -2
  528. package/dist/core/web/public/next/assets/CloudBudgetForm-4SWIGJLs.js.map +0 -1
  529. package/dist/core/web/public/next/assets/CommandPalette-B4QaFGY5.js +0 -3
  530. package/dist/core/web/public/next/assets/CommandPalette-B4QaFGY5.js.map +0 -1
  531. package/dist/core/web/public/next/assets/CommandSection-8TFjYitt.js +0 -3
  532. package/dist/core/web/public/next/assets/CommandSection-8TFjYitt.js.map +0 -1
  533. package/dist/core/web/public/next/assets/CommandWorkflowForm-B2ooVjof.js +0 -9
  534. package/dist/core/web/public/next/assets/CommandWorkflowForm-B2ooVjof.js.map +0 -1
  535. package/dist/core/web/public/next/assets/CommandWorkflowPicker-C09vJiUG.js +0 -3
  536. package/dist/core/web/public/next/assets/CommandWorkflowPicker-C09vJiUG.js.map +0 -1
  537. package/dist/core/web/public/next/assets/CompareDialog-CaopnGI0.js +0 -4
  538. package/dist/core/web/public/next/assets/CompareDialog-CaopnGI0.js.map +0 -1
  539. package/dist/core/web/public/next/assets/ComputerControl-BflC6wd1.js +0 -2
  540. package/dist/core/web/public/next/assets/ComputerControl-BflC6wd1.js.map +0 -1
  541. package/dist/core/web/public/next/assets/ConfirmDialog-CTeMFavv.js +0 -2
  542. package/dist/core/web/public/next/assets/ConfirmDialog-CTeMFavv.js.map +0 -1
  543. package/dist/core/web/public/next/assets/DeleteChatDialog-B2bUTuZ9.js +0 -2
  544. package/dist/core/web/public/next/assets/DeleteChatDialog-B2bUTuZ9.js.map +0 -1
  545. package/dist/core/web/public/next/assets/DevinStopDialog-DPP34cna.js +0 -2
  546. package/dist/core/web/public/next/assets/DevinStopDialog-DPP34cna.js.map +0 -1
  547. package/dist/core/web/public/next/assets/Dialog-r4j4R4b6.js +0 -2
  548. package/dist/core/web/public/next/assets/Dialog-r4j4R4b6.js.map +0 -1
  549. package/dist/core/web/public/next/assets/DiffPane-CKnpzqaU.js +0 -2
  550. package/dist/core/web/public/next/assets/DiffPane-CKnpzqaU.js.map +0 -1
  551. package/dist/core/web/public/next/assets/DiffViewer-BzQ7245p.js +0 -2
  552. package/dist/core/web/public/next/assets/DiffViewer-BzQ7245p.js.map +0 -1
  553. package/dist/core/web/public/next/assets/DockHost-BCZtC_lm.js +0 -2
  554. package/dist/core/web/public/next/assets/DockHost-BCZtC_lm.js.map +0 -1
  555. package/dist/core/web/public/next/assets/EmptyState-Cwpga8L9.js +0 -2
  556. package/dist/core/web/public/next/assets/EmptyState-Cwpga8L9.js.map +0 -1
  557. package/dist/core/web/public/next/assets/Epistemic-BBwXv-C1.js +0 -2
  558. package/dist/core/web/public/next/assets/Epistemic-BBwXv-C1.js.map +0 -1
  559. package/dist/core/web/public/next/assets/EvidenceTimeline-hAENJQCa.js +0 -2
  560. package/dist/core/web/public/next/assets/EvidenceTimeline-hAENJQCa.js.map +0 -1
  561. package/dist/core/web/public/next/assets/FilesPane-CrPN5zlx.js +0 -2
  562. package/dist/core/web/public/next/assets/FilesPane-CrPN5zlx.js.map +0 -1
  563. package/dist/core/web/public/next/assets/FleetScreen-Cz9HQ-st.js +0 -2
  564. package/dist/core/web/public/next/assets/FleetScreen-Cz9HQ-st.js.map +0 -1
  565. package/dist/core/web/public/next/assets/FleetSection-CmZKQ1rr.js +0 -5
  566. package/dist/core/web/public/next/assets/FleetSection-CmZKQ1rr.js.map +0 -1
  567. package/dist/core/web/public/next/assets/Funnel-Cfg55EZp.js +0 -2
  568. package/dist/core/web/public/next/assets/Funnel-Cfg55EZp.js.map +0 -1
  569. package/dist/core/web/public/next/assets/GearTray-D-Mhc8TJ.js +0 -2
  570. package/dist/core/web/public/next/assets/GearTray-D-Mhc8TJ.js.map +0 -1
  571. package/dist/core/web/public/next/assets/GitDialogs-e-7RQEGv.js +0 -2
  572. package/dist/core/web/public/next/assets/GitDialogs-e-7RQEGv.js.map +0 -1
  573. package/dist/core/web/public/next/assets/GrowthSection-DsIrdTDd.js +0 -3
  574. package/dist/core/web/public/next/assets/GrowthSection-DsIrdTDd.js.map +0 -1
  575. package/dist/core/web/public/next/assets/HandoffDialog-1MB2fmT1.js +0 -2
  576. package/dist/core/web/public/next/assets/HandoffDialog-1MB2fmT1.js.map +0 -1
  577. package/dist/core/web/public/next/assets/HomeBody-n_t3A58_.js +0 -3
  578. package/dist/core/web/public/next/assets/HomeBody-n_t3A58_.js.map +0 -1
  579. package/dist/core/web/public/next/assets/HomeSeats-DA66aOWC.js +0 -2
  580. package/dist/core/web/public/next/assets/HomeSeats-DA66aOWC.js.map +0 -1
  581. package/dist/core/web/public/next/assets/Input-Bt6fp051.js +0 -2
  582. package/dist/core/web/public/next/assets/Input-Bt6fp051.js.map +0 -1
  583. package/dist/core/web/public/next/assets/LaunchDialog-BCd7XqCv.js +0 -9
  584. package/dist/core/web/public/next/assets/LaunchDialog-BCd7XqCv.js.map +0 -1
  585. package/dist/core/web/public/next/assets/LeaderCard-DFAFcyfZ.js +0 -2
  586. package/dist/core/web/public/next/assets/LeaderCard-DFAFcyfZ.js.map +0 -1
  587. package/dist/core/web/public/next/assets/LeaderConversation-LSenfZzT.js +0 -3
  588. package/dist/core/web/public/next/assets/LeaderConversation-LSenfZzT.js.map +0 -1
  589. package/dist/core/web/public/next/assets/LeaderScreen-B2UxRWUm.js +0 -2
  590. package/dist/core/web/public/next/assets/LeaderScreen-B2UxRWUm.js.map +0 -1
  591. package/dist/core/web/public/next/assets/LessonsPanel-D86ZT0we.js +0 -2
  592. package/dist/core/web/public/next/assets/LessonsPanel-D86ZT0we.js.map +0 -1
  593. package/dist/core/web/public/next/assets/LiveTimer-AtG5hPwV.js +0 -2
  594. package/dist/core/web/public/next/assets/LiveTimer-AtG5hPwV.js.map +0 -1
  595. package/dist/core/web/public/next/assets/LocalSeatBadge-XfGRZCA3.js +0 -2
  596. package/dist/core/web/public/next/assets/LocalSeatBadge-XfGRZCA3.js.map +0 -1
  597. package/dist/core/web/public/next/assets/MatrixHeatmap-PSnyMJ2h.js +0 -2
  598. package/dist/core/web/public/next/assets/MatrixHeatmap-PSnyMJ2h.js.map +0 -1
  599. package/dist/core/web/public/next/assets/McpSection-BG2FSkgH.js +0 -2
  600. package/dist/core/web/public/next/assets/McpSection-BG2FSkgH.js.map +0 -1
  601. package/dist/core/web/public/next/assets/MessageMarkdown-CQEqoMvf.js +0 -3
  602. package/dist/core/web/public/next/assets/MessageMarkdown-CQEqoMvf.js.map +0 -1
  603. package/dist/core/web/public/next/assets/MessageMarkdownRenderer-DU-VLDhb.js +0 -72
  604. package/dist/core/web/public/next/assets/MessageMarkdownRenderer-DU-VLDhb.js.map +0 -1
  605. package/dist/core/web/public/next/assets/Meter-BfaE-BjY.js +0 -2
  606. package/dist/core/web/public/next/assets/Meter-BfaE-BjY.js.map +0 -1
  607. package/dist/core/web/public/next/assets/MicButton-BbGB7y_9.js +0 -2
  608. package/dist/core/web/public/next/assets/MicButton-BbGB7y_9.js.map +0 -1
  609. package/dist/core/web/public/next/assets/MindSection-CX0VaHo1.js +0 -3
  610. package/dist/core/web/public/next/assets/MindSection-CX0VaHo1.js.map +0 -1
  611. package/dist/core/web/public/next/assets/MobileComposer-CFeLWUCz.js +0 -2
  612. package/dist/core/web/public/next/assets/MobileComposer-CFeLWUCz.js.map +0 -1
  613. package/dist/core/web/public/next/assets/MobileGuardSheet-cGW9RCTr.js +0 -2
  614. package/dist/core/web/public/next/assets/MobileGuardSheet-cGW9RCTr.js.map +0 -1
  615. package/dist/core/web/public/next/assets/MobileRuntime-BWTZ_QLr.js +0 -3
  616. package/dist/core/web/public/next/assets/MobileRuntime-BWTZ_QLr.js.map +0 -1
  617. package/dist/core/web/public/next/assets/MoreScreen-BcHZhVrR.js +0 -2
  618. package/dist/core/web/public/next/assets/MoreScreen-BcHZhVrR.js.map +0 -1
  619. package/dist/core/web/public/next/assets/MultiModelBar-COxIRv7m.js +0 -7
  620. package/dist/core/web/public/next/assets/MultiModelBar-COxIRv7m.js.map +0 -1
  621. package/dist/core/web/public/next/assets/MutationTokenDialog-Dnf_rcnc.js +0 -2
  622. package/dist/core/web/public/next/assets/MutationTokenDialog-Dnf_rcnc.js.map +0 -1
  623. package/dist/core/web/public/next/assets/NeedsYouDrawer-COrUlnd0.js +0 -3
  624. package/dist/core/web/public/next/assets/NeedsYouDrawer-COrUlnd0.js.map +0 -1
  625. package/dist/core/web/public/next/assets/NeedsYouList-AXzOe4EL.js +0 -2
  626. package/dist/core/web/public/next/assets/NeedsYouList-AXzOe4EL.js.map +0 -1
  627. package/dist/core/web/public/next/assets/NeedsYouScreen-HSXybHgd.js +0 -2
  628. package/dist/core/web/public/next/assets/NeedsYouScreen-HSXybHgd.js.map +0 -1
  629. package/dist/core/web/public/next/assets/NewAgentScreen-BI849ZsG.js +0 -2
  630. package/dist/core/web/public/next/assets/NewAgentScreen-BI849ZsG.js.map +0 -1
  631. package/dist/core/web/public/next/assets/NewChatDialog-BHoCnP6Q.js +0 -4
  632. package/dist/core/web/public/next/assets/NewChatDialog-BHoCnP6Q.js.map +0 -1
  633. package/dist/core/web/public/next/assets/OnboardingFlow-BVljU2uy.js +0 -3
  634. package/dist/core/web/public/next/assets/OnboardingFlow-BVljU2uy.js.map +0 -1
  635. package/dist/core/web/public/next/assets/OnboardingGate-DlI4L7Ki.js +0 -3
  636. package/dist/core/web/public/next/assets/OnboardingGate-DlI4L7Ki.js.map +0 -1
  637. package/dist/core/web/public/next/assets/PlaybooksSection-hhNpXnsR.js +0 -9
  638. package/dist/core/web/public/next/assets/PlaybooksSection-hhNpXnsR.js.map +0 -1
  639. package/dist/core/web/public/next/assets/PreviewPane-BbXr63u2.js +0 -2
  640. package/dist/core/web/public/next/assets/PreviewPane-BbXr63u2.js.map +0 -1
  641. package/dist/core/web/public/next/assets/ProviderLogo-BliSWEMw.js +0 -2
  642. package/dist/core/web/public/next/assets/ProviderLogo-BliSWEMw.js.map +0 -1
  643. package/dist/core/web/public/next/assets/RailStatus-SnrVxLnp.js +0 -2
  644. package/dist/core/web/public/next/assets/RailStatus-SnrVxLnp.js.map +0 -1
  645. package/dist/core/web/public/next/assets/ReasoningPane-C04_bOAi.js +0 -2
  646. package/dist/core/web/public/next/assets/ReasoningPane-C04_bOAi.js.map +0 -1
  647. package/dist/core/web/public/next/assets/ReasoningSheet-BvNFwtuX.js +0 -2
  648. package/dist/core/web/public/next/assets/ReasoningSheet-BvNFwtuX.js.map +0 -1
  649. package/dist/core/web/public/next/assets/RefreshIndicator-BNptNJiV.js +0 -2
  650. package/dist/core/web/public/next/assets/RefreshIndicator-BNptNJiV.js.map +0 -1
  651. package/dist/core/web/public/next/assets/RemoteMobileApp-osaSEvnm.js +0 -2
  652. package/dist/core/web/public/next/assets/RemoteMobileApp-osaSEvnm.js.map +0 -1
  653. package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-LO31zjUR.js +0 -7
  654. package/dist/core/web/public/next/assets/ResourcePoolConsoleApp-LO31zjUR.js.map +0 -1
  655. package/dist/core/web/public/next/assets/ResourcesChrome-ByZE532G.js +0 -3
  656. package/dist/core/web/public/next/assets/ResourcesChrome-ByZE532G.js.map +0 -1
  657. package/dist/core/web/public/next/assets/ResourcesChrome-p_VCkMZH.css +0 -1
  658. package/dist/core/web/public/next/assets/ResourcesDrawer-BH9uwNE8.js +0 -3
  659. package/dist/core/web/public/next/assets/ResourcesDrawer-BH9uwNE8.js.map +0 -1
  660. package/dist/core/web/public/next/assets/ReviewMenu-B2A_YDPi.js +0 -2
  661. package/dist/core/web/public/next/assets/ReviewMenu-B2A_YDPi.js.map +0 -1
  662. package/dist/core/web/public/next/assets/RouteErrorBoundary-CVabFM97.js +0 -2
  663. package/dist/core/web/public/next/assets/RouteErrorBoundary-CVabFM97.js.map +0 -1
  664. package/dist/core/web/public/next/assets/RunInCloudAction-BpNHE7m8.js +0 -2
  665. package/dist/core/web/public/next/assets/RunInCloudAction-BpNHE7m8.js.map +0 -1
  666. package/dist/core/web/public/next/assets/RunInDevinAction-Bkf5Gb3a.js +0 -2
  667. package/dist/core/web/public/next/assets/RunInDevinAction-Bkf5Gb3a.js.map +0 -1
  668. package/dist/core/web/public/next/assets/SchedulingEvidence-B08-qhhm.js +0 -2
  669. package/dist/core/web/public/next/assets/SchedulingEvidence-B08-qhhm.js.map +0 -1
  670. package/dist/core/web/public/next/assets/ScreenHost-BGSxFyWK.js +0 -3
  671. package/dist/core/web/public/next/assets/ScreenHost-BGSxFyWK.js.map +0 -1
  672. package/dist/core/web/public/next/assets/SeatSelector-B4lRZl0K.js +0 -3
  673. package/dist/core/web/public/next/assets/SeatSelector-B4lRZl0K.js.map +0 -1
  674. package/dist/core/web/public/next/assets/Segmented-Dokzywy8.js +0 -2
  675. package/dist/core/web/public/next/assets/Segmented-Dokzywy8.js.map +0 -1
  676. package/dist/core/web/public/next/assets/Select-tf4lNvWD.js +0 -2
  677. package/dist/core/web/public/next/assets/Select-tf4lNvWD.js.map +0 -1
  678. package/dist/core/web/public/next/assets/SessionGate-Bab2qO29.js +0 -2
  679. package/dist/core/web/public/next/assets/SessionGate-Bab2qO29.js.map +0 -1
  680. package/dist/core/web/public/next/assets/SessionInsightChip-C-fj8h4A.js +0 -2
  681. package/dist/core/web/public/next/assets/SessionInsightChip-C-fj8h4A.js.map +0 -1
  682. package/dist/core/web/public/next/assets/SessionSearch-CqjjwOW2.js +0 -2
  683. package/dist/core/web/public/next/assets/SessionSearch-CqjjwOW2.js.map +0 -1
  684. package/dist/core/web/public/next/assets/SettingsSection-DfOsHzl6.js +0 -2
  685. package/dist/core/web/public/next/assets/SettingsSection-DfOsHzl6.js.map +0 -1
  686. package/dist/core/web/public/next/assets/SetupChecklist-BsxCTcYY.js +0 -2
  687. package/dist/core/web/public/next/assets/SetupChecklist-BsxCTcYY.js.map +0 -1
  688. package/dist/core/web/public/next/assets/ShadowDecisions-B1ZPv7K-.js +0 -3
  689. package/dist/core/web/public/next/assets/ShadowDecisions-B1ZPv7K-.js.map +0 -1
  690. package/dist/core/web/public/next/assets/Sheet-DLlZ00Lu.js +0 -2
  691. package/dist/core/web/public/next/assets/Sheet-DLlZ00Lu.js.map +0 -1
  692. package/dist/core/web/public/next/assets/ShortcutsOverlay-CDwQdpGV.js +0 -2
  693. package/dist/core/web/public/next/assets/ShortcutsOverlay-CDwQdpGV.js.map +0 -1
  694. package/dist/core/web/public/next/assets/Sidebar-H5WNri2S.js +0 -3
  695. package/dist/core/web/public/next/assets/Sidebar-H5WNri2S.js.map +0 -1
  696. package/dist/core/web/public/next/assets/SkipToContent-BjJE6yOo.js +0 -2
  697. package/dist/core/web/public/next/assets/SkipToContent-BjJE6yOo.js.map +0 -1
  698. package/dist/core/web/public/next/assets/Slider-C68TumXj.js +0 -2
  699. package/dist/core/web/public/next/assets/Slider-C68TumXj.js.map +0 -1
  700. package/dist/core/web/public/next/assets/SourcesPane-DHYs4YIg.js +0 -2
  701. package/dist/core/web/public/next/assets/SourcesPane-DHYs4YIg.js.map +0 -1
  702. package/dist/core/web/public/next/assets/SourcesPanel-DFyLfYBO.js +0 -2
  703. package/dist/core/web/public/next/assets/SourcesPanel-DFyLfYBO.js.map +0 -1
  704. package/dist/core/web/public/next/assets/StatTile-CTUuhOLS.js +0 -2
  705. package/dist/core/web/public/next/assets/StatTile-CTUuhOLS.js.map +0 -1
  706. package/dist/core/web/public/next/assets/StatusBadge-DrVbi5dF.js +0 -2
  707. package/dist/core/web/public/next/assets/StatusBadge-DrVbi5dF.js.map +0 -1
  708. package/dist/core/web/public/next/assets/StepBand-CXDpnu2R.js +0 -2
  709. package/dist/core/web/public/next/assets/StepBand-CXDpnu2R.js.map +0 -1
  710. package/dist/core/web/public/next/assets/Surface-DCL7uORg.js +0 -2
  711. package/dist/core/web/public/next/assets/Surface-DCL7uORg.js.map +0 -1
  712. package/dist/core/web/public/next/assets/Swimlane-BAEjfoVU.js +0 -2
  713. package/dist/core/web/public/next/assets/Swimlane-BAEjfoVU.js.map +0 -1
  714. package/dist/core/web/public/next/assets/Switch-Z7RmRjWE.js +0 -2
  715. package/dist/core/web/public/next/assets/Switch-Z7RmRjWE.js.map +0 -1
  716. package/dist/core/web/public/next/assets/Tag-Ciht3C94.js +0 -2
  717. package/dist/core/web/public/next/assets/Tag-Ciht3C94.js.map +0 -1
  718. package/dist/core/web/public/next/assets/TerminalPane-BdIyhtzJ.js +0 -26
  719. package/dist/core/web/public/next/assets/TerminalPane-BdIyhtzJ.js.map +0 -1
  720. package/dist/core/web/public/next/assets/TerminalPane-DJKT600N.js +0 -3
  721. package/dist/core/web/public/next/assets/TerminalPane-DJKT600N.js.map +0 -1
  722. package/dist/core/web/public/next/assets/ThinkingBlock-CHRZX_fJ.js +0 -2
  723. package/dist/core/web/public/next/assets/ThinkingBlock-CHRZX_fJ.js.map +0 -1
  724. package/dist/core/web/public/next/assets/UniverseConsoleApp-QSoaY_Fk.js +0 -2
  725. package/dist/core/web/public/next/assets/UniverseConsoleApp-QSoaY_Fk.js.map +0 -1
  726. package/dist/core/web/public/next/assets/UniverseView-ZXAOJ0Rq.js +0 -9
  727. package/dist/core/web/public/next/assets/UniverseView-ZXAOJ0Rq.js.map +0 -1
  728. package/dist/core/web/public/next/assets/UsageSection-BEAa-W_q.js +0 -3
  729. package/dist/core/web/public/next/assets/UsageSection-BEAa-W_q.js.map +0 -1
  730. package/dist/core/web/public/next/assets/UsePlaybookAction-S7Yky_M8.js +0 -2
  731. package/dist/core/web/public/next/assets/UsePlaybookAction-S7Yky_M8.js.map +0 -1
  732. package/dist/core/web/public/next/assets/VerseConsoleApp-Cj6yPJo3.js +0 -3
  733. package/dist/core/web/public/next/assets/VerseConsoleApp-Cj6yPJo3.js.map +0 -1
  734. package/dist/core/web/public/next/assets/VerseConsoleApp-n6qr3lCF.css +0 -1
  735. package/dist/core/web/public/next/assets/VerseMobileApp-BRayqF_2.js +0 -3
  736. package/dist/core/web/public/next/assets/VerseMobileApp-BRayqF_2.js.map +0 -1
  737. package/dist/core/web/public/next/assets/VerseShared-CH8mV5ew.js +0 -2
  738. package/dist/core/web/public/next/assets/VerseShared-CH8mV5ew.js.map +0 -1
  739. package/dist/core/web/public/next/assets/VoiceHud-CO4yGRlr.js +0 -2
  740. package/dist/core/web/public/next/assets/VoiceHud-CO4yGRlr.js.map +0 -1
  741. package/dist/core/web/public/next/assets/VoiceInput-fSLnbGJ4.js +0 -2
  742. package/dist/core/web/public/next/assets/VoiceInput-fSLnbGJ4.js.map +0 -1
  743. package/dist/core/web/public/next/assets/WikiSection-CN-HansV.js +0 -2
  744. package/dist/core/web/public/next/assets/WikiSection-CN-HansV.js.map +0 -1
  745. package/dist/core/web/public/next/assets/Workspace-dufi6DmW.js +0 -6
  746. package/dist/core/web/public/next/assets/Workspace-dufi6DmW.js.map +0 -1
  747. package/dist/core/web/public/next/assets/actions-gBplqbpY.js +0 -2
  748. package/dist/core/web/public/next/assets/actions-gBplqbpY.js.map +0 -1
  749. package/dist/core/web/public/next/assets/agent-tools-client-ClFut2J1.js +0 -2
  750. package/dist/core/web/public/next/assets/agent-tools-client-ClFut2J1.js.map +0 -1
  751. package/dist/core/web/public/next/assets/agents-focus-DjBz83BQ.js +0 -2
  752. package/dist/core/web/public/next/assets/agents-focus-DjBz83BQ.js.map +0 -1
  753. package/dist/core/web/public/next/assets/app-version-B0FcXqqB.js +0 -2
  754. package/dist/core/web/public/next/assets/app-version-B0FcXqqB.js.map +0 -1
  755. package/dist/core/web/public/next/assets/apps-model-C-SdWY0N.js +0 -2
  756. package/dist/core/web/public/next/assets/apps-model-C-SdWY0N.js.map +0 -1
  757. package/dist/core/web/public/next/assets/ask-seat-DhGxiGSd.js +0 -2
  758. package/dist/core/web/public/next/assets/ask-seat-DhGxiGSd.js.map +0 -1
  759. package/dist/core/web/public/next/assets/authority-model-CoXAS-Z6.js +0 -2
  760. package/dist/core/web/public/next/assets/authority-model-CoXAS-Z6.js.map +0 -1
  761. package/dist/core/web/public/next/assets/automations-focus-CeneF7lP.js +0 -2
  762. package/dist/core/web/public/next/assets/automations-focus-CeneF7lP.js.map +0 -1
  763. package/dist/core/web/public/next/assets/budget-queries-DCZevH2S.js +0 -2
  764. package/dist/core/web/public/next/assets/budget-queries-DCZevH2S.js.map +0 -1
  765. package/dist/core/web/public/next/assets/capacity-strip-model-Wna9o0dS.js +0 -2
  766. package/dist/core/web/public/next/assets/capacity-strip-model-Wna9o0dS.js.map +0 -1
  767. package/dist/core/web/public/next/assets/charts-CzqC55eL.js +0 -2
  768. package/dist/core/web/public/next/assets/charts-CzqC55eL.js.map +0 -1
  769. package/dist/core/web/public/next/assets/chat-pane-data-BBA55Pw-.js +0 -2
  770. package/dist/core/web/public/next/assets/chat-pane-data-BBA55Pw-.js.map +0 -1
  771. package/dist/core/web/public/next/assets/checkpoint-queries-gP6Vh70H.js +0 -2
  772. package/dist/core/web/public/next/assets/checkpoint-queries-gP6Vh70H.js.map +0 -1
  773. package/dist/core/web/public/next/assets/cloud-queries-Bsqo7wye.js +0 -2
  774. package/dist/core/web/public/next/assets/cloud-queries-Bsqo7wye.js.map +0 -1
  775. package/dist/core/web/public/next/assets/command-catalog-Dnx-iMLX.js +0 -2
  776. package/dist/core/web/public/next/assets/command-catalog-Dnx-iMLX.js.map +0 -1
  777. package/dist/core/web/public/next/assets/composer-queries-DHGJlnFJ.js +0 -2
  778. package/dist/core/web/public/next/assets/composer-queries-DHGJlnFJ.js.map +0 -1
  779. package/dist/core/web/public/next/assets/connectivity-BViMMNcD.js +0 -2
  780. package/dist/core/web/public/next/assets/connectivity-BViMMNcD.js.map +0 -1
  781. package/dist/core/web/public/next/assets/context-queries-Bsl-w0q-.js +0 -2
  782. package/dist/core/web/public/next/assets/context-queries-Bsl-w0q-.js.map +0 -1
  783. package/dist/core/web/public/next/assets/control-queries-CUNa6TAx.js +0 -2
  784. package/dist/core/web/public/next/assets/control-queries-CUNa6TAx.js.map +0 -1
  785. package/dist/core/web/public/next/assets/copy-setup-C2goNcTZ.js +0 -2
  786. package/dist/core/web/public/next/assets/copy-setup-C2goNcTZ.js.map +0 -1
  787. package/dist/core/web/public/next/assets/deep-link-Dg_zaqAl.js +0 -2
  788. package/dist/core/web/public/next/assets/deep-link-Dg_zaqAl.js.map +0 -1
  789. package/dist/core/web/public/next/assets/device-permissions-CEXY0Vor.js +0 -2
  790. package/dist/core/web/public/next/assets/device-permissions-CEXY0Vor.js.map +0 -1
  791. package/dist/core/web/public/next/assets/devin-queries-Cu_YYhw2.js +0 -2
  792. package/dist/core/web/public/next/assets/devin-queries-Cu_YYhw2.js.map +0 -1
  793. package/dist/core/web/public/next/assets/dock-icons-DGZoDN6N.js +0 -2
  794. package/dist/core/web/public/next/assets/dock-icons-DGZoDN6N.js.map +0 -1
  795. package/dist/core/web/public/next/assets/dock-panes-BgSO9q_f.js +0 -2
  796. package/dist/core/web/public/next/assets/dock-panes-BgSO9q_f.js.map +0 -1
  797. package/dist/core/web/public/next/assets/fleet-control-queries-clsJWanE.js +0 -2
  798. package/dist/core/web/public/next/assets/fleet-control-queries-clsJWanE.js.map +0 -1
  799. package/dist/core/web/public/next/assets/fleet-queries-DX1AwHEt.js +0 -2
  800. package/dist/core/web/public/next/assets/fleet-queries-DX1AwHEt.js.map +0 -1
  801. package/dist/core/web/public/next/assets/fleet-state-EgNiSDxu.js +0 -3
  802. package/dist/core/web/public/next/assets/fleet-state-EgNiSDxu.js.map +0 -1
  803. package/dist/core/web/public/next/assets/focus-trap-B1vuEhZX.js +0 -2
  804. package/dist/core/web/public/next/assets/focus-trap-B1vuEhZX.js.map +0 -1
  805. package/dist/core/web/public/next/assets/git-model-Bu59fz1m.js +0 -5
  806. package/dist/core/web/public/next/assets/git-model-Bu59fz1m.js.map +0 -1
  807. package/dist/core/web/public/next/assets/global-BJ_kVFpD.js +0 -3
  808. package/dist/core/web/public/next/assets/global-BJ_kVFpD.js.map +0 -1
  809. package/dist/core/web/public/next/assets/guarded-action-CzvG7Qgc.js +0 -3
  810. package/dist/core/web/public/next/assets/guarded-action-CzvG7Qgc.js.map +0 -1
  811. package/dist/core/web/public/next/assets/guarded-runners-BPM0KdoQ.js +0 -2
  812. package/dist/core/web/public/next/assets/guarded-runners-BPM0KdoQ.js.map +0 -1
  813. package/dist/core/web/public/next/assets/health-queries-CMxSsJKS.js +0 -2
  814. package/dist/core/web/public/next/assets/health-queries-CMxSsJKS.js.map +0 -1
  815. package/dist/core/web/public/next/assets/icons-MYfI6vZr.js +0 -2
  816. package/dist/core/web/public/next/assets/icons-MYfI6vZr.js.map +0 -1
  817. package/dist/core/web/public/next/assets/index-DOAOxiKl.js +0 -11
  818. package/dist/core/web/public/next/assets/index-DOAOxiKl.js.map +0 -1
  819. package/dist/core/web/public/next/assets/jev-queries-CS2A5uWe.js +0 -2
  820. package/dist/core/web/public/next/assets/jev-queries-CS2A5uWe.js.map +0 -1
  821. package/dist/core/web/public/next/assets/ladder-queries-CBoG3heV.js +0 -2
  822. package/dist/core/web/public/next/assets/ladder-queries-CBoG3heV.js.map +0 -1
  823. package/dist/core/web/public/next/assets/leader-focus-DDQlv0TB.js +0 -2
  824. package/dist/core/web/public/next/assets/leader-focus-DDQlv0TB.js.map +0 -1
  825. package/dist/core/web/public/next/assets/live-model-CCjYFk48.js +0 -2
  826. package/dist/core/web/public/next/assets/live-model-CCjYFk48.js.map +0 -1
  827. package/dist/core/web/public/next/assets/mobile-actions-XqB_h7a8.js +0 -2
  828. package/dist/core/web/public/next/assets/mobile-actions-XqB_h7a8.js.map +0 -1
  829. package/dist/core/web/public/next/assets/mobile-toast-eIrghd9o.js +0 -2
  830. package/dist/core/web/public/next/assets/mobile-toast-eIrghd9o.js.map +0 -1
  831. package/dist/core/web/public/next/assets/multimodel-flows-CzI-yHg5.js +0 -7
  832. package/dist/core/web/public/next/assets/multimodel-flows-CzI-yHg5.js.map +0 -1
  833. package/dist/core/web/public/next/assets/multimodel-queries-DxIT9AZY.js +0 -2
  834. package/dist/core/web/public/next/assets/multimodel-queries-DxIT9AZY.js.map +0 -1
  835. package/dist/core/web/public/next/assets/mutations-BlGALvmG.js +0 -2
  836. package/dist/core/web/public/next/assets/mutations-BlGALvmG.js.map +0 -1
  837. package/dist/core/web/public/next/assets/nav-ByibvQW1.js +0 -2
  838. package/dist/core/web/public/next/assets/nav-ByibvQW1.js.map +0 -1
  839. package/dist/core/web/public/next/assets/needs-you-actions-Dp5UxM3X.js +0 -2
  840. package/dist/core/web/public/next/assets/needs-you-actions-Dp5UxM3X.js.map +0 -1
  841. package/dist/core/web/public/next/assets/needs-you-model-DYsqHMqy.js +0 -2
  842. package/dist/core/web/public/next/assets/needs-you-model-DYsqHMqy.js.map +0 -1
  843. package/dist/core/web/public/next/assets/open-terminal-dOVyLFvn.js +0 -2
  844. package/dist/core/web/public/next/assets/open-terminal-dOVyLFvn.js.map +0 -1
  845. package/dist/core/web/public/next/assets/open-terminal-request-BIhvirIl.js +0 -2
  846. package/dist/core/web/public/next/assets/open-terminal-request-BIhvirIl.js.map +0 -1
  847. package/dist/core/web/public/next/assets/overnight-queries-KxqH6BRN.js +0 -2
  848. package/dist/core/web/public/next/assets/overnight-queries-KxqH6BRN.js.map +0 -1
  849. package/dist/core/web/public/next/assets/palette-handoff-69pw9oBv.js +0 -2
  850. package/dist/core/web/public/next/assets/palette-handoff-69pw9oBv.js.map +0 -1
  851. package/dist/core/web/public/next/assets/panes-CHt3427X.js +0 -3
  852. package/dist/core/web/public/next/assets/panes-CHt3427X.js.map +0 -1
  853. package/dist/core/web/public/next/assets/path-display-DuIZF5G3.js +0 -2
  854. package/dist/core/web/public/next/assets/path-display-DuIZF5G3.js.map +0 -1
  855. package/dist/core/web/public/next/assets/playbook-composer-DipWgX7t.js +0 -2
  856. package/dist/core/web/public/next/assets/playbook-composer-DipWgX7t.js.map +0 -1
  857. package/dist/core/web/public/next/assets/playbook-focus-EXJPMBBI.js +0 -2
  858. package/dist/core/web/public/next/assets/playbook-focus-EXJPMBBI.js.map +0 -1
  859. package/dist/core/web/public/next/assets/playbooks-queries-BlpGBpOV.js +0 -2
  860. package/dist/core/web/public/next/assets/playbooks-queries-BlpGBpOV.js.map +0 -1
  861. package/dist/core/web/public/next/assets/preloaded-TmpzuCEi.js +0 -2
  862. package/dist/core/web/public/next/assets/preloaded-TmpzuCEi.js.map +0 -1
  863. package/dist/core/web/public/next/assets/primitives-CDKCUR2v.js +0 -1
  864. package/dist/core/web/public/next/assets/pwa-CTGMm-wR.js +0 -2
  865. package/dist/core/web/public/next/assets/pwa-CTGMm-wR.js.map +0 -1
  866. package/dist/core/web/public/next/assets/queries--mGK10fL.js +0 -2
  867. package/dist/core/web/public/next/assets/queries--mGK10fL.js.map +0 -1
  868. package/dist/core/web/public/next/assets/reasoning-pref-CWGL9MD2.js +0 -2
  869. package/dist/core/web/public/next/assets/reasoning-pref-CWGL9MD2.js.map +0 -1
  870. package/dist/core/web/public/next/assets/remote-session-I4RXlsas.js +0 -3
  871. package/dist/core/web/public/next/assets/remote-session-I4RXlsas.js.map +0 -1
  872. package/dist/core/web/public/next/assets/resolved-store-DwGn9hb_.js +0 -2
  873. package/dist/core/web/public/next/assets/resolved-store-DwGn9hb_.js.map +0 -1
  874. package/dist/core/web/public/next/assets/resources-queries-T6ER_hPN.js +0 -2
  875. package/dist/core/web/public/next/assets/resources-queries-T6ER_hPN.js.map +0 -1
  876. package/dist/core/web/public/next/assets/reveal-anchor-CHtvhrYm.js +0 -2
  877. package/dist/core/web/public/next/assets/reveal-anchor-CHtvhrYm.js.map +0 -1
  878. package/dist/core/web/public/next/assets/sheet-BlzGO1wo.js +0 -2
  879. package/dist/core/web/public/next/assets/sheet-BlzGO1wo.js.map +0 -1
  880. package/dist/core/web/public/next/assets/slots-40edgV7X.js +0 -3
  881. package/dist/core/web/public/next/assets/slots-40edgV7X.js.map +0 -1
  882. package/dist/core/web/public/next/assets/sources-queries-BrM41X16.js +0 -4
  883. package/dist/core/web/public/next/assets/sources-queries-BrM41X16.js.map +0 -1
  884. package/dist/core/web/public/next/assets/sse-CAFwslNC.js +0 -2
  885. package/dist/core/web/public/next/assets/sse-CAFwslNC.js.map +0 -1
  886. package/dist/core/web/public/next/assets/surface-data-D_oFOgkh.js +0 -2
  887. package/dist/core/web/public/next/assets/surface-data-D_oFOgkh.js.map +0 -1
  888. package/dist/core/web/public/next/assets/surface-prefetch-wqfiATYQ.js +0 -2
  889. package/dist/core/web/public/next/assets/surface-prefetch-wqfiATYQ.js.map +0 -1
  890. package/dist/core/web/public/next/assets/terminal-client-iL4DagCN.js +0 -2
  891. package/dist/core/web/public/next/assets/terminal-client-iL4DagCN.js.map +0 -1
  892. package/dist/core/web/public/next/assets/terminal-icons-BakeOpKV.js +0 -2
  893. package/dist/core/web/public/next/assets/terminal-icons-BakeOpKV.js.map +0 -1
  894. package/dist/core/web/public/next/assets/terminal-view-D6AAh08q.js +0 -6
  895. package/dist/core/web/public/next/assets/terminal-view-D6AAh08q.js.map +0 -1
  896. package/dist/core/web/public/next/assets/thread-data-CSDZ514s.js +0 -2
  897. package/dist/core/web/public/next/assets/thread-data-CSDZ514s.js.map +0 -1
  898. package/dist/core/web/public/next/assets/ui-parts-DubQJIoq.js +0 -2
  899. package/dist/core/web/public/next/assets/ui-parts-DubQJIoq.js.map +0 -1
  900. package/dist/core/web/public/next/assets/usage-queries-BONqdout.js +0 -2
  901. package/dist/core/web/public/next/assets/usage-queries-BONqdout.js.map +0 -1
  902. package/dist/core/web/public/next/assets/use-chat-activity-BZjdPPNP.js +0 -2
  903. package/dist/core/web/public/next/assets/use-chat-activity-BZjdPPNP.js.map +0 -1
  904. package/dist/core/web/public/next/assets/use-guarded-action-xJ4rxyVo.js +0 -2
  905. package/dist/core/web/public/next/assets/use-guarded-action-xJ4rxyVo.js.map +0 -1
  906. package/dist/core/web/public/next/assets/use-ticker-Bsu0cMvl.js +0 -2
  907. package/dist/core/web/public/next/assets/use-ticker-Bsu0cMvl.js.map +0 -1
  908. package/dist/core/web/public/next/assets/use-token-gate-E-xzEAu6.js +0 -2
  909. package/dist/core/web/public/next/assets/use-token-gate-E-xzEAu6.js.map +0 -1
  910. package/dist/core/web/public/next/assets/useAutoSeat-CXC9e4vx.js +0 -2
  911. package/dist/core/web/public/next/assets/useAutoSeat-CXC9e4vx.js.map +0 -1
  912. package/dist/core/web/public/next/assets/useOnboarding-Csw_AXrj.js +0 -2
  913. package/dist/core/web/public/next/assets/useOnboarding-Csw_AXrj.js.map +0 -1
  914. package/dist/core/web/public/next/assets/useSeatHealth-B6AXxre9.js +0 -2
  915. package/dist/core/web/public/next/assets/useSeatHealth-B6AXxre9.js.map +0 -1
  916. package/dist/core/web/public/next/assets/useSeatsRefresh-BIAa7Exn.js +0 -2
  917. package/dist/core/web/public/next/assets/useSeatsRefresh-BIAa7Exn.js.map +0 -1
  918. package/dist/core/web/public/next/assets/useVerseSession-BOyvOEDi.js +0 -2
  919. package/dist/core/web/public/next/assets/useVerseSession-BOyvOEDi.js.map +0 -1
  920. package/dist/core/web/public/next/assets/useVerseTranscript-BOhcfdp7.js +0 -2
  921. package/dist/core/web/public/next/assets/useVerseTranscript-BOhcfdp7.js.map +0 -1
  922. package/dist/core/web/public/next/assets/verse-bootstrap-query-D-fU89IT.js +0 -2
  923. package/dist/core/web/public/next/assets/verse-bootstrap-query-D-fU89IT.js.map +0 -1
  924. package/dist/core/web/public/next/assets/verse-icons-UKbUG3gv.js +0 -2
  925. package/dist/core/web/public/next/assets/verse-icons-UKbUG3gv.js.map +0 -1
  926. package/dist/core/web/public/next/assets/warmup-CZ-IBU5L.js +0 -3
  927. package/dist/core/web/public/next/assets/warmup-CZ-IBU5L.js.map +0 -1
  928. package/dist/core/web/public/next/assets/wiki-focus-DhAvbMnX.js +0 -2
  929. package/dist/core/web/public/next/assets/wiki-focus-DhAvbMnX.js.map +0 -1
@@ -1 +0,0 @@
1
- {"version":3,"file":"usage-queries-BONqdout.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/usage/usage-contract.ts","../../../../../../src/web-ui/routes/verse/usage/usage-queries.ts"],"sourcesContent":["/**\n * routes/verse/usage/usage-contract.ts\n *\n * ┌───────────────────────────────────────────────────────────────────────┐\n * │ INTEGRATION — RECONCILED AGAINST OWNER T'S REAL ROUTES (V2.1) │\n * │ │\n * │ GET /api/verse/accounts → VerseAccountsSnapshot │\n * │ GET /api/verse/usage-series → {window, byDay, estimated, caveats} │\n * │ GET /api/verse/local-models → VerseLocalModelsSnapshot │\n * │ │\n * │ T's types now exist and are imported below as the WIRE shapes. The │\n * │ interfaces in this file are no longer stand-ins for them: they are │\n * │ the DISPLAY shapes this section renders, and they differ from the │\n * │ wire on purpose in three places the seam actually required — │\n * │ │\n * │ 1. local-models arrives as TWO runtime reports (ollama, lmStudio) │\n * │ plus a `machine` budget. This section shows one list of models │\n * │ against one budget, so `projectLocalModels` flattens them. │\n * │ 2. usage-series arrives as `{byDay}`, not `{days}` (T's documented │\n * │ deviation 1). The projector reads `byDay` and still accepts │\n * │ `days`/a bare array so an older server degrades rather than dies. │\n * │ 3. `unsupported` is not a wire field. T reports the version-pin │\n * │ failure in `reason` as the verbatim probe code, so it is DERIVED │\n * │ here from that code plus T's exported pin constant rather than │\n * │ being added to T's contract late in the run. │\n * │ │\n * │ The `WIRE_*_KEYS` blocks below are the executable seam contract: │\n * │ every canonical field name this module reads is pinned to `keyof` the │\n * │ corresponding core type, so a rename in src/core/verse breaks THIS │\n * │ build instead of silently degrading the panel to \"unknown\" at run │\n * │ time — which is exactly how this seam was broken when integration │\n * │ started. │\n * └───────────────────────────────────────────────────────────────────────┘\n *\n * Why every read goes through a structural narrower instead of a cast:\n *\n * - This section must render correctly against a server that does NOT have\n * T's routes (404) and against one that has an earlier spelling of them.\n * A cast would turn a field-name drift into `undefined.something` at\n * render time; a narrower turns it into an honest \"unknown\" with a reason.\n * - Nothing here is ever coerced. A missing percentage stays `null`, never\n * 0 — `usedPercent: 0` and \"no reading\" are different facts and the UI\n * draws them differently (docs/VERSE-TELEMETRY-V2.md, closing rules).\n *\n * SECURITY (docs/VERSE-CONTRACT-V2.md ground rules): a native-profile\n * launcher command must never reach a surface. `sanitizeCommand` below is a\n * client-side backstop on top of the server's own stripping — if a payload\n * ever carries a launcher path, this module drops it rather than printing it.\n *\n * Pure: no React, no I/O.\n */\n// EVERY import from src/core here MUST be type-only.\n//\n// `core/verse/accounts.ts` is the server's collector: it pulls node:fs,\n// node:child_process, the quota lease and the connection monitor. A VALUE\n// import of even a one-word constant from it drags that entire graph into the\n// browser bundle — `vite build` externalizes the node built-ins and the build\n// fails. Type-only imports are erased, so the seam guards below cost nothing\n// at runtime. The two constants this module needs are therefore re-declared\n// locally and PINNED TO CORE'S LITERAL TYPES (see below), which gives the same\n// drift protection with no emitted import.\nimport type {\n VerseAccountRecord,\n VerseAccountWindow,\n VerseAccountsCollectorStatus,\n VerseAccountsSnapshot,\n VerseCodexCredits,\n} from '../../../../core/verse/accounts.js';\nimport type {\n VerseLocalModel,\n VerseLocalModelsSnapshot,\n VerseLocalRuntimeReport,\n} from '../../../../core/verse/local-models.js';\nimport type { DailyUsage as CoreDailyUsage } from '../../../../core/types.js';\n\n// ---------------------------------------------------------------------------\n// Seam contract — compile-time only, zero runtime cost.\n//\n// Each entry pins a field name this module reads off the wire to `keyof` the\n// core type that produces it. Renaming a field in src/core/verse now fails\n// `npm run typecheck:web` here, at the seam, rather than turning a live panel\n// into a silent \"unknown\".\n// ---------------------------------------------------------------------------\n\nconst WIRE_ACCOUNT_KEYS = {\n id: 'id',\n label: 'label',\n provider: 'provider',\n state: 'state',\n authentication: 'authentication',\n health: 'health',\n planType: 'planType',\n observedAt: 'observedAt',\n windows: 'windows',\n binding: 'binding',\n credits: 'credits',\n reason: 'reason',\n notes: 'notes',\n} as const satisfies Record<string, keyof VerseAccountRecord>;\n\nconst WIRE_WINDOW_KEYS = {\n id: 'id',\n usedPercent: 'usedPercent',\n resetsAt: 'resetsAt',\n nativeReport: 'nativeReport',\n limitReached: 'limitReached',\n measured: 'measured',\n} as const satisfies Record<string, keyof VerseAccountWindow>;\n\nconst WIRE_CREDITS_KEYS = {\n hasCredits: 'hasCredits',\n unlimited: 'unlimited',\n balance: 'balance',\n} as const satisfies Record<string, keyof VerseCodexCredits>;\n\nconst WIRE_ACCOUNTS_SNAPSHOT_KEYS = {\n sampledAt: 'sampledAt',\n refreshing: 'refreshing',\n accounts: 'accounts',\n collector: 'collector',\n notes: 'notes',\n} as const satisfies Record<string, keyof VerseAccountsSnapshot>;\n\nconst WIRE_COLLECTOR_KEYS = {\n owner: 'owner',\n note: 'note',\n} as const satisfies Record<string, keyof VerseAccountsCollectorStatus>;\n\nconst WIRE_LOCAL_SNAPSHOT_KEYS = {\n machine: 'machine',\n ollama: 'ollama',\n lmStudio: 'lmStudio',\n} as const satisfies Record<string, keyof VerseLocalModelsSnapshot>;\n\nconst WIRE_LOCAL_RUNTIME_KEYS = {\n reachable: 'reachable',\n models: 'models',\n reason: 'reason',\n detailInspection: 'detailInspection',\n // V2.1: a RETAINED known-good reading rather than a fresh probe. Both must\n // be projected — a stale reading presented as fresh is the exact failure\n // this seam exists to prevent.\n stale: 'stale',\n staleForMs: 'staleForMs',\n} as const satisfies Record<string, keyof VerseLocalRuntimeReport>;\n\nconst WIRE_LOCAL_MODEL_KEYS = {\n id: 'id',\n label: 'label',\n state: 'state',\n sizeBytes: 'sizeBytes',\n sizeVramBytes: 'sizeVramBytes',\n placement: 'placement',\n gpuPercent: 'gpuPercent',\n memoryPercent: 'memoryPercent',\n family: 'family',\n arch: 'arch',\n expiresAt: 'expiresAt',\n contextLength: 'contextLength',\n nativeContextLength: 'nativeContextLength',\n parameterSize: 'parameterSize',\n quantization: 'quantization',\n capabilities: 'capabilities',\n supportsTools: 'supportsTools',\n} as const satisfies Record<string, keyof VerseLocalModel>;\n\n/**\n * Claude's version-pin constants, re-declared rather than imported.\n *\n * The annotations are the drift guard: `typeof import(...)` is a TYPE position,\n * so it is erased at build time, but it resolves to core's literal type\n * (`'2.1.257'`, `'usage-version-unsupported'`). Change either constant in\n * `core/verse/accounts.ts` and this file stops compiling — the same protection\n * a value import would give, without pulling node:fs into the browser.\n */\ntype CoreAccountsModule = typeof import('../../../../core/verse/accounts.js');\n\nexport const CLAUDE_VERSION_REASON: CoreAccountsModule['VERSE_CLAUDE_VERSION_REASON'] =\n 'usage-version-unsupported';\n\nexport const CLAUDE_USAGE_PINNED_VERSION: CoreAccountsModule['VERSE_CLAUDE_USAGE_PINNED_VERSION'] =\n '2.1.280';\n\n/** `byDay` is the wire key (T's deviation 1); `DailyUsage` below mirrors core. */\nconst WIRE_DAILY_USAGE_KEYS = {\n day: 'day',\n tokensIn: 'tokensIn',\n tokensOut: 'tokensOut',\n estCostUsd: 'estCostUsd',\n sessions: 'sessions',\n cacheRead: 'cacheRead',\n cacheWrite: 'cacheWrite',\n cacheHitRate: 'cacheHitRate',\n} as const satisfies Record<string, keyof CoreDailyUsage>;\n\n// Referenced so the guards are not dead code under `noUnusedLocals`.\nexport const WIRE_CONTRACT_KEYS = {\n account: WIRE_ACCOUNT_KEYS,\n window: WIRE_WINDOW_KEYS,\n credits: WIRE_CREDITS_KEYS,\n accountsSnapshot: WIRE_ACCOUNTS_SNAPSHOT_KEYS,\n collector: WIRE_COLLECTOR_KEYS,\n localSnapshot: WIRE_LOCAL_SNAPSHOT_KEYS,\n localRuntime: WIRE_LOCAL_RUNTIME_KEYS,\n localModel: WIRE_LOCAL_MODEL_KEYS,\n dailyUsage: WIRE_DAILY_USAGE_KEYS,\n} as const;\n\n// ---------------------------------------------------------------------------\n// GET /api/verse/accounts\n// ---------------------------------------------------------------------------\n\n/** Provider ids this surface knows how to describe. */\nexport type AccountProvider = 'claude' | 'codex' | 'grok';\n\n/**\n * One quota window on an account.\n *\n * `resetsAt` is an ISO string when the provider gave a real timestamp (Codex\n * publishes an epoch the server normalizes). Claude's is STRUCTURALLY always\n * null and the human sentence lives in `nativeReport.resetDescription`, which\n * is rendered verbatim and never turned into a countdown.\n */\nexport interface AccountWindow {\n id: string;\n /** Human label when the server supplies one; otherwise `id` is shown. */\n label: string | null;\n /** 0–100. `null` is \"no reading\", never 0. */\n usedPercent: number | null;\n /** ISO 8601, or null. */\n resetsAt: string | null;\n /** Verbatim provider prose, e.g. \"resets Sep 25 at 7pm (America/New_York)\". */\n resetDescription: string | null;\n /**\n * True when the provider signalled `rateLimitReachedType` — the upstream\n * writes the SENTINEL 100, which is a flag, not a measurement. Rendered as\n * \"limit reached\", never as \"100% used\".\n */\n limitReached: boolean;\n /**\n * False when `usedPercent` is a FLAGGED SENTINEL rather than a reading.\n *\n * Codex writes `rateLimitReachedType` upstream as the value 100, so a bare\n * 100 is indistinguishable from a genuinely measured 100 by the time it\n * arrives. The server distinguishes them; this surface must not collapse\n * them back together. Absent on the wire → assumed measured UNLESS the\n * limit flag is set, which is the only case where the sentinel is written.\n */\n measured: boolean;\n}\n\n/**\n * Codex credits. Independent of the window: a 100%-used week with a spendable\n * balance is NOT blocked, and this surface must not say it is.\n */\nexport interface AccountCredits {\n hasCredits: boolean;\n unlimited: boolean;\n /** Raw decimal string from the provider, kept verbatim for the title text. */\n balance: string | null;\n /** `balance` parsed, or null when it was absent/unparseable. */\n balanceValue: number | null;\n}\n\nexport interface Account {\n id: string;\n label: string;\n provider: AccountProvider;\n state: 'checking' | 'observed' | 'signed-out' | 'unavailable';\n authentication: 'signed-in' | 'signed-out' | 'unknown';\n /**\n * The connection monitor's own health verdict. Claude's is ALWAYS `unknown`\n * by construction (docs/VERSE-TELEMETRY-V2.md) — that is not a fault and is\n * never rendered as one.\n */\n health: string | null;\n planType: string | null;\n observedAt: string | null;\n windows: AccountWindow[];\n /**\n * The server's computed binding window (highest used percent). Kept as its\n * own field rather than recomputed blindly, but `accounts-model.ts` verifies\n * it against `windows` and falls back to computing it when absent.\n */\n binding: AccountWindow | null;\n credits: AccountCredits | null;\n /** Plain-language reason for a non-observed state. */\n reason: string | null;\n /**\n * Present when a probe failed CLOSED on a version pin (Claude's probe is\n * pinned to a specific Claude Code build). The fix is a one-line constant\n * bump, so the UI names it instead of showing a silent \"unknown\".\n */\n unsupported: { code: string; pinnedVersion: string | null } | null;\n /** Already sanitized — see `sanitizeCommand`. Null when nothing safe to show. */\n reconnectCommand: string | null;\n /**\n * The server's plain-language facts for this account (`VerseAccountRecord.\n * notes`). Grok's \"reconnect through `ashlr resources`, profile path withheld\n * on purpose\" lives here, which is why this surface shows notes rather than\n * only the machine-readable `reason`.\n */\n notes: string[];\n}\n\nexport interface AccountsSnapshot {\n sampledAt: string | null;\n refreshing: boolean;\n accounts: Account[];\n /**\n * Set when another collector process owns the quota-refresh lease, so these\n * readings are read-only and may be staler than this server's poll interval.\n */\n collectorNote: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// GET /api/verse/usage-series?window=7d|30d\n// ---------------------------------------------------------------------------\n\nexport type SeriesWindow = '7d' | '30d';\n\n/** `buildRollup(window, cfg).byDay` — see docs/VERSE-TELEMETRY-V2.md. */\nexport interface DailyUsage {\n /** YYYY-MM-DD. */\n day: string;\n tokensIn: number;\n tokensOut: number;\n /** ESTIMATED from a static price table. Never a billed figure. */\n estCostUsd: number;\n sessions: number;\n /** Optional: absent means the rollup carried no cache columns for that day. */\n cacheRead: number | null;\n cacheWrite: number | null;\n /** 0–1 fraction, or null. */\n cacheHitRate: number | null;\n}\n\nexport interface UsageSeries {\n window: SeriesWindow;\n days: DailyUsage[];\n generatedAt: string | null;\n /**\n * The server states outright that every cost column here is estimated.\n * Carried through rather than re-asserted locally so the disclosure the UI\n * prints is the one the producer actually made.\n */\n estimated: boolean;\n /** The server's own caveats, rendered verbatim beside the charts. */\n caveats: string[];\n}\n\n// ---------------------------------------------------------------------------\n// GET /api/verse/local-models\n// ---------------------------------------------------------------------------\n\nexport interface LocalModel {\n name: string;\n /** Which runtime reported it, so a flattened list stays attributable. */\n runtime: 'ollama' | 'lmstudio' | null;\n /** Resident in memory right now (Ollama /api/ps), vs merely installed. */\n loaded: boolean;\n /** Total resident bytes, or null when not reported. */\n sizeBytes: number | null;\n /** Of `sizeBytes`, how much sits in VRAM. null = not reported. */\n sizeVramBytes: number | null;\n /**\n * Where the weights actually sit. `split` is the one that matters: a model\n * that only half-fits the GPU runs at a fraction of the speed of one that\n * fits, and that is the difference between usable and not.\n */\n placement: 'gpu' | 'cpu' | 'split' | 'unknown';\n /** The runtime's own GPU share, 0–100. Preferred over recomputing it. */\n gpuPercent: number | null;\n /** Resident size against total machine memory, 0–100, else null. */\n memoryPercent: number | null;\n family: string | null;\n arch: string | null;\n /** Keep-alive expiry (ISO). Only meaningful while `loaded`. */\n expiresAt: string | null;\n /** e.g. \"79.7B\". Provider string, never parsed into a number for display. */\n parameterSize: string | null;\n /** e.g. \"Q4_K_M\". */\n quantization: string | null;\n /** Native context from model_info[\"<arch>.context_length\"]. */\n nativeContext: number | null;\n /** Context Ashlr actually configures for this seat, when it differs. */\n configuredContext: number | null;\n /**\n * `capabilities` from /api/show. `null` means the capability list was not\n * reported — which is NOT the same as \"does not support tools\".\n */\n capabilities: string[] | null;\n /**\n * The runtime's own answer to \"can this drive an agentic session\", which is\n * AUTHORITATIVE over `capabilities` and must be preferred when non-null.\n *\n * This matters: owner T sends `capabilities: []` when a runtime reported no\n * capability list, and reading that array alone would render \"no tools\" —\n * a hard, wrong gate — where T's `supportsTools: null` correctly means\n * \"unknown\". Deriving tool support from the array alone was a real defect\n * at this seam, not a cosmetic one.\n */\n supportsTools: boolean | null;\n}\n\n/**\n * One runtime's own reachability, kept per-runtime rather than folded into the\n * flattened list, because STALENESS is per-runtime and must be stated.\n *\n * `stale` means the server served a RETAINED known-good reading after a probe\n * TIMED OUT (core `VERSE_LOCAL_LAST_GOOD_TTL_MS`). That is the honest choice\n * server-side — a timeout is \"no answer yet\", not \"the runtime is gone\" — but\n * it obliges this surface to say plainly that the numbers are N seconds old\n * rather than presenting them as fresh.\n */\nexport interface LocalRuntimeStatus {\n runtime: 'ollama' | 'lmstudio';\n reachable: boolean;\n /** Machine-readable degradation code; never rendered as a sentence. */\n reason: string | null;\n /** True when this report is a retained reading rather than a fresh probe. */\n stale: boolean;\n /** Age of that retained reading in ms. Null when `stale` is false. */\n staleForMs: number | null;\n modelCount: number;\n detailInspection?: { attempted: number; pending: number };\n}\n\nexport interface LocalModelsSnapshot {\n reachable: boolean;\n models: LocalModel[];\n /** Machine memory budget in bytes, or null when the server did not say. */\n memoryBudgetBytes: number | null;\n /** Machine memory reported free right now, or null. */\n freeMemoryBytes: number | null;\n reason: string | null;\n /** Per-runtime reachability and staleness. Empty on a flat legacy body. */\n runtimes: LocalRuntimeStatus[];\n /** The server's own plain-language caveats for this snapshot. */\n notes: string[];\n sampledAt: string | null;\n}\n\n// ---------------------------------------------------------------------------\n// Narrowing helpers\n// ---------------------------------------------------------------------------\n\nfunction record(value: unknown): Record<string, unknown> | null {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : null;\n}\n\nfunction str(source: Record<string, unknown>, key: string): string | null {\n const v = source[key];\n return typeof v === 'string' && v.length > 0 ? v : null;\n}\n\nfunction num(source: Record<string, unknown>, key: string): number | null {\n const v = source[key];\n return typeof v === 'number' && Number.isFinite(v) ? v : null;\n}\n\nfunction bool(source: Record<string, unknown>, key: string, fallback = false): boolean {\n const v = source[key];\n return typeof v === 'boolean' ? v : fallback;\n}\n\nfunction list(value: unknown): unknown[] {\n return Array.isArray(value) ? value : [];\n}\n\n/**\n * Drop anything that looks like a native-profile launcher invocation or an\n * absolute path into the private account store. The server is supposed to\n * strip these; this is the client-side backstop, because the cost of printing\n * one is unacceptable and the cost of showing \"no command\" is a sentence.\n */\nconst FORBIDDEN_COMMAND = /(launcher\\.mjs|native-profiles|account-connections|console-startup|\\/\\.ashlr\\b|Bearer\\s|--token\\b)/i;\n\nexport function sanitizeCommand(value: unknown): string | null {\n if (typeof value !== 'string') return null;\n const trimmed = value.trim();\n if (trimmed.length === 0 || trimmed.length > 200) return null;\n if (FORBIDDEN_COMMAND.test(trimmed)) return null;\n // A newline would let a payload smuggle a second command onto the surface.\n if (/[\\r\\n]/.test(trimmed)) return null;\n return trimmed;\n}\n\nfunction clampPercent(value: number | null): number | null {\n if (value === null) return null;\n return Math.max(0, Math.min(100, value));\n}\n\nfunction projectWindow(raw: unknown): AccountWindow | null {\n const r = record(raw);\n if (!r) return null;\n const id = str(r, 'id') ?? str(r, 'label');\n if (id === null) return null;\n const native = record(r['nativeReport']);\n const limitReached = bool(r, 'limitReached') || bool(r, 'rateLimitReached');\n const measuredRaw = r['measured'];\n return {\n id,\n label: str(r, 'label'),\n usedPercent: clampPercent(num(r, 'usedPercent') ?? num(r, 'used_percent')),\n resetsAt: str(r, 'resetsAt') ?? str(r, 'resets_at'),\n resetDescription:\n (native ? str(native, 'resetDescription') : null) ?? str(r, 'resetDescription'),\n limitReached,\n // Absent → measured, EXCEPT under a limit flag, which is the one case the\n // upstream writes the sentinel 100. Defaulting a flagged window to\n // `measured: true` would let a denial print as \"100% used\".\n measured: typeof measuredRaw === 'boolean' ? measuredRaw : !limitReached,\n };\n}\n\nfunction projectCredits(raw: unknown): AccountCredits | null {\n const r = record(raw);\n if (!r) return null;\n const balance = str(r, 'balance');\n const parsed = balance === null ? num(r, 'balance') : Number.parseFloat(balance);\n return {\n hasCredits: bool(r, 'hasCredits') || bool(r, 'has_credits'),\n unlimited: bool(r, 'unlimited'),\n balance,\n balanceValue: typeof parsed === 'number' && Number.isFinite(parsed) ? parsed : null,\n };\n}\n\nconst PROVIDERS: readonly string[] = ['claude', 'codex', 'grok'];\n\nfunction projectAccount(raw: unknown): Account | null {\n const r = record(raw);\n if (!r) return null;\n const id = str(r, 'id');\n const provider = str(r, 'provider');\n if (id === null || provider === null || !PROVIDERS.includes(provider)) return null;\n\n const windows = list(r['windows'])\n .map(projectWindow)\n .filter((w): w is AccountWindow => w !== null);\n\n const state = str(r, 'state');\n const auth = str(r, 'authentication');\n const unsupportedRaw = record(r['unsupported']);\n\n return {\n id,\n label: str(r, 'label') ?? id,\n provider: provider as AccountProvider,\n state:\n state === 'checking' || state === 'observed' || state === 'signed-out' || state === 'unavailable'\n ? state\n : 'unavailable',\n authentication: auth === 'signed-in' || auth === 'signed-out' ? auth : 'unknown',\n health: str(r, 'health'),\n planType: str(r, 'planType') ?? str(r, 'plan_type'),\n observedAt: str(r, 'observedAt'),\n windows,\n binding: projectWindow(r['binding']),\n credits: projectCredits(r['credits']),\n reason: str(r, 'reason'),\n unsupported: projectUnsupported(r, unsupportedRaw),\n reconnectCommand: sanitizeCommand(r['reconnectCommand']),\n notes: list(r['notes']).filter((n): n is string => typeof n === 'string'),\n };\n}\n\n/**\n * A version-pinned probe that failed CLOSED, named rather than swallowed.\n *\n * `unsupported` is not a field on the wire. Owner T reports the failure as the\n * verbatim probe code in `reason` (`usage-version-unsupported`) and states the\n * pin in `notes`, so this derives the structured form from those rather than\n * requiring a late contract change. An explicit `unsupported` object is still\n * honoured first, so a server that grows one later wins without a client edit.\n */\nfunction projectUnsupported(\n r: Record<string, unknown>,\n explicit: Record<string, unknown> | null,\n): Account['unsupported'] {\n if (explicit) {\n return {\n code: str(explicit, 'code') ?? CLAUDE_VERSION_REASON,\n pinnedVersion: str(explicit, 'pinnedVersion') ?? str(explicit, 'version'),\n };\n }\n const reason = str(r, 'reason');\n if (reason !== CLAUDE_VERSION_REASON) return null;\n return { code: reason, pinnedVersion: CLAUDE_USAGE_PINNED_VERSION };\n}\n\n/**\n * The read-only banner. Owner T reports lease ownership as a structured\n * `collector` status, not a flat `collectorNote`, so the note is derived from\n * it — and ONLY when another process owns the lease, because that is the one\n * case where these readings may be staler than this server's poll interval.\n * A stray `collectorNote` string is still accepted for forward compatibility.\n */\nfunction projectCollectorNote(root: Record<string, unknown>): string | null {\n const flat = str(root, 'collectorNote');\n if (flat) return flat;\n const collector = record(root['collector']);\n if (!collector) return null;\n if (str(collector, 'owner') !== 'another-collector') return null;\n return (\n str(collector, 'note') ??\n 'Another collector process owns the quota-refresh lease, so these readings are read-only and may be staler than this server’s poll interval.'\n );\n}\n\nexport function projectAccountsSnapshot(raw: unknown): AccountsSnapshot | null {\n const root = record(raw);\n if (!root) return null;\n const rawAccounts = Array.isArray(root['accounts']) ? root['accounts'] : Array.isArray(raw) ? raw : null;\n if (rawAccounts === null) return null;\n return {\n sampledAt: str(root, 'sampledAt'),\n refreshing: bool(root, 'refreshing'),\n accounts: rawAccounts.map(projectAccount).filter((a): a is Account => a !== null),\n collectorNote: projectCollectorNote(root),\n };\n}\n\nfunction projectDay(raw: unknown): DailyUsage | null {\n const r = record(raw);\n if (!r) return null;\n const day = str(r, 'day');\n if (day === null || !/^\\d{4}-\\d{2}-\\d{2}$/.test(day)) return null;\n return {\n day,\n tokensIn: num(r, 'tokensIn') ?? 0,\n tokensOut: num(r, 'tokensOut') ?? 0,\n estCostUsd: num(r, 'estCostUsd') ?? 0,\n sessions: num(r, 'sessions') ?? 0,\n cacheRead: num(r, 'cacheRead'),\n cacheWrite: num(r, 'cacheWrite'),\n cacheHitRate: num(r, 'cacheHitRate'),\n };\n}\n\n/**\n * `byDay` is the wire key. Owner T wraps the series as\n * `{window, byDay, estimated, caveats}` rather than returning a bare array\n * (documented deviation 1), so `byDay` is read FIRST. `days` and a bare array\n * remain accepted so an older or differently-shaped server degrades to a\n * rendered series instead of a dead panel.\n */\nexport function projectUsageSeries(raw: unknown, requested: SeriesWindow): UsageSeries | null {\n const root = record(raw);\n const rawDays = root\n ? Array.isArray(root['byDay'])\n ? root['byDay']\n : Array.isArray(root['days'])\n ? root['days']\n : null\n : Array.isArray(raw)\n ? raw\n : null;\n if (rawDays === null) return null;\n const windowValue = root ? str(root, 'window') : null;\n return {\n window: windowValue === '7d' || windowValue === '30d' ? windowValue : requested,\n days: rawDays\n .map(projectDay)\n .filter((d): d is DailyUsage => d !== null)\n .sort((a, b) => a.day.localeCompare(b.day)),\n generatedAt: root ? str(root, 'generatedAt') : null,\n // The producer asserts estimation explicitly. Absent → still true: every\n // cost column on this route is price-table derived, and defaulting the\n // disclosure OFF would drop it exactly when the server is older.\n estimated: root ? bool(root, 'estimated', true) : true,\n caveats: root ? list(root['caveats']).filter((c): c is string => typeof c === 'string') : [],\n };\n}\n\nfunction projectLocalModel(raw: unknown, runtime: LocalModel['runtime']): LocalModel | null {\n const r = record(raw);\n if (!r) return null;\n // `label`/`id` are owner T's spellings; `name`/`model` are the Ollama-native\n // ones a differently-shaped server might send.\n const name = str(r, 'label') ?? str(r, 'id') ?? str(r, 'name') ?? str(r, 'model');\n if (name === null) return null;\n const caps = r['capabilities'];\n const state = str(r, 'state');\n const supportsTools = r['supportsTools'];\n\n // `nativeContextLength` is the architecture maximum; `contextLength` is what\n // the runtime actually configured for the loaded instance. They are two\n // different facts and the panel shows the gap between them, so they must not\n // collapse onto one field.\n const nativeContext = num(r, 'nativeContextLength') ?? num(r, 'nativeContext');\n const configuredContext = num(r, 'contextLength') ?? num(r, 'configuredContext');\n\n const placement = str(r, 'placement');\n\n return {\n name,\n runtime,\n loaded: state !== null ? state === 'loaded' : bool(r, 'loaded') || bool(r, 'resident'),\n sizeBytes: num(r, 'sizeBytes') ?? num(r, 'size'),\n sizeVramBytes: num(r, 'sizeVramBytes') ?? num(r, 'size_vram'),\n placement:\n placement === 'gpu' || placement === 'cpu' || placement === 'split' ? placement : 'unknown',\n gpuPercent: clampPercent(num(r, 'gpuPercent')),\n memoryPercent: clampPercent(num(r, 'memoryPercent')),\n family: str(r, 'family'),\n arch: str(r, 'arch'),\n expiresAt: str(r, 'expiresAt') ?? str(r, 'expires_at'),\n parameterSize: str(r, 'parameterSize') ?? str(r, 'parameter_size'),\n quantization: str(r, 'quantization') ?? str(r, 'quantization_level'),\n nativeContext,\n // Only a genuine narrowing is worth showing. When the runtime reports the\n // same number twice there is no truncation to report.\n configuredContext:\n configuredContext !== null && nativeContext !== null && configuredContext === nativeContext\n ? null\n : configuredContext,\n capabilities: Array.isArray(caps) ? caps.filter((c): c is string => typeof c === 'string') : null,\n supportsTools: typeof supportsTools === 'boolean' ? supportsTools : null,\n };\n}\n\nfunction projectRuntimeReport(\n raw: unknown,\n runtime: NonNullable<LocalModel['runtime']>,\n): { status: LocalRuntimeStatus; models: LocalModel[] } | null {\n const r = record(raw);\n if (!r) return null;\n const rawModels = Array.isArray(r['models']) ? r['models'] : null;\n if (rawModels === null) return null;\n const models = rawModels\n .map((m) => projectLocalModel(m, runtime))\n .filter((m): m is LocalModel => m !== null);\n const stale = bool(r, 'stale');\n const inspection = record(r['detailInspection']);\n const attempted = inspection ? num(inspection, 'attempted') : null;\n const pending = inspection ? num(inspection, 'pending') : null;\n const detailInspection = attempted !== null && pending !== null && Number.isInteger(attempted) && Number.isInteger(pending) && attempted >= 0 && pending > 0 && attempted + pending === models.length ? { attempted, pending } : undefined;\n return {\n models,\n status: {\n runtime,\n reachable: bool(r, 'reachable'),\n reason: str(r, 'reason'),\n stale,\n // Only meaningful under `stale`. A staleForMs on a fresh report would be\n // a contradiction, and printing it would age a current reading.\n staleForMs: stale ? num(r, 'staleForMs') : null,\n modelCount: models.length,\n ...(detailInspection ? { detailInspection } : {}),\n },\n };\n}\n\n/**\n * Owner T reports local availability per RUNTIME (`ollama`, `lmStudio`) with a\n * shared `machine` budget. This panel answers one question — \"what can I run\n * right now, and against how much memory\" — so the runtimes are flattened into\n * one list, each row keeping its `runtime` so it stays attributable.\n *\n * Reachability is the OR of the runtimes: one dead runtime is not an unreachable\n * local stack. `reason` is only carried when NOTHING is reachable, because a\n * degradation note beside a working list would misdescribe what is on screen.\n *\n * A flat `{reachable, models, memoryBudgetBytes}` body is still accepted, so an\n * older or differently-shaped server degrades rather than rendering nothing.\n */\nexport function projectLocalModels(raw: unknown): LocalModelsSnapshot | null {\n const root = record(raw);\n if (!root) return null;\n\n const ollama = projectRuntimeReport(root['ollama'], 'ollama');\n const lmStudio = projectRuntimeReport(root['lmStudio'] ?? root['lmstudio'], 'lmstudio');\n\n if (ollama !== null || lmStudio !== null) {\n const reports = [ollama, lmStudio].filter((x): x is NonNullable<typeof x> => x !== null);\n const reachable = reports.some((x) => x.status.reachable);\n const machine = record(root['machine']);\n return {\n reachable,\n models: reports.flatMap((x) => x.models),\n memoryBudgetBytes:\n (machine ? num(machine, 'totalMemoryBytes') : null) ??\n num(root, 'memoryBudgetBytes') ??\n num(root, 'memoryBudget'),\n freeMemoryBytes: machine ? num(machine, 'freeMemoryBytes') : null,\n reason: reachable\n ? null\n : (reports.map((x) => x.status.reason).find((x) => x !== null) ?? null),\n runtimes: reports.map((x) => x.status),\n notes: list(root['notes']).filter((n): n is string => typeof n === 'string'),\n sampledAt: str(root, 'sampledAt'),\n };\n }\n\n const rawModels = Array.isArray(root['models']) ? root['models'] : null;\n if (rawModels === null) return null;\n return {\n reachable: bool(root, 'reachable', true),\n models: rawModels.map((m) => projectLocalModel(m, null)).filter((m): m is LocalModel => m !== null),\n memoryBudgetBytes: num(root, 'memoryBudgetBytes') ?? num(root, 'memoryBudget'),\n freeMemoryBytes: num(root, 'freeMemoryBytes'),\n reason: str(root, 'reason'),\n // A flat legacy body carries no per-runtime reachability, so there is\n // nothing to attribute and nothing to call stale. An empty list says that\n // honestly; a fabricated entry would not.\n runtimes: [],\n notes: list(root['notes']).filter((n): n is string => typeof n === 'string'),\n sampledAt: str(root, 'sampledAt'),\n };\n}\n","/**\n * routes/verse/usage/usage-queries.ts — the reads behind the Usage section.\n *\n * `/api/control` is fetched through the shared `controlSnapshotQuery` so this\n * section rides the same cache (and the same SSE invalidation) as every other\n * view rather than opening a second copy of a large snapshot.\n *\n * `/api/verse/control` is owner B's new route. It is fetched through a\n * NON-throwing wrapper because this section must still render when the route\n * is absent (server started without --allow-dispatch, or B's route not landed\n * yet): a missing configured-caps source is a degraded panel, not a dead\n * section. 401 is the one error that still propagates — an expired read\n * session is an unauthorized state for the whole surface, not a degraded one.\n *\n * The cache key is deliberately NOT shared with the Autonomy section's own\n * read of the same route: this module stores a wrapper shape, and two owners\n * writing different value types under one key would be a real bug.\n */\nimport type { FrontierUsage } from '../../../../core/usage/frontier-usage.js';\nimport { ApiError, apiGet } from '../../../data/client.js';\nimport type { QueryDef } from '../../../data/queries.js';\nimport { projectLocalModels, type SeriesWindow } from './usage-contract.js';\n\nexport const USAGE_FRONTIER_KEY = 'verse-usage-frontier';\nexport const USAGE_VERSE_CONTROL_KEY = 'verse-usage-control';\n\n/** GET /api/usage — per-engine frontier usage (see core/usage/frontier-usage.ts). */\nexport const frontierUsageQuery: QueryDef<FrontierUsage> = {\n key: USAGE_FRONTIER_KEY,\n fetch: (signal) => apiGet<FrontierUsage>('/api/usage', signal),\n};\n\nexport interface VerseControlRead {\n /** Raw body; narrowed by `projectVerseControl` (owner B's types are not landed). */\n raw: unknown;\n available: boolean;\n reason: string | null;\n}\n\nfunction describeControlFailure(err: unknown): string {\n if (err instanceof ApiError) {\n if (err.status === 404) {\n return 'This server does not expose /api/verse/control, so configured caps and today’s spend are unavailable here.';\n }\n return `Configured caps unavailable (HTTP ${err.status}).`;\n }\n return 'Configured caps unavailable: the request failed.';\n}\n\nexport const verseControlQuery: QueryDef<VerseControlRead> = {\n key: USAGE_VERSE_CONTROL_KEY,\n fetch: async (signal) => {\n try {\n const raw = await apiGet<unknown>('/api/verse/control', signal);\n return { raw, available: true, reason: null };\n } catch (err) {\n if (err instanceof ApiError && err.status === 401) throw err;\n if (err instanceof DOMException && err.name === 'AbortError') throw err;\n return { raw: null, available: false, reason: describeControlFailure(err) };\n }\n },\n};\n\n// ---------------------------------------------------------------------------\n// Owner T's routes (GET /api/verse/{accounts,usage-series,local-models})\n// ---------------------------------------------------------------------------\n//\n// These three are fetched through the SAME non-throwing wrapper pattern as\n// /api/verse/control, for the same reason and one more: they are landing in\n// parallel with this section. A server that predates them answers 404, and a\n// 404 here means \"this panel is degraded\", not \"the Usage view is broken\".\n// 401 still propagates, because an expired read session is an unauthorized\n// state for the whole surface.\n//\n// The bodies are narrowed structurally by usage-contract.ts rather than cast,\n// so a field-name drift between T's route and this client degrades to an\n// honest \"unknown\" instead of throwing at render time.\n\nexport const USAGE_ACCOUNTS_KEY = 'verse-usage-accounts';\nexport const USAGE_LOCAL_MODELS_KEY = 'verse-usage-local-models';\nexport const USAGE_SERIES_KEY_PREFIX = 'verse-usage-series';\n\n/** A read that is allowed to be absent. `raw` is null when it was. */\nexport interface OptionalRead {\n raw: unknown;\n available: boolean;\n reason: string | null;\n}\n\nfunction describeOptionalFailure(path: string, err: unknown): string {\n if (err instanceof ApiError) {\n if (err.status === 404) {\n return `This server does not expose ${path} yet, so this panel has no source.`;\n }\n return `${path} answered HTTP ${err.status}.`;\n }\n return `${path} could not be reached.`;\n}\n\nfunction optionalGet(path: string): (signal?: AbortSignal) => Promise<OptionalRead> {\n return async (signal) => {\n try {\n const raw = await apiGet<unknown>(path, signal);\n return { raw, available: true, reason: null };\n } catch (err) {\n if (err instanceof ApiError && err.status === 401) throw err;\n if (err instanceof DOMException && err.name === 'AbortError') throw err;\n return { raw: null, available: false, reason: describeOptionalFailure(path, err) };\n }\n };\n}\n\n/** GET /api/verse/accounts — per-account state, windows, credits, plan. */\nexport const verseAccountsQuery: QueryDef<OptionalRead> = {\n key: USAGE_ACCOUNTS_KEY,\n fetch: optionalGet('/api/verse/accounts'),\n};\n\n// ---------------------------------------------------------------------------\n// GET /api/verse/local-models — and why this one read retries\n// ---------------------------------------------------------------------------\n//\n// `/api/verse/local-models` probes the runtimes live on every request, with a\n// 2s per-probe timeout (core/verse/local-models.ts\n// VERSE_LOCAL_PROBE_TIMEOUT_MS). A probe that times out is reported as\n// `{reachable: false, reason: 'ollama-unreachable'}` in a perfectly ordinary\n// HTTP 200 — which is correct on the server's terms (it genuinely did not get\n// an answer) but is NOT the same fact as \"Ollama is not running\", and nothing\n// in the payload distinguishes the two.\n//\n// That distinction matters here because this section is the thing that causes\n// the timeout. Mounting Usage, and every press of its Refresh button, fires\n// seven reads at once, several of which spawn short-lived account-probe\n// processes server-side; measured against a live Ollama with twelve models,\n// roughly one burst in ten starves the 2s probe and comes back\n// `ollama-unreachable`. Nothing re-reads this route afterwards — it has no SSE\n// invalidation key — so that one false negative is what the operator stares\n// at, and pressing Refresh re-creates the very burst that produced it.\n//\n// So a reported-unreachable local stack is RE-READ, up to twice, with a short\n// gap for the burst to drain. This is not \"ignore the failure\": the retries\n// are bounded, each one is a real request, and whatever the last read says is\n// what this section renders — a runtime that is genuinely down answers fast\n// (connection refused, not a timeout) and still reports unreachable, three\n// times, in well under a second.\n//\n// Only an AVAILABLE read is retried. A 404/500 (`available: false`) is a\n// statement about the route, not about the runtime, and re-asking cannot\n// change it.\n\n/** Two extra reads at most, spaced so the section's own request burst drains. */\nconst LOCAL_MODELS_RETRY_DELAYS_MS = [350, 1200] as const;\n\nconst readLocalModels = optionalGet('/api/verse/local-models');\n\nfunction reportsNothingReachable(read: OptionalRead): boolean {\n if (!read.available) return false;\n const snapshot = projectLocalModels(read.raw);\n return snapshot !== null && !snapshot.reachable;\n}\n\nfunction sleep(ms: number, signal?: AbortSignal): Promise<void> {\n return new Promise<void>((resolve, reject) => {\n if (signal?.aborted) {\n reject(new DOMException('Aborted', 'AbortError'));\n return;\n }\n const onAbort = (): void => {\n clearTimeout(timer);\n reject(new DOMException('Aborted', 'AbortError'));\n };\n const timer = setTimeout(() => {\n signal?.removeEventListener('abort', onAbort);\n resolve();\n }, ms);\n signal?.addEventListener('abort', onAbort, { once: true });\n });\n}\n\n/** GET /api/verse/local-models — resident vs installed, VRAM split, tools. */\nexport const verseLocalModelsQuery: QueryDef<OptionalRead> = {\n key: USAGE_LOCAL_MODELS_KEY,\n fetch: async (signal) => {\n let read = await readLocalModels(signal);\n for (const delayMs of LOCAL_MODELS_RETRY_DELAYS_MS) {\n if (!reportsNothingReachable(read)) return read;\n await sleep(delayMs, signal);\n read = await readLocalModels(signal);\n }\n return read;\n },\n};\n\n// One QueryDef per window, created once at module scope: useQuery keys on\n// `def.key`, and minting a fresh object per render would be harmless but\n// useRefresh/useRefetch's useCallback deps would churn for no reason.\nconst SERIES_QUERIES: Record<SeriesWindow, QueryDef<OptionalRead>> = {\n '7d': {\n key: `${USAGE_SERIES_KEY_PREFIX}:7d`,\n fetch: optionalGet('/api/verse/usage-series?window=7d'),\n },\n '30d': {\n key: `${USAGE_SERIES_KEY_PREFIX}:30d`,\n fetch: optionalGet('/api/verse/usage-series?window=30d'),\n },\n};\n\nexport function usageSeriesQuery(window: SeriesWindow): QueryDef<OptionalRead> {\n return SERIES_QUERIES[window];\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{s as t}from"./index-DOAOxiKl.js";import{N as n,S as r,l as i,o as a,u as o,w as s}from"./global-BJ_kVFpD.js";import{S as c,b as l,d as u,f as d,j as f}from"./VerseShared-CH8mV5ew.js";var p=[`user-message`,`turn-started`,`text-delta`,`assistant-message`,`thinking`,`tool-use`,`tool-result`,`usage`,`turn-done`,`error`,`cancelled`,`compaction`,`context`,`thinking-delta`,`thinking-progress`,`progress`,`status`,`recovered`,`history-truncated`,`source`,`remote-status`,`remote-pr`];function m(e){return Math.min(1e3*2**e,15e3)}var h=e=>e===null||typeof e==`number`&&Number.isFinite(e)&&e>=0;function g(e){return e.type===`context`?typeof e.contextTokens==`number`&&Number.isFinite(e.contextTokens)&&e.contextTokens>=0&&typeof e.exact==`boolean`&&h(e.contextWindow)&&(e.autoCompactAt===void 0||h(e.autoCompactAt)):e.type!==`compaction`||(e.trigger===`auto`||e.trigger===`manual`)&&h(e.preTokens)&&h(e.postTokens)&&h(e.durationMs)}var _=e=>e===void 0||typeof e==`number`&&Number.isFinite(e)&&e>=0;function v(e){switch(e.type){case`thinking-delta`:return typeof e.text==`string`;case`thinking-progress`:return e.estimatedTokens!==void 0&&_(e.estimatedTokens);case`progress`:return(e.phase===`thinking`||e.phase===`tool`||e.phase===`writing`||e.phase===`waiting`)&&typeof e.elapsedMs==`number`&&Number.isFinite(e.elapsedMs)&&e.elapsedMs>=0&&(e.tool===void 0||typeof e.tool==`string`)&&_(e.outTokens)&&_(e.tokPerSec);case`status`:return(e.kind===`retry`||e.kind===`preflight`||e.kind===`watchdog`)&&typeof e.message==`string`;case`history-truncated`:return typeof e.droppedBefore==`number`&&Number.isFinite(e.droppedBefore);case`source`:{let t=e.source;return!!t&&typeof t==`object`&&typeof t.kind==`string`&&typeof t.ref==`string`&&t.ref.length>0&&typeof t.title==`string`&&typeof t.origin==`string`}default:return!0}}function y(e){try{let t=JSON.parse(e);if(!t||typeof t!=`object`)return null;let n=t;return typeof n.seq!=`number`||typeof n.type!=`string`||!g(t)||!v(t)?null:t}catch{return null}}var b=`verse-sessions`;function x(e=!0){return n()?`/api/events?topics=${b}`:`/api/events?${e?`topics=${b}&`:``}client=${encodeURIComponent(s())}`}var S=!1;function C(){let e=null,t=null,i=0,a=!1,o=!1,s=()=>{if(a||typeof EventSource>`u`||r().phase!==`authenticated`)return;let c=n()||!S&&!o,l=new EventSource(x(c),{withCredentials:!0}),d=!1;e=l,l.onopen=()=>{d=!0,i=0,o&&=(S=!0,!1)},l.addEventListener(`verse-sessions`,()=>u()),l.onerror=()=>{if(l.close(),e===l&&(e=null),!(a||r().phase!==`authenticated`)){if(!d&&c&&!n()){o=!0,s();return}o=!1,t=setTimeout(()=>{t=null,i+=1,s()},m(i))}}};return s(),()=>{a=!0,t&&clearTimeout(t),t=null,e?.close(),e=null}}var w=e(t(),1),T=5e3,E=new Map,D=new Set;function O(e){return D.add(e),()=>D.delete(e)}function k(){return E}function A(e,t){if(!((E.get(e)??-1)>=t)){E=new Map(E).set(e,t);for(let e of[...D])e();d(e,t)}}function j(){return(0,w.useSyncExternalStore)(O,k,k)}function M(){let e=i(l,{freshMs:4500}),t=i(c),n=o(l),r=(0,w.useCallback)(()=>n(),[n]);f(r,T);let s=j();return{activity:e.data??null,meta:t.data??null,metaError:t.status===`error`?a(t.error):null,localSeen:s}}export{y as a,C as i,M as n,p as r,A as t};
2
- //# sourceMappingURL=use-chat-activity-BZjdPPNP.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-chat-activity-BZjdPPNP.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/verse-events.ts","../../../../../../src/web-ui/routes/verse/chat/use-chat-activity.ts"],"sourcesContent":["/**\n * routes/verse/verse-events.ts — the Verse console's SSE vocabulary and its\n * sidebar channel, since scoped consoles never join data/sse.ts's global feed:\n *\n * - VERSE_EVENT_TYPES + parseVerseEventFrame: every VerseEvent name a\n * session stream can carry, and the frame validation both streams share.\n * The per-session stream itself (resume by `?after=`, one store update\n * per animation frame, ref-counted connections) lives in\n * session-stream.ts (V3.10); the replay-from-zero opener that used to sit\n * here had no callers left and was removed.\n * - openVerseListChannel: one EventSource against /api/events for the\n * `verse-sessions` list digest, which just invalidates the sidebar's\n * cache keys. It subscribes with `?topics=verse-sessions` (V3.10) so the\n * server skips the dashboard snapshot and the other groups this console\n * would only discard.\n *\n * Every URL carries the per-tab client proof as `?client=` — the same\n * construction data/client.ts's eventsUrl() uses, because EventSource cannot\n * send the proof as a header (see read-session.ts readSessionClientProof).\n */\nimport type { VerseEvent, VerseEventType } from '../../data/api-types.js';\nimport { getAuthSnapshot, getReadClientProof } from '../../data/auth-store.js';\nimport { isRemoteMobileMode } from '../../data/remote-mode.js';\nimport { invalidateVerseLists } from './verse-queries.js';\n\n/**\n * Every VerseEvent name the stream can carry. EventSource only dispatches\n * NAMED events to listeners registered by name, so a type missing here is\n * silently dropped — the check below turns a new union member into a compile\n * error in this file instead of a meter that never moves.\n */\nconst EVENT_TYPES = [\n 'user-message',\n 'turn-started',\n 'text-delta',\n 'assistant-message',\n 'thinking',\n 'tool-use',\n 'tool-result',\n 'usage',\n 'turn-done',\n 'error',\n 'cancelled',\n // V3.9 — a server that predates them simply never sends these names.\n 'compaction',\n 'context',\n // V3.10 transient (SSE only, never replayed — see VERSE_TRANSIENT_EVENT_TYPES\n // in core/verse/types.ts). They carry the last PERSISTED seq, so a store that\n // dedupes by seq and does not know them yet simply drops them.\n 'thinking-delta',\n 'thinking-progress',\n 'progress',\n 'status',\n // V3.10 persisted.\n 'recovered',\n 'history-truncated',\n // V3.15 persisted (additive): injected / seat-reported sources.\n 'source',\n // 3.15 persisted (Devin seats).\n 'remote-status',\n 'remote-pr',\n] as const satisfies readonly VerseEventType[];\n\ntype UnlistedEventType = Exclude<VerseEventType, (typeof EVENT_TYPES)[number]>;\n// Fails to compile when VerseEventType gains a member EVENT_TYPES does not list.\nconst EVENT_TYPES_EXHAUSTIVE: [UnlistedEventType] extends [never] ? true : never = true;\nvoid EVENT_TYPES_EXHAUSTIVE;\n\nexport const VERSE_EVENT_TYPES: readonly VerseEventType[] = EVENT_TYPES;\n\nfunction backoffMs(attempt: number): number {\n return Math.min(1000 * 2 ** attempt, 15_000);\n}\n\nconst nullableCount = (v: unknown): boolean => v === null || (typeof v === 'number' && Number.isFinite(v) && v >= 0);\n\n/**\n * The two V3.9 frames feed arithmetic (the meter, the compaction count), so a\n * malformed one is dropped here rather than turning the meter into `NaN`.\n * Older event types keep the original seq/type-only check.\n */\nfunction v39FieldsValid(e: Record<string, unknown>): boolean {\n if (e.type === 'context') {\n return typeof e.contextTokens === 'number' && Number.isFinite(e.contextTokens) && e.contextTokens >= 0 &&\n typeof e.exact === 'boolean' && nullableCount(e.contextWindow) &&\n (e.autoCompactAt === undefined || nullableCount(e.autoCompactAt));\n }\n if (e.type === 'compaction') {\n return (e.trigger === 'auto' || e.trigger === 'manual') &&\n nullableCount(e.preTokens) && nullableCount(e.postTokens) && nullableCount(e.durationMs);\n }\n return true;\n}\n\nconst optionalCount = (v: unknown): boolean => v === undefined || (typeof v === 'number' && Number.isFinite(v) && v >= 0);\n\n/**\n * V3.10 frames that feed arithmetic or a live label (elapsed, tok/s, token\n * estimate) — same rule as v39FieldsValid: malformed → dropped, never NaN.\n */\nfunction v310FieldsValid(e: Record<string, unknown>): boolean {\n switch (e.type) {\n case 'thinking-delta':\n return typeof e.text === 'string';\n case 'thinking-progress':\n return e.estimatedTokens !== undefined && optionalCount(e.estimatedTokens);\n case 'progress':\n return (e.phase === 'thinking' || e.phase === 'tool' || e.phase === 'writing' || e.phase === 'waiting') &&\n typeof e.elapsedMs === 'number' && Number.isFinite(e.elapsedMs) && e.elapsedMs >= 0 &&\n (e.tool === undefined || typeof e.tool === 'string') &&\n optionalCount(e.outTokens) && optionalCount(e.tokPerSec);\n case 'status':\n return (e.kind === 'retry' || e.kind === 'preflight' || e.kind === 'watchdog') && typeof e.message === 'string';\n case 'history-truncated':\n return typeof e.droppedBefore === 'number' && Number.isFinite(e.droppedBefore);\n case 'source': {\n // Kept inline (not core/verse/trace isVerseSource): this file is on the\n // chat's first-paint path and must not pull the trace module in.\n const s = e.source as Record<string, unknown> | null | undefined;\n return !!s && typeof s === 'object' && typeof s.kind === 'string' && typeof s.ref === 'string' && s.ref.length > 0 &&\n typeof s.title === 'string' && typeof s.origin === 'string';\n }\n default:\n return true;\n }\n}\n\n/** Exported for tests: one SSE frame's data → a VerseEvent, or null when malformed. */\nexport function parseVerseEventFrame(raw: string): VerseEvent | null {\n try {\n const parsed = JSON.parse(raw) as unknown;\n if (!parsed || typeof parsed !== 'object') return null;\n const candidate = parsed as Partial<VerseEvent>;\n if (typeof candidate.seq !== 'number' || typeof candidate.type !== 'string') return null;\n if (!v39FieldsValid(parsed as Record<string, unknown>)) return null;\n if (!v310FieldsValid(parsed as Record<string, unknown>)) return null;\n return parsed as VerseEvent;\n } catch {\n return null;\n }\n}\n\n/** The only /api/events group the Verse console listens to. */\nexport const VERSE_LIST_TOPICS = 'verse-sessions';\n\n/**\n * The sidebar channel's URL. `topics` narrows the server to the one group\n * this console listens to; `client` stays last, as in eventsUrl(). Without\n * `topics` the server sends every group — the historical request, which is\n * also what the refusal fallback below falls back to.\n */\nexport function verseListEventsUrl(withTopics = true): string {\n // The gateway accepts only the scoped topic and adds the Hub client proof\n // on its private hop. A phone must never construct or send that proof.\n if (isRemoteMobileMode()) return `/api/events?topics=${VERSE_LIST_TOPICS}`;\n const topics = withTopics ? `topics=${VERSE_LIST_TOPICS}&` : '';\n return `/api/events?${topics}client=${encodeURIComponent(getReadClientProof())}`;\n}\n\n/**\n * Set once this page has PROVEN that the server refuses `?topics=`: a\n * connection with it failed before it ever opened, and the same channel\n * without it then opened. The read-session boundary on SSE paths used to\n * answer 401 to any parameter besides `client`, and a sidebar that never\n * updates is far worse than one that is sent (and discards) extra groups.\n * Page-lifetime only — the same rule session-stream.ts applies to `?after=`:\n * a server that gains support is used again after a reload.\n */\nlet topicsRefused = false;\n\n/** Tests: forget a proven refusal. */\nexport function resetVerseListChannelCapabilities(): void {\n topicsRefused = false;\n}\n\n/**\n * Sidebar digest channel: listens only for `verse-sessions` on /api/events\n * and refreshes the session list + bootstrap when it fires.\n */\nexport function openVerseListChannel(): () => void {\n let source: EventSource | null = null;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let attempt = 0;\n let disposed = false;\n /** This connection is the no-`topics` retry that tests whether `topics` was refused. */\n let probing = false;\n\n const connect = () => {\n if (disposed || typeof EventSource === 'undefined') return;\n if (getAuthSnapshot().phase !== 'authenticated') return;\n const withTopics = isRemoteMobileMode() || (!topicsRefused && !probing);\n const es = new EventSource(verseListEventsUrl(withTopics), { withCredentials: true });\n let opened = false;\n source = es;\n es.onopen = () => {\n opened = true;\n attempt = 0;\n if (probing) {\n topicsRefused = true;\n probing = false;\n }\n };\n es.addEventListener('verse-sessions', () => invalidateVerseLists());\n es.onerror = () => {\n es.close();\n if (source === es) source = null;\n if (disposed || getAuthSnapshot().phase !== 'authenticated') return;\n if (!opened && withTopics && !isRemoteMobileMode()) {\n // Refused before it opened, with `topics`: find out at once whether\n // the parameter is what was refused (see topicsRefused). One probe,\n // no delay — a real outage fails the probe too and falls through to\n // the ordinary backoff below.\n probing = true;\n connect();\n return;\n }\n probing = false;\n timer = setTimeout(() => {\n timer = null;\n attempt += 1;\n connect();\n }, backoffMs(attempt));\n };\n };\n\n connect();\n\n return () => {\n disposed = true;\n if (timer) clearTimeout(timer);\n timer = null;\n source?.close();\n source = null;\n };\n}\n","/**\n * routes/verse/chat/use-chat-activity.ts — the Chat surface's view of C1's\n * activity + session-meta routes (unit C2).\n *\n * WHY NOT C1's useActivity: that hook runs the shell's CURSOR loop (it owns\n * completions, the rail badges and the native \"Finished:\" notifications).\n * The chat list needs only the present tense — who is running, what they are\n * doing, what needs the operator — so it reads the same route without a\n * cursor, through the shared query cache under VERSE_ACTIVITY_KEY. Any other\n * reader of that key (the rail, a future pane) shares the one request.\n *\n * Polls every 5 s ONLY while the Chat surface and the window are visible\n * (C0's usePollWhileVisible), and catches up the moment it is shown again.\n * Activity answers in < 5 ms from memory (SPEC-310C budget), so this is\n * cheap; it is still never faster than the 2 s floor.\n *\n * Also owns this tab's \"seen\" map: opening a chat clears its unread dot NOW,\n * whether or not the server-side POST can run (it needs a held token).\n */\nimport { useCallback, useSyncExternalStore } from 'react';\nimport { readFailureReason } from '../../../data/client.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { usePollWhileVisible } from '../shell/section-visibility.js';\nimport { markVerseSessionSeen, verseActivityQuery, verseSessionMetaQuery } from '../verse-queries.js';\n\nexport const CHAT_ACTIVITY_POLL_MS = 5_000;\n\n// ---- local seen map --------------------------------------------------------\n\nlet seen = new Map<string, number>();\nconst seenListeners = new Set<() => void>();\n\nfunction subscribeSeen(listener: () => void): () => void {\n seenListeners.add(listener);\n return () => seenListeners.delete(listener);\n}\n\nfunction getSeen(): ReadonlyMap<string, number> {\n return seen;\n}\n\n/** Record that the operator saw `sessionId` up to `turnCount`, locally and (best-effort) on the server. */\nexport function noteSessionSeen(sessionId: string, turnCount: number): void {\n if ((seen.get(sessionId) ?? -1) >= turnCount) return;\n seen = new Map(seen).set(sessionId, turnCount);\n for (const listener of [...seenListeners]) listener();\n void markVerseSessionSeen(sessionId, turnCount);\n}\n\n/** Test seam. */\nexport function resetLocalSeen(): void {\n seen = new Map();\n for (const listener of [...seenListeners]) listener();\n}\n\nexport function useLocalSeen(): ReadonlyMap<string, number> {\n return useSyncExternalStore(subscribeSeen, getSeen, getSeen);\n}\n\n// ---- queries ---------------------------------------------------------------\n\nexport function useChatActivity() {\n const activity = useQuery(verseActivityQuery, { freshMs: CHAT_ACTIVITY_POLL_MS - 500 });\n const meta = useQuery(verseSessionMetaQuery);\n const refetchActivity = useRefetch(verseActivityQuery);\n const tick = useCallback(() => refetchActivity(), [refetchActivity]);\n usePollWhileVisible(tick, CHAT_ACTIVITY_POLL_MS);\n const localSeen = useLocalSeen();\n return {\n /** null = the route is not mounted on this server (or has not answered yet). */\n activity: activity.data ?? null,\n meta: meta.data ?? null,\n /**\n * Why session-meta could not be read (the route's own sentence, e.g. the\n * chat engine is not answering), or null. A 404 is not an error here — it\n * reads as `meta: null` (\"not on this server\").\n */\n metaError: meta.status === 'error' ? readFailureReason(meta.error) : null,\n localSeen,\n };\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{s as t}from"./index-DOAOxiKl.js";import{T as n,n as r,t as i}from"./global-BJ_kVFpD.js";import{y as a}from"./format-V6IiIMAL.js";import{n as o}from"./control-queries-CUNa6TAx.js";var s=e(t(),1);function c(e){return e instanceof r?`This server runs without dispatch, so that action is unavailable.`:e instanceof o?e.message:e instanceof i?e.status===401?"The mutation token was rejected. Unlock again with the token `ashlr verse` printed.":e.detail?a(e.detail):e.status===400?a(e.message):e.status===409?`The server refused the action, and sent no reason.`:a(e.message):e instanceof Error?a(e.message):`That action failed. Try again.`}function l(){let[e,t]=(0,s.useState)(!1),[i,a]=(0,s.useState)(null),[o,l]=(0,s.useState)(!1),[u,d]=(0,s.useState)(!1),[f,p]=(0,s.useState)(``),m=(0,s.useRef)(null),h=(0,s.useCallback)(async(e,n)=>{t(!0),a(null);try{let t=await e();n?.(t)}catch(e){e instanceof r?l(!0):a(c(e))}finally{t(!1)}},[]),g=(0,s.useCallback)((e,t,r)=>{a(null);let i=r;if(n()){h(e,i);return}m.current={fn:e,onResult:i},p(t),d(!0)},[h]),_=(0,s.useCallback)(()=>{d(!1);let e=m.current;m.current=null,e&&n()&&h(e.fn,e.onResult)},[h]);return{request:g,busy:e,error:i,clearError:(0,s.useCallback)(()=>a(null),[]),readOnly:o,tokenOpen:u,tokenReason:f,closeToken:_}}export{l as n,c as t};
2
- //# sourceMappingURL=use-guarded-action-xJ4rxyVo.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-guarded-action-xJ4rxyVo.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/autonomy/use-guarded-action.ts"],"sourcesContent":["/**\n * routes/verse/autonomy/use-guarded-action.ts — the one place a Verse control\n * surface turns \"the operator clicked something destructive\" into an actual\n * request. Shared by the Autonomy cockpit and the Approvals surface.\n *\n * It folds together the three things every mutating click in this app has to\n * do, which were previously re-implemented per call site:\n *\n * - **Token hand-off.** No mutation hold yet → remember the action, open\n * MutationTokenDialog, and run it once the token lands. The hold is read\n * LIVE on dialog close, never from a render-time snapshot, because\n * MutationTokenDialog's onClose fires before this component re-renders.\n * - **Read-only sessions.** Every POST 404s when the server was started\n * without dispatch. That is a session mode, not a failure, so it flips a\n * `readOnly` flag the surface renders as an explanation — never as an error\n * toast and never as a crash.\n * - **Busy + error state** for exactly one in-flight action at a time.\n */\nimport { useCallback, useRef, useState } from 'react';\nimport { hasMutationHold } from '../../../data/auth-store.js';\nimport { ApiError, DispatchDisabledError } from '../../../data/client.js';\nimport { VerseControlLockedError } from './control-queries.js';\nimport { tidyProse } from './format.js';\n\nexport function describeControlError(err: unknown): string {\n if (err instanceof DispatchDisabledError) return 'This server runs without dispatch, so that action is unavailable.';\n if (err instanceof VerseControlLockedError) return err.message;\n if (err instanceof ApiError) {\n if (err.status === 401) return 'The mutation token was rejected. Unlock again with the token `ashlr verse` printed.';\n // The control plane writes a careful refusal ladder — \"no repositories are\n // enrolled, so the loop would do nothing. Add scope first.\" — and returns\n // it as `note` on the 409 body. A blanket \"something else is already\n // running\" replaced every one of those with a sentence that was usually\n // false and never actionable. Show the server's own words whenever it\n // sent any; the generic line is now only the last resort. `tidyProse`\n // reads any ISO instant in those words as local time.\n if (err.detail) return tidyProse(err.detail);\n if (err.status === 400) return tidyProse(err.message);\n if (err.status === 409) return 'The server refused the action, and sent no reason.';\n return tidyProse(err.message);\n }\n return err instanceof Error ? tidyProse(err.message) : 'That action failed. Try again.';\n}\n\nexport interface GuardedAction {\n /**\n * Run `fn`, prompting for the mutation token first when none is held.\n *\n * `onResult` receives `fn`'s resolved value when it succeeds. It exists\n * because the value was previously dropped on the floor, and for the daemon\n * routes that value carries the server's own account of what just happened\n * (`VerseDaemonActionResult.note` — e.g. that an ordinary stop also engaged\n * the global kill switch). It is not called when `fn` throws.\n */\n request: <T>(fn: () => Promise<T>, reason: string, onResult?: (result: T) => void) => void;\n busy: boolean;\n error: string | null;\n clearError: () => void;\n /** True once a POST 404'd — the server has no dispatch enabled. */\n readOnly: boolean;\n /** Bind these three to <MutationTokenDialog/>. */\n tokenOpen: boolean;\n tokenReason: string;\n closeToken: () => void;\n}\n\nexport function useGuardedAction(): GuardedAction {\n const [busy, setBusy] = useState(false);\n const [error, setError] = useState<string | null>(null);\n const [readOnly, setReadOnly] = useState(false);\n const [tokenOpen, setTokenOpen] = useState(false);\n const [tokenReason, setTokenReason] = useState('');\n // The deferred action and the callback that wants its result travel together\n // — the token dialog may run it a render later, long after `request` returned.\n const pending = useRef<{ fn: () => Promise<unknown>; onResult?: (result: never) => void } | null>(null);\n\n const perform = useCallback(\n async (fn: () => Promise<unknown>, onResult?: (result: never) => void) => {\n setBusy(true);\n setError(null);\n try {\n const result = await fn();\n onResult?.(result as never);\n } catch (err) {\n if (err instanceof DispatchDisabledError) setReadOnly(true);\n else setError(describeControlError(err));\n } finally {\n setBusy(false);\n }\n },\n [],\n );\n\n const request = useCallback(\n <T,>(fn: () => Promise<T>, reason: string, onResult?: (result: T) => void) => {\n setError(null);\n const handler = onResult as ((result: never) => void) | undefined;\n if (hasMutationHold()) {\n void perform(fn, handler);\n return;\n }\n pending.current = { fn, onResult: handler };\n setTokenReason(reason);\n setTokenOpen(true);\n },\n [perform],\n );\n\n const closeToken = useCallback(() => {\n setTokenOpen(false);\n const next = pending.current;\n pending.current = null;\n // Live read: the dialog closes synchronously after setToken().\n if (next && hasMutationHold()) void perform(next.fn, next.onResult);\n }, [perform]);\n\n const clearError = useCallback(() => setError(null), []);\n\n return { request, busy, error, clearError, readOnly, tokenOpen, tokenReason, closeToken };\n}\n"],"mappings":"4PAwBA,SAAgB,EAAqB,EAAsB,CAiBzD,OAhBI,aAAe,EAA8B,oEAC7C,aAAe,EAAgC,EAAI,QACnD,aAAe,EACb,EAAI,SAAW,IAAY,sFAQ3B,EAAI,OAAe,EAAU,EAAI,MAAM,EACvC,EAAI,SAAW,IAAY,EAAU,EAAI,OAAO,EAChD,EAAI,SAAW,IAAY,qDACxB,EAAU,EAAI,OAAO,EAEvB,aAAe,MAAQ,EAAU,EAAI,OAAO,EAAI,gCACzD,CAwBA,SAAgB,GAAkC,CAChD,GAAM,CAAC,EAAM,IAAA,EAAW,EAAA,SAAA,CAAS,EAAK,EAChC,CAAC,EAAO,IAAA,EAAY,EAAA,SAAA,CAAwB,IAAI,EAChD,CAAC,EAAU,IAAA,EAAe,EAAA,SAAA,CAAS,EAAK,EACxC,CAAC,EAAW,IAAA,EAAgB,EAAA,SAAA,CAAS,EAAK,EAC1C,CAAC,EAAa,IAAA,EAAkB,EAAA,SAAA,CAAS,EAAE,EAG3C,GAAA,EAAU,EAAA,OAAA,CAAkF,IAAI,EAEhG,GAAA,EAAU,EAAA,YAAA,CACd,MAAO,EAA4B,IAAuC,CACxE,EAAQ,EAAI,EACZ,EAAS,IAAI,EACb,GAAI,CACF,IAAM,EAAS,MAAM,EAAG,EACxB,IAAW,CAAe,CAC5B,OAAS,EAAK,CACR,aAAe,EAAuB,EAAY,EAAI,EACrD,EAAS,EAAqB,CAAG,CAAC,CACzC,QAAU,CACR,EAAQ,EAAK,CACf,CACF,EACA,CAAC,CACH,EAEM,GAAA,EAAU,EAAA,YAAA,EACT,EAAsB,EAAgB,IAAmC,CAC5E,EAAS,IAAI,EACb,IAAM,EAAU,EAChB,GAAI,EAAgB,EAAG,CACrB,EAAa,EAAI,CAAO,EACxB,MACF,CACA,EAAQ,QAAU,CAAE,KAAI,SAAU,CAAQ,EAC1C,EAAe,CAAM,EACrB,EAAa,EAAI,CACnB,EACA,CAAC,CAAO,CACV,EAEM,GAAA,EAAa,EAAA,YAAA,KAAkB,CACnC,EAAa,EAAK,EAClB,IAAM,EAAO,EAAQ,QACrB,EAAQ,QAAU,KAEd,GAAQ,EAAgB,GAAG,EAAa,EAAK,GAAI,EAAK,QAAQ,CACpE,EAAG,CAAC,CAAO,CAAC,EAIZ,MAAO,CAAE,UAAS,OAAM,QAAO,YAAA,EAFZ,EAAA,YAAA,KAAkB,EAAS,IAAI,EAAG,CAAC,CAEvB,EAAY,WAAU,YAAW,cAAa,YAAW,CAC1F"}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{s as t}from"./index-DOAOxiKl.js";var n=e(t(),1);function r(e=1e3){let[t,r]=(0,n.useState)(()=>Date.now());return(0,n.useEffect)(()=>{let t=setInterval(()=>r(Date.now()),e);return()=>clearInterval(t)},[e]),t}export{r as t};
2
- //# sourceMappingURL=use-ticker-Bsu0cMvl.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-ticker-Bsu0cMvl.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/autonomy/use-ticker.ts"],"sourcesContent":["/**\n * routes/verse/autonomy/use-ticker.ts — a shared 1Hz clock for the countdown\n * and the relative ages in the status header — one interval per consumer\n * rather than a bespoke timer inside each panel.\n *\n * It deliberately keeps ticking under `prefers-reduced-motion`: a countdown is\n * information, not decoration. The design language's quiet-motion rule governs\n * transitions and animation, not numbers that have to stay true.\n */\nimport { useEffect, useState } from 'react';\n\nexport function useNow(intervalMs = 1000): number {\n const [now, setNow] = useState(() => Date.now());\n useEffect(() => {\n const id = setInterval(() => setNow(Date.now()), intervalMs);\n return () => clearInterval(id);\n }, [intervalMs]);\n return now;\n}\n"],"mappings":"0GAWA,SAAgB,EAAO,EAAa,IAAc,CAChD,GAAM,CAAC,EAAK,IAAA,EAAU,EAAA,SAAA,KAAe,KAAK,IAAI,CAAC,EAK/C,OAJA,EAAA,EAAA,UAAA,KAAgB,CACd,IAAM,EAAK,gBAAkB,EAAO,KAAK,IAAI,CAAC,EAAG,CAAU,EAC3D,UAAa,cAAc,CAAE,CAC/B,EAAG,CAAC,CAAU,CAAC,EACR,CACT"}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{s as t}from"./index-DOAOxiKl.js";import{T as n,n as r,t as i}from"./global-BJ_kVFpD.js";import{r as a}from"./VerseShared-CH8mV5ew.js";import{y as o}from"./format-V6IiIMAL.js";var s=e(t(),1);function c(){let[e,t]=(0,s.useState)({open:!1,reason:``}),r=(0,s.useRef)(null),i=(0,s.useCallback)((e,i)=>n()?i():(r.current?.cancel(),new Promise((n,a)=>{r.current={run:()=>{i().then(n,a)},cancel:()=>n(null)},t({open:!0,reason:e})})),[]),a=(0,s.useCallback)(()=>{t({open:!1,reason:``});let e=r.current;e&&setTimeout(()=>{r.current===e&&(r.current=null,e.cancel())},0)},[]),o=(0,s.useCallback)(()=>{let e=r.current;r.current=null,e?.run()},[]);return{run:i,dialog:{open:e.open,reason:e.reason,onClose:a,onUnlocked:o}}}function l(e){return e instanceof r?"This server is read-only (started without dispatch — run `ashlr verse`), or older than this console.":e instanceof a?`Unlock actions with the mutation token first.`:e instanceof i?e.status===401?"The mutation token was rejected. Unlock again with the token `ashlr verse` printed.":e.code===`VERSE_SESSION_NOT_FOUND`?`This chat no longer exists on the server — it may have been deleted. Refresh the chat list.`:e.detail?o(e.detail):e.status===404?"This server does not have that route yet — update Ashlr and restart `ashlr verse`.":e.status===409?`A turn is already running in this chat. Wait for it or stop it first.`:o(e.message):e instanceof Error&&e.message?o(e.message):`Something went wrong.`}export{c as n,l as t};
2
- //# sourceMappingURL=use-token-gate-E-xzEAu6.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"use-token-gate-E-xzEAu6.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/context/use-token-gate.ts"],"sourcesContent":["/**\n * routes/verse/context/use-token-gate.ts — the mutation-token hand-off for\n * the self-contained context surfaces (handoff dialog, memory panel).\n *\n * Same contract as ChatSection's `withToken`, extracted because these\n * components are mounted by OTHER owners (the workspace header, the resources\n * panel) that cannot thread a guard down to them:\n *\n * - a held token → the action runs now;\n * - no token → the action is parked, MutationTokenDialog opens with a reason\n * saying what the click will do, and the action runs once unlocked;\n * - the dialog dismissed → the promise resolves `null`, so the caller can\n * tell \"not done\" from \"done\" without an exception.\n *\n * The hold is read LIVE (`hasMutationHold()`), never from a render snapshot:\n * MutationTokenDialog calls `onClose` before `onUnlocked` in the same tick,\n * so a snapshot taken at render time is always one step behind.\n */\nimport { useCallback, useRef, useState } from 'react';\nimport { hasMutationHold } from '../../../data/auth-store.js';\nimport { ApiError, DispatchDisabledError } from '../../../data/client.js';\nimport { VerseMutationLockedError } from '../verse-queries.js';\nimport { tidyProse } from '../autonomy/format.js';\n\nexport interface TokenGateDialogProps {\n open: boolean;\n reason: string;\n onClose: () => void;\n onUnlocked: () => void;\n}\n\nexport interface TokenGate {\n run<T>(reason: string, action: () => Promise<T>): Promise<T | null>;\n /** Spread onto <MutationTokenDialog />. */\n dialog: TokenGateDialogProps;\n}\n\nexport function useTokenGate(): TokenGate {\n const [prompt, setPrompt] = useState<{ open: boolean; reason: string }>({ open: false, reason: '' });\n const pending = useRef<{ run: () => void; cancel: () => void } | null>(null);\n\n const run = useCallback(<T,>(reason: string, action: () => Promise<T>): Promise<T | null> => {\n if (hasMutationHold()) return action();\n // A second click while the prompt is up supersedes the first: the earlier\n // caller is told \"not done\" rather than left waiting forever.\n pending.current?.cancel();\n return new Promise<T | null>((resolve, reject) => {\n pending.current = {\n run: () => { action().then(resolve, reject); },\n cancel: () => resolve(null),\n };\n setPrompt({ open: true, reason });\n });\n }, []);\n\n const onClose = useCallback(() => {\n setPrompt({ open: false, reason: '' });\n // onClose fires BEFORE onUnlocked on a successful submit, so only treat\n // this as a dismissal if nothing claimed the parked action by next tick.\n const parked = pending.current;\n if (!parked) return;\n setTimeout(() => {\n if (pending.current === parked) {\n pending.current = null;\n parked.cancel();\n }\n }, 0);\n }, []);\n\n const onUnlocked = useCallback(() => {\n const parked = pending.current;\n pending.current = null;\n parked?.run();\n }, []);\n\n return { run, dialog: { open: prompt.open, reason: prompt.reason, onClose, onUnlocked } };\n}\n\n/**\n * One sentence for a failed context action. Prefers the server's own words\n * (`ApiError.detail`), which the context routes write for a person.\n */\nexport function describeContextError(err: unknown): string {\n if (err instanceof DispatchDisabledError) {\n // A CODELESS 404 on a write: the dispatch gate, or a server that predates\n // this route — the two answer the same bare body by design (client.ts).\n // A missing chat is NOT this: it carries VERSE_SESSION_NOT_FOUND below.\n return 'This server is read-only (started without dispatch — run `ashlr verse`), or older than this console.';\n }\n if (err instanceof VerseMutationLockedError) return 'Unlock actions with the mutation token first.';\n if (err instanceof ApiError) {\n if (err.status === 401) return 'The mutation token was rejected. Unlock again with the token `ashlr verse` printed.';\n if (err.code === 'VERSE_SESSION_NOT_FOUND') return 'This chat no longer exists on the server — it may have been deleted. Refresh the chat list.';\n // The server's own words, with any ISO instant in them read as local time.\n if (err.detail) return tidyProse(err.detail);\n if (err.status === 404) return 'This server does not have that route yet — update Ashlr and restart `ashlr verse`.';\n if (err.status === 409) return 'A turn is already running in this chat. Wait for it or stop it first.';\n return tidyProse(err.message);\n }\n return err instanceof Error && err.message ? tidyProse(err.message) : 'Something went wrong.';\n}\n"],"mappings":"wPAqCA,SAAgB,GAA0B,CACxC,GAAM,CAAC,EAAQ,IAAA,EAAa,EAAA,SAAA,CAA4C,CAAE,KAAM,GAAO,OAAQ,EAAG,CAAC,EAC7F,GAAA,EAAU,EAAA,OAAA,CAAuD,IAAI,EAErE,GAAA,EAAM,EAAA,YAAA,EAAiB,EAAgB,IACvC,EAAgB,EAAU,EAAO,GAGrC,EAAQ,SAAS,OAAO,EACjB,IAAI,SAAmB,EAAS,IAAW,CAChD,EAAQ,QAAU,CAChB,QAAW,CAAE,EAAO,CAAC,CAAC,KAAK,EAAS,CAAM,CAAG,EAC7C,WAAc,EAAQ,IAAI,CAC5B,EACA,EAAU,CAAE,KAAM,GAAM,QAAO,CAAC,CAClC,CAAC,GACA,CAAC,CAAC,EAEC,GAAA,EAAU,EAAA,YAAA,KAAkB,CAChC,EAAU,CAAE,KAAM,GAAO,OAAQ,EAAG,CAAC,EAGrC,IAAM,EAAS,EAAQ,QAClB,GACL,eAAiB,CACX,EAAQ,UAAY,IACtB,EAAQ,QAAU,KAClB,EAAO,OAAO,EAElB,EAAG,CAAC,CACN,EAAG,CAAC,CAAC,EAEC,GAAA,EAAa,EAAA,YAAA,KAAkB,CACnC,IAAM,EAAS,EAAQ,QACvB,EAAQ,QAAU,KAClB,GAAQ,IAAI,CACd,EAAG,CAAC,CAAC,EAEL,MAAO,CAAE,MAAK,OAAQ,CAAE,KAAM,EAAO,KAAM,OAAQ,EAAO,OAAQ,UAAS,YAAW,CAAE,CAC1F,CAMA,SAAgB,EAAqB,EAAsB,CAiBzD,OAhBI,aAAe,EAIV,uGAEL,aAAe,EAAiC,gDAChD,aAAe,EACb,EAAI,SAAW,IAAY,sFAC3B,EAAI,OAAS,0BAAkC,8FAE/C,EAAI,OAAe,EAAU,EAAI,MAAM,EACvC,EAAI,SAAW,IAAY,qFAC3B,EAAI,SAAW,IAAY,wEACxB,EAAU,EAAI,OAAO,EAEvB,aAAe,OAAS,EAAI,QAAU,EAAU,EAAI,OAAO,EAAI,uBACxE"}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{s as t}from"./index-DOAOxiKl.js";import{l as n}from"./global-BJ_kVFpD.js";import{F as r,H as i,N as a,P as o,R as s,V as c,a as l,z as u}from"./verse-model-DAOz9LrY.js";import{f as d,i as f}from"./verse-store-DAqqNIyD.js";import{n as p}from"./budget-queries-DCZevH2S.js";import{n as m}from"./policy-DS7wupkn.js";import{l as h,u as g}from"./multimodel-flows-CzI-yHg5.js";import{a as _}from"./multimodel-queries-DxIT9AZY.js";import{a as v,n as y,o as b,r as x}from"./headroom-CduXLVmZ.js";var S=e(t(),1);Object.freeze({kind:`unknown`,at:null,description:null,source:null});function C(e){if(!e||typeof e!=`object`||Array.isArray(e))return!1;let t=e;if(![`fixed-period`,`weekly-deadline`,`rolling-release`,`balance`,`unknown`].includes(t.kind)||t.description!==null&&typeof t.description!=`string`||t.source!==null&&typeof t.source!=`string`)return!1;let n=e=>typeof e==`string`&&Number.isFinite(Date.parse(e))&&new Date(e).toISOString()===e;return t.at!==null&&!n(t.at)||t.startsAt!=null&&!n(t.startsAt)||t.kind===`fixed-period`&&(!n(t.at)||!n(t.startsAt)||t.startsAt>=t.at||!t.source)||t.kind===`weekly-deadline`&&(!n(t.at)||t.startsAt!=null||t.source!==`claude-native-usage-report`||![`pro`,`max`].includes(t.plan??``))?!1:t.kind!==`balance`||t.at===null}function w(e){return e.kind===`fixed-period`||e.kind===`weekly-deadline`}function T(e,t,n){let r=e?.durationMs,i=t===null?NaN:Date.parse(t)-n;return!r||!Number.isFinite(i)||i<=0?`unknown`:r.p75<=i?`likely-before-reset`:r.p25>i?`unlikely-before-reset`:`uncertain`}function E(e,t){if(e.admission!==`eligible`||e.opportunity.kind!==`before-reset`||!w(e.reset)||!C(e.reset)||!Number.isFinite(t))return 0;let n=e.forecast?.durationMs?.p75,r=e.reset.at===null?NaN:Date.parse(e.reset.at)-t;if(typeof n!=`number`||!Number.isFinite(n)||n<=0||!Number.isFinite(r)||r<=0)return 0;let i=1/(1+r/n),a=T(e.forecast,e.reset.at,t);return a===`likely-before-reset`?1+i:a===`uncertain`?i:0}var D=.8,O=Object.freeze({lambdaCost:1,lambdaPressure:1,lambdaLatency:.25}),k={elite:`elite`,fast:`fast`,free:`free`},A=r,j=[...r].reverse();function M(e){return e.tier??u(e.engine)}function N(e){return e.free||(e.costBasis??s(e.engine))===`free`?`free`:M(e)}function P(e){return j.indexOf(N(e))}function F(e,t){let n={by:`tier`,order:A},r={by:`cost`,order:j};if(!t.autonomous)return n;let i=t.task===`leader`&&t.difficulty!==`high`?`high`:t.difficulty;return t.task===`bulk`||i===`low`?r:e===`reserve`?i===`high`?{by:`tier`,order:[`fast`,`elite`,`free`]}:r:i===`medium`?e===`all-in`?{by:`tier`,order:[`fast`,`elite`,`free`]}:{by:`cost`,order:[`fast`,`free`,`elite`]}:n}function I(e,t,n){let r=[],i=null;e.signedOut&&r.push({kind:`signed-out`,text:`Signed out — reconnect this account.`}),e.reachable===!1&&!e.signedOut&&r.push({kind:`unreachable`,text:`Not reachable right now.`});let a=y(e,{seatId:e.seatId,enabled:!0,reservePercent:0},{nowMs:t,readingMaxAgeMs:n});return a.exhausted&&(r.push(...a.spentDetails),i=a.reopensAt),{capacity:e,index:0,headroom:a.headroom,eligible:r.length===0,details:r,nextEligibleAt:i}}function L(e,t,n,r){let i=m(t,e.seatId,e.engine),a=y(e,i,{nowMs:n,readingMaxAgeMs:r});return{capacity:e,index:0,headroom:a.headroom,eligible:a.headroom.eligibleForAutonomy,details:a.headroom.eligibleForAutonomy?[]:a.details,nextEligibleAt:a.headroom.eligibleForAutonomy?null:a.reopensAt}}function R(e){return e>=1e6?`${(e/1e6).toFixed(1)}M`:e>=1e3?`${Math.round(e/1e3)}k`:String(e)}function z(e,t){if(t===void 0||!Number.isFinite(t)||t<=0)return e;let n=e.capacity.contextWindow;return n===null||t<=n*.8?e:{...e,eligible:!1,details:[...e.details,{kind:`context`,text:`Needs about ${R(t)} tokens of context; this seat's window is ${R(n)} (at most ${Math.round(D*100)}% is used for a task).`}],nextEligibleAt:null}}function B(e,t){return e<t?-1:+(e>t)}var ee=.5,te=.019,ne=50,re=1e-9;function ie(e){let t=t=>{let n=e?.[t];return typeof n==`number`&&Number.isFinite(n)&&n>=0?Math.min(n,10):O[t]};return{lambdaCost:t(`lambdaCost`),lambdaPressure:t(`lambdaPressure`),lambdaLatency:t(`lambdaLatency`)}}function ae(e){return e.lambdaCost===O.lambdaCost&&e.lambdaPressure===O.lambdaPressure&&e.lambdaLatency===O.lambdaLatency}function oe(e,t){let n=new Map,r=e.flatMap(e=>{let n=t?.[e.capacity.seatId];return typeof n==`number`&&Number.isFinite(n)&&n>=0?[n]:[]});if(r.length===0)return n;let i=Math.min(...r),a=Math.max(...r)-i;for(let r of e){let e=t?.[r.capacity.seatId],o=typeof e==`number`&&Number.isFinite(e)&&e>=0;n.set(r.capacity.seatId,o?a===0?0:(e-i)/a:.5)}return n}function se(e,t,n,r){let i=(100-(e.headroom?.autonomyHeadroomPercent??(e.capacity.windowless?ne:-1)))/101;return t+(n.lambdaCost-1)*P(e.capacity)+n.lambdaPressure*ee*i+n.lambdaCost*ce*le(e.capacity)+n.lambdaLatency*te*r}var ce=.1;function le(e){let t=e.costBasis??s(e.engine);return o[t]}function ue(e,t,n,r,i){let a=e=>{let n=t.by===`cost`?N(e):M(e),r=t.order.indexOf(n);return r===-1?t.order.length:r},o=oe(e,r),s=new Map(e.map(e=>[e,se(e,a(e.capacity),n,o.get(e.capacity.seatId)??0)])),c=[...e].sort((e,t)=>{let n=s.get(e)-s.get(t);return Math.abs(n)>re?n:e.index===t.index?B(e.capacity.seatId,t.capacity.seatId):e.index-t.index});if(!i?.scheduling)return c;let l=new Map(c.map((e,t)=>[e,t])),u=new Map;c.forEach((e,t)=>{let n=a(e.capacity),r=u.get(n)??[];r.push(t),u.set(n,r)});for(let e of u.values()){let t=e.map(e=>c[e]).sort((e,t)=>{let n=i.scheduling[e.capacity.seatId],r=i.scheduling[t.capacity.seatId],a=n?E(n,i.nowMs):0,o=r?E(r,i.nowMs):0;if(a!==o)return o-a;if(i.advisorySeatId){let n=Number(t.capacity.seatId===i.advisorySeatId)-Number(e.capacity.seatId===i.advisorySeatId);if(n)return n}if(a>0&&n?.reset.at&&r?.reset.at){let e=Date.parse(n.reset.at)-Date.parse(r.reset.at);if(e)return e}return l.get(e)-l.get(t)});e.forEach((e,n)=>{c[e]=t[n]})}return c}function V(e){return String(Math.round(e*100)/100)}function H(e){return e.length>0?e.charAt(0).toLowerCase()+e.slice(1):e}function U(e){return`${e.difficulty}-difficulty ${e.task} work`}function de(e){let t=e.details?.[0]?.text??e.reasons[0]??`not eligible`;return`${e.seatId}: ${H(t).replace(/\.$/,``)}`}function fe(e,t=3){let n=e.slice(0,t).map(de).join(`; `);return e.length>t?`${n}; and ${e.length-t} more`:n}function pe(e){return{capacity:e,index:0,headroom:null,eligible:!1,details:[{kind:`lane`,text:`The fleet runs Devin as its own session lane under the Devin budget, not through the seat router.`}],nextEligibleAt:null}}function me(e,t,n,r){let i=r.readingMaxAgeMs??9e5,a=t.map((t,a)=>({...e.autonomous&&t.engine===`devin`?pe(t):z(e.autonomous?L(t,n,r.nowMs,i):I(t,r.nowMs,i),e.contextTokens),index:a}));if(e.autonomous&&r.scheduling)for(let e of a){let t=r.scheduling[e.capacity.seatId];e.eligible&&t?.admission===`unknown`&&(e.eligible=!1,e.details.push({kind:`unknown-usage`,text:`Current account-window evidence is incomplete or has passed its reported period.`}))}let o=F(n.mode,e),s=ie(r.weights),c=ue(a.filter(e=>e.eligible),o,s,r.latencyMs,r),l=a.filter(e=>!e.eligible).map(e=>({seatId:e.capacity.seatId,reasons:b(e.details),nextEligibleAt:e.nextEligibleAt,details:e.details})).sort((e,t)=>B(e.seatId,t.seatId)),u=c[0]??null,d=c.map(e=>e.capacity.seatId),f=e.autonomous?`autonomous `:``,p,m;if(u){let t=k[o.by===`cost`?N(u.capacity):M(u.capacity)],r=u.headroom?.autonomyHeadroomPercent,i=u.headroom?.bindingWindow===`session`?`5-hour`:`weekly`,a=e.autonomous&&!u.capacity.free&&typeof r==`number`,c=a?` with ${r}% of its ${i} window left for autonomy`:u.capacity.free?` at no cost`:``,d=l.length===0?``:`; held back ${l.length===1?`1 seat`:`${l.length} seats`} (${v(l.map(e=>e.seatId))})`,h=ae(s)?``:`; routing weights cost ×${V(s.lambdaCost)}, headroom ×${V(s.lambdaPressure)}, latency ×${V(s.lambdaLatency)}`;p=`Routed ${f}${U(e)} to ${u.capacity.label} (${u.capacity.seatId})${c}: ${n.mode} mode prefers the ${t} tier first for this work${h}${d}.`;let g=a?` — ${r}% of its ${i} window left`:u.capacity.free?` — free, no usage window`:``;m=g?`${u.capacity.label}${g}; ${n.mode} mode prefers the ${t} tier for this work.`:`${u.capacity.label} — ${n.mode} mode prefers the ${t} tier for this work.`}else if(t.length===0)p=`No seats are known, so ${f}${U(e)} has nowhere to run.`,m=`No seats are known, so this work has nowhere to run.`;else{let t=l.flatMap(e=>e.nextEligibleAt?[e.nextEligibleAt]:[]).sort((e,t)=>Date.parse(e)-Date.parse(t))[0]??null;p=`No seat can take ${f}${U(e)} in ${n.mode} mode (${fe(l)})${t?`; the earliest known reopening is ${t}`:``}.`,m=`No seat can take this ${U(e)} in ${n.mode} mode right now.`}return{seatId:u?.capacity.seatId??null,candidates:d,exclusions:l,why:p,summary:m,mode:n.mode}}var he=[`claude`,`codex`,`devin`,`grok`,`local`],ge=3.5,_e=1.25,ve=.75,ye=3,be=.5,xe=new Set([`code`,`debug`,`refactor`,`bulk`]),Se=new Set([`code`,`debug`,`refactor`,`bulk`,`review`]);function Ce(e,t){let n=e.difficulty===`high`||(e.needsFrontier??0)>=.7,r;return r=t===`cheap-first`?n?1:4:n?1:e.difficulty===`low`?3:1.5,{...O,lambdaCost:r}}function we(e,t,n){if(!e||!Se.has(n))return 0;let r=Object.values(e).filter(e=>e.dispatches>=10&&e.shipRate!==null),i=e[t];if(!i||i.dispatches<10||i.shipRate===null||r.length<2)return 0;let a=r.reduce((e,t)=>e+(t.shipRate??0),0)/r.length;return-Math.max(-.75,Math.min(ve,(i.shipRate-a)*2))}function Te(e,t){if(!t)return;let n={};for(let r of e){let e=t[r.engine]?.avgLatencyMs;typeof e==`number`&&Number.isFinite(e)&&e>0&&(n[r.seatId]=e)}return Object.keys(n).length>0?n:void 0}function Ee(e){return e===`session`?`5-hour`:`weekly`}function De(e){return e===`free`?`free on your plan`:e===`credits`?`spends credits (ACUs)`:`${a[e??`subscription`]} · no usage window reported`}function W(e,t){if(e.local)return e.private?`free · private on this Mac`:`free · local runtime`;if(e.capacity.windowless)return De(e.capacity.costBasis);let n=y(e.capacity,{seatId:e.seatId,enabled:!0,reservePercent:0},{nowMs:t}),r=n.headroom.autonomyHeadroomPercent;return n.exhausted?`usage spent`:typeof r==`number`?`${Math.max(0,r)}% of its ${Ee(n.headroom.bindingWindow)} window left`:`no usage reading`}function G(e,t){return{seatId:e.seatId,label:e.label,engine:e.engine,model:e.model,local:e.local,note:W(e,t),tier:M(e.capacity)}}function K(e,t=!0,n=!0){return e.base+(t?e.learned.tilt:0)+e.roi+(n?e.sticky:0)+e.tools+e.local}function Oe(e,t){return!t||!e.cheaper?e:{...e,model:e.cheaper.model,capacity:e.cheaper.capacity}}function q(e,t=!0,n=!0){return e.map((e,t)=>({r:e,i:t})).sort((e,r)=>K(e.r,t,n)-K(r.r,t,n)||e.i-r.i).map(e=>e.r)}function J(e,t=160){return e.length<=t?e:`${e.slice(0,t-1).trimEnd()}…`}function ke(e){let{classification:t,mode:n,nowMs:r}=e,i={on:e.localOnly?.on===!0,reason:e.localOnly?.reason??null},a=t.difficulty===`high`||(t.needsFrontier??0)>=.7,o=!a&&(n===`cheap-first`||t.difficulty===`low`||t.task===`bulk`),s=e.seats.filter(e=>he.includes(e.engine)&&e.model!==null).map(e=>Oe(e,o)),c=i.on?s.filter(e=>e.local&&e.private):s,l=new Map(c.map(e=>[e.seatId,e])),u=[];i.on&&u.push(`This repo is local-only${i.reason?` — ${i.reason.replace(/\.$/,``)}`:``}.`),u.push(`Read as ${t.label}${t.decidedBy===`jev`?` (labelled by Jev, ${Math.round((t.confidence??0)*100)}% sure)`:``}${t.signals.length>0?`: ${t.signals.slice(0,3).join(`, `)}`:``}.`);let d=Ce(t,n),f=Math.max(0,e.contextTokens??0)+t.estTokens,p=Te(c,e.roi),m=me({task:t.task,difficulty:(t.needsFrontier??0)>=.7&&t.difficulty!==`high`?`high`:t.difficulty,contextTokens:f,autonomous:!1},c.map(e=>e.capacity),e.policy,{nowMs:r,weights:d,...p?{latencyMs:p}:{}}),g=m.exclusions.map(e=>({seatId:e.seatId,label:l.get(e.seatId)?.label??e.seatId,reason:(e.details?.[0]?.text??e.reasons[0]??`Not available right now.`).replace(/\s+$/,``)})),_=(e.turnCount??0)>0&&typeof e.currentSeatId==`string`,v=n===`cheap-first`||a?_e:ge,y=m.candidates.flatMap((n,r)=>{let i=l.get(n);return i?[{seat:i,base:r,learned:h(e.learned,t.kind,i),roi:we(e.roi,i.engine,t.kind),sticky:_&&n===e.currentSeatId?-v:0,tools:i.local&&i.supportsTools===!1&&xe.has(t.kind)?ye:0,local:0}]:[]});if(a&&!i.on){let e=e=>M(e.seat.capacity)===`elite`,t=y.reduce((t,n)=>!n.seat.local&&e(n)?Math.max(t,n.base):t,-1);for(let n of y)n.seat.local&&e(n)&&t>n.base&&(n.local=t-n.base+be)}let b=e=>({choice:null,stay:!1,why:e,factors:u,alternatives:[],held:g,classification:t,mode:n,localOnly:i,routerWhy:m.why});if(y.length===0)return i.on&&c.length===0?b(`This repo is local-only and no local model is running — start Ollama or LM Studio, or pick a seat yourself.`):b(J(m.summary??m.why));let x=q(y),S=e.pinnedSeatId?x.find(t=>t.seat.seatId===e.pinnedSeatId)??null:null,C=S??x[0],w=C.seat,T=typeof e.currentSeatId==`string`&&w.seatId===e.currentSeatId,E=q(y,!1)[0].seat.seatId,D=q(y,!0,!1)[0].seat.seatId,k=q(y.map(e=>({...e,tools:0})))[0].seat.seatId,A=y.find(e=>e.seat.seatId===k),j=q(y.map(e=>({...e,local:0})))[0].seat.seatId,N=y.find(e=>e.seat.seatId===j),P;P=S?`you pinned this seat`:i.on?`${t.label} on a local-only repo — stays on this Mac`:T&&_&&D!==w.seatId?`${t.label}, mid-conversation — moving would re-send the whole context`:C.learned.phrase&&E!==w.seatId?`${t.label}; ${C.learned.phrase}`:A.seat.seatId!==w.seatId&&A.tools>0?`${t.label} edits files, and ${A.seat.label} cannot use tools`:N.seat.seatId!==w.seatId&&N.local>0?`${t.label} needs the strongest model now — a hosted seat answers faster than ${N.seat.label}`:w.local?n===`cheap-first`?`${t.label} — local drafts first, escalates only if the draft is weak`:`${t.label} — free and private on this Mac`:a?`${t.label} needs the strongest model`:t.label;let F=w.local?``:`; ${W(w,r)}`,I=J(`${T?`Staying on ${w.label}`:w.label} — ${P}${F}.`);return u.push(`Router (${m.mode} mode, interactive — fleet reserves do not apply to you): ${m.summary??m.why}`),d.lambdaCost!==O.lambdaCost&&u.push(`Cost weight ×${d.lambdaCost} for ${t.difficulty}-difficulty work${n===`cheap-first`?` in cheap-first mode`:``}.`),C.learned.phrase&&u.push(`Learned: ${C.learned.phrase}.`),C.roi!==0&&u.push(`Fleet record: ${w.engine} ships ${C.roi<0?`above`:`below`} the average for code work.`),g.length>0&&u.push(`Held back: ${g.map(e=>`${e.label} (${e.reason.replace(/\.$/,``).toLowerCase()})`).join(`; `)}.`),{choice:G(w,r),stay:T,why:I,factors:u,alternatives:x.filter(e=>e!==C).slice(0,4).map(e=>G(e.seat,r)),held:g,classification:t,mode:n,localOnly:i,routerWhy:m.why}}var Y=[`off`,`auto`,`cheap-first`],X=`ashlr.verse.multimodel.v1`,Ae=`auto`;function Z(){try{let e=JSON.parse(localStorage.getItem(X)??`{}`);if(typeof e!=`object`||!e||Array.isArray(e))return{};let t={};for(let[n,r]of Object.entries(e))Y.includes(r)&&(t[n]=r);return t}catch{return{}}}function je(e){let t=Z();return(e?t[e]:void 0)??t[`*`]??Ae}function Q(e,t){try{let n=Z();e&&(n[e]=t),n[`*`]=t;let r=Object.entries(n),i=Object.fromEntries(r.slice(Math.max(0,r.length-201)));localStorage.setItem(X,JSON.stringify(i))}catch{}}function Me(e){return(0,S.useSyncExternalStore)(t=>e?d(e,t):()=>void 0,()=>f(e).session,()=>f(e).session)}function Ne(e,t){return t?.find(t=>t.seatId===e.id)?.private===!0}function Pe(e,t){let n=i(c(e.engine,t));return e.models.find(t=>!t.unavailableReason&&i(c(e.engine,t.id))>n)?.id??null}function $(e,t){return e.flatMap(e=>{if(e.health.state===`unavailable`)return[];let n=l(e);if(!n)return[];let r=e.engine===`local`,i=t?.find(t=>t.seatId===e.id),a=Pe(e,n.id);return[{seatId:e.id,engine:e.engine,label:e.label,model:n.id,local:r,private:r&&Ne(e,t),supportsTools:i?.supportsTools??null,capacity:x(e,void 0,n.id),...a?{cheaper:{model:a,capacity:x(e,void 0,a)}}:{}}]})}function Fe(e,t){let[n,r]=(0,S.useState)(e);return(0,S.useEffect)(()=>{let n=setTimeout(()=>r(e),t);return()=>clearTimeout(n)},[e,t]),n}var Ie={mode:`balanced`,seats:{},updatedAt:new Date(0).toISOString()};function Le(e){let t=Me(e.sessionId),r=n(_(e.sessionId?{sessionId:e.sessionId}:{projectPath:null})).data??null,i=n(p).data??null,a=i?{mode:i.mode,seats:i.seats,updatedAt:i.updatedAt}:null,o=Fe(e.text.trim(),250),s=t?.usage?.contextTokens??0,c=(0,S.useMemo)(()=>$(e.seats,r?.local),[e.seats,r?.local]),l=(0,S.useMemo)(()=>o&&e.pref!==`off`?g(o,{contextTokens:s}):null,[o,e.pref,s]),u=(n,i=e.pinnedSeatId)=>e.pref===`off`||r===null?null:ke({classification:n,seats:c,policy:a??Ie,mode:e.pref,nowMs:Date.now(),currentSeatId:t?.seatId??null,turnCount:t?.turnCount??0,contextTokens:s,localOnly:r?.localOnly??null,learned:r?.learned??null,roi:r?.roi??null,pinnedSeatId:i});return{session:t,context:r,policy:a,classification:l,advice:l?u(l):null,advisorSeats:c,adviseWith:u}}export{Le as a,$ as i,je as n,Q as r,Y as t};
2
- //# sourceMappingURL=useAutoSeat-CXC9e4vx.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useAutoSeat-CXC9e4vx.js","names":[],"sources":["../../../../../../src/core/routing/reset-pressure.ts","../../../../../../src/core/routing/router.ts","../../../../../../src/core/verse/multimodel/advisor.ts","../../../../../../src/web-ui/routes/verse/multimodel/useAutoSeat.ts"],"sourcesContent":["/** Pure provenance-aware reset opportunity, independent of dispatch authority. */\nimport { assessSeat, classifyWindow, HEADROOM_READING_MAX_AGE_MS, type SeatCapacity } from './headroom.js';\nimport { costBasisOf } from './tiers.js';\nimport type { SeatBudgetPolicy } from './types.js';\nimport type { AccountSchedulingView, ResetProvenance, TaskWorkForecast } from './scheduling-types.js';\n\nexport const UNKNOWN_RESET: Readonly<ResetProvenance> = Object.freeze({ kind: 'unknown', at: null, description: null, source: null });\n\n/** Refuse inconsistent timestamps/semantics; a date alone never proves expiry. */\nexport function validResetProvenance(value: unknown): value is ResetProvenance {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n const v = value as ResetProvenance;\n if (!['fixed-period', 'weekly-deadline', 'rolling-release', 'balance', 'unknown'].includes(v.kind) ||\n v.description !== null && typeof v.description !== 'string' || v.source !== null && typeof v.source !== 'string') return false;\n const instant = (s: unknown): s is string => typeof s === 'string' && Number.isFinite(Date.parse(s)) && new Date(s).toISOString() === s;\n if (v.at !== null && !instant(v.at) || v.startsAt != null && !instant(v.startsAt)) return false;\n if (v.kind === 'fixed-period' && (!instant(v.at) || !instant(v.startsAt) || v.startsAt >= v.at || !v.source)) return false;\n if (v.kind === 'weekly-deadline' && (!instant(v.at) || v.startsAt != null ||\n v.source !== 'claude-native-usage-report' || !['pro', 'max'].includes(v.plan ?? ''))) return false;\n return !(v.kind === 'balance' && v.at !== null);\n}\n\n/** A qualified account deadline, not a promise of no allowance carryover. */\nexport function hasResetDeadline(reset: ResetProvenance): boolean {\n return reset.kind === 'fixed-period' || reset.kind === 'weekly-deadline';\n}\n\nexport function forecastFit(forecast: { durationMs: Pick<NonNullable<TaskWorkForecast['durationMs']>, 'p25' | 'p75'> | null } | null, resetAt: string | null, nowMs: number): TaskWorkForecast['fit'] {\n const duration = forecast?.durationMs;\n const slack = resetAt === null ? NaN : Date.parse(resetAt) - nowMs;\n if (!duration || !Number.isFinite(slack) || slack <= 0) return 'unknown';\n return duration.p75 <= slack ? 'likely-before-reset' : duration.p25 > slack ? 'unlikely-before-reset' : 'uncertain';\n}\n\nexport function assessResetOpportunity(seat: SeatCapacity, policy: SeatBudgetPolicy, nowMs: number,\n forecast: TaskWorkForecast | null = null): AccountSchedulingView {\n const assessment = assessSeat(seat, policy, { nowMs });\n const observed = seat.observedAt === null ? NaN : Date.parse(seat.observedAt);\n const fresh = seat.free || Number.isFinite(observed) && observed <= nowMs && nowMs - observed <= HEADROOM_READING_MAX_AGE_MS;\n // Every account-wide window must still be current. An expired conflicting\n // window cannot be ignored simply because another period looks attractive.\n const accountWindows = seat.windows.filter((w) => classifyWindow(seat.engine,w,nowMs) !== 'model');\n const outsidePeriod = accountWindows.some((w) => w.resetProvenance?.kind === 'fixed-period' &&\n validResetProvenance(w.resetProvenance) && (Date.parse(w.resetProvenance.startsAt!) > nowMs || Date.parse(w.resetProvenance.at!) <= nowMs));\n const expired = accountWindows.some((w) => w.resetsAt !== null && Date.parse(w.resetsAt) <= nowMs);\n // A billing date is not proof that paid credits expire. Only the actual\n // effective subscription lane qualifies for allowance-deadline preference.\n // Other lanes retain ordinary admission; verified gift expiry is a separate\n // provider/account evidence contract that this projection does not invent.\n const subscription = (seat.costBasis ?? costBasisOf(seat.engine)) === 'subscription';\n const finitePeriods = accountWindows.filter((w) => subscription && w.resetProvenance && validResetProvenance(w.resetProvenance) &&\n w.resetsAt === w.resetProvenance.at && Date.parse(w.resetProvenance.at!) > nowMs &&\n (w.resetProvenance.kind === 'fixed-period' && Date.parse(w.resetProvenance.startsAt!) <= nowMs ||\n w.resetProvenance.kind === 'weekly-deadline' && seat.engine === 'claude' && w.id === 'seven_day'));\n const earliest = finitePeriods.sort((a, b) => Date.parse(a.resetProvenance!.at!) - Date.parse(b.resetProvenance!.at!))[0];\n const unknownWindow = seat.windows.find((w) => w.resetDescription || w.resetsAt);\n const reported = accountWindows.find((w) => w.resetProvenance && !hasResetDeadline(w.resetProvenance) && validResetProvenance(w.resetProvenance));\n const reset: ResetProvenance = earliest?.resetProvenance ?? reported?.resetProvenance ?? (seat.windowless ? {\n kind: 'balance', at: null, description: 'No expiring quota window reported.', source: 'seat-cost-contract',\n } : { ...UNKNOWN_RESET, at: unknownWindow?.resetsAt ?? null, description: unknownWindow?.resetDescription ?? null });\n const admission = !fresh || expired || outsidePeriod || assessment.unknownUsage ? 'unknown'\n : assessment.headroom.eligibleForAutonomy ? 'eligible' : 'held';\n const fit = forecastFit(forecast, hasResetDeadline(reset) ? reset.at : null, nowMs);\n const qualified = forecast === null ? null : { ...forecast, fit };\n return { seatId: seat.seatId, observedAt: seat.observedAt, admission,\n headroomPercent: assessment.headroom.autonomyHeadroomPercent, reset,\n opportunity: { kind: admission === 'unknown' ? 'unknown' : admission === 'held' ? 'held'\n : hasResetDeadline(reset) && fit !== 'unlikely-before-reset' ? 'before-reset' : 'ordinary',\n reason: admission === 'unknown' ? 'A fresh, current account-window observation is required.'\n : admission === 'held' ? assessment.headroom.reasons[0] ?? 'Current policy holds this account.'\n : hasResetDeadline(reset) ? fit === 'unlikely-before-reset' ? 'Observed work duration exceeds this period; prefer shorter useful work.'\n : reset.kind === 'weekly-deadline' ? 'Qualified native subscription weekly deadline has admitted headroom; work fit remains an estimate.'\n : 'Provider-reported fixed period ends with admitted headroom; work fit remains an estimate.'\n : 'Use ordinary admitted routing; allowance expiry is not established.' }, forecast: qualified };\n}\n\n/** Only compare opportunities after the caller has enforced eligibility and tier. */\nexport function opportunityPriority(view: AccountSchedulingView, nowMs: number): number {\n if (view.admission !== 'eligible' || view.opportunity.kind !== 'before-reset') return 0;\n if (!hasResetDeadline(view.reset) || !validResetProvenance(view.reset) || !Number.isFinite(nowMs)) return 0;\n const duration = view.forecast?.durationMs?.p75;\n const remaining = view.reset.at === null ? NaN : Date.parse(view.reset.at) - nowMs;\n if (typeof duration !== 'number' || !Number.isFinite(duration) || duration <= 0 || !Number.isFinite(remaining) || remaining <= 0) return 0;\n // Continuous proximity, not a fixed urgency horizon: it increases as the\n // reported deadline approaches this work's observed upper-quartile duration.\n // Fit bands preserve likely-over-uncertain preference; no estimate means no\n // priority. Explicit time also prevents a recorded fit surviving its reset.\n const proximity = 1 / (1 + remaining / duration);\n const fit = forecastFit(view.forecast, view.reset.at, nowMs);\n return fit === 'likely-before-reset' ? 1 + proximity : fit === 'uncertain' ? proximity : 0;\n}\n","/**\n * Seat router — `routeSeat(req, capacity, policy): SeatDecision` (V3.10 unit A9).\n *\n * PURE and DETERMINISTIC: same inputs, same decision. No clock reads (pass\n * `nowMs`), no I/O, no model calls. That is what lets the fleet run it in\n * SHADOW mode (Track B) — every would-be dispatch is decided and logged next\n * to what actually ran, and the two can be compared before the router is\n * given any authority.\n *\n * STAGES\n * 1. Eligibility. Autonomous work goes through `assessSeat` (budget policy,\n * reserves, live windows, \"unknown usage is not headroom\"). Mason's own\n * interactive work ignores reserves — they exist FOR him — and is refused\n * only by what would make a turn fail: signed out, spent, unreachable.\n * 2. Fit. A request whose context estimate exceeds 80% of a seat's window\n * is not sent there; the router never truncates silently.\n * 3. Rank. An explicit TIER order per (mode, task, difficulty) — see\n * `tierPreference` and routing/tiers.ts (elite · fast · free) — then,\n * inside a tier, more headroom first, then marginal cost (a subscription\n * turn before a credits turn), then latency, then seat id. There is NO\n * provider order: Claude, Codex and Devin are the same tier and nothing\n * but their live numbers separates them (3.15, \"equal partners\"). The λ\n * routing weights (`RouterWeights`, from the harness / Leader\n * `router.tune`) tilt that order — see `seatScore`.\n *\n * Local models are never excluded for quality; the free tier is ranked after\n * the paid tiers where quality matters (high difficulty, leader work), so\n * work still flows when the paid seats are held back for Mason.\n *\n * DEVIN. Mason's own chats may be routed to a Devin seat like any other\n * elite seat. Autonomous (fleet) work never is: the fleet launches Devin\n * only through devin/fleet-launcher.ts under its grant and ACU reserve, and\n * the capacity snapshot refuses a Devin row — see `devinFleetVerdict`.\n */\nimport { opportunityPriority } from './reset-pressure.js';\nimport type { AccountSchedulingView } from './scheduling-types.js';\nimport { assessSeat, HEADROOM_READING_MAX_AGE_MS, type SeatCapacity } from './headroom.js';\nimport { effectiveSeatPolicy } from './policy.js';\nimport { listSeatIds, reasonSentences } from './seat-reasons.js';\nimport { COST_BASIS_RANK, costBasisOf, engineTier, RESOURCE_TIERS, type ResourceTier } from './tiers.js';\nimport type {\n BudgetMode,\n BudgetPolicy,\n RoutingDifficulty,\n RoutingRequest,\n SeatDecision,\n SeatExclusion,\n SeatHeadroom,\n SeatReason,\n} from './types.js';\n\n/** A request may use at most this share of a seat's context window. */\nexport const ROUTER_CONTEXT_FIT_FRACTION = 0.8;\n\nexport interface RouteOptions {\n nowMs: number;\n readingMaxAgeMs?: number;\n /** The λ objective weights; absent = `DEFAULT_ROUTER_WEIGHTS` (today's explicit order). */\n weights?: Partial<RouterWeights>;\n /**\n * Observed turn latency per seat id, in ms (e.g. a recent median). Only\n * `lambdaLatency` reads it; a seat absent here is scored neutral. Absent =\n * no latency evidence, so latency cannot move anything.\n */\n latencyMs?: Readonly<Record<string, number>>;\n /** Actual selected-task opportunity; eligibility/quality remain mandatory. */\n scheduling?: Readonly<Record<string,AccountSchedulingView>>;\n advisorySeatId?: string | null;\n}\n\n/**\n * The router's λ objective weights — the same three numbers as\n * learn/harness-types.ts `HarnessRoutingWeights` (restated structurally so\n * this browser-safe module does not import the harness). Each λ is ≥ 0.\n *\n * lambdaCost — how hard to lean on COST against the mode's\n * quality/cost tier order. 1 = the mode's own balance;\n * above 1 leans toward cheaper tiers, below 1 toward\n * pricier (higher-quality) ones. Inside a tier it also\n * scales the marginal-cost term (subscription before\n * credits).\n * lambdaPressure — how much a seat's remaining HEADROOM counts. 1 = the\n * deciding key inside one tier; higher lets a much\n * emptier seat of a less-preferred tier win; 0 ignores\n * headroom.\n * lambdaLatency — how much observed LATENCY (`RouteOptions.latencyMs`)\n * counts. At the default 0.25 it only separates seats\n * whose headroom is equal.\n */\nexport interface RouterWeights {\n lambdaCost: number;\n lambdaPressure: number;\n lambdaLatency: number;\n}\n\n/**\n * Defaults = the compiled baseline (`BASELINE_HARNESS_CONFIG.routing`; a test\n * pins the two together). At these values `rank` orders seats by tier, then\n * headroom, then marginal cost, then latency.\n */\nexport const DEFAULT_ROUTER_WEIGHTS: Readonly<RouterWeights> = Object.freeze({\n lambdaCost: 1,\n lambdaPressure: 1,\n lambdaLatency: 0.25,\n});\n\n/** How a tier is named inside a `why` sentence. */\nconst TIER_WORDS: Readonly<Record<ResourceTier, string>> = { elite: 'elite', fast: 'fast', free: 'free' };\n\n/** Best tier first — interactive work and hard autonomous work. */\nconst QUALITY_FIRST: readonly ResourceTier[] = RESOURCE_TIERS;\n/** Cheapest rung first — the cost ladder (free → fast → elite). */\nconst CHEAP_FIRST: readonly ResourceTier[] = [...RESOURCE_TIERS].reverse();\n\n/** A seat's tier: what its capacity says (per model), else its engine's. */\nexport function capacityTier(capacity: Pick<SeatCapacity, 'engine' | 'tier'>): ResourceTier {\n return capacity.tier ?? engineTier(capacity.engine);\n}\n\n/**\n * A seat's rung on the COST ladder: `free` when a turn costs nothing (every\n * local model — the elite Qwen included — and Devin's plan-included SWE),\n * otherwise its tier. Tier and cost only differ for those free-but-strong\n * seats, which is exactly why they are two axes.\n */\nexport function costRung(capacity: Pick<SeatCapacity, 'engine' | 'tier' | 'costBasis' | 'free'>): ResourceTier {\n if (capacity.free || (capacity.costBasis ?? costBasisOf(capacity.engine)) === 'free') return 'free';\n return capacityTier(capacity);\n}\n\n/** Relative cost step (0 = free). CHEAP_FIRST is exactly the cost ladder, so it doubles as the table. */\nfunction costStep(capacity: SeatCapacity): number {\n return CHEAP_FIRST.indexOf(costRung(capacity));\n}\n\n/**\n * The mode's order for one request: over TIERS (quality) or over the COST\n * ladder, never over providers — which seat of a rung wins is decided by\n * headroom, marginal cost and latency (`seatScore`).\n */\nexport interface RankOrder {\n /** `tier` ranks a seat by what it can do; `cost` by what a turn costs. */\n by: 'tier' | 'cost';\n order: readonly ResourceTier[];\n}\n\n/**\n * Low-difficulty and bulk work always goes to the cheapest capable seat\n * first (the cost ladder — so the free elite Qwen and Devin's free SWE lead);\n * quality-first ordering is reserved for work that needs it. Interactive\n * requests are ordered for \"what else can I use right now\": the elite\n * partners, then fast, then free.\n */\nexport function tierPreference(mode: BudgetMode, req: RoutingRequest): RankOrder {\n const quality: RankOrder = { by: 'tier', order: QUALITY_FIRST };\n const cheap: RankOrder = { by: 'cost', order: CHEAP_FIRST };\n if (!req.autonomous) return quality;\n const difficulty: RoutingDifficulty = req.task === 'leader' && req.difficulty !== 'high' ? 'high' : req.difficulty;\n if (req.task === 'bulk' || difficulty === 'low') return cheap;\n if (mode === 'reserve') {\n // Free first for everything but genuinely hard work, and even that only\n // reaches the small paid slice the reserve-mode ceilings leave.\n return difficulty === 'high' ? { by: 'tier', order: ['fast', 'elite', 'free'] } : cheap;\n }\n if (difficulty === 'medium') {\n return mode === 'all-in'\n ? { by: 'tier', order: ['fast', 'elite', 'free'] }\n : { by: 'cost', order: ['fast', 'free', 'elite'] };\n }\n return quality;\n}\n\ninterface Verdict {\n capacity: SeatCapacity;\n /** Position in the caller's list — discovery order, which ranks the operator's preferred local tags first. */\n index: number;\n headroom: SeatHeadroom | null;\n eligible: boolean;\n /** The blockers as data; `SeatExclusion.reasons` is derived from them. */\n details: SeatReason[];\n nextEligibleAt: string | null;\n}\n\nfunction interactiveVerdict(capacity: SeatCapacity, nowMs: number, readingMaxAgeMs: number): Verdict {\n const details: SeatReason[] = [];\n let nextEligibleAt: string | null = null;\n if (capacity.signedOut) details.push({ kind: 'signed-out', text: 'Signed out — reconnect this account.' });\n if (capacity.reachable === false && !capacity.signedOut) details.push({ kind: 'unreachable', text: 'Not reachable right now.' });\n // Reuse the autonomy assessment only for the facts it establishes about\n // the ACCOUNT (spent windows and their resets) — never its reserves.\n const facts = assessSeat(capacity, { seatId: capacity.seatId, enabled: true, reservePercent: 0 }, {\n nowMs,\n readingMaxAgeMs,\n });\n if (facts.exhausted) {\n details.push(...facts.spentDetails);\n nextEligibleAt = facts.reopensAt;\n }\n return { capacity, index: 0, headroom: facts.headroom, eligible: details.length === 0, details, nextEligibleAt };\n}\n\nfunction autonomousVerdict(capacity: SeatCapacity, policy: BudgetPolicy, nowMs: number, readingMaxAgeMs: number): Verdict {\n const seatPolicy = effectiveSeatPolicy(policy, capacity.seatId, capacity.engine);\n const assessed = assessSeat(capacity, seatPolicy, { nowMs, readingMaxAgeMs });\n return {\n capacity,\n index: 0,\n headroom: assessed.headroom,\n eligible: assessed.headroom.eligibleForAutonomy,\n // Blocked seats report the blockers; the \"N% left\" line is for eligible ones.\n details: assessed.headroom.eligibleForAutonomy ? [] : assessed.details,\n nextEligibleAt: assessed.headroom.eligibleForAutonomy ? null : assessed.reopensAt,\n };\n}\n\nfunction formatTokens(n: number): string {\n if (n >= 1_000_000) return `${(n / 1_000_000).toFixed(1)}M`;\n if (n >= 1_000) return `${Math.round(n / 1_000)}k`;\n return String(n);\n}\n\nfunction applyFit(verdict: Verdict, contextTokens: number | undefined): Verdict {\n if (contextTokens === undefined || !Number.isFinite(contextTokens) || contextTokens <= 0) return verdict;\n const window = verdict.capacity.contextWindow;\n if (window === null) return verdict;\n if (contextTokens <= window * ROUTER_CONTEXT_FIT_FRACTION) return verdict;\n return {\n ...verdict,\n eligible: false,\n details: [...verdict.details, {\n kind: 'context',\n text: `Needs about ${formatTokens(contextTokens)} tokens of context; this seat's window is `\n + `${formatTokens(window)} (at most ${Math.round(ROUTER_CONTEXT_FIT_FRACTION * 100)}% is used for a task).`,\n }],\n // A window does not grow back on a schedule.\n nextEligibleAt: null,\n };\n}\n\nfunction compareIds(a: string, b: string): number {\n return a < b ? -1 : a > b ? 1 : 0;\n}\n\n/**\n * Scale of the headroom term at λ = 1: its whole range (100% left vs unknown)\n * is worth half a tier step, so at the default weight it can only order\n * seats of the SAME tier — where it is the deciding key.\n */\nconst PRESSURE_SCALE = 0.5;\n\n/**\n * Scale of the latency term at λ = 1. Headroom percents are whole numbers\n * (headroom.ts rounds them), so one point of headroom is worth\n * PRESSURE_SCALE / 101 ≈ 0.00495 at λ = 1. At the default λ = 0.25 the whole\n * latency range (0.25 × 0.019 = 0.00475) stays below that, which keeps\n * latency a pure tie-breaker; at λ = 10 it is worth ~38 points of headroom\n * and still never a whole tier step (0.5 + 0.1 + 0.19 < 1).\n */\nconst LATENCY_SCALE = 0.019;\n\n/** The headroom a windowless seat is ranked with: the middle of the range. */\nconst WINDOWLESS_HEADROOM = 50;\n\n/** Scores closer than this are a tie (they fall through to caller order, then id). */\nconst SCORE_EPSILON = 1e-9;\n\n/**\n * The largest λ the router honours — the harness registry's own bound\n * (HARNESS_CONFIG_BOUNDS.lambdaMax; a test pins the two together, restated so\n * this browser-safe module does not import the harness). A larger value is\n * clamped here, so every score stays finite: an unbounded λ could overflow to\n * Infinity, and Infinity − Infinity = NaN would make the comparator\n * inconsistent (the sort order would then depend on the engine's algorithm).\n */\nexport const ROUTER_LAMBDA_MAX = 10;\n\nfunction resolveWeights(weights: Partial<RouterWeights> | undefined): RouterWeights {\n // A malformed λ (NaN, ±Infinity, negative, not a number) falls back to its\n // default rather than poisoning the ranking; an over-large one is clamped\n // to ROUTER_LAMBDA_MAX (it keeps its direction, bounded).\n const pick = (key: keyof RouterWeights): number => {\n const v = weights?.[key];\n return typeof v === 'number' && Number.isFinite(v) && v >= 0 ? Math.min(v, ROUTER_LAMBDA_MAX) : DEFAULT_ROUTER_WEIGHTS[key];\n };\n return { lambdaCost: pick('lambdaCost'), lambdaPressure: pick('lambdaPressure'), lambdaLatency: pick('lambdaLatency') };\n}\n\nfunction isDefaultWeights(w: RouterWeights): boolean {\n return w.lambdaCost === DEFAULT_ROUTER_WEIGHTS.lambdaCost\n && w.lambdaPressure === DEFAULT_ROUTER_WEIGHTS.lambdaPressure\n && w.lambdaLatency === DEFAULT_ROUTER_WEIGHTS.lambdaLatency;\n}\n\n/**\n * Latency per seat normalised to [0, 1] across the seats with evidence\n * (fastest 0, slowest 1). A seat without evidence gets 0.5: unknown latency\n * is neither rewarded nor punished. No evidence anywhere = all 0.\n */\nfunction latencyTerms(verdicts: readonly Verdict[], latencyMs: RouteOptions['latencyMs']): Map<string, number> {\n const out = new Map<string, number>();\n const known = verdicts.flatMap((v) => {\n const ms = latencyMs?.[v.capacity.seatId];\n return typeof ms === 'number' && Number.isFinite(ms) && ms >= 0 ? [ms] : [];\n });\n if (known.length === 0) return out;\n const min = Math.min(...known);\n const span = Math.max(...known) - min;\n for (const v of verdicts) {\n const ms = latencyMs?.[v.capacity.seatId];\n const has = typeof ms === 'number' && Number.isFinite(ms) && ms >= 0;\n out.set(v.capacity.seatId, !has ? 0.5 : span === 0 ? 0 : (ms - min) / span);\n }\n return out;\n}\n\n/**\n * The λ objective for one seat — LOWER is better:\n *\n * position quality: the mode's TIER order (fixed anchor)\n * + (λcost − 1) · costStep cost: one tier step per cost step per unit of λ\n * + λpressure · PRESSURE_SCALE · p headroom: p = (100 − left%) / 101, unknown = 1\n * + λcost · MARGINAL_COST_SCALE · m marginal: m = 1 for credits / per-token, else 0\n * + λlatency · LATENCY_SCALE · l latency: l from `latencyTerms`\n *\n * Why `λcost − 1`: the tier order ALREADY prices cost in for the mode\n * (CHEAP_FIRST is literally the cost ladder), so λcost = 1 must add nothing\n * across tiers. At λcost = 2 a quality-first order flattens (every tier ties\n * and headroom decides); at 0 a cheap-first order does. No term names a\n * provider.\n */\nfunction seatScore(v: Verdict, position: number, w: RouterWeights, latency: number): number {\n // A windowless seat (Devin: ACUs / plan usage, no window) has no reading\n // BY DESIGN — neutral, not the worst. Only interactive work reaches here\n // with one (autonomous Devin is refused before ranking).\n const left = v.headroom?.autonomyHeadroomPercent ?? (v.capacity.windowless ? WINDOWLESS_HEADROOM : -1);\n const pressure = (100 - left) / 101;\n return position\n + (w.lambdaCost - 1) * costStep(v.capacity)\n + w.lambdaPressure * PRESSURE_SCALE * pressure\n + w.lambdaCost * MARGINAL_COST_SCALE * marginalCost(v.capacity)\n + w.lambdaLatency * LATENCY_SCALE * latency;\n}\n\n/**\n * Marginal cost of one more turn inside a tier: 0 for a subscription (its\n * window refills) or a free seat, 1 for a seat that spends a balance\n * (credits, ACUs, per-token). Worth a tenth of the headroom range at λ = 1 —\n * about 20 points of headroom — so a metered seat wins only when it has\n * clearly more room than a subscription seat of the same tier.\n */\nconst MARGINAL_COST_SCALE = 0.1;\n\nfunction marginalCost(capacity: SeatCapacity): number {\n const basis = capacity.costBasis ?? costBasisOf(capacity.engine);\n return COST_BASIS_RANK[basis];\n}\n\n/**\n * Rank eligible verdicts by `seatScore`, then the caller's order (seat\n * discovery lists the operator's preferred local tags first —\n * `preferredLocalTags` in seats.ts — so two free local seats with equal\n * headroom resolve to the one he chose), then id. At the default weights this\n * is a lexicographic order — tier, then headroom / marginal cost / latency —\n * because those terms together stay under one tier step.\n */\nfunction rank(verdicts: Verdict[], rankOrder: RankOrder, w: RouterWeights, latencyMs: RouteOptions['latencyMs'], options?: RouteOptions): Verdict[] {\n const position = (capacity: SeatCapacity): number => {\n const rung = rankOrder.by === 'cost' ? costRung(capacity) : capacityTier(capacity);\n const index = rankOrder.order.indexOf(rung);\n return index === -1 ? rankOrder.order.length : index;\n };\n const latency = latencyTerms(verdicts, latencyMs);\n const score = new Map(verdicts.map((v) => [\n v, seatScore(v, position(v.capacity), w, latency.get(v.capacity.seatId) ?? 0),\n ]));\n const ranked = [...verdicts].sort((a, b) => {\n const diff = score.get(a)! - score.get(b)!;\n if (Math.abs(diff) > SCORE_EPSILON) return diff;\n if (a.index !== b.index) return a.index - b.index;\n return compareIds(a.capacity.seatId, b.capacity.seatId);\n });\n if (!options?.scheduling) return ranked;\n // Preserve the weighted placement of different tiers. Permute only the\n // already occupied slots of each tier, rather than mixing two comparators\n // (which can form cycles when non-default weights interleave tiers).\n const baselineIndex = new Map(ranked.map((v,i)=>[v,i]));\n const groups = new Map<number, number[]>();\n ranked.forEach((v,i) => { const key = position(v.capacity); const indexes = groups.get(key) ?? []; indexes.push(i); groups.set(key,indexes); });\n for (const indexes of groups.values()) {\n const ordered = indexes.map((i) => ranked[i]!).sort((a,b) => {\n const av = options.scheduling![a.capacity.seatId]; const bv = options.scheduling![b.capacity.seatId];\n const ap = av ? opportunityPriority(av, options.nowMs) : 0; const bp = bv ? opportunityPriority(bv, options.nowMs) : 0;\n if (ap !== bp) return bp-ap;\n if (options.advisorySeatId) {\n const advice = Number(b.capacity.seatId === options.advisorySeatId)-Number(a.capacity.seatId === options.advisorySeatId);\n if (advice) return advice;\n }\n if (ap > 0 && av?.reset.at && bv?.reset.at) {\n const earlier = Date.parse(av.reset.at)-Date.parse(bv.reset.at);\n if (earlier) return earlier;\n }\n return baselineIndex.get(a)!-baselineIndex.get(b)!;\n });\n indexes.forEach((index,i) => { ranked[index] = ordered[i]!; });\n }\n return ranked;\n}\n\nfunction formatWeight(n: number): string {\n return String(Math.round(n * 100) / 100);\n}\n\nfunction lowerFirst(text: string): string {\n return text.length > 0 ? text.charAt(0).toLowerCase() + text.slice(1) : text;\n}\n\nfunction describeWork(req: RoutingRequest): string {\n return `${req.difficulty}-difficulty ${req.task} work`;\n}\n\n/**\n * \"codex-cmp: autonomy is switched off for this seat\" — the FIRST reason, as\n * text without its reset clause, so a list of these never nests parentheses.\n */\nexport function describeExclusion(exclusion: SeatExclusion): string {\n const first = exclusion.details?.[0]?.text ?? exclusion.reasons[0] ?? 'not eligible';\n return `${exclusion.seatId}: ${lowerFirst(first).replace(/\\.$/, '')}`;\n}\n\n/** Up to `max` exclusions described, then \"and N more\" — never a bare \"…\". */\nexport function describeExclusions(exclusions: readonly SeatExclusion[], max = 3): string {\n const shown = exclusions.slice(0, max).map(describeExclusion).join('; ');\n return exclusions.length > max ? `${shown}; and ${exclusions.length - max} more` : shown;\n}\n\n/**\n * 3.15: a Devin seat is never a candidate for AUTONOMOUS work. The fleet\n * launches Devin only through devin/fleet-launcher.ts under its grant and its\n * own ACU reserve; the capacity snapshot refuses a `devin` seat\n * (budget-store.ts sanitizeSeatCapacity), and this is the second lock, so a\n * hand-built capacity list cannot route fleet work to it either. Mason's own\n * (interactive) work routes to Devin like any other elite seat.\n */\nfunction devinFleetVerdict(capacity: SeatCapacity): Verdict {\n const details: SeatReason[] = [{\n kind: 'lane',\n text: 'The fleet runs Devin as its own session lane under the Devin budget, not through the seat router.',\n }];\n return { capacity, index: 0, headroom: null, eligible: false, details, nextEligibleAt: null };\n}\n\n/**\n * Decide which seat `req` should use. Pure. Every seat in `capacity` ends up\n * in exactly one of `candidates` or `exclusions`.\n */\nexport function routeSeat(\n req: RoutingRequest,\n capacity: readonly SeatCapacity[],\n policy: BudgetPolicy,\n opts: RouteOptions,\n): SeatDecision {\n const readingMaxAgeMs = opts.readingMaxAgeMs ?? HEADROOM_READING_MAX_AGE_MS;\n const verdicts = capacity.map((seat, index) => ({\n ...(req.autonomous && seat.engine === 'devin'\n ? devinFleetVerdict(seat)\n : applyFit(\n req.autonomous\n ? autonomousVerdict(seat, policy, opts.nowMs, readingMaxAgeMs)\n : interactiveVerdict(seat, opts.nowMs, readingMaxAgeMs),\n req.contextTokens,\n )),\n index,\n }));\n\n if (req.autonomous && opts.scheduling) {\n for (const v of verdicts) {\n const advisory = opts.scheduling[v.capacity.seatId];\n if (v.eligible && advisory?.admission === 'unknown') {\n v.eligible = false;\n v.details.push({kind:'unknown-usage',text:'Current account-window evidence is incomplete or has passed its reported period.'});\n }\n }\n }\n const order = tierPreference(policy.mode, req);\n const weights = resolveWeights(opts.weights);\n const eligible = rank(verdicts.filter((v) => v.eligible), order, weights, opts.latencyMs, opts);\n const exclusions: SeatExclusion[] = verdicts\n .filter((v) => !v.eligible)\n .map((v) => ({\n seatId: v.capacity.seatId,\n reasons: reasonSentences(v.details),\n nextEligibleAt: v.nextEligibleAt,\n details: v.details,\n }))\n .sort((a, b) => compareIds(a.seatId, b.seatId));\n\n const chosen = eligible[0] ?? null;\n const candidates = eligible.map((v) => v.capacity.seatId);\n const who = req.autonomous ? 'autonomous ' : '';\n\n // `why` is the full sentence the logs and the CLI print; `summary` is the\n // short headline a UI shows above its own per-seat list. Neither repeats\n // the per-seat reasons — `exclusions` carries those as data.\n let why: string;\n let summary: string;\n if (chosen) {\n const tier = TIER_WORDS[order.by === 'cost' ? costRung(chosen.capacity) : capacityTier(chosen.capacity)];\n const room = chosen.headroom?.autonomyHeadroomPercent;\n const windowWord = chosen.headroom?.bindingWindow === 'session' ? '5-hour' : 'weekly';\n const hasRoom = req.autonomous && !chosen.capacity.free && typeof room === 'number';\n const roomText = hasRoom\n ? ` with ${room}% of its ${windowWord} window left for autonomy`\n : chosen.capacity.free ? ' at no cost' : '';\n const held = exclusions.length === 0 ? ''\n : `; held back ${exclusions.length === 1 ? '1 seat' : `${exclusions.length} seats`} (${listSeatIds(exclusions.map((e) => e.seatId))})`;\n // Tuned weights can put a seat ahead of the mode's own order, so the\n // sentence names them; at the defaults it stays byte-identical.\n const tuned = isDefaultWeights(weights) ? ''\n : `; routing weights cost ×${formatWeight(weights.lambdaCost)}, headroom ×${formatWeight(weights.lambdaPressure)}, `\n + `latency ×${formatWeight(weights.lambdaLatency)}`;\n why = `Routed ${who}${describeWork(req)} to ${chosen.capacity.label} (${chosen.capacity.seatId})${roomText}: `\n + `${policy.mode} mode prefers the ${tier} tier first for this work${tuned}${held}.`;\n const lead = hasRoom\n ? ` — ${room}% of its ${windowWord} window left`\n : chosen.capacity.free ? ' — free, no usage window' : '';\n summary = lead\n ? `${chosen.capacity.label}${lead}; ${policy.mode} mode prefers the ${tier} tier for this work.`\n : `${chosen.capacity.label} — ${policy.mode} mode prefers the ${tier} tier for this work.`;\n } else if (capacity.length === 0) {\n why = `No seats are known, so ${who}${describeWork(req)} has nowhere to run.`;\n summary = 'No seats are known, so this work has nowhere to run.';\n } else {\n const reopen = exclusions.flatMap((e) => (e.nextEligibleAt ? [e.nextEligibleAt] : []))\n .sort((a, b) => Date.parse(a) - Date.parse(b))[0] ?? null;\n why = `No seat can take ${who}${describeWork(req)} in ${policy.mode} mode (${describeExclusions(exclusions)})`\n + `${reopen ? `; the earliest known reopening is ${reopen}` : ''}.`;\n summary = `No seat can take this ${describeWork(req)} in ${policy.mode} mode right now.`;\n }\n\n return {\n seatId: chosen?.capacity.seatId ?? null,\n candidates,\n exclusions,\n why,\n summary,\n mode: policy.mode,\n };\n}\n\n/**\n * Ranked seats Mason could use INSTEAD of `blockedSeatId` for his own work\n * right now (reserves do not apply to him). For the readiness gate's\n * `SeatReadiness.alternatives`.\n */\nexport function rankAlternatives(\n blockedSeatId: string,\n capacity: readonly SeatCapacity[],\n policy: BudgetPolicy,\n opts: RouteOptions,\n): string[] {\n const blocked = capacity.find((c) => c.seatId === blockedSeatId);\n const decision = routeSeat(\n { task: 'code', difficulty: 'medium', autonomous: false },\n capacity.filter((c) => c.seatId !== blockedSeatId),\n policy,\n opts,\n );\n if (!blocked) return decision.candidates;\n // Same engine first (a second account of the same provider is the least\n // surprising substitute), then the router's own order.\n const sameEngine = new Set(capacity.filter((c) => c.engine === blocked.engine).map((c) => c.seatId));\n return [\n ...decision.candidates.filter((id) => sameEngine.has(id)),\n ...decision.candidates.filter((id) => !sameEngine.has(id)),\n ];\n}\n","/**\n * The Auto seat — which seat should THIS message go to, and why, in one line.\n *\n * NOT A NEW ROUTER. It asks the seat router (routing/router.ts `routeSeat`)\n * the question the router already answers for Mason's own work\n * (`autonomous: false`: fleet reserves do not bind him, only a signed-out,\n * spent or unreachable seat is refused, and a request that would not fit a\n * seat's window is never sent there). What it adds is the INPUT the router\n * needs and the explanation a person reads:\n *\n * 1. Task + difficulty from classify.ts (or the decision layer, once per send).\n * 2. The router's own λ weights, set per message: a quick question leans on\n * cost (λcost 3 → local and Grok first), hard work keeps the quality order\n * (λcost 1). Cheap-first mode leans harder (λcost 4) and only hard work\n * keeps quality. Latency comes from fleet ROI (M322 avgLatencyMs).\n * 3. Bounded re-ranking of the router's eligible list by:\n * - stickiness: mid-conversation, the current seat gets a head start —\n * moving re-sends the context and loses the provider’s prompt cache (a weak head start for hard work and in cheap-first);\n * - what Mason taught it (learning.ts; at most ±1.5 positions);\n * - fleet ship rate per engine for code work (M335; at most ±0.75);\n * - a local model that cannot use tools is last for edit work.\n * None of these can make an ineligible seat eligible.\n * 4. Privacy: a local-only repo is routed over LOCAL seats only — the\n * filter runs before the router sees anything.\n * 5. Model fit inside a seat (3.15): a seat that also offers a cheaper-tier\n * model (Devin's free SWE on the Devin CLI) competes with THAT model for\n * cheap work, and with its default for everything else.\n *\n * EQUAL PARTNERS (3.15). Claude, Codex and Devin are one tier (routing/\n * tiers.ts); nothing here or in the router prefers one provider. Devin seats\n * are routable like any other. The one locality rule: for HARD work Mason is\n * waiting on, a local model (even the elite Qwen) lines up behind the hosted\n * elite seats — it is slower — but still ahead of everything else.\n *\n * PURE and deterministic (callers pass `nowMs`). BROWSER-SAFE: the composer\n * runs it per pause in typing over the seat list it already polls.\n */\nimport { assessSeat, type SeatCapacity } from '../../routing/headroom.js';\nimport type { BudgetEngine } from '../../routing/policy.js';\nimport { COST_BASIS_LABELS, type CostBasis } from '../../routing/tiers.js';\nimport { capacityTier, DEFAULT_ROUTER_WEIGHTS, routeSeat, type RouterWeights } from '../../routing/router.js';\nimport type { BudgetPolicy, SeatDecision } from '../../routing/types.js';\nimport { learnedTilt } from './learning.js';\nimport type {\n AutoMode,\n EngineRoi,\n LearnedTable,\n PromptClassification,\n PromptKind,\n SeatAdvice,\n SeatAdviceOption,\n} from './types.js';\n\n/**\n * Engines the Auto seat may pick — every chat engine (3.15: Devin is a chat\n * seat and an equal partner, so it is routable like Claude and Codex).\n */\nexport const ROUTABLE_ENGINES: readonly BudgetEngine[] = ['claude', 'codex', 'devin', 'grok', 'local'];\n\n/**\n * Mid-conversation head start for the current seat, in ranking positions.\n * Moving re-sends the context as a note and drops the provider's prompt\n * cache, so ordinary work stays put (STICKINESS covers the whole engine\n * ladder at the low-difficulty cost weight). It is small where moving is\n * the point: hard work on a weaker seat, and cheap-first, whose purpose is to\n * come back down to the free seat once the hard turn is done.\n */\nexport const STICKINESS = 3.5;\nexport const STICKINESS_WEAK = 1.25;\n/** Bound on the fleet-ROI tilt, in ranking positions. */\nexport const ROI_MAX_TILT = 0.75;\n/** Fleet evidence below this many dispatches per engine is ignored. */\nexport const ROI_MIN_DISPATCHES = 10;\n/** Where a tool-less local model lands for edit work: behind everything. */\nconst NO_TOOLS_PENALTY = 3;\n/**\n * Hard work Mason is waiting on: an elite local model (slower on this Mac)\n * lines up just behind the LAST hosted elite seat — this far past it, in\n * ranking positions. Latency, not quality: it still beats every fast / free\n * seat, and a hosted elite seat that is held back leaves it first.\n */\nexport const LOCAL_HARD_OFFSET = 0.5;\n\nconst EDIT_KINDS: ReadonlySet<PromptKind> = new Set(['code', 'debug', 'refactor', 'bulk']);\nconst ROI_KINDS: ReadonlySet<PromptKind> = new Set(['code', 'debug', 'refactor', 'bulk', 'review']);\n\nexport interface AdvisorSeat {\n seatId: string;\n engine: string;\n label: string;\n /** The model a new chat on this seat would use (first runnable); null = none runnable. */\n model: string | null;\n /** Runs on this Mac (a local runtime seat). */\n local: boolean;\n /** Local AND its endpoint is loopback — nothing leaves the machine. */\n private: boolean;\n /** Can drive an agentic session; null = the runtime did not say (not \"no\"). */\n supportsTools: boolean | null;\n capacity: SeatCapacity;\n /**\n * 3.15: a runnable model of this seat in a CHEAPER tier than its default\n * (Devin CLI's free SWE), with the capacity it would route as. Used for\n * cheap work only; absent = the seat has one tier.\n */\n cheaper?: { model: string; capacity: SeatCapacity } | null;\n}\n\nexport interface AdviseInput {\n classification: PromptClassification;\n seats: readonly AdvisorSeat[];\n policy: BudgetPolicy;\n mode: AutoMode;\n nowMs: number;\n /** The chat's seat, when there is a chat. */\n currentSeatId?: string | null;\n /** Turns the chat already has; stickiness applies only mid-conversation. */\n turnCount?: number;\n /** What the chat already holds — the router refuses seats it would not fit. */\n contextTokens?: number | null;\n localOnly?: { on: boolean; reason: string | null } | null;\n learned?: LearnedTable | null;\n roi?: Readonly<Record<string, EngineRoi>> | null;\n /** The operator's override: honoured whenever that seat is eligible. */\n pinnedSeatId?: string | null;\n}\n\n/**\n * The λ weights for one message. Only `lambdaCost` moves; pressure and\n * latency keep the router's defaults so headroom stays a tie-breaker inside\n * an engine and latency a tie-breaker inside that.\n */\nexport function weightsFor(classification: PromptClassification, mode: AutoMode): RouterWeights {\n const hard = classification.difficulty === 'high' || (classification.needsFrontier ?? 0) >= 0.7;\n let lambdaCost: number;\n if (mode === 'cheap-first') lambdaCost = hard ? 1 : 4;\n else lambdaCost = hard ? 1 : classification.difficulty === 'low' ? 3 : 1.5;\n return { ...DEFAULT_ROUTER_WEIGHTS, lambdaCost };\n}\n\nfunction roiTilt(roi: AdviseInput['roi'], engine: string, kind: PromptKind): number {\n if (!roi || !ROI_KINDS.has(kind)) return 0;\n const rows = Object.values(roi).filter((r) => r.dispatches >= ROI_MIN_DISPATCHES && r.shipRate !== null);\n const mine = roi[engine];\n if (!mine || mine.dispatches < ROI_MIN_DISPATCHES || mine.shipRate === null || rows.length < 2) return 0;\n const mean = rows.reduce((sum, r) => sum + (r.shipRate ?? 0), 0) / rows.length;\n return -Math.max(-ROI_MAX_TILT, Math.min(ROI_MAX_TILT, (mine.shipRate - mean) * 2));\n}\n\nfunction latencyFromRoi(seats: readonly AdvisorSeat[], roi: AdviseInput['roi']): Record<string, number> | undefined {\n if (!roi) return undefined;\n const out: Record<string, number> = {};\n for (const seat of seats) {\n const ms = roi[seat.engine]?.avgLatencyMs;\n if (typeof ms === 'number' && Number.isFinite(ms) && ms > 0) out[seat.seatId] = ms;\n }\n return Object.keys(out).length > 0 ? out : undefined;\n}\n\nfunction windowWord(binding: 'session' | 'weekly' | null): string {\n return binding === 'session' ? '5-hour' : 'weekly';\n}\n\n/** How a windowless seat is described: it has no window to be \"N% left\" of. */\nfunction windowlessNote(basis: CostBasis | undefined): string {\n if (basis === 'free') return 'free on your plan';\n if (basis === 'credits') return 'spends credits (ACUs)';\n return `${COST_BASIS_LABELS[basis ?? 'subscription']} · no usage window reported`;\n}\n\n/** \"free · private on this Mac\" / \"62% of its 5-hour window left\" / \"no usage reading\". */\nexport function seatNote(seat: AdvisorSeat, nowMs: number): string {\n if (seat.local) return seat.private ? 'free · private on this Mac' : 'free · local runtime';\n if (seat.capacity.windowless) return windowlessNote(seat.capacity.costBasis);\n const assessed = assessSeat(seat.capacity, { seatId: seat.seatId, enabled: true, reservePercent: 0 }, { nowMs });\n const left = assessed.headroom.autonomyHeadroomPercent;\n if (assessed.exhausted) return 'usage spent';\n if (typeof left !== 'number') return 'no usage reading';\n return `${Math.max(0, left)}% of its ${windowWord(assessed.headroom.bindingWindow)} window left`;\n}\n\nfunction option(seat: AdvisorSeat, nowMs: number): SeatAdviceOption {\n return {\n seatId: seat.seatId, label: seat.label, engine: seat.engine, model: seat.model, local: seat.local, note: seatNote(seat, nowMs),\n tier: capacityTier(seat.capacity),\n };\n}\n\ninterface Ranked {\n seat: AdvisorSeat;\n base: number;\n learned: ReturnType<typeof learnedTilt>;\n roi: number;\n sticky: number;\n tools: number;\n local: number;\n}\n\nfunction total(r: Ranked, withLearned = true, withSticky = true): number {\n return r.base + (withLearned ? r.learned.tilt : 0) + r.roi + (withSticky ? r.sticky : 0) + r.tools + r.local;\n}\n\n/**\n * The seat as it competes for THIS message: its cheaper-tier model for cheap\n * work (when it has one), else itself.\n */\nfunction forMessage(seat: AdvisorSeat, cheap: boolean): AdvisorSeat {\n if (!cheap || !seat.cheaper) return seat;\n return { ...seat, model: seat.cheaper.model, capacity: seat.cheaper.capacity };\n}\n\n\nfunction order(rows: Ranked[], withLearned = true, withSticky = true): Ranked[] {\n // Stable: equal totals keep the router's order.\n return rows.map((r, i) => ({ r, i })).sort((a, b) => (total(a.r, withLearned, withSticky) - total(b.r, withLearned, withSticky)) || a.i - b.i).map((x) => x.r);\n}\n\nfunction clip(text: string, max = 160): string {\n return text.length <= max ? text : `${text.slice(0, max - 1).trimEnd()}…`;\n}\n\n/** Which seat this message should go to. Never throws; `choice: null` says why nothing can. */\nexport function adviseSeat(input: AdviseInput): SeatAdvice {\n const { classification: cls, mode, nowMs } = input;\n const localOnly = { on: input.localOnly?.on === true, reason: input.localOnly?.reason ?? null };\n const hard = cls.difficulty === 'high' || (cls.needsFrontier ?? 0) >= 0.7;\n // Cheap work may use a seat's cheaper-tier model (Devin SWE); hard work never does.\n const cheap = !hard && (mode === 'cheap-first' || cls.difficulty === 'low' || cls.task === 'bulk');\n const known = input.seats\n .filter((s) => (ROUTABLE_ENGINES as readonly string[]).includes(s.engine) && s.model !== null)\n .map((s) => forMessage(s, cheap));\n const pool = localOnly.on ? known.filter((s) => s.local && s.private) : known;\n const byId = new Map(pool.map((s) => [s.seatId, s]));\n const factors: string[] = [];\n if (localOnly.on) factors.push(`This repo is local-only${localOnly.reason ? ` — ${localOnly.reason.replace(/\\.$/, '')}` : ''}.`);\n factors.push(`Read as ${cls.label}${cls.decidedBy === 'jev' ? ` (labelled by Jev, ${Math.round((cls.confidence ?? 0) * 100)}% sure)` : ''}${cls.signals.length > 0 ? `: ${cls.signals.slice(0, 3).join(', ')}` : ''}.`);\n\n const weights = weightsFor(cls, mode);\n const context = Math.max(0, input.contextTokens ?? 0) + cls.estTokens;\n const latencyMs = latencyFromRoi(pool, input.roi);\n const decision: SeatDecision = routeSeat(\n { task: cls.task, difficulty: (cls.needsFrontier ?? 0) >= 0.7 && cls.difficulty !== 'high' ? 'high' : cls.difficulty, contextTokens: context, autonomous: false },\n pool.map((s) => s.capacity),\n input.policy,\n { nowMs, weights, ...(latencyMs ? { latencyMs } : {}) },\n );\n\n const held = decision.exclusions.map((e) => ({\n seatId: e.seatId,\n label: byId.get(e.seatId)?.label ?? e.seatId,\n reason: (e.details?.[0]?.text ?? e.reasons[0] ?? 'Not available right now.').replace(/\\s+$/, ''),\n }));\n\n const midChat = (input.turnCount ?? 0) > 0 && typeof input.currentSeatId === 'string';\n const stickiness = mode === 'cheap-first' || hard ? STICKINESS_WEAK : STICKINESS;\n const rows: Ranked[] = decision.candidates.flatMap((id, index) => {\n const seat = byId.get(id);\n if (!seat) return [];\n return [{\n seat,\n base: index,\n learned: learnedTilt(input.learned, cls.kind, seat),\n roi: roiTilt(input.roi, seat.engine, cls.kind),\n sticky: midChat && id === input.currentSeatId ? -stickiness : 0,\n tools: seat.local && seat.supportsTools === false && EDIT_KINDS.has(cls.kind) ? NO_TOOLS_PENALTY : 0,\n local: 0,\n }];\n });\n if (hard && !localOnly.on) {\n // Only an ELITE local seat competes with hosted elite ones; a free-tier\n // local seat is already behind them.\n const isElite = (r: Ranked) => capacityTier(r.seat.capacity) === 'elite';\n const lastHosted = rows.reduce((max, r) => (!r.seat.local && isElite(r) ? Math.max(max, r.base) : max), -1);\n for (const r of rows) {\n if (r.seat.local && isElite(r) && lastHosted > r.base) r.local = lastHosted - r.base + LOCAL_HARD_OFFSET;\n }\n }\n\n const empty = (why: string): SeatAdvice => ({\n choice: null, stay: false, why, factors, alternatives: [], held, classification: cls, mode, localOnly, routerWhy: decision.why,\n });\n if (rows.length === 0) {\n if (localOnly.on && pool.length === 0) {\n return empty('This repo is local-only and no local model is running — start Ollama or LM Studio, or pick a seat yourself.');\n }\n return empty(clip(decision.summary ?? decision.why));\n }\n\n const ranked = order(rows);\n const pinned = input.pinnedSeatId ? ranked.find((r) => r.seat.seatId === input.pinnedSeatId) ?? null : null;\n const winner = pinned ?? ranked[0]!;\n const seat = winner.seat;\n const stay = typeof input.currentSeatId === 'string' && seat.seatId === input.currentSeatId;\n\n // The ONE reason that decided it — the most specific that actually moved the result.\n const withoutLearned = order(rows, false)[0]!.seat.seatId;\n const withoutSticky = order(rows, true, false)[0]!.seat.seatId;\n const toollessId = order(rows.map((r) => ({ ...r, tools: 0 })))[0]!.seat.seatId;\n const toolless = rows.find((r) => r.seat.seatId === toollessId)!;\n const hostedFirstId = order(rows.map((r) => ({ ...r, local: 0 })))[0]!.seat.seatId;\n const hostedFirst = rows.find((r) => r.seat.seatId === hostedFirstId)!;\n let reason: string;\n if (pinned) {\n reason = 'you pinned this seat';\n } else if (localOnly.on) {\n reason = `${cls.label} on a local-only repo — stays on this Mac`;\n } else if (stay && midChat && withoutSticky !== seat.seatId) {\n reason = `${cls.label}, mid-conversation — moving would re-send the whole context`;\n } else if (winner.learned.phrase && withoutLearned !== seat.seatId) {\n reason = `${cls.label}; ${winner.learned.phrase}`;\n } else if (toolless.seat.seatId !== seat.seatId && toolless.tools > 0) {\n reason = `${cls.label} edits files, and ${toolless.seat.label} cannot use tools`;\n } else if (hostedFirst.seat.seatId !== seat.seatId && hostedFirst.local > 0) {\n reason = `${cls.label} needs the strongest model now — a hosted seat answers faster than ${hostedFirst.seat.label}`;\n } else if (seat.local) {\n reason = mode === 'cheap-first' ? `${cls.label} — local drafts first, escalates only if the draft is weak` : `${cls.label} — free and private on this Mac`;\n } else if (hard) {\n reason = `${cls.label} needs the strongest model`;\n } else {\n reason = cls.label;\n }\n const note = seat.local ? '' : `; ${seatNote(seat, nowMs)}`;\n const why = clip(`${stay ? `Staying on ${seat.label}` : seat.label} — ${reason}${note}.`);\n\n factors.push(`Router (${decision.mode} mode, interactive — fleet reserves do not apply to you): ${decision.summary ?? decision.why}`);\n if (weights.lambdaCost !== DEFAULT_ROUTER_WEIGHTS.lambdaCost) {\n factors.push(`Cost weight ×${weights.lambdaCost} for ${cls.difficulty}-difficulty work${mode === 'cheap-first' ? ' in cheap-first mode' : ''}.`);\n }\n if (winner.learned.phrase) factors.push(`Learned: ${winner.learned.phrase}.`);\n if (winner.roi !== 0) factors.push(`Fleet record: ${seat.engine} ships ${winner.roi < 0 ? 'above' : 'below'} the average for code work.`);\n if (held.length > 0) factors.push(`Held back: ${held.map((h) => `${h.label} (${h.reason.replace(/\\.$/, '').toLowerCase()})`).join('; ')}.`);\n\n return {\n choice: option(seat, nowMs),\n stay,\n why,\n factors,\n alternatives: ranked.filter((r) => r !== winner).slice(0, 4).map((r) => option(r.seat, nowMs)),\n held,\n classification: cls,\n mode,\n localOnly,\n routerWhy: decision.why,\n };\n}\n","/**\n * routes/verse/multimodel/useAutoSeat.ts — the Auto seat for one chat's\n * composer: classify the draft (rules, after a pause in typing), ask the pure\n * advisor over the seat list the app already polls, and say which seat and\n * why. Nothing here sends anything or leaves the page with the draft.\n *\n * Also the per-chat Auto preference (Off / Auto / Cheap-first), kept in\n * localStorage beside the drafts: a view preference, never a server setting.\n */\nimport { useEffect, useMemo, useState, useSyncExternalStore } from 'react';\nimport type { VerseSeat, VerseSession } from '../../../data/api-types.js';\nimport { capacityFromSeat } from '../../../../core/routing/headroom.js';\nimport { seatTier, tierRank } from '../../../../core/routing/tiers.js';\nimport type { BudgetPolicy } from '../../../../core/routing/types.js';\nimport { adviseSeat, type AdvisorSeat } from '../../../../core/verse/multimodel/advisor.js';\nimport { classifyPrompt } from '../../../../core/verse/multimodel/classify.js';\nimport type { AutoMode, LocalModelBadge, MultimodelContext, PromptClassification, SeatAdvice } from '../../../../core/verse/multimodel/types.js';\nimport { useQuery } from '../../../data/hooks.js';\nimport { budgetQuery } from '../budget/budget-queries.js';\nimport { getVerseSessionHead, subscribeVerseSession } from '../verse-store.js';\nimport { firstRunnableModel } from '../verse-model.js';\nimport { multimodelContextQuery } from './multimodel-queries.js';\n\nexport type AutoPref = 'off' | AutoMode;\nexport const AUTO_PREFS: readonly AutoPref[] = ['off', 'auto', 'cheap-first'];\nconst PREF_KEY = 'ashlr.verse.multimodel.v1';\nconst DEFAULT_PREF: AutoPref = 'auto';\n/** Classify after this long without a keystroke. */\nexport const CLASSIFY_DEBOUNCE_MS = 250;\n\nfunction readPrefs(): Record<string, AutoPref> {\n try {\n const parsed = JSON.parse(localStorage.getItem(PREF_KEY) ?? '{}') as unknown;\n if (parsed === null || typeof parsed !== 'object' || Array.isArray(parsed)) return {};\n const out: Record<string, AutoPref> = {};\n for (const [k, v] of Object.entries(parsed as Record<string, unknown>)) if ((AUTO_PREFS as readonly unknown[]).includes(v)) out[k] = v as AutoPref;\n return out;\n } catch {\n return {};\n }\n}\n\n/** A chat's own choice, else the last one made anywhere (`*`), else Auto. */\nexport function loadAutoPref(sessionId: string | null): AutoPref {\n const prefs = readPrefs();\n return (sessionId ? prefs[sessionId] : undefined) ?? prefs['*'] ?? DEFAULT_PREF;\n}\n\nexport function saveAutoPref(sessionId: string | null, pref: AutoPref): void {\n try {\n const prefs = readPrefs();\n if (sessionId) prefs[sessionId] = pref;\n prefs['*'] = pref;\n // Bounded: the newest 200 chats keep their own choice.\n const entries = Object.entries(prefs);\n const kept = Object.fromEntries(entries.slice(Math.max(0, entries.length - 201)));\n localStorage.setItem(PREF_KEY, JSON.stringify(kept));\n } catch { /* private mode: the choice lasts for this page */ }\n}\n\n/** The chat record from the store, without opening a stream (the host already did). */\nexport function useSessionRecord(sessionId: string | null): VerseSession | null {\n return useSyncExternalStore(\n (listener) => (sessionId ? subscribeVerseSession(sessionId, listener) : () => undefined),\n () => getVerseSessionHead(sessionId).session,\n () => getVerseSessionHead(sessionId).session,\n );\n}\n\nfunction isLoopback(seat: VerseSeat, badges: readonly LocalModelBadge[] | undefined): boolean {\n // The server is the authority on the endpoint; without its badge a local\n // seat is still local, and \"private\" is claimed only when it said so.\n return badges?.find((b) => b.seatId === seat.id)?.private === true;\n}\n\n/**\n * The seat's first runnable model in a CHEAPER tier than `defaultId`'s — the\n * Devin CLI's free SWE next to its elite default (routing/tiers.ts). Null\n * when the seat has one tier.\n */\nfunction cheaperModel(seat: VerseSeat, defaultId: string): string | null {\n const base = tierRank(seatTier(seat.engine, defaultId));\n const found = seat.models.find((m) => !m.unavailableReason && tierRank(seatTier(seat.engine, m.id)) > base);\n return found?.id ?? null;\n}\n\n/** Project the polled seats into what the advisor ranks. Every chat engine, Devin included. */\nexport function toAdvisorSeats(seats: readonly VerseSeat[], badges?: readonly LocalModelBadge[]): AdvisorSeat[] {\n return seats.flatMap((seat) => {\n if (seat.health.state === 'unavailable') return [];\n const model = firstRunnableModel(seat);\n if (!model) return [];\n const local = seat.engine === 'local';\n const badge = badges?.find((b) => b.seatId === seat.id);\n const cheaper = cheaperModel(seat, model.id);\n return [{\n seatId: seat.id,\n engine: seat.engine,\n label: seat.label,\n model: model.id,\n local,\n private: local && isLoopback(seat, badges),\n supportsTools: badge?.supportsTools ?? null,\n capacity: capacityFromSeat(seat, undefined, model.id),\n ...(cheaper ? { cheaper: { model: cheaper, capacity: capacityFromSeat(seat, undefined, cheaper) } } : {}),\n }];\n });\n}\n\nfunction useDebounced<T>(value: T, ms: number): T {\n const [out, setOut] = useState(value);\n useEffect(() => {\n const id = setTimeout(() => setOut(value), ms);\n return () => clearTimeout(id);\n }, [value, ms]);\n return out;\n}\n\nexport interface AutoSeatState {\n session: VerseSession | null;\n context: MultimodelContext | null;\n policy: BudgetPolicy | null;\n classification: PromptClassification | null;\n advice: SeatAdvice | null;\n advisorSeats: AdvisorSeat[];\n /** Re-advise with a label from the decision layer (once per send). */\n adviseWith(classification: PromptClassification, pinnedSeatId?: string | null): SeatAdvice | null;\n}\n\nconst FALLBACK_POLICY: BudgetPolicy = { mode: 'balanced', seats: {}, updatedAt: new Date(0).toISOString() };\n\nexport function useAutoSeat(input: {\n sessionId: string | null;\n seats: readonly VerseSeat[];\n text: string;\n pref: AutoPref;\n pinnedSeatId: string | null;\n}): AutoSeatState {\n const session = useSessionRecord(input.sessionId);\n // By chat id: the server checks EVERY root the chat reaches, not just the primary.\n const context = useQuery(multimodelContextQuery(input.sessionId ? { sessionId: input.sessionId } : { projectPath: null })).data ?? null;\n const budget = useQuery(budgetQuery).data ?? null;\n const policy: BudgetPolicy | null = budget ? { mode: budget.mode, seats: budget.seats, updatedAt: budget.updatedAt } : null;\n const draft = useDebounced(input.text.trim(), CLASSIFY_DEBOUNCE_MS);\n const contextTokens = session?.usage?.contextTokens ?? 0;\n const advisorSeats = useMemo(() => toAdvisorSeats(input.seats, context?.local), [input.seats, context?.local]);\n\n const classification = useMemo(\n () => (draft && input.pref !== 'off' ? classifyPrompt(draft, { contextTokens }) : null),\n [draft, input.pref, contextTokens],\n );\n\n const adviseWith = (cls: PromptClassification, pinnedSeatId: string | null = input.pinnedSeatId): SeatAdvice | null => {\n // No advice until the privacy check (context) has answered: a local-only\n // repo must never be routed off this Mac on a guess.\n if (input.pref === 'off' || context === null) return null;\n return adviseSeat({\n classification: cls,\n seats: advisorSeats,\n policy: policy ?? FALLBACK_POLICY,\n mode: input.pref,\n nowMs: Date.now(),\n currentSeatId: session?.seatId ?? null,\n turnCount: session?.turnCount ?? 0,\n contextTokens,\n localOnly: context?.localOnly ?? null,\n learned: context?.learned ?? null,\n roi: context?.roi ?? null,\n pinnedSeatId,\n });\n };\n\n // Recomputed per render on purpose: capacity readings age, and the advisor\n // is cheap (a sort over a handful of seats).\n const advice = classification ? adviseWith(classification) : null;\n return { session, context, policy, classification, advice, advisorSeats, adviseWith };\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{s as t}from"./index-DOAOxiKl.js";var n=e(t(),1),r=`ashlr.verse.onboarding.v1`,i={completedAt:null,dismissedAt:null,expanded:!1,step:0};function a(){try{let e=localStorage.getItem(r);if(!e)return i;let t=JSON.parse(e);return!t||typeof t!=`object`?i:{completedAt:typeof t.completedAt==`string`?t.completedAt:null,dismissedAt:typeof t.dismissedAt==`string`?t.dismissedAt:null,expanded:t.expanded===!0,step:typeof t.step==`number`&&Number.isFinite(t.step)?Math.max(0,Math.trunc(t.step)):0}}catch{return{...i,dismissedAt:new Date(0).toISOString()}}}function o(){let e={completedAt:l.completedAt,dismissedAt:l.dismissedAt,expanded:l.expanded,step:l.step};try{localStorage.setItem(r,JSON.stringify(e))}catch{}}function s(e){return e.completedAt===null&&e.dismissedAt===null}var c=a(),l={completedAt:c.completedAt,dismissedAt:c.dismissedAt,open:s(c),expanded:c.expanded,step:c.step},u=new Set;function d(e,t=!1){let n={...l,...e};if(!Object.keys(e).every(e=>Object.is(l[e],n[e]))){l=n,t&&o();for(let e of u)e()}}function f(e){return u.add(e),()=>u.delete(e)}function p(){return l}function m(e){d({step:Math.max(0,Math.trunc(e))},!0)}function h(){d({expanded:!0},!0)}function g(){d({expanded:!1},!0)}function _(){d({dismissedAt:new Date().toISOString(),open:!1},!0)}function v(){d({completedAt:new Date().toISOString(),open:!1},!0)}function y(){d({open:!0,expanded:!0,step:0})}function b(){return(0,n.useSyncExternalStore)(f,p,p)}export{h as a,_ as i,g as n,y as o,v as r,m as s,b as t};
2
- //# sourceMappingURL=useOnboarding-Csw_AXrj.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useOnboarding-Csw_AXrj.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/onboarding/onboarding-store.ts","../../../../../../src/web-ui/routes/verse/onboarding/useOnboarding.ts"],"sourcesContent":["/**\n * routes/verse/onboarding/onboarding-store.ts — whether the first-run tour\n * is showing, and whether it has already been answered.\n *\n * Framework-free, same shape as verse-ui-store.ts: a module-level snapshot,\n * a listener set, and one `useSyncExternalStore` hook in ./useOnboarding.ts.\n *\n * Persisted under `ashlr.verse.onboarding.v1`. Two facts are stored and they\n * are deliberately different:\n *\n * - `completedAt` — the operator walked to the end.\n * - `dismissedAt` — the operator skipped, or closed it part-way.\n *\n * Either one silences the tour for good; storing which happened means a\n * later build can tell \"has seen it\" from \"chose not to\", and it makes the\n * Settings replay affordance honest about what it is replaying.\n *\n * Two UI prefs ride along in the same record:\n *\n * - `expanded` — the tour starts as a one-line chip (\"Getting started\n * 1/6 →\") and only becomes the full card when the operator opens it. A\n * 420×640 card over every surface on first launch covered half a 900px\n * window; the chip asks for nothing. Whichever the operator last chose\n * is kept across launches.\n * - `step` — where they were, so the chip's \"2/6\" survives a relaunch.\n *\n * SHOWING IT IS FAIL-SAFE IN THE QUIET DIRECTION. A storage read that throws\n * (private window, storage disabled) or returns something malformed resolves\n * to NOT showing the tour. A first-run flow that reappears on every launch\n * because storage is unavailable would be worse than one that never appears:\n * the app is fully usable without it, and it is reachable from Settings.\n */\n\nexport interface OnboardingRecord {\n /** ISO timestamp of the run that reached the last step. */\n completedAt: string | null;\n /** ISO timestamp of a skip or an early close. */\n dismissedAt: string | null;\n}\n\n/** What is stored: the answer plus the two UI prefs. */\ninterface StoredOnboarding extends OnboardingRecord {\n expanded: boolean;\n step: number;\n}\n\nexport interface OnboardingState extends OnboardingRecord {\n /** Is the flow on screen right now (as the chip or the card)? */\n open: boolean;\n /** The full card (true) or the one-line chip (false). */\n expanded: boolean;\n /** 0-based index into the step list (./onboarding-model.ts ONBOARDING_STEPS). */\n step: number;\n}\n\nexport const VERSE_ONBOARDING_STORAGE_KEY = 'ashlr.verse.onboarding.v1';\n\nconst EMPTY: StoredOnboarding = { completedAt: null, dismissedAt: null, expanded: false, step: 0 };\n\nfunction readStored(): StoredOnboarding {\n try {\n const raw = localStorage.getItem(VERSE_ONBOARDING_STORAGE_KEY);\n if (!raw) return EMPTY;\n const parsed = JSON.parse(raw) as Partial<StoredOnboarding> | null;\n if (!parsed || typeof parsed !== 'object') return EMPTY;\n return {\n completedAt: typeof parsed.completedAt === 'string' ? parsed.completedAt : null,\n dismissedAt: typeof parsed.dismissedAt === 'string' ? parsed.dismissedAt : null,\n expanded: parsed.expanded === true,\n step: typeof parsed.step === 'number' && Number.isFinite(parsed.step) ? Math.max(0, Math.trunc(parsed.step)) : 0,\n };\n } catch {\n // Unreadable storage means \"answered\" — see the fail-safe note above.\n return { ...EMPTY, dismissedAt: new Date(0).toISOString() };\n }\n}\n\nfunction persist(): void {\n const stored: StoredOnboarding = {\n completedAt: state.completedAt,\n dismissedAt: state.dismissedAt,\n expanded: state.expanded,\n step: state.step,\n };\n try {\n localStorage.setItem(VERSE_ONBOARDING_STORAGE_KEY, JSON.stringify(stored));\n } catch {\n /* best-effort: a private window without storage still runs the app */\n }\n}\n\n/** True when neither answer has been recorded yet. */\nexport function isFirstRun(record: OnboardingRecord): boolean {\n return record.completedAt === null && record.dismissedAt === null;\n}\n\nconst initialStored = readStored();\n\nlet state: OnboardingState = {\n completedAt: initialStored.completedAt,\n dismissedAt: initialStored.dismissedAt,\n open: isFirstRun(initialStored),\n expanded: initialStored.expanded,\n step: initialStored.step,\n};\n\nconst listeners = new Set<() => void>();\n\n/** Apply `delta`; notify (and, with `save`, persist) only when something changed. */\nfunction patch(delta: Partial<OnboardingState>, save = false): void {\n const next = { ...state, ...delta };\n if ((Object.keys(delta) as (keyof OnboardingState)[]).every((k) => Object.is(state[k], next[k]))) return;\n state = next;\n if (save) persist();\n for (const l of listeners) l();\n}\n\nexport function subscribeOnboarding(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function getOnboardingState(): OnboardingState {\n return state;\n}\n\nexport function setOnboardingStep(step: number): void {\n patch({ step: Math.max(0, Math.trunc(step)) }, true);\n}\n\n/** The chip was clicked: show the full card. */\nexport function expandOnboarding(): void {\n patch({ expanded: true }, true);\n}\n\n/** Back to the one-line chip — the tour is NOT answered, just out of the way. */\nexport function collapseOnboarding(): void {\n patch({ expanded: false }, true);\n}\n\n/** Skip, or the chip's × — the same answer. */\nexport function dismissOnboarding(): void {\n patch({ dismissedAt: new Date().toISOString(), open: false }, true);\n}\n\n/** Walked to the end. */\nexport function completeOnboarding(): void {\n patch({ completedAt: new Date().toISOString(), open: false }, true);\n}\n\n/** Settings → \"Replay onboarding\". Reopens at the first step, as the full\n * card (the operator asked for it); the stored answer is kept, so closing\n * the replay does not re-arm the first run. */\nexport function replayOnboarding(): void {\n patch({ open: true, expanded: true, step: 0 });\n}\n\n/** Test hygiene — forgets the stored answer and re-arms the first run (as the chip). */\nexport function resetOnboarding(): void {\n try {\n localStorage.removeItem(VERSE_ONBOARDING_STORAGE_KEY);\n } catch {\n /* ignore */\n }\n state = { completedAt: null, dismissedAt: null, open: true, expanded: false, step: 0 };\n for (const l of listeners) l();\n}\n","/**\n * routes/verse/onboarding/useOnboarding.ts — the single React binding over\n * onboarding-store.ts, kept in its own file for the same reason\n * useVerseUi.ts is: the store stays framework-free and unit-testable\n * without a DOM.\n */\nimport { useSyncExternalStore } from 'react';\nimport { getOnboardingState, subscribeOnboarding, type OnboardingState } from './onboarding-store.js';\n\nexport function useOnboarding(): OnboardingState {\n return useSyncExternalStore(subscribeOnboarding, getOnboardingState, getOnboardingState);\n}\n"],"mappings":"0GAuDa,EAA+B,4BAEtC,EAA0B,CAAE,YAAa,KAAM,YAAa,KAAM,SAAU,GAAO,KAAM,CAAE,EAEjG,SAAS,GAA+B,CACtC,GAAI,CACF,IAAM,EAAM,aAAa,QAAQ,CAA4B,EAC7D,GAAI,CAAC,EAAK,OAAO,EACjB,IAAM,EAAS,KAAK,MAAM,CAAG,EAE7B,MADI,CAAC,GAAU,OAAO,GAAW,SAAiB,EAC3C,CACL,YAAa,OAAO,EAAO,aAAgB,SAAW,EAAO,YAAc,KAC3E,YAAa,OAAO,EAAO,aAAgB,SAAW,EAAO,YAAc,KAC3E,SAAU,EAAO,WAAa,GAC9B,KAAM,OAAO,EAAO,MAAS,UAAY,OAAO,SAAS,EAAO,IAAI,EAAI,KAAK,IAAI,EAAG,KAAK,MAAM,EAAO,IAAI,CAAC,EAAI,CACjH,CACF,MAAQ,CAEN,MAAO,CAAE,GAAG,EAAO,YAAa,IAAI,KAAK,CAAC,CAAA,CAAE,YAAY,CAAE,CAC5D,CACF,CAEA,SAAS,GAAgB,CACvB,IAAM,EAA2B,CAC/B,YAAa,EAAM,YACnB,YAAa,EAAM,YACnB,SAAU,EAAM,SAChB,KAAM,EAAM,IACd,EACA,GAAI,CACF,aAAa,QAAQ,EAA8B,KAAK,UAAU,CAAM,CAAC,CAC3E,MAAQ,CAER,CACF,CAGA,SAAgB,EAAW,EAAmC,CAC5D,OAAO,EAAO,cAAgB,MAAQ,EAAO,cAAgB,IAC/D,CAEA,IAAM,EAAgB,EAAW,EAE7B,EAAyB,CAC3B,YAAa,EAAc,YAC3B,YAAa,EAAc,YAC3B,KAAM,EAAW,CAAa,EAC9B,SAAU,EAAc,SACxB,KAAM,EAAc,IACtB,EAEM,EAAY,IAAI,IAGtB,SAAS,EAAM,EAAiC,EAAO,GAAa,CAClE,IAAM,EAAO,CAAE,GAAG,EAAO,GAAG,CAAM,EAC7B,WAAO,KAAK,CAAK,CAAC,CAA+B,MAAO,GAAM,OAAO,GAAG,EAAM,GAAI,EAAK,EAAE,CAAC,EAE/F,CADA,EAAQ,EACJ,GAAM,EAAQ,EAClB,IAAK,IAAM,KAAK,EAAW,EAAE,CADX,CAEpB,CAEA,SAAgB,EAAoB,EAAkC,CAEpE,OADA,EAAU,IAAI,CAAQ,MACT,EAAU,OAAO,CAAQ,CACxC,CAEA,SAAgB,GAAsC,CACpD,OAAO,CACT,CAEA,SAAgB,EAAkB,EAAoB,CACpD,EAAM,CAAE,KAAM,KAAK,IAAI,EAAG,KAAK,MAAM,CAAI,CAAC,CAAE,EAAG,EAAI,CACrD,CAGA,SAAgB,GAAyB,CACvC,EAAM,CAAE,SAAU,EAAK,EAAG,EAAI,CAChC,CAGA,SAAgB,GAA2B,CACzC,EAAM,CAAE,SAAU,EAAM,EAAG,EAAI,CACjC,CAGA,SAAgB,GAA0B,CACxC,EAAM,CAAE,YAAa,IAAI,KAAK,CAAA,CAAE,YAAY,EAAG,KAAM,EAAM,EAAG,EAAI,CACpE,CAGA,SAAgB,GAA2B,CACzC,EAAM,CAAE,YAAa,IAAI,KAAK,CAAA,CAAE,YAAY,EAAG,KAAM,EAAM,EAAG,EAAI,CACpE,CAKA,SAAgB,GAAyB,CACvC,EAAM,CAAE,KAAM,GAAM,SAAU,GAAM,KAAM,CAAE,CAAC,CAC/C,CClJA,SAAgB,GAAiC,CAC/C,OAAA,EAAO,EAAA,qBAAA,CAAqB,EAAqB,EAAoB,CAAkB,CACzF"}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{s as t}from"./index-DOAOxiKl.js";import{l as n,u as r}from"./global-BJ_kVFpD.js";import{a as i}from"./health-queries-CMxSsJKS.js";var a=e(t(),1),o=3e4;function s(e=!0){let t=n(i),s=r(i);return(0,a.useEffect)(()=>{if(!e)return;let t=()=>{(typeof document>`u`||document.visibilityState!==`hidden`)&&s()},n=window.setInterval(t,o);return document.addEventListener(`visibilitychange`,t),()=>{window.clearInterval(n),document.removeEventListener(`visibilitychange`,t)}},[e,s]),t}export{s as t};
2
- //# sourceMappingURL=useSeatHealth-B6AXxre9.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useSeatHealth-B6AXxre9.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/health/useSeatHealth.ts"],"sourcesContent":["/**\n * routes/verse/health/useSeatHealth.ts — the seat health reports, kept live\n * while the app is on screen.\n *\n * The SERVER sweeps every ten minutes whether or not anyone looks\n * (core/verse/account-health.ts) — that is what catches a sign-out while the\n * app is hidden, and it is what the desktop shell's notifications read. This\n * hook only has to keep a VISIBLE page current, so it polls a cheap cached\n * read every 30 s (no probe runs per request), skips ticks while hidden, and\n * re-reads the moment the page is looked at again.\n */\nimport { useEffect } from 'react';\nimport type { VerseHealthResponse } from '../../../../core/verse/health-types.js';\nimport type { QueryEntry } from '../../../data/cache.js';\nimport { useQuery, useRefetch } from '../../../data/hooks.js';\nimport { verseHealthQuery } from './health-queries.js';\n\n/** The fastest poll the performance budget allows is 2 s; 30 s is plenty for a status line. */\nexport const HEALTH_POLL_MS = 30_000;\n\nexport function useSeatHealth(active = true): QueryEntry<VerseHealthResponse> {\n const entry = useQuery(verseHealthQuery);\n const refetch = useRefetch(verseHealthQuery);\n useEffect(() => {\n if (!active) return;\n const tick = (): void => {\n if (typeof document !== 'undefined' && document.visibilityState === 'hidden') return;\n refetch();\n };\n const timer = window.setInterval(tick, HEALTH_POLL_MS);\n document.addEventListener('visibilitychange', tick);\n return () => {\n window.clearInterval(timer);\n document.removeEventListener('visibilitychange', tick);\n };\n }, [active, refetch]);\n return entry;\n}\n"],"mappings":"2MAkBa,EAAiB,IAE9B,SAAgB,EAAc,EAAS,GAAuC,CAC5E,IAAM,EAAQ,EAAS,CAAgB,EACjC,EAAU,EAAW,CAAgB,EAc3C,OAbA,EAAA,EAAA,UAAA,KAAgB,CACd,GAAI,CAAC,EAAQ,OACb,IAAM,MAAmB,EACnB,OAAO,SAAa,KAAe,SAAS,kBAAoB,WACpE,EAAQ,CACV,EACM,EAAQ,OAAO,YAAY,EAAM,CAAc,EAErD,OADA,SAAS,iBAAiB,mBAAoB,CAAI,MACrC,CACX,OAAO,cAAc,CAAK,EAC1B,SAAS,oBAAoB,mBAAoB,CAAI,CACvD,CACF,EAAG,CAAC,EAAQ,CAAO,CAAC,EACb,CACT"}
@@ -1,2 +0,0 @@
1
- import{r as e}from"./rolldown-runtime-hePW80VL.js";import{s as t}from"./index-DOAOxiKl.js";import{B as n,G as r,S as i,W as a,i as o,j as s}from"./global-BJ_kVFpD.js";import"./VerseShared-CH8mV5ew.js";import{n as c,t as l}from"./verse-bootstrap-query-D-fU89IT.js";import{n as u}from"./health-queries-CMxSsJKS.js";var d=e(t(),1),f=3e4,p=2e3,m=`/api/verse/seats`;function h(e,t){return{...e,seats:t.seats,localRuntime:t.localRuntime,accountTelemetry:t.accountTelemetry}}function g(e){let t=n(l).data,i=()=>c.fetch();return(t=>e?a(l,t,!0):r(l,t))(t===void 0?i:u(async()=>{let e=await o(m);return h(n(`verse-bootstrap`).data??t,e)},i))}function _(){return g(!1)}function v(){return g(!0)}var y=0,b=null;function x(){let e,t=0,r=Date.now(),a=!0,o=i().phase,c=()=>a&&o!==`unauthenticated`&&document.visibilityState!==`hidden`,u=()=>{window.clearTimeout(e),e=void 0},d=()=>{if(!c())return;let i=t;_().finally(()=>{if(!c()||i!==t)return;let a=n(l).data?.accountTelemetry,o=(a==null||!Array.isArray(a.pendingAccountIds)||a.pendingAccountIds.length>0)&&Date.now()-r<3e4?p:f;e=window.setTimeout(d,o)})},m=()=>{u(),t+=1,r=Date.now(),d()},h=()=>{document.visibilityState===`hidden`?(u(),t+=1):m()},g=s(()=>{let e=i().phase;e!==o&&(o=e,m())});return document.addEventListener(`visibilitychange`,h),d(),()=>{a=!1,t+=1,u(),g(),document.removeEventListener(`visibilitychange`,h)}}function S(e=!0){(0,d.useEffect)(()=>{if(e)return y+=1,y===1&&(b=x()),()=>{--y,y===0&&(b?.(),b=null)}},[e])}export{S as n,v as t};
2
- //# sourceMappingURL=useSeatsRefresh-BIAa7Exn.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"useSeatsRefresh-BIAa7Exn.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/useSeatsRefresh.ts"],"sourcesContent":["/**\n * routes/verse/useSeatsRefresh.ts — keep the seat roster live.\n *\n * THE BUG THIS CLOSES. `GET /api/verse/bootstrap` carries the seats, and it\n * has NO entry in sse.ts's `EVENT_TO_CACHE_KEYS`: nothing on the server can\n * push a new reading into it. It is re-read only on mount and after a write\n * (`invalidateVerseLists`). The historical startup investigation found first collector readings\n * only after roughly a cycle and a half (about 75 seconds in that run). That\n * observation explains the original bug; it is not a current latency promise. Open the app cold, as Mason does, and the one read that ever happens\n * lands BEFORE any reading exists. Every seat then shows \"unknown\" for the\n * rest of the session, on the surface he looks at all day, and no amount of\n * correct rendering downstream can fix that.\n *\n * Visible surfaces now share a startup catch-up and steady-state poll. The\n * cost is a cached JSON read, not a probe: the\n * collector spawns its processes on its own 30s cycle regardless of whether\n * anyone asks, and this only picks up what it already published. Owner S's\n * V2.1 bootstrap handler recomputes seat telemetry on every read\n * (`liveSeats` in core/verse/verse-api.ts), so a poll of this key genuinely\n * returns the collector's CURRENT state rather than a warm cache.\n *\n * V3.10 — POLL `GET /api/verse/seats`, NOT BOOTSTRAP. Bootstrap also\n * re-reads projects, preferences and the workspace registry; measured, it\n * blocked the server's event loop ~384 ms per poll (research r2/perf-server).\n * `/seats` is the same live seat list and nothing else. The seats still have\n * to land in the `verse-bootstrap` cache key, because that is what ChatSection\n * hands to the sidebar, workspace, seat selector and new-chat dialog — so the\n * poll MERGES `/seats` into the cached bootstrap (`mergeSeatsIntoBootstrap`)\n * instead of re-reading all of it.\n *\n * The cache remembers the last fetcher it ran for a key and re-runs it on\n * every later `invalidate` (after a write). A plain \"/seats and merge\" fetcher\n * would therefore turn every later full refresh into a seats-only one; the\n * poll registers a ONE-SHOT fetcher (health/health-queries.ts\n * `oneShotFetcher`) that merges once and falls back to the real bootstrap read.\n * With no bootstrap cached yet there is nothing to merge into, so the poll\n * reads bootstrap itself.\n *\n * Two deliberate choices:\n *\n * - Refetch semantics, not refresh. A refetch collapses a burst of ticks (and\n * a tick landing on a read that just started) into ONE request, which is\n * what a poll wants. A forced refresh never joins, which is what a person\n * pressing a button wants; the panel's own Refresh control uses that.\n * - A shared, bounded startup burst picks up independent initial checks;\n * reliable completion returns to the 30s cadence. Older servers receive\n * only the bounded burst, never an infinite wait for missing quota.\n * - Nothing is requested while the document is hidden, and a read is issued\n * the moment it becomes visible again. A backgrounded app polls zero times\n * and is nonetheless correct the instant it is looked at.\n */\nimport { useEffect } from 'react';\nimport { getAuthSnapshot, subscribeAuth } from '../../data/auth-store.js';\nimport type { VerseBootstrap } from '../../data/api-types.js';\nimport type { VerseSeatsResponse } from '../../../core/verse/types.js';\nimport { getQuerySnapshot, refetchQuery, runQuery } from '../../data/cache.js';\nimport { apiGet } from '../../data/client.js';\nimport { oneShotFetcher } from './health/health-queries.js';\nimport { VERSE_BOOTSTRAP_KEY, verseBootstrapQuery } from './verse-queries.js';\n\n/** Steady-state cached reads follow the collector's cadence. */\nexport const SEATS_POLL_MS = 30_000;\n/** Bounded startup catch-up reads snapshots only, never triggers a provider probe. */\nexport const SEATS_STARTUP_POLL_MS = 2_000;\nexport const SEATS_STARTUP_WINDOW_MS = 30_000;\n\nexport const VERSE_SEATS_URL = '/api/verse/seats';\n\n/** The cached bootstrap with its seat list (and local runtime) replaced by a live `/seats` read. */\nexport function mergeSeatsIntoBootstrap(bootstrap: VerseBootstrap, live: VerseSeatsResponse): VerseBootstrap {\n return { ...bootstrap, seats: live.seats, localRuntime: live.localRuntime, accountTelemetry: live.accountTelemetry };\n}\n\n/** One poll tick: `/seats` merged into the cached bootstrap, or a full bootstrap when none is cached. */\nfunction readSeats(force: boolean): Promise<void> {\n const cached = getQuerySnapshot<VerseBootstrap>(VERSE_BOOTSTRAP_KEY).data;\n const full = (): Promise<VerseBootstrap> => verseBootstrapQuery.fetch();\n // Polls join any outstanding snapshot, including a person's newer refresh.\n const read = (fetcher: () => Promise<VerseBootstrap>) => force\n ? refetchQuery(VERSE_BOOTSTRAP_KEY, fetcher, true)\n : runQuery(VERSE_BOOTSTRAP_KEY, fetcher);\n if (cached === undefined) return read(full);\n const merged = async (): Promise<VerseBootstrap> => {\n const live = await apiGet<VerseSeatsResponse>(VERSE_SEATS_URL);\n // Merge into whatever is cached NOW, not at tick time: a write may have\n // refreshed the rest of the bootstrap while this read was in flight.\n const current = getQuerySnapshot<VerseBootstrap>(VERSE_BOOTSTRAP_KEY).data ?? cached;\n return mergeSeatsIntoBootstrap(current, live);\n };\n return read(oneShotFetcher(merged, full));\n}\n\n/** Polls coalesce; a person's refresh always supersedes an older read. */\nexport function pollSeats(): Promise<void> { return readSeats(false); }\nexport function refreshSeats(): Promise<void> { return readSeats(true); }\n\n// One visible-page scheduler, shared by the rail, chat, drawer and selectors.\n// Initial collector checks are a pending signal; missing quota never is.\n// Older servers get a bounded catch-up burst, then normal cadence.\nlet readers = 0;\nlet stopSharedRefresh: (() => void) | null = null;\n\nfunction startSharedRefresh(): () => void {\n let timer: number | undefined;\n let generation = 0;\n let startedAt = Date.now();\n let alive = true;\n let phase = getAuthSnapshot().phase;\n const visible = () => alive && phase !== 'unauthenticated' && document.visibilityState !== 'hidden';\n const cancelTimer = () => { window.clearTimeout(timer); timer = undefined; };\n const tick = () => {\n if (!visible()) return;\n const ownGeneration = generation;\n void pollSeats().finally(() => {\n if (!visible() || ownGeneration !== generation) return;\n const telemetry = getQuerySnapshot<VerseBootstrap>(VERSE_BOOTSTRAP_KEY).data?.accountTelemetry;\n const pending = telemetry == null || !Array.isArray(telemetry.pendingAccountIds) || telemetry.pendingAccountIds.length > 0;\n const delay = pending && Date.now() - startedAt < SEATS_STARTUP_WINDOW_MS ? SEATS_STARTUP_POLL_MS : SEATS_POLL_MS;\n timer = window.setTimeout(tick, delay);\n });\n };\n const restart = () => {\n cancelTimer();\n generation += 1;\n startedAt = Date.now();\n tick();\n };\n const onVisibility = () => {\n if (document.visibilityState === 'hidden') { cancelTimer(); generation += 1; }\n else restart();\n };\n const unsubscribeAuth = subscribeAuth(() => {\n const next = getAuthSnapshot().phase;\n if (next === phase) return;\n phase = next;\n restart(); // expired identities stop; the next authenticated session starts fresh.\n });\n document.addEventListener('visibilitychange', onVisibility);\n tick();\n return () => {\n alive = false;\n generation += 1;\n cancelTimer();\n unsubscribeAuth();\n document.removeEventListener('visibilitychange', onVisibility);\n };\n}\n\nexport function useSeatsRefresh(active = true): void {\n useEffect(() => {\n if (!active) return undefined;\n readers += 1;\n if (readers === 1) stopSharedRefresh = startSharedRefresh();\n return () => {\n readers -= 1;\n if (readers === 0) { stopSharedRefresh?.(); stopSharedRefresh = null; }\n };\n }, [active]);\n}\n"],"mappings":"wUA6Da,EAAgB,IAEhB,EAAwB,IAGxB,EAAkB,mBAG/B,SAAgB,EAAwB,EAA2B,EAA0C,CAC3G,MAAO,CAAE,GAAG,EAAW,MAAO,EAAK,MAAO,aAAc,EAAK,aAAc,iBAAkB,EAAK,gBAAiB,CACrH,CAGA,SAAS,EAAU,EAA+B,CAChD,IAAM,EAAS,EAAiC,CAAmB,CAAC,CAAC,KAC/D,MAAsC,EAAoB,MAAM,EAatE,OAXc,GAA2C,EACrD,EAAa,EAAqB,EAAS,EAAI,EAC/C,EAAS,EAAqB,CAAO,EACR,CAA7B,IAAW,IAAA,GAAuB,EAQ1B,EAAe,SAPyB,CAClD,IAAM,EAAO,MAAM,EAA2B,CAAe,EAI7D,OAAO,EADS,EAAA,iBAAoD,CAAC,CAAC,MAAQ,EACtC,CAAI,CAC9C,EACmC,CAAI,CARG,CAS5C,CAGA,SAAgB,GAA2B,CAAE,OAAO,EAAU,EAAK,CAAG,CACtE,SAAgB,GAA8B,CAAE,OAAO,EAAU,EAAI,CAAG,CAKxE,IAAI,EAAU,EACV,EAAyC,KAE7C,SAAS,GAAiC,CACxC,IAAI,EACA,EAAa,EACb,EAAY,KAAK,IAAI,EACrB,EAAQ,GACR,EAAQ,EAAgB,CAAC,CAAC,MACxB,MAAgB,GAAS,IAAU,mBAAqB,SAAS,kBAAoB,SACrF,MAAoB,CAAE,OAAO,aAAa,CAAK,EAAG,EAAQ,IAAA,EAAW,EACrE,MAAa,CACjB,GAAI,CAAC,EAAQ,EAAG,OAChB,IAAM,EAAgB,EACtB,EAAe,CAAC,CAAC,YAAc,CAC7B,GAAI,CAAC,EAAQ,GAAK,IAAkB,EAAY,OAChD,IAAM,EAAY,EAAiC,CAAmB,CAAC,CAAC,MAAM,iBAExE,GADU,GAAa,MAAQ,CAAC,MAAM,QAAQ,EAAU,iBAAiB,GAAK,EAAU,kBAAkB,OAAS,IAChG,KAAK,IAAI,EAAI,EAAA,IAAsC,EAAwB,EACpG,EAAQ,OAAO,WAAW,EAAM,CAAK,CACvC,CAAC,CACH,EACM,MAAgB,CACpB,EAAY,EACZ,GAAc,EACd,EAAY,KAAK,IAAI,EACrB,EAAK,CACP,EACM,MAAqB,CACrB,SAAS,kBAAoB,UAAY,EAAY,EAAG,GAAc,GACrE,EAAQ,CACf,EACM,EAAkB,MAAoB,CAC1C,IAAM,EAAO,EAAgB,CAAC,CAAC,MAC3B,IAAS,IACb,EAAQ,EACR,EAAQ,EACV,CAAC,EAGD,OAFA,SAAS,iBAAiB,mBAAoB,CAAY,EAC1D,EAAK,MACQ,CACX,EAAQ,GACR,GAAc,EACd,EAAY,EACZ,EAAgB,EAChB,SAAS,oBAAoB,mBAAoB,CAAY,CAC/D,CACF,CAEA,SAAgB,EAAgB,EAAS,GAAY,EACnD,EAAA,EAAA,UAAA,KAAgB,CACT,KAGL,MAFA,IAAW,EACP,IAAY,IAAG,EAAoB,EAAmB,OAC7C,CACX,IACI,IAAY,IAAK,IAAoB,EAAG,EAAoB,KAClE,CACF,EAAG,CAAC,CAAM,CAAC,CACb"}