@ashlr/hub 3.11.3 → 3.11.5

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 (556) hide show
  1. package/CHANGELOG.md +34 -0
  2. package/README.md +44 -18
  3. package/dist/authority-surface.json +72 -57
  4. package/dist/build-identity.json +2 -2
  5. package/dist/cli/authority.d.ts +39 -0
  6. package/dist/cli/authority.js +222 -55
  7. package/dist/cli/authority.js.map +1 -1
  8. package/dist/cli/help.js +1 -1
  9. package/dist/cli/help.js.map +1 -1
  10. package/dist/cli/verse.d.ts +3 -0
  11. package/dist/cli/verse.js +10 -0
  12. package/dist/cli/verse.js.map +1 -1
  13. package/dist/core/authority/types.d.ts +2 -2
  14. package/dist/core/cloud/cloud-api.js +1 -1
  15. package/dist/core/cloud/cloud-api.js.map +1 -1
  16. package/dist/core/cloud/delivery-contract.d.ts +1 -1
  17. package/dist/core/cloud/delivery-contract.js +25 -15
  18. package/dist/core/cloud/delivery-contract.js.map +1 -1
  19. package/dist/core/cloud/store.js +6 -0
  20. package/dist/core/cloud/store.js.map +1 -1
  21. package/dist/core/cloud/tracker.d.ts +2 -0
  22. package/dist/core/cloud/tracker.js +140 -37
  23. package/dist/core/cloud/tracker.js.map +1 -1
  24. package/dist/core/cloud/types.d.ts +9 -1
  25. package/dist/core/cloud/types.js.map +1 -1
  26. package/dist/core/comms/dispatch.d.ts +5 -0
  27. package/dist/core/comms/dispatch.js +12 -1
  28. package/dist/core/comms/dispatch.js.map +1 -1
  29. package/dist/core/comms/requests.d.ts +27 -1
  30. package/dist/core/comms/requests.js +50 -1
  31. package/dist/core/comms/requests.js.map +1 -1
  32. package/dist/core/daemon/loop.d.ts +14 -0
  33. package/dist/core/daemon/loop.js +35 -0
  34. package/dist/core/daemon/loop.js.map +1 -1
  35. package/dist/core/fabric/claude-usage.js +23 -1
  36. package/dist/core/fabric/claude-usage.js.map +1 -1
  37. package/dist/core/fleet/dispatch-router.d.ts +7 -0
  38. package/dist/core/fleet/dispatch-router.js +4 -1
  39. package/dist/core/fleet/dispatch-router.js.map +1 -1
  40. package/dist/core/fleet/tick-hooks-live.d.ts +5 -1
  41. package/dist/core/fleet/tick-hooks-live.js +10 -1
  42. package/dist/core/fleet/tick-hooks-live.js.map +1 -1
  43. package/dist/core/local-runtime/llama/config.d.ts +14 -0
  44. package/dist/core/local-runtime/llama/config.js +20 -2
  45. package/dist/core/local-runtime/llama/config.js.map +1 -1
  46. package/dist/core/local-runtime/llama/process.d.ts +19 -0
  47. package/dist/core/local-runtime/llama/process.js +67 -17
  48. package/dist/core/local-runtime/llama/process.js.map +1 -1
  49. package/dist/core/local-runtime/llama/supervisor.js +14 -3
  50. package/dist/core/local-runtime/llama/supervisor.js.map +1 -1
  51. package/dist/core/observability/rollup.d.ts +12 -0
  52. package/dist/core/observability/rollup.js +37 -2
  53. package/dist/core/observability/rollup.js.map +1 -1
  54. package/dist/core/observability/usage-source.js +49 -1
  55. package/dist/core/observability/usage-source.js.map +1 -1
  56. package/dist/core/resources/connection-monitor.js +47 -4
  57. package/dist/core/resources/connection-monitor.js.map +1 -1
  58. package/dist/core/resources/engineering-mission-store.d.ts +1 -1
  59. package/dist/core/routing/headroom.js +7 -2
  60. package/dist/core/routing/headroom.js.map +1 -1
  61. package/dist/core/routing/router.d.ts +48 -0
  62. package/dist/core/routing/router.js +129 -13
  63. package/dist/core/routing/router.js.map +1 -1
  64. package/dist/core/run/best-of-n.d.ts +7 -0
  65. package/dist/core/run/best-of-n.js +3 -0
  66. package/dist/core/run/best-of-n.js.map +1 -1
  67. package/dist/core/run/harness-dispatch.d.ts +147 -0
  68. package/dist/core/run/harness-dispatch.js +234 -0
  69. package/dist/core/run/harness-dispatch.js.map +1 -0
  70. package/dist/core/run/orchestrator.js +3 -0
  71. package/dist/core/run/orchestrator.js.map +1 -1
  72. package/dist/core/run/provider-client.d.ts +8 -0
  73. package/dist/core/run/provider-client.js +4 -0
  74. package/dist/core/run/provider-client.js.map +1 -1
  75. package/dist/core/run/sandboxed-engine.d.ts +8 -0
  76. package/dist/core/run/sandboxed-engine.js +60 -7
  77. package/dist/core/run/sandboxed-engine.js.map +1 -1
  78. package/dist/core/types.d.ts +14 -0
  79. package/dist/core/types.js.map +1 -1
  80. package/dist/core/universe/builtins/preparation/manifest.json +1 -1
  81. package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +181 -5
  82. package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +180 -4
  83. package/dist/core/universe/firm-demo.d.ts +1 -1
  84. package/dist/core/universe/firm-graph.d.ts +2 -2
  85. package/dist/core/util/scrub.js +16 -3
  86. package/dist/core/util/scrub.js.map +1 -1
  87. package/dist/core/verse/accounts.d.ts +9 -1
  88. package/dist/core/verse/accounts.js +52 -11
  89. package/dist/core/verse/accounts.js.map +1 -1
  90. package/dist/core/verse/apps-api.d.ts +12 -0
  91. package/dist/core/verse/apps-api.js +22 -4
  92. package/dist/core/verse/apps-api.js.map +1 -1
  93. package/dist/core/verse/apps.js +22 -12
  94. package/dist/core/verse/apps.js.map +1 -1
  95. package/dist/core/verse/local-models.js +3 -7
  96. package/dist/core/verse/local-models.js.map +1 -1
  97. package/dist/core/verse/model-display-name.d.ts +34 -0
  98. package/dist/core/verse/model-display-name.js +125 -0
  99. package/dist/core/verse/model-display-name.js.map +1 -0
  100. package/dist/core/verse/seats.d.ts +11 -2
  101. package/dist/core/verse/seats.js +42 -18
  102. package/dist/core/verse/seats.js.map +1 -1
  103. package/dist/core/verse/transient-events.d.ts +21 -0
  104. package/dist/core/verse/transient-events.js +12 -0
  105. package/dist/core/verse/transient-events.js.map +1 -0
  106. package/dist/core/verse/types.d.ts +6 -13
  107. package/dist/core/verse/types.js +5 -36
  108. package/dist/core/verse/types.js.map +1 -1
  109. package/dist/core/web/public/next/assets/ActionMenu-DffwPklw.js +2 -0
  110. package/dist/core/web/public/next/assets/{ActionMenu-FxXeRbPx.js.map → ActionMenu-DffwPklw.js.map} +1 -1
  111. package/dist/core/web/public/next/assets/Advanced-CxzE6ekM.js +2 -0
  112. package/dist/core/web/public/next/assets/Advanced-CxzE6ekM.js.map +1 -0
  113. package/dist/core/web/public/next/assets/App-DFlp-vdv.js +7 -0
  114. package/dist/core/web/public/next/assets/App-DFlp-vdv.js.map +1 -0
  115. package/dist/core/web/public/next/assets/AppsSection-Ct2O605-.js +2 -0
  116. package/dist/core/web/public/next/assets/AppsSection-Ct2O605-.js.map +1 -0
  117. package/dist/core/web/public/next/assets/AreaTrend-o-GLl2Is.js +2 -0
  118. package/dist/core/web/public/next/assets/{AreaTrend-CDxrQU4b.js.map → AreaTrend-o-GLl2Is.js.map} +1 -1
  119. package/dist/core/web/public/next/assets/AutonomyOffState-CXhXpsim.js +2 -0
  120. package/dist/core/web/public/next/assets/AutonomyOffState-CXhXpsim.js.map +1 -0
  121. package/dist/core/web/public/next/assets/AutonomyOffState-DmbE71vI.css +1 -0
  122. package/dist/core/web/public/next/assets/AutonomySection-BTg7yVa1.js +2 -0
  123. package/dist/core/web/public/next/assets/{AutonomySection-DuQkHGD_.js.map → AutonomySection-BTg7yVa1.js.map} +1 -1
  124. package/dist/core/web/public/next/assets/BranchBar-BjPFtGsj.js +2 -0
  125. package/dist/core/web/public/next/assets/{BranchBar-CLsvOcyK.js.map → BranchBar-BjPFtGsj.js.map} +1 -1
  126. package/dist/core/web/public/next/assets/BudgetControl-ng6swoZp.js +2 -0
  127. package/dist/core/web/public/next/assets/{BudgetControl-TL3FeZ1D.js.map → BudgetControl-ng6swoZp.js.map} +1 -1
  128. package/dist/core/web/public/next/assets/{Button-HHXgoXGr.js → Button-OjVJSrFq.js} +2 -2
  129. package/dist/core/web/public/next/assets/{Button-HHXgoXGr.js.map → Button-OjVJSrFq.js.map} +1 -1
  130. package/dist/core/web/public/next/assets/CapacityStrip-Bx4c3dxD.js +2 -0
  131. package/dist/core/web/public/next/assets/{CapacityStrip-qReu0RaF.js.map → CapacityStrip-Bx4c3dxD.js.map} +1 -1
  132. package/dist/core/web/public/next/assets/{useChartWidth-BW6SwYIK.css → ChartFrame-BVuBe6RP.css} +1 -1
  133. package/dist/core/web/public/next/assets/ChartFrame-B_w2Siqg.js +2 -0
  134. package/dist/core/web/public/next/assets/ChartFrame-B_w2Siqg.js.map +1 -0
  135. package/dist/core/web/public/next/assets/ChatSection-Bisj9R6E.js +3 -0
  136. package/dist/core/web/public/next/assets/ChatSection-Bisj9R6E.js.map +1 -0
  137. package/dist/core/web/public/next/assets/CloudBudgetForm-5Gf4iAok.js +2 -0
  138. package/dist/core/web/public/next/assets/CloudBudgetForm-5Gf4iAok.js.map +1 -0
  139. package/dist/core/web/public/next/assets/CommandPalette-iTpk6I8r.js +2 -0
  140. package/dist/core/web/public/next/assets/CommandPalette-iTpk6I8r.js.map +1 -0
  141. package/dist/core/web/public/next/assets/CommandSection-CvAVd1w4.css +1 -0
  142. package/dist/core/web/public/next/assets/CommandSection-D8ZihzvE.js +2 -0
  143. package/dist/core/web/public/next/assets/CommandSection-D8ZihzvE.js.map +1 -0
  144. package/dist/core/web/public/next/assets/ConfirmDialog-_S9iE-cJ.js +2 -0
  145. package/dist/core/web/public/next/assets/{ConfirmDialog-DLrLKM0c.js.map → ConfirmDialog-_S9iE-cJ.js.map} +1 -1
  146. package/dist/core/web/public/next/assets/DeleteChatDialog-KUYUygiA.js +2 -0
  147. package/dist/core/web/public/next/assets/DeleteChatDialog-KUYUygiA.js.map +1 -0
  148. package/dist/core/web/public/next/assets/Dialog-BuIaG6HF.js +2 -0
  149. package/dist/core/web/public/next/assets/{Dialog-BS9Dxi3G.js.map → Dialog-BuIaG6HF.js.map} +1 -1
  150. package/dist/core/web/public/next/assets/DiffPane-De4IQt82.js +2 -0
  151. package/dist/core/web/public/next/assets/{DiffPane-TOmUf3b2.js.map → DiffPane-De4IQt82.js.map} +1 -1
  152. package/dist/core/web/public/next/assets/DiffViewer-B75t6Ile.js +2 -0
  153. package/dist/core/web/public/next/assets/{DiffViewer-BpH56302.js.map → DiffViewer-B75t6Ile.js.map} +1 -1
  154. package/dist/core/web/public/next/assets/DockHost-BPqyhtCP.js +2 -0
  155. package/dist/core/web/public/next/assets/DockHost-BPqyhtCP.js.map +1 -0
  156. package/dist/core/web/public/next/assets/{EmptyState-BqR5YAmf.js → EmptyState-DXkT4vhW.js} +2 -2
  157. package/dist/core/web/public/next/assets/{EmptyState-BqR5YAmf.js.map → EmptyState-DXkT4vhW.js.map} +1 -1
  158. package/dist/core/web/public/next/assets/{Epistemic-dhvDTwAZ.js → Epistemic-CfqFe_aP.js} +2 -2
  159. package/dist/core/web/public/next/assets/{Epistemic-dhvDTwAZ.js.map → Epistemic-CfqFe_aP.js.map} +1 -1
  160. package/dist/core/web/public/next/assets/FleetSection-B7f-XBiX.js +3 -0
  161. package/dist/core/web/public/next/assets/FleetSection-B7f-XBiX.js.map +1 -0
  162. package/dist/core/web/public/next/assets/Funnel-pXYySwXQ.js +2 -0
  163. package/dist/core/web/public/next/assets/{Funnel-D2u7Wlzc.js.map → Funnel-pXYySwXQ.js.map} +1 -1
  164. package/dist/core/web/public/next/assets/GearTray-gj6lT7ba.js +2 -0
  165. package/dist/core/web/public/next/assets/{GearTray-Cb2npoxM.js.map → GearTray-gj6lT7ba.js.map} +1 -1
  166. package/dist/core/web/public/next/assets/GrowthSection-D8e9m9Wy.js +2 -0
  167. package/dist/core/web/public/next/assets/{GrowthSection-C5aDPs8B.js.map → GrowthSection-D8e9m9Wy.js.map} +1 -1
  168. package/dist/core/web/public/next/assets/HandoffDialog-VfKxKhxF.js +2 -0
  169. package/dist/core/web/public/next/assets/{HandoffDialog-BF3AYg-X.js.map → HandoffDialog-VfKxKhxF.js.map} +1 -1
  170. package/dist/core/web/public/next/assets/Input-u1YR_Ogl.js +2 -0
  171. package/dist/core/web/public/next/assets/{Input-B5dmGLZx.js.map → Input-u1YR_Ogl.js.map} +1 -1
  172. package/dist/core/web/public/next/assets/LeaderCard-BDELBrnx.js +2 -0
  173. package/dist/core/web/public/next/assets/LeaderCard-BDELBrnx.js.map +1 -0
  174. package/dist/core/web/public/next/assets/MatrixHeatmap-NKLF2srR.js +2 -0
  175. package/dist/core/web/public/next/assets/{MatrixHeatmap-BgEUs2Eu.js.map → MatrixHeatmap-NKLF2srR.js.map} +1 -1
  176. package/dist/core/web/public/next/assets/McpSection-D1tDvlRa.js +2 -0
  177. package/dist/core/web/public/next/assets/{McpSection-DZkiOuoq.js.map → McpSection-D1tDvlRa.js.map} +1 -1
  178. package/dist/core/web/public/next/assets/MessageMarkdown-DlfLEJxu.js +3 -0
  179. package/dist/core/web/public/next/assets/{MessageMarkdown-BauY8ZTY.js.map → MessageMarkdown-DlfLEJxu.js.map} +1 -1
  180. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DLBNLfsn.js → MessageMarkdownRenderer-BYZzI115.js} +4 -4
  181. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DLBNLfsn.js.map → MessageMarkdownRenderer-BYZzI115.js.map} +1 -1
  182. package/dist/core/web/public/next/assets/{Meter-DNeocJnD.js → Meter-BSVhU43Q.js} +2 -2
  183. package/dist/core/web/public/next/assets/{Meter-DNeocJnD.js.map → Meter-BSVhU43Q.js.map} +1 -1
  184. package/dist/core/web/public/next/assets/MindSection-lqV2e_Sq.js +2 -0
  185. package/dist/core/web/public/next/assets/MindSection-lqV2e_Sq.js.map +1 -0
  186. package/dist/core/web/public/next/assets/MutationTokenDialog-CLGP72g6.js +2 -0
  187. package/dist/core/web/public/next/assets/{MutationTokenDialog-mxrw0Yvy.js.map → MutationTokenDialog-CLGP72g6.js.map} +1 -1
  188. package/dist/core/web/public/next/assets/NeedsYouDrawer-D992XTOn.js +2 -0
  189. package/dist/core/web/public/next/assets/{NeedsYouDrawer-CO-Balfp.js.map → NeedsYouDrawer-D992XTOn.js.map} +1 -1
  190. package/dist/core/web/public/next/assets/NeedsYouList-eBOlJr0b.js +2 -0
  191. package/dist/core/web/public/next/assets/{NeedsYouList-CzDZbzRD.js.map → NeedsYouList-eBOlJr0b.js.map} +1 -1
  192. package/dist/core/web/public/next/assets/NewChatDialog-DoYTH26M.js +3 -0
  193. package/dist/core/web/public/next/assets/NewChatDialog-DoYTH26M.js.map +1 -0
  194. package/dist/core/web/public/next/assets/OnboardingFlow-D3yfITK1.js +2 -0
  195. package/dist/core/web/public/next/assets/OnboardingFlow-D3yfITK1.js.map +1 -0
  196. package/dist/core/web/public/next/assets/OnboardingFlow-HUNQGQuU.css +1 -0
  197. package/dist/core/web/public/next/assets/OnboardingGate-DrDEVBqw.js +3 -0
  198. package/dist/core/web/public/next/assets/OnboardingGate-DrDEVBqw.js.map +1 -0
  199. package/dist/core/web/public/next/assets/PreviewPane-ULN673zm.js +2 -0
  200. package/dist/core/web/public/next/assets/{PreviewPane-BS-CleCd.js.map → PreviewPane-ULN673zm.js.map} +1 -1
  201. package/dist/core/web/public/next/assets/{ProviderLogo-C5mBg8i0.js → ProviderLogo-8WaUjTlN.js} +2 -2
  202. package/dist/core/web/public/next/assets/{ProviderLogo-C5mBg8i0.js.map → ProviderLogo-8WaUjTlN.js.map} +1 -1
  203. package/dist/core/web/public/next/assets/RailStatus-Ckw9nvYU.js +2 -0
  204. package/dist/core/web/public/next/assets/{RailStatus-cPRyOmrk.js.map → RailStatus-Ckw9nvYU.js.map} +1 -1
  205. package/dist/core/web/public/next/assets/{RefreshIndicator-CMwSCiz5.js → RefreshIndicator-DGubF4vR.js} +2 -2
  206. package/dist/core/web/public/next/assets/{RefreshIndicator-CMwSCiz5.js.map → RefreshIndicator-DGubF4vR.js.map} +1 -1
  207. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BFi1opsC.js → ResourcePoolConsoleApp-BahEaY4d.js} +4 -4
  208. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BFi1opsC.js.map → ResourcePoolConsoleApp-BahEaY4d.js.map} +1 -1
  209. package/dist/core/web/public/next/assets/ResourcesChrome-C2ZrA7la.js +3 -0
  210. package/dist/core/web/public/next/assets/ResourcesChrome-C2ZrA7la.js.map +1 -0
  211. package/dist/core/web/public/next/assets/ResourcesDrawer-BC93fzwQ.js +2 -0
  212. package/dist/core/web/public/next/assets/ResourcesDrawer-BC93fzwQ.js.map +1 -0
  213. package/dist/core/web/public/next/assets/ResourcesDrawer-BCFJ2Uq8.css +1 -0
  214. package/dist/core/web/public/next/assets/RouteErrorBoundary-BvhHNpE_.js +2 -0
  215. package/dist/core/web/public/next/assets/{RouteErrorBoundary-DYtwc2ja.js.map → RouteErrorBoundary-BvhHNpE_.js.map} +1 -1
  216. package/dist/core/web/public/next/assets/RunInCloudAction-Dywfnw0C.js +2 -0
  217. package/dist/core/web/public/next/assets/{RunInCloudAction-BEGEEM8O.js.map → RunInCloudAction-Dywfnw0C.js.map} +1 -1
  218. package/dist/core/web/public/next/assets/SeatSelector-CH7hTgwy.js +3 -0
  219. package/dist/core/web/public/next/assets/{SeatSelector-CYHRR7Wp.js.map → SeatSelector-CH7hTgwy.js.map} +1 -1
  220. package/dist/core/web/public/next/assets/Segmented-Wynbg0F5.js +2 -0
  221. package/dist/core/web/public/next/assets/{Segmented-BE53BenI.js.map → Segmented-Wynbg0F5.js.map} +1 -1
  222. package/dist/core/web/public/next/assets/Select-DMyLCkId.js +2 -0
  223. package/dist/core/web/public/next/assets/{Select-BwSGkHCS.js.map → Select-DMyLCkId.js.map} +1 -1
  224. package/dist/core/web/public/next/assets/SessionGate-8RtQFWeZ.js +2 -0
  225. package/dist/core/web/public/next/assets/{SessionGate-e0dFJm9d.js.map → SessionGate-8RtQFWeZ.js.map} +1 -1
  226. package/dist/core/web/public/next/assets/SessionInsightChip-zBJbKv2L.js +2 -0
  227. package/dist/core/web/public/next/assets/{SessionInsightChip-CxlSyueJ.js.map → SessionInsightChip-zBJbKv2L.js.map} +1 -1
  228. package/dist/core/web/public/next/assets/SessionSearch-DfJIcxxM.js +2 -0
  229. package/dist/core/web/public/next/assets/{SessionSearch-_yp7S2TP.js.map → SessionSearch-DfJIcxxM.js.map} +1 -1
  230. package/dist/core/web/public/next/assets/SettingsSection-Da9RYyH5.js +2 -0
  231. package/dist/core/web/public/next/assets/SettingsSection-Da9RYyH5.js.map +1 -0
  232. package/dist/core/web/public/next/assets/Sheet-DhXyIDmq.js +2 -0
  233. package/dist/core/web/public/next/assets/{Sheet-DVP2Mgy6.js.map → Sheet-DhXyIDmq.js.map} +1 -1
  234. package/dist/core/web/public/next/assets/ShortcutsOverlay-Bi5f-wUw.js +2 -0
  235. package/dist/core/web/public/next/assets/{ShortcutsOverlay-BcIcoClX.js.map → ShortcutsOverlay-Bi5f-wUw.js.map} +1 -1
  236. package/dist/core/web/public/next/assets/Sidebar-BuO3sViG.js +3 -0
  237. package/dist/core/web/public/next/assets/Sidebar-BuO3sViG.js.map +1 -0
  238. package/dist/core/web/public/next/assets/Slider-Bd9YFWEV.js +2 -0
  239. package/dist/core/web/public/next/assets/{Slider-BypUWjpH.js.map → Slider-Bd9YFWEV.js.map} +1 -1
  240. package/dist/core/web/public/next/assets/StatTile-DScTd3c-.js +2 -0
  241. package/dist/core/web/public/next/assets/StatTile-DScTd3c-.js.map +1 -0
  242. package/dist/core/web/public/next/assets/{StatusBadge-HCZp416_.js → StatusBadge-DQ1UtQAJ.js} +2 -2
  243. package/dist/core/web/public/next/assets/{StatusBadge-HCZp416_.js.map → StatusBadge-DQ1UtQAJ.js.map} +1 -1
  244. package/dist/core/web/public/next/assets/StepBand-BB3IJxhr.js +2 -0
  245. package/dist/core/web/public/next/assets/{StepBand-Duz1PUes.js.map → StepBand-BB3IJxhr.js.map} +1 -1
  246. package/dist/core/web/public/next/assets/Surface-DWMtQe3Q.js +2 -0
  247. package/dist/core/web/public/next/assets/Surface-DWMtQe3Q.js.map +1 -0
  248. package/dist/core/web/public/next/assets/Surface-e1z6GdZt.css +1 -0
  249. package/dist/core/web/public/next/assets/Swimlane-DcENqtdp.js +2 -0
  250. package/dist/core/web/public/next/assets/{Swimlane-DGcIcnNA.js.map → Swimlane-DcENqtdp.js.map} +1 -1
  251. package/dist/core/web/public/next/assets/{Switch-iveI-8NY.js → Switch-CenChEYf.js} +2 -2
  252. package/dist/core/web/public/next/assets/{Switch-iveI-8NY.js.map → Switch-CenChEYf.js.map} +1 -1
  253. package/dist/core/web/public/next/assets/{Tag-DH15CUJp.js → Tag-D4k5E3u0.js} +2 -2
  254. package/dist/core/web/public/next/assets/{Tag-DH15CUJp.js.map → Tag-D4k5E3u0.js.map} +1 -1
  255. package/dist/core/web/public/next/assets/TerminalPane-DCQTukcE.js +7 -0
  256. package/dist/core/web/public/next/assets/TerminalPane-DCQTukcE.js.map +1 -0
  257. package/dist/core/web/public/next/assets/UniverseConsoleApp-DsuWT0pi.js +2 -0
  258. package/dist/core/web/public/next/assets/{UniverseConsoleApp-C8yQ0AaR.js.map → UniverseConsoleApp-DsuWT0pi.js.map} +1 -1
  259. package/dist/core/web/public/next/assets/{UniverseView-_nPURPqe.js → UniverseView-DyI5ApsA.js} +3 -3
  260. package/dist/core/web/public/next/assets/{UniverseView-_nPURPqe.js.map → UniverseView-DyI5ApsA.js.map} +1 -1
  261. package/dist/core/web/public/next/assets/UsageSection-Imr28nwK.js +3 -0
  262. package/dist/core/web/public/next/assets/UsageSection-Imr28nwK.js.map +1 -0
  263. package/dist/core/web/public/next/assets/VerseConsoleApp-DeuBEvAO.js +3 -0
  264. package/dist/core/web/public/next/assets/VerseConsoleApp-DeuBEvAO.js.map +1 -0
  265. package/dist/core/web/public/next/assets/Workspace-CpxBO98E.js +10 -0
  266. package/dist/core/web/public/next/assets/Workspace-CpxBO98E.js.map +1 -0
  267. package/dist/core/web/public/next/assets/actions-BmIf9avl.css +1 -0
  268. package/dist/core/web/public/next/assets/actions-DE8NoWV_.js +2 -0
  269. package/dist/core/web/public/next/assets/actions-DE8NoWV_.js.map +1 -0
  270. package/dist/core/web/public/next/assets/apps-model-CFGCUu9p.js +2 -0
  271. package/dist/core/web/public/next/assets/apps-model-CFGCUu9p.js.map +1 -0
  272. package/dist/core/web/public/next/assets/authority-model-CmnfJzmM.js +2 -0
  273. package/dist/core/web/public/next/assets/authority-model-CmnfJzmM.js.map +1 -0
  274. package/dist/core/web/public/next/assets/binding-left-DZpq5sLf.js +2 -0
  275. package/dist/core/web/public/next/assets/binding-left-DZpq5sLf.js.map +1 -0
  276. package/dist/core/web/public/next/assets/{budget-queries-V3wcJVK_.js → budget-queries-DjrPRFwl.js} +2 -2
  277. package/dist/core/web/public/next/assets/{budget-queries-V3wcJVK_.js.map → budget-queries-DjrPRFwl.js.map} +1 -1
  278. package/dist/core/web/public/next/assets/capacity-strip-model-C7cdQnuK.js +2 -0
  279. package/dist/core/web/public/next/assets/capacity-strip-model-C7cdQnuK.js.map +1 -0
  280. package/dist/core/web/public/next/assets/charts-DUD_jprE.js +2 -0
  281. package/dist/core/web/public/next/assets/charts-DUD_jprE.js.map +1 -0
  282. package/dist/core/web/public/next/assets/charts-DhKTrQLw.css +1 -0
  283. package/dist/core/web/public/next/assets/clipboard-DkZdqlxf.js +2 -0
  284. package/dist/core/web/public/next/assets/clipboard-DkZdqlxf.js.map +1 -0
  285. package/dist/core/web/public/next/assets/cloud-D-HXms6q.css +1 -0
  286. package/dist/core/web/public/next/assets/cloud-model-DoxBMDvx.js +2 -0
  287. package/dist/core/web/public/next/assets/cloud-model-DoxBMDvx.js.map +1 -0
  288. package/dist/core/web/public/next/assets/cloud-queries-CTGvO-k-.js +2 -0
  289. package/dist/core/web/public/next/assets/cloud-queries-CTGvO-k-.js.map +1 -0
  290. package/dist/core/web/public/next/assets/cloud.module-DOP-N4Ch.js +2 -0
  291. package/dist/core/web/public/next/assets/cloud.module-DOP-N4Ch.js.map +1 -0
  292. package/dist/core/web/public/next/assets/command-catalog-CmrHNFzh.js +2 -0
  293. package/dist/core/web/public/next/assets/command-catalog-CmrHNFzh.js.map +1 -0
  294. package/dist/core/web/public/next/assets/context-model-2Owp2jYF.js +3 -0
  295. package/dist/core/web/public/next/assets/context-model-2Owp2jYF.js.map +1 -0
  296. package/dist/core/web/public/next/assets/context-model-9xywbXxX.js +2 -0
  297. package/dist/core/web/public/next/assets/context-model-9xywbXxX.js.map +1 -0
  298. package/dist/core/web/public/next/assets/{context-queries-CrPcHWTz.js → context-queries-wvcRnV-I.js} +2 -2
  299. package/dist/core/web/public/next/assets/{context-queries-CrPcHWTz.js.map → context-queries-wvcRnV-I.js.map} +1 -1
  300. package/dist/core/web/public/next/assets/{control-queries-CmgBgKV7.js → control-queries-DB6Kh7UN.js} +2 -2
  301. package/dist/core/web/public/next/assets/{control-queries-CmgBgKV7.js.map → control-queries-DB6Kh7UN.js.map} +1 -1
  302. package/dist/core/web/public/next/assets/copy-setup-CJQhFl-4.js +2 -0
  303. package/dist/core/web/public/next/assets/copy-setup-CJQhFl-4.js.map +1 -0
  304. package/dist/core/web/public/next/assets/dock-icons-BBUGl4tE.js +2 -0
  305. package/dist/core/web/public/next/assets/{dock-icons-CUh8dOxJ.js.map → dock-icons-BBUGl4tE.js.map} +1 -1
  306. package/dist/core/web/public/next/assets/fleet-model-BRfRWkZl.js +2 -0
  307. package/dist/core/web/public/next/assets/fleet-model-BRfRWkZl.js.map +1 -0
  308. package/dist/core/web/public/next/assets/fleet-queries-tU6UEXN2.js +2 -0
  309. package/dist/core/web/public/next/assets/fleet-queries-tU6UEXN2.js.map +1 -0
  310. package/dist/core/web/public/next/assets/{focus-trap-HtcoXeEq.js → focus-trap-BGOceFvj.js} +2 -2
  311. package/dist/core/web/public/next/assets/{focus-trap-HtcoXeEq.js.map → focus-trap-BGOceFvj.js.map} +1 -1
  312. package/dist/core/web/public/next/assets/format-DEAaVF6X.js +2 -0
  313. package/dist/core/web/public/next/assets/format-DEAaVF6X.js.map +1 -0
  314. package/dist/core/web/public/next/assets/{git-model-bk_RXh3y.js → git-model-53iRLInY.js} +2 -2
  315. package/dist/core/web/public/next/assets/{git-model-bk_RXh3y.js.map → git-model-53iRLInY.js.map} +1 -1
  316. package/dist/core/web/public/next/assets/global-CXHHMz9o.js +2 -0
  317. package/dist/core/web/public/next/assets/{global-oEl9Qj8u.js.map → global-CXHHMz9o.js.map} +1 -1
  318. package/dist/core/web/public/next/assets/{guarded-runners-LHLXmXIk.js → guarded-runners-B8zFVBVZ.js} +2 -2
  319. package/dist/core/web/public/next/assets/{guarded-runners-LHLXmXIk.js.map → guarded-runners-B8zFVBVZ.js.map} +1 -1
  320. package/dist/core/web/public/next/assets/icons-D4s-jlxX.js +2 -0
  321. package/dist/core/web/public/next/assets/icons-D4s-jlxX.js.map +1 -0
  322. package/dist/core/web/public/next/assets/{index-BVxOlseC.js → index-BG177cPN.js} +3 -3
  323. package/dist/core/web/public/next/assets/{index-BVxOlseC.js.map → index-BG177cPN.js.map} +1 -1
  324. package/dist/core/web/public/next/assets/live-model-CEf01wrW.js +2 -0
  325. package/dist/core/web/public/next/assets/live-model-CEf01wrW.js.map +1 -0
  326. package/dist/core/web/public/next/assets/local-model-C9xNi9fN.js +2 -0
  327. package/dist/core/web/public/next/assets/local-model-C9xNi9fN.js.map +1 -0
  328. package/dist/core/web/public/next/assets/mind.module-D_xk6HIQ.js +2 -0
  329. package/dist/core/web/public/next/assets/{mind.module-gTGAuJt1.js.map → mind.module-D_xk6HIQ.js.map} +1 -1
  330. package/dist/core/web/public/next/assets/mutations-CbTSofVH.js +2 -0
  331. package/dist/core/web/public/next/assets/{mutations-C5S7okTW.js.map → mutations-CbTSofVH.js.map} +1 -1
  332. package/dist/core/web/public/next/assets/nav-CmZcbPFJ.js +2 -0
  333. package/dist/core/web/public/next/assets/{nav-NVtnuG7A.js.map → nav-CmZcbPFJ.js.map} +1 -1
  334. package/dist/core/web/public/next/assets/{overnight-queries-DGm3qL1b.js → overnight-queries-CR0b_j-V.js} +2 -2
  335. package/dist/core/web/public/next/assets/{overnight-queries-DGm3qL1b.js.map → overnight-queries-CR0b_j-V.js.map} +1 -1
  336. package/dist/core/web/public/next/assets/primitives-DNI-uJBd.js +1 -0
  337. package/dist/core/web/public/next/assets/{queries-CYisSAAB.js → queries-rvRsAGW2.js} +2 -2
  338. package/dist/core/web/public/next/assets/{queries-CYisSAAB.js.map → queries-rvRsAGW2.js.map} +1 -1
  339. package/dist/core/web/public/next/assets/reasoning-pref-DMPQkujg.js +2 -0
  340. package/dist/core/web/public/next/assets/{reasoning-pref-BUcFF_5G.js.map → reasoning-pref-DMPQkujg.js.map} +1 -1
  341. package/dist/core/web/public/next/assets/{reveal-anchor-D-tV8xau.js → reveal-anchor-BKk2wZZZ.js} +2 -2
  342. package/dist/core/web/public/next/assets/{reveal-anchor-D-tV8xau.js.map → reveal-anchor-BKk2wZZZ.js.map} +1 -1
  343. package/dist/core/web/public/next/assets/seat-subscription-CLn2ReSZ.js +2 -0
  344. package/dist/core/web/public/next/assets/{seat-subscription-B-f9ViU2.js.map → seat-subscription-CLn2ReSZ.js.map} +1 -1
  345. package/dist/core/web/public/next/assets/{sidebar-model-DQ-FyBHW.js → sidebar-model-CjQLvdag.js} +2 -2
  346. package/dist/core/web/public/next/assets/{sidebar-model-DQ-FyBHW.js.map → sidebar-model-CjQLvdag.js.map} +1 -1
  347. package/dist/core/web/public/next/assets/slots-DRxNosZg.js +3 -0
  348. package/dist/core/web/public/next/assets/{slots-BhP8b8tf.js.map → slots-DRxNosZg.js.map} +1 -1
  349. package/dist/core/web/public/next/assets/surface-data-DshUC_TU.js +2 -0
  350. package/dist/core/web/public/next/assets/surface-data-DshUC_TU.js.map +1 -0
  351. package/dist/core/web/public/next/assets/surface-prefetch-DO8r4ttQ.js +2 -0
  352. package/dist/core/web/public/next/assets/surface-prefetch-DO8r4ttQ.js.map +1 -0
  353. package/dist/core/web/public/next/assets/{tasks-model-BKDNqmmt.js → tasks-model-BKPFZAmZ.js} +2 -2
  354. package/dist/core/web/public/next/assets/{tasks-model-BKDNqmmt.js.map → tasks-model-BKPFZAmZ.js.map} +1 -1
  355. package/dist/core/web/public/next/assets/{terminal-icons-D2xe-aM1.js → terminal-icons-DoeQkP3y.js} +2 -2
  356. package/dist/core/web/public/next/assets/{terminal-icons-D2xe-aM1.js.map → terminal-icons-DoeQkP3y.js.map} +1 -1
  357. package/dist/core/web/public/next/assets/transient-events-nTLhMBND.js +2 -0
  358. package/dist/core/web/public/next/assets/transient-events-nTLhMBND.js.map +1 -0
  359. package/dist/core/web/public/next/assets/types-D5XOdyw8.js.map +1 -1
  360. package/dist/core/web/public/next/assets/{usage-queries-BZuAANlI.js → usage-queries-MnUeYzwp.js} +2 -2
  361. package/dist/core/web/public/next/assets/{usage-queries-BZuAANlI.js.map → usage-queries-MnUeYzwp.js.map} +1 -1
  362. package/dist/core/web/public/next/assets/{use-guarded-action-Cf4MeNBa.js → use-guarded-action-P12MfNwU.js} +2 -2
  363. package/dist/core/web/public/next/assets/{use-guarded-action-Cf4MeNBa.js.map → use-guarded-action-P12MfNwU.js.map} +1 -1
  364. package/dist/core/web/public/next/assets/{use-ticker-D9yi49my.js → use-ticker-DIvAZ4Ey.js} +2 -2
  365. package/dist/core/web/public/next/assets/{use-ticker-D9yi49my.js.map → use-ticker-DIvAZ4Ey.js.map} +1 -1
  366. package/dist/core/web/public/next/assets/{use-token-gate-DqrSXdX6.js → use-token-gate-DfEja7Wr.js} +2 -2
  367. package/dist/core/web/public/next/assets/{use-token-gate-DqrSXdX6.js.map → use-token-gate-DfEja7Wr.js.map} +1 -1
  368. package/dist/core/web/public/next/assets/useOnboarding-CkOHadqC.js +2 -0
  369. package/dist/core/web/public/next/assets/useOnboarding-CkOHadqC.js.map +1 -0
  370. package/dist/core/web/public/next/assets/useSeatsRefresh-BDlbDlIU.js +2 -0
  371. package/dist/core/web/public/next/assets/useSeatsRefresh-BDlbDlIU.js.map +1 -0
  372. package/dist/core/web/public/next/assets/useVerseTranscript-BGtA55k2.js +2 -0
  373. package/dist/core/web/public/next/assets/{useVerseTranscript-CDYrrWOO.js.map → useVerseTranscript-BGtA55k2.js.map} +1 -1
  374. package/dist/core/web/public/next/assets/verse-icons-wOet9JZy.js +2 -0
  375. package/dist/core/web/public/next/assets/verse-icons-wOet9JZy.js.map +1 -0
  376. package/dist/core/web/public/next/assets/verse-model-CSzzdyu2.js +2 -0
  377. package/dist/core/web/public/next/assets/verse-model-CSzzdyu2.js.map +1 -0
  378. package/dist/core/web/public/next/assets/verse-store-DNVRuiJL.js +2 -0
  379. package/dist/core/web/public/next/assets/verse-store-DNVRuiJL.js.map +1 -0
  380. package/dist/core/web/public/next/assets/warmup-CecO_Nk0.js +3 -0
  381. package/dist/core/web/public/next/assets/{warmup-HG5vYbsN.js.map → warmup-CecO_Nk0.js.map} +1 -1
  382. package/dist/core/web/public/next/assets/why-seat-model-D68ZA7G8.js +2 -0
  383. package/dist/core/web/public/next/assets/why-seat-model-D68ZA7G8.js.map +1 -0
  384. package/dist/core/web/public/next/assets/{workspace-model-CbhdPhei.js → workspace-model-BdIVybKr.js} +2 -2
  385. package/dist/core/web/public/next/assets/{workspace-model-CbhdPhei.js.map → workspace-model-BdIVybKr.js.map} +1 -1
  386. package/dist/core/web/public/next/index.html +1 -1
  387. package/dist/release-dependency-inventory.json +1 -1
  388. package/docs/README.md +2 -1
  389. package/package.json +1 -1
  390. package/dist/core/web/public/next/assets/ActionMenu-FxXeRbPx.js +0 -2
  391. package/dist/core/web/public/next/assets/Advanced-D_eS4472.js +0 -2
  392. package/dist/core/web/public/next/assets/Advanced-D_eS4472.js.map +0 -1
  393. package/dist/core/web/public/next/assets/App-Cj4zKbG3.js +0 -7
  394. package/dist/core/web/public/next/assets/App-Cj4zKbG3.js.map +0 -1
  395. package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js +0 -2
  396. package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js.map +0 -1
  397. package/dist/core/web/public/next/assets/AreaTrend-CDxrQU4b.js +0 -2
  398. package/dist/core/web/public/next/assets/AutonomySection-DuQkHGD_.js +0 -2
  399. package/dist/core/web/public/next/assets/BranchBar-CLsvOcyK.js +0 -2
  400. package/dist/core/web/public/next/assets/BudgetControl-TL3FeZ1D.js +0 -2
  401. package/dist/core/web/public/next/assets/BurnDown-sFXkUGdB.js +0 -2
  402. package/dist/core/web/public/next/assets/BurnDown-sFXkUGdB.js.map +0 -1
  403. package/dist/core/web/public/next/assets/CapacityStrip-qReu0RaF.js +0 -2
  404. package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js +0 -3
  405. package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js.map +0 -1
  406. package/dist/core/web/public/next/assets/CloudBudgetForm-DJbiT1wi.js +0 -2
  407. package/dist/core/web/public/next/assets/CloudBudgetForm-DJbiT1wi.js.map +0 -1
  408. package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js +0 -2
  409. package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js.map +0 -1
  410. package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js +0 -2
  411. package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js.map +0 -1
  412. package/dist/core/web/public/next/assets/ConfirmDialog-DLrLKM0c.js +0 -2
  413. package/dist/core/web/public/next/assets/Dialog-BS9Dxi3G.js +0 -2
  414. package/dist/core/web/public/next/assets/DiffPane-TOmUf3b2.js +0 -2
  415. package/dist/core/web/public/next/assets/DiffViewer-BpH56302.js +0 -2
  416. package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js +0 -2
  417. package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js.map +0 -1
  418. package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js +0 -3
  419. package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js.map +0 -1
  420. package/dist/core/web/public/next/assets/Funnel-D2u7Wlzc.js +0 -2
  421. package/dist/core/web/public/next/assets/GearTray-Cb2npoxM.js +0 -2
  422. package/dist/core/web/public/next/assets/GrowthSection-C5aDPs8B.js +0 -2
  423. package/dist/core/web/public/next/assets/HandoffDialog-BF3AYg-X.js +0 -2
  424. package/dist/core/web/public/next/assets/Input-B5dmGLZx.js +0 -2
  425. package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js +0 -2
  426. package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js.map +0 -1
  427. package/dist/core/web/public/next/assets/MatrixHeatmap-BgEUs2Eu.js +0 -2
  428. package/dist/core/web/public/next/assets/McpSection-DZkiOuoq.js +0 -2
  429. package/dist/core/web/public/next/assets/MessageMarkdown-BauY8ZTY.js +0 -3
  430. package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js +0 -2
  431. package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js.map +0 -1
  432. package/dist/core/web/public/next/assets/MutationTokenDialog-mxrw0Yvy.js +0 -2
  433. package/dist/core/web/public/next/assets/NeedsYouDrawer-CO-Balfp.js +0 -2
  434. package/dist/core/web/public/next/assets/NeedsYouList-CzDZbzRD.js +0 -2
  435. package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js +0 -3
  436. package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js.map +0 -1
  437. package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js +0 -2
  438. package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js.map +0 -1
  439. package/dist/core/web/public/next/assets/OnboardingFlow-DSpPj8UE.css +0 -1
  440. package/dist/core/web/public/next/assets/PreviewPane-BS-CleCd.js +0 -2
  441. package/dist/core/web/public/next/assets/RailStatus-cPRyOmrk.js +0 -2
  442. package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js +0 -3
  443. package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js.map +0 -1
  444. package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js +0 -2
  445. package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js.map +0 -1
  446. package/dist/core/web/public/next/assets/ResourcesDrawer-CSKIO_wZ.css +0 -1
  447. package/dist/core/web/public/next/assets/RouteErrorBoundary-DYtwc2ja.js +0 -2
  448. package/dist/core/web/public/next/assets/RunInCloudAction-BEGEEM8O.js +0 -2
  449. package/dist/core/web/public/next/assets/SeatSelector-CYHRR7Wp.js +0 -3
  450. package/dist/core/web/public/next/assets/Segmented-BE53BenI.js +0 -2
  451. package/dist/core/web/public/next/assets/Select-BwSGkHCS.js +0 -2
  452. package/dist/core/web/public/next/assets/SessionGate-e0dFJm9d.js +0 -2
  453. package/dist/core/web/public/next/assets/SessionInsightChip-CxlSyueJ.js +0 -2
  454. package/dist/core/web/public/next/assets/SessionSearch-_yp7S2TP.js +0 -2
  455. package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js +0 -2
  456. package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js.map +0 -1
  457. package/dist/core/web/public/next/assets/Sheet-DVP2Mgy6.js +0 -2
  458. package/dist/core/web/public/next/assets/ShortcutsOverlay-BcIcoClX.js +0 -2
  459. package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js +0 -3
  460. package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js.map +0 -1
  461. package/dist/core/web/public/next/assets/Slider-BypUWjpH.js +0 -2
  462. package/dist/core/web/public/next/assets/StepBand-Duz1PUes.js +0 -2
  463. package/dist/core/web/public/next/assets/Surface-B75lVfzm.js +0 -2
  464. package/dist/core/web/public/next/assets/Surface-B75lVfzm.js.map +0 -1
  465. package/dist/core/web/public/next/assets/Surface-DMca0gAe.css +0 -1
  466. package/dist/core/web/public/next/assets/Swimlane-DGcIcnNA.js +0 -2
  467. package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js +0 -7
  468. package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js.map +0 -1
  469. package/dist/core/web/public/next/assets/UniverseConsoleApp-C8yQ0AaR.js +0 -2
  470. package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js +0 -2
  471. package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js.map +0 -1
  472. package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js +0 -3
  473. package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js.map +0 -1
  474. package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js +0 -10
  475. package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js.map +0 -1
  476. package/dist/core/web/public/next/assets/actions-Ddfg2iLl.css +0 -1
  477. package/dist/core/web/public/next/assets/actions-tWevL9HV.js +0 -2
  478. package/dist/core/web/public/next/assets/actions-tWevL9HV.js.map +0 -1
  479. package/dist/core/web/public/next/assets/apps-model-CDFvmsQV.js +0 -2
  480. package/dist/core/web/public/next/assets/apps-model-CDFvmsQV.js.map +0 -1
  481. package/dist/core/web/public/next/assets/capacity-strip-model-BDbmQ3e3.js +0 -2
  482. package/dist/core/web/public/next/assets/capacity-strip-model-BDbmQ3e3.js.map +0 -1
  483. package/dist/core/web/public/next/assets/charts-CfAjuKMv.js +0 -2
  484. package/dist/core/web/public/next/assets/charts-CfAjuKMv.js.map +0 -1
  485. package/dist/core/web/public/next/assets/charts-uSX6xVYN.css +0 -1
  486. package/dist/core/web/public/next/assets/cloud-C1KPNRHC.css +0 -1
  487. package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js +0 -2
  488. package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js.map +0 -1
  489. package/dist/core/web/public/next/assets/cloud.module-ascz58c3.js +0 -2
  490. package/dist/core/web/public/next/assets/cloud.module-ascz58c3.js.map +0 -1
  491. package/dist/core/web/public/next/assets/command-bus-xYZoK9nQ.js +0 -2
  492. package/dist/core/web/public/next/assets/command-bus-xYZoK9nQ.js.map +0 -1
  493. package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js +0 -2
  494. package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js.map +0 -1
  495. package/dist/core/web/public/next/assets/composer-keys-su0g1h9o.js +0 -2
  496. package/dist/core/web/public/next/assets/composer-keys-su0g1h9o.js.map +0 -1
  497. package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js +0 -2
  498. package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js.map +0 -1
  499. package/dist/core/web/public/next/assets/context-model-CIBmSugV.js +0 -2
  500. package/dist/core/web/public/next/assets/context-model-CIBmSugV.js.map +0 -1
  501. package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js +0 -2
  502. package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js.map +0 -1
  503. package/dist/core/web/public/next/assets/dock-icons-CUh8dOxJ.js +0 -2
  504. package/dist/core/web/public/next/assets/dock-store-B2vlxqPu.js +0 -2
  505. package/dist/core/web/public/next/assets/dock-store-B2vlxqPu.js.map +0 -1
  506. package/dist/core/web/public/next/assets/fleet-model-7i-FbzKI.js +0 -2
  507. package/dist/core/web/public/next/assets/fleet-model-7i-FbzKI.js.map +0 -1
  508. package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js +0 -2
  509. package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js.map +0 -1
  510. package/dist/core/web/public/next/assets/format-BkWdOQDL.js +0 -2
  511. package/dist/core/web/public/next/assets/format-BkWdOQDL.js.map +0 -1
  512. package/dist/core/web/public/next/assets/global-oEl9Qj8u.js +0 -2
  513. package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js +0 -3
  514. package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js.map +0 -1
  515. package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js +0 -2
  516. package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js.map +0 -1
  517. package/dist/core/web/public/next/assets/icons-DEQa2rTx.js +0 -2
  518. package/dist/core/web/public/next/assets/icons-DEQa2rTx.js.map +0 -1
  519. package/dist/core/web/public/next/assets/live-model-bmsJgnYD.js +0 -2
  520. package/dist/core/web/public/next/assets/live-model-bmsJgnYD.js.map +0 -1
  521. package/dist/core/web/public/next/assets/local-model-DFyjKX0b.js +0 -2
  522. package/dist/core/web/public/next/assets/local-model-DFyjKX0b.js.map +0 -1
  523. package/dist/core/web/public/next/assets/mind.module-gTGAuJt1.js +0 -2
  524. package/dist/core/web/public/next/assets/mutations-C5S7okTW.js +0 -2
  525. package/dist/core/web/public/next/assets/nav-NVtnuG7A.js +0 -2
  526. package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js +0 -2
  527. package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js.map +0 -1
  528. package/dist/core/web/public/next/assets/primitives-DyCKYSBG.js +0 -1
  529. package/dist/core/web/public/next/assets/reasoning-pref-BUcFF_5G.js +0 -2
  530. package/dist/core/web/public/next/assets/seat-subscription-B-f9ViU2.js +0 -2
  531. package/dist/core/web/public/next/assets/section-visibility-Yctxu-if.js +0 -2
  532. package/dist/core/web/public/next/assets/section-visibility-Yctxu-if.js.map +0 -1
  533. package/dist/core/web/public/next/assets/slots-BhP8b8tf.js +0 -3
  534. package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js +0 -2
  535. package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js.map +0 -1
  536. package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js +0 -2
  537. package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js.map +0 -1
  538. package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js +0 -2
  539. package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js.map +0 -1
  540. package/dist/core/web/public/next/assets/useSeatsRefresh-DgFy-Ph4.js +0 -2
  541. package/dist/core/web/public/next/assets/useSeatsRefresh-DgFy-Ph4.js.map +0 -1
  542. package/dist/core/web/public/next/assets/useVerseTranscript-CDYrrWOO.js +0 -2
  543. package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js +0 -2
  544. package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js.map +0 -1
  545. package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js +0 -2
  546. package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js.map +0 -1
  547. package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js +0 -3
  548. package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js.map +0 -1
  549. package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js +0 -3
  550. package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js.map +0 -1
  551. package/dist/core/web/public/next/assets/viewport-nTubFCwf.js +0 -2
  552. package/dist/core/web/public/next/assets/viewport-nTubFCwf.js.map +0 -1
  553. package/dist/core/web/public/next/assets/warmup-HG5vYbsN.js +0 -3
  554. package/dist/core/web/public/next/assets/workbench-types-DzN-5trg.js +0 -2
  555. package/dist/core/web/public/next/assets/workbench-types-DzN-5trg.js.map +0 -1
  556. /package/dist/core/web/public/next/assets/{BurnDown-BuLMsJMx.css → StatTile-BuLMsJMx.css} +0 -0
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-model-CIBmSugV.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/usage/context-model.ts"],"sourcesContent":["/**\n * routes/verse/usage/context-model.ts — the ONE projection of context facts\n * for every surface that shows a seat: the seat picker's rows, the new-chat\n * dialog's context block, the resources panel's \"This chat\" efficiency block,\n * and the Usage section's per-seat efficiency table.\n *\n * WHY ONE MODULE. Before V3.9 every surface read `seat.contextWindow` (the\n * DEFAULT model's window) or the session's creation-time window, and three of\n * them rendered \"200k\" for a 1M Claude model. The arithmetic now lives in\n * core/verse/context-math.ts, shared with the server; this module is only the\n * wording and the aggregation, so the picker, the dialog and the panel cannot\n * describe one model's budget three different ways.\n *\n * HONESTY RULES this module enforces (docs/VERSE-CONTEXT.md):\n *\n * 1. UNKNOWN IS NOT A NUMBER. A model whose budget is unknown reads \"window\n * unknown\", never a default dressed as a fact. A Verse fallback window is\n * marked \"est.\", and its source says so in words.\n * 2. AN UPPER BOUND IS NOT A MEASUREMENT. Codex's turn total sums every model\n * call; until its rollout is read, occupancy is \"≤ N\", and any statistic\n * built on such a reading carries the same flag.\n * 3. NO CACHE REPORTED IS NOT A 0% HIT RATE. A provider that reported no\n * cache activity at all (Ollama; codex on its very first call) gets \"none\n * reported\", not a 0% that reads \"caching is broken\".\n * 4. NOTHING HERE SPENDS. Every figure is derived from what the server\n * already returned (seats, sessions, the open chat's event log).\n *\n * Pure: no React, no I/O.\n */\nimport {\n CACHE_IDLE_TTL_MS,\n budgetFor,\n cacheHitRatio,\n fitVerdict,\n hasExpansiveMode,\n sessionOverheadTokens,\n} from '../../../../core/verse/context-math.js';\nimport type {\n VerseContextBudget,\n VerseContextFit,\n VerseContextMode,\n VerseEngine,\n VerseEvent,\n VerseFitVerdict,\n VerseModelOption,\n VerseSeat,\n VerseSession,\n VerseUsage,\n VerseWindowSource,\n} from '../../../../core/verse/types.js';\nimport { CODEX_EXPANSIVE_METERING_NOTE, WINDOW_SOURCE_TEXT, modelOptionFor, seatUnavailableReason, sessionContextBudget } from '../verse-model.js';\nimport { formatTokens } from '../verse-store.js';\nimport { formatWholePercent } from '../autonomy/format.js';\n\n// ---------------------------------------------------------------------------\n// Models and modes\n// ---------------------------------------------------------------------------\n\n/**\n * A seat's option for a model id, matching through the alias table (a chat\n * remembered on `claude-opus-5.5` is the catalog's `claude-opus-5-5`). The\n * lookup itself is verse-model's `modelOptionFor`, the one the context meter\n * uses, so the picker and the meter can never resolve one id two ways.\n */\nexport function seatModelOption(seat: VerseSeat | null | undefined, modelId: string): VerseModelOption | null {\n return seat ? modelOptionFor([seat], { seatId: seat.id, model: modelId }) : null;\n}\n\n/** `mode` when this model has a budget for it, else `standard` — never a mode the CLI cannot be told. */\nexport function resolveContextMode(option: VerseModelOption | null | undefined, mode: VerseContextMode): VerseContextMode {\n return mode !== 'standard' && budgetFor(option, mode) !== null ? mode : 'standard';\n}\n\n/** The budget a model runs with in a mode (resolved), or null when even its standard window is unknown. */\nexport function effectiveBudget(option: VerseModelOption | null | undefined, mode: VerseContextMode): VerseContextBudget | null {\n return budgetFor(option, resolveContextMode(option, mode));\n}\n\n/** Why this model cannot be chosen on this seat, or null when it can. The seat's own outage wins. */\nexport function modelUnavailableReason(seat: VerseSeat, option: VerseModelOption): string | null {\n const seatReason = seatUnavailableReason(seat);\n if (seatReason !== null) return seatReason;\n const reason = option.unavailableReason;\n return typeof reason === 'string' && reason.trim().length > 0 ? reason.trim() : null;\n}\n\nexport const CONTEXT_MODE_LABEL: Record<VerseContextMode, string> = {\n standard: 'Standard',\n expansive: 'Expansive',\n};\n\n/** How each seat's CLI is named when its pinned version is shown. */\nexport const ENGINE_CLI_NAME: Record<VerseEngine, string> = {\n claude: 'Claude Code',\n codex: 'Codex CLI',\n grok: 'Grok CLI',\n local: 'Claude Code',\n};\n\n/** \"Claude Code 2.1.257\" — the binary this seat is pinned to; null when unknown (local seats, old servers). */\nexport function seatCliLine(seat: VerseSeat): string | null {\n const version = typeof seat.cliVersion === 'string' ? seat.cliVersion.trim() : '';\n return version.length > 0 ? `${ENGINE_CLI_NAME[seat.engine]} ${version}` : null;\n}\n\n/** The seat's own plain-language context facts (binary skew, catalog not yet fetched, …). */\nexport function seatContextNotes(seat: VerseSeat): string[] {\n return (seat.notes ?? []).filter((n): n is string => typeof n === 'string' && n.trim().length > 0);\n}\n\n// ---------------------------------------------------------------------------\n// Window provenance\n// ---------------------------------------------------------------------------\n\n// Window provenance wording is verse-model's `WINDOW_SOURCE_TEXT` — the\n// meter's tooltip, the picker and the resources panel all read that one table.\n\nexport function isEstimatedWindow(source: VerseWindowSource | null | undefined): boolean {\n return source === 'fallback';\n}\n\n// ---------------------------------------------------------------------------\n// Picker and dialog wording\n// ---------------------------------------------------------------------------\n\n/**\n * The compact per-model phrase a picker row carries: \"1M ctx · compacts ≈367k\".\n * Uses the budget for `mode` when the model has one, and names the mode only\n * when it is not the default, so an ordinary row stays short.\n */\nexport function modelContextPhrase(option: VerseModelOption, mode: VerseContextMode = 'standard'): string {\n const resolved = resolveContextMode(option, mode);\n const budget = budgetFor(option, resolved);\n if (!budget) return 'window unknown';\n const window = `${formatTokens(budget.contextWindow)} ctx${isEstimatedWindow(option.windowSource) ? ' (est.)' : ''}`;\n const compacts = budget.autoCompactAt === null ? '' : ` · compacts ≈${formatTokens(budget.autoCompactAt)}`;\n return `${window}${compacts}${resolved === 'expansive' ? ' (expansive)' : ''}`;\n}\n\n/**\n * The full sentence for a tooltip or the dialog: the window, where each mode\n * compacts, and how the window is known.\n */\nexport function modelContextSentence(option: VerseModelOption): string {\n const standard = budgetFor(option, 'standard');\n const expansive = hasExpansiveMode(option) ? budgetFor(option, 'expansive') : null;\n const parts: string[] = [];\n if (!standard) {\n parts.push('Context window unknown for this model.');\n } else {\n const where = standard.autoCompactAt === null\n ? ''\n : `; compacts at about ${formatTokens(standard.autoCompactAt)}${expansive ? ' in Standard' : ''}`;\n parts.push(`${formatTokens(standard.contextWindow)}-token window${where}.`);\n }\n if (expansive) {\n parts.push(`Expansive runs to about ${formatTokens(expansive.autoCompactAt ?? expansive.contextWindow)} before compacting.`);\n }\n if (option.windowSource) parts.push(`Window ${WINDOW_SOURCE_TEXT[option.windowSource]}.`);\n return parts.join(' ');\n}\n\n/**\n * The metering caveat an Expansive cost sentence must carry for this engine,\n * or null when there is none. The wording is verse-model's\n * CODEX_EXPANSIVE_METERING_NOTE — ONE sentence for the new-chat dialog, the\n * handoff dialog, the in-chat mode menu and the \"Expansive could help\" chip.\n * The ratio those surfaces quote (≈3.2× for a 785k vs 245k codex turn) counts\n * re-sent TOKENS only; GPT-5.6-class requests above 272k reportedly also\n * count about 2× against plan limits (docs/VERSE-CONTEXT.md §2.3, a single\n * secondary source), so the note is worded as reported, never as a measured\n * multiplier. Standard never crosses 272k; Expansive does by design.\n */\nexport function expansiveMeteringNote(engine: VerseEngine | null | undefined): string | null {\n return engine === 'codex' ? CODEX_EXPANSIVE_METERING_NOTE : null;\n}\n\n/**\n * \"A turn at 967k re-sends 2.6× the tokens of one at 367k.\" — the only ratio\n * any Expansive cost sentence quotes, and it is arithmetic on the model's own\n * budgets. Null when either compaction point is unknown. It comes BEFORE the\n * codex metering note, whose \"twice that\" refers to it.\n */\nexport function expansiveRatioSentence(option: VerseModelOption | null | undefined): string | null {\n const standard = budgetFor(option, 'standard');\n const expansive = budgetFor(option, 'expansive');\n const stdCap = standard ? standard.autoCompactAt ?? standard.contextWindow : null;\n const expCap = expansive ? expansive.autoCompactAt ?? expansive.contextWindow : null;\n if (stdCap === null || expCap === null || stdCap <= 0) return null;\n return `A turn at ${formatTokens(expCap)} re-sends ${(expCap / stdCap).toFixed(1)}× the tokens of one at ${formatTokens(stdCap)}.`;\n}\n\n/**\n * What each mode costs, in plain words, for the mode selector. Numbers come\n * from the model's own budgets; the only ratio quoted is arithmetic (every\n * turn re-sends everything held, so a turn at X re-sends X/Y of one at Y) —\n * a token ratio, not a usage multiplier, which is why codex also carries the\n * shared metering caveat.\n */\nexport function contextModeDescription(engine: VerseEngine, option: VerseModelOption, mode: VerseContextMode): string {\n const standard = budgetFor(option, 'standard');\n const expansive = budgetFor(option, 'expansive');\n const stdCap = standard ? standard.autoCompactAt ?? standard.contextWindow : null;\n const expCap = expansive ? expansive.autoCompactAt ?? expansive.contextWindow : null;\n if (mode === 'standard' || expCap === null) {\n if (stdCap === null) return 'The CLI compacts at its own default point for this model.';\n return engine === 'claude'\n ? `Compacts at about ${formatTokens(stdCap)}. Every turn re-sends the whole context, so holding it under this point keeps each turn cheaper and recall sharper.`\n : `Compacts at about ${formatTokens(stdCap)} — the CLI's own default budget for this model.`;\n }\n const ratio = expansiveRatioSentence(option);\n const metering = expansiveMeteringNote(engine);\n return `Runs to about ${formatTokens(expCap)} before compacting — for tightly coupled, cross-cutting work that needs everything in view at once. Each turn re-sends everything held, so a long expansive chat uses noticeably more of your plan per turn.${ratio ? ` ${ratio}` : ''}${metering ? ` ${metering}` : ''}`;\n}\n\n/** Why a model offers no mode choice, for the one line where the selector would be. */\nexport function noModeReason(engine: VerseEngine, option: VerseModelOption): string {\n if (!budgetFor(option, 'standard')) return 'This model’s window is unknown, so Verse cannot offer a larger budget for it.';\n if (engine === 'grok' || engine === 'local') return 'One budget: this CLI compacts at its own fixed point, and Verse cannot raise it per chat.';\n return 'One budget: this model has no larger window to expand into.';\n}\n\n// ---------------------------------------------------------------------------\n// Context fit\n// ---------------------------------------------------------------------------\n\n/** Short form for a picker row, where it sits beside the capacity words. */\nexport const FIT_SHORT: Record<VerseFitVerdict, string> = {\n fits: 'code fits',\n tight: 'code fits, tight',\n expansive: 'code needs expansive',\n split: 'code too big — split',\n};\n\n/** Badge text for the chosen model. */\nexport const FIT_LABEL: Record<VerseFitVerdict, string> = {\n fits: 'Fits',\n tight: 'Tight fit',\n expansive: 'Needs expansive',\n split: 'Split the work',\n};\n\n/** A fit reading that is a FLOOR (a root hit its file or time cap). */\nexport function fitIsFloor(fit: VerseContextFit): boolean {\n return fit.roots.some((r) => r.truncated);\n}\n\n/**\n * The verdict for a model IN THE MODE THE CHAT WOULD RUN IN, or null when its\n * budget is unknown (never guessed).\n *\n * `engine` is the seat's engine: the fixed prompt added to the code is that\n * CLI's estimate (context-math `sessionOverheadTokens` — ≈15k local, ≈25k\n * claude), not one flat figure. With a flat 30k a 64k local seat (compacts\n * ≈32.5k) called anything over ~2.5k tokens of code \"too big — split\". Null\n * falls back to the largest estimate.\n *\n * In Standard this is context-math's `fitVerdict` as is — including\n * \"expansive\", the suggestion that only the bigger budget holds the code. In\n * Expansive the bigger budget IS the budget, so the same thresholds are\n * applied to it: the code fits, fits tightly, or no single context on this\n * model holds it. Without this, a chat already set to Expansive would still be\n * told its code \"fits tightly under ≈367k\" — true of a budget it is not using.\n */\nexport function modelFit(\n tokens: number | null | undefined,\n option: VerseModelOption | null | undefined,\n mode: VerseContextMode,\n engine: VerseEngine | null,\n): VerseFitVerdict | null {\n if (typeof tokens !== 'number' || !Number.isFinite(tokens) || tokens < 0) return null;\n const overhead = sessionOverheadTokens(engine);\n if (resolveContextMode(option, mode) === 'expansive' && option) {\n const expansive = budgetFor(option, 'expansive')!;\n return fitVerdict(tokens, { ...option, contextWindow: expansive.contextWindow, autoCompactAt: expansive.autoCompactAt, expansive: null }, overhead);\n }\n return fitVerdict(tokens, option, overhead);\n}\n\n/**\n * The sentence under the fit badge, for the verdict `modelFit` gave in the\n * chat's mode. In Standard a tight fit also names the Expansive budget when\n * one exists, and \"needs expansive\" says what to do — suggestions only;\n * nothing here switches the mode.\n */\nexport function fitExplanation(input: {\n verdict: VerseFitVerdict;\n tokens: number;\n option: VerseModelOption;\n mode: VerseContextMode;\n floor?: boolean;\n}): string {\n const amount = `${input.floor ? 'at least ' : ''}~${formatTokens(input.tokens)} tokens of tracked code`;\n const inExpansive = resolveContextMode(input.option, input.mode) === 'expansive';\n const standard = budgetFor(input.option, 'standard');\n const expansive = budgetFor(input.option, 'expansive');\n const stdCap = standard ? formatTokens(standard.autoCompactAt ?? standard.contextWindow) : null;\n const expCap = expansive ? formatTokens(expansive.autoCompactAt ?? expansive.contextWindow) : null;\n const cap = inExpansive ? expCap : stdCap;\n const budget = inExpansive ? 'Expansive budget' : 'budget';\n switch (input.verdict) {\n case 'fits':\n return `All ${amount} fits well inside this model's ${budget}${cap ? ` (compacts ≈${cap})` : ''}, with room left for the conversation.`;\n case 'tight': {\n const roomier = !inExpansive && expCap !== null && hasExpansiveMode(input.option)\n ? ` Expansive (≈${expCap}) would hold it with room to spare.`\n : '';\n return `${capitalize(amount)} fits under the ≈${cap ?? '?'} compaction point${inExpansive ? ' of the Expansive budget' : ''}, with little room for the conversation — expect it to compact if the agent reads widely.${roomier}`;\n }\n case 'expansive':\n return `${capitalize(amount)} is more than the Standard budget (≈${stdCap ?? '?'}) holds; only Expansive (≈${expCap ?? '?'}) takes it all. Switch to Expansive, or narrow the folders to the part you are changing.`;\n case 'split':\n return `${capitalize(amount)} is more than any single context on this model holds${expCap ? `, even Expansive (≈${expCap})` : ''}. Split the work: fan it out across several chats, each scoped to one folder or subsystem, or narrow this chat to the part you are changing.`;\n }\n}\n\n/**\n * How the working-set figure is made — shown once, beside the badge. Names the\n * fixed-prompt figure the verdict added, and calls it an estimate: no CLI\n * reports its base prompt before a turn has run.\n */\nexport function fitMethodNote(engine: VerseEngine | null): string {\n const cli = engine ? ` for ${ENGINE_CLI_NAME[engine]}` : '';\n return `Estimated from the size of tracked text files (bytes ÷ 4), plus an estimated ~${formatTokens(sessionOverheadTokens(engine))} of fixed prompt${cli} that every chat starts with. An agent rarely reads everything, so this is a ceiling, not a forecast.`;\n}\n\nfunction capitalize(text: string): string {\n return text.length === 0 ? text : text.charAt(0).toUpperCase() + text.slice(1);\n}\n\n// ---------------------------------------------------------------------------\n// One session's context\n// ---------------------------------------------------------------------------\n\nexport interface SessionContextView {\n tokens: number;\n /** False when `tokens` is an upper bound (codex before its rollout is read). */\n exact: boolean;\n window: number | null;\n autoCompactAt: number | null;\n /** How the window is known; null when nothing says (no window, or a stored one without provenance). */\n source: VerseWindowSource | null;\n mode: VerseContextMode;\n /** The session's model has a real expansive budget on its seat. */\n hasModes: boolean;\n}\n\n/**\n * The window a session is measured against, by the precedence every surface\n * shares — runtime → the seat's CURRENT catalog budget for the model and mode\n * → what the record stored → the seat default. The precedence itself lives in\n * verse-model's `sessionContextBudget` (the context meter reads it too); this\n * only adds whether the model offers a second mode, for the panels here.\n */\nexport function sessionContext(session: VerseSession, seats: readonly VerseSeat[]): SessionContextView {\n const budget = sessionContextBudget(seats, session);\n return {\n tokens: Math.floor(budget.contextTokens),\n exact: budget.exact,\n window: budget.contextWindow,\n autoCompactAt: budget.autoCompactAt,\n source: budget.source,\n mode: budget.mode,\n hasModes: hasExpansiveMode(budget.option),\n };\n}\n\n/**\n * Cache-hit ratio, except when the provider reported no cache activity at all\n * — then null (\"none reported\"), because 0% would claim caching failed when\n * the truth is that nothing was said about it.\n */\nexport function reportedCacheHitRatio(usage: Pick<VerseUsage, 'inputTokens' | 'cacheReadTokens' | 'cacheCreationTokens'>): number | null {\n if (usage.cacheReadTokens <= 0 && usage.cacheCreationTokens <= 0) return null;\n return cacheHitRatio(usage);\n}\n\n/** A 0–1 ratio as a whole percent; a real sliver reads \"<1%\", never \"0%\". */\nexport function formatRatio(ratio: number | null): string {\n if (ratio === null || !Number.isFinite(ratio)) return '—';\n return formatWholePercent(ratio);\n}\n\nexport interface TurnContextStats {\n /** Turns with at least one context reading. */\n turns: number;\n /** Mean of each turn's context (its largest trustworthy reading); null with no turns. */\n average: number | null;\n /** Largest per-turn context seen. */\n peak: number | null;\n /** False when any counted turn had only an upper-bound reading. */\n exact: boolean;\n /** Compactions recorded in the log. */\n compactions: number;\n /** Cache-hit ratio of the most recent turn (see `reportedCacheHitRatio`). */\n lastTurnCacheHit: number | null;\n}\n\n/**\n * Context per turn from the open chat's event log.\n *\n * A turn's context is its LARGEST trustworthy reading: within one turn the\n * prompt only grows, except across a compaction, and the peak is what the\n * turn actually paid for. Exact readings (`context` events, usage frames not\n * flagged as upper bounds) win; a turn whose only reading is codex's turn\n * total contributes that total and flags the statistic as an upper bound —\n * that figure can be many times the real prompt, so it is never mixed in\n * where an exact one exists.\n */\nexport function turnContextStats(events: readonly VerseEvent[]): TurnContextStats {\n const perTurn = new Map<string, { exact: number | null; bound: number | null }>();\n let compactions = 0;\n let lastUsage: VerseUsage | null = null;\n const note = (turnId: string, tokens: number, exact: boolean): void => {\n if (!Number.isFinite(tokens) || tokens < 0) return;\n const entry = perTurn.get(turnId) ?? { exact: null, bound: null };\n if (exact) entry.exact = Math.max(entry.exact ?? 0, tokens);\n else entry.bound = Math.max(entry.bound ?? 0, tokens);\n perTurn.set(turnId, entry);\n };\n for (const event of events) {\n switch (event.type) {\n case 'usage':\n lastUsage = event.usage;\n note(event.turnId, event.usage.contextTokens, event.usage.contextTokensExact !== false);\n break;\n case 'context':\n if (event.turnId !== null) note(event.turnId, event.contextTokens, event.exact);\n break;\n case 'compaction':\n compactions += 1;\n break;\n default:\n break;\n }\n }\n let sum = 0;\n let peak: number | null = null;\n let exact = true;\n let turns = 0;\n for (const entry of perTurn.values()) {\n const value = entry.exact ?? entry.bound;\n if (value === null) continue;\n if (entry.exact === null) exact = false;\n turns += 1;\n sum += value;\n peak = peak === null ? value : Math.max(peak, value);\n }\n return {\n turns,\n average: turns === 0 ? null : Math.round(sum / turns),\n peak,\n exact,\n compactions,\n lastTurnCacheHit: lastUsage === null ? null : reportedCacheHitRatio(lastUsage),\n };\n}\n\nexport interface IdleCacheWarning {\n idleMs: number;\n tokens: number;\n /** A local model: the cost is time, not spend. */\n local: boolean;\n}\n\n/**\n * The next turn of an idle chat re-reads its whole context uncached once the\n * provider's prompt cache has expired (CACHE_IDLE_TTL_MS). Below the fixed\n * prompt every new chat on this engine pays anyway (its estimate) there is\n * nothing worth warning about.\n */\nexport function idleCacheWarning(\n session: Pick<VerseSession, 'status' | 'engine'>,\n tokens: number,\n now: number,\n /**\n * When the chat last TALKED to its provider (`lastTurnActivityAt(events)`),\n * never `session.updatedAt`: a rename or mode switch moves that without\n * warming the provider's cache. Null (no turn yet / log not loaded) → no warning.\n */\n lastActivityAt: string | null,\n): IdleCacheWarning | null {\n if (session.status === 'running' || lastActivityAt === null) return null;\n const last = Date.parse(lastActivityAt);\n if (!Number.isFinite(last)) return null;\n const idleMs = now - last;\n if (idleMs < CACHE_IDLE_TTL_MS || tokens < sessionOverheadTokens(session.engine)) return null;\n return { idleMs, tokens, local: session.engine === 'local' };\n}\n\n// ---------------------------------------------------------------------------\n// Per-seat efficiency across sessions (Usage section)\n// ---------------------------------------------------------------------------\n\nexport interface SeatEfficiencyRow {\n seatId: string;\n label: string;\n engine: VerseEngine;\n /** The seat is no longer in the roster (its sessions remain on disk). */\n retired: boolean;\n sessions: number;\n turns: number;\n /** input + cache read + cache write: every prompt token the seat was sent. */\n promptTokens: number;\n outputTokens: number;\n /** Null when the provider reported no cache activity on any of these sessions. */\n cacheHitRatio: number | null;\n compactions: number;\n expansiveSessions: number;\n /** The fullest context among these sessions right now, as a share of its window. */\n fullest: { sessionId: string; title: string; tokens: number; window: number | null; exact: boolean } | null;\n}\n\n/**\n * \"Fullest\" is a share of the window when both windows are known; a context\n * with a known window outranks one without (its fullness is a fact, the other\n * a size); two unknown windows compare by size.\n */\nfunction fuller(a: NonNullable<SeatEfficiencyRow['fullest']>, b: NonNullable<SeatEfficiencyRow['fullest']>): boolean {\n if (a.window !== null && b.window !== null) return a.tokens / a.window > b.tokens / b.window;\n if (a.window !== null) return true;\n if (b.window !== null) return false;\n return a.tokens > b.tokens;\n}\n\n/**\n * Aggregate every session by seat. Ratios are computed from SUMS, never as a\n * mean of per-session ratios — a two-turn chat must not weigh as much as a\n * two-hundred-turn one. Seats with no sessions are omitted rather than shown\n * as zeros. Sorted by prompt tokens, largest first: that is where efficiency\n * matters most.\n */\nexport function seatEfficiency(sessions: readonly VerseSession[], seats: readonly VerseSeat[]): SeatEfficiencyRow[] {\n const bySeat = new Map<string, VerseSession[]>();\n for (const s of sessions) {\n const list = bySeat.get(s.seatId) ?? [];\n list.push(s);\n bySeat.set(s.seatId, list);\n }\n const rows: SeatEfficiencyRow[] = [];\n for (const [seatId, list] of bySeat) {\n const seat = seats.find((s) => s.id === seatId) ?? null;\n let input = 0;\n let read = 0;\n let write = 0;\n let output = 0;\n let turns = 0;\n let compactions = 0;\n let expansiveSessions = 0;\n let fullest: SeatEfficiencyRow['fullest'] = null;\n for (const s of list) {\n input += s.usage.inputTokens;\n read += s.usage.cacheReadTokens;\n write += s.usage.cacheCreationTokens;\n output += s.usage.outputTokens;\n turns += s.turnCount;\n compactions += s.compactionCount ?? 0;\n // The mode as the meter resolves it (verse-model sessionContextBudget),\n // counted before the empty-reading skip: the mode is a fact about the\n // chat, not about its reading.\n const view = sessionContext(s, seats);\n if (view.mode === 'expansive') expansiveSessions += 1;\n if (view.tokens <= 0) continue;\n const candidate = { sessionId: s.id, title: s.title, tokens: view.tokens, window: view.window, exact: view.exact };\n if (fullest === null || fuller(candidate, fullest)) fullest = candidate;\n }\n rows.push({\n seatId,\n label: seat?.label ?? seatId,\n engine: seat?.engine ?? list[0]!.engine,\n retired: seat === null,\n sessions: list.length,\n turns,\n promptTokens: input + read + write,\n outputTokens: output,\n cacheHitRatio: reportedCacheHitRatio({ inputTokens: input, cacheReadTokens: read, cacheCreationTokens: write }),\n compactions,\n expansiveSessions,\n fullest,\n });\n }\n return rows.sort((a, b) => b.promptTokens - a.promptTokens || a.label.localeCompare(b.label));\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- function e(e){return e?e.darkSince===void 0?e.state===`dark`?e.lastActivityAt:null:e.darkSince:null}function t(e){let t=new Date(e);return`${t.getFullYear()}-${String(t.getMonth()+1).padStart(2,`0`)}-${String(t.getDate()).padStart(2,`0`)}`}function n(e){let t=Date.parse(e);return Number.isFinite(t)?new Date(t).toLocaleDateString(`en-US`,{month:`short`,day:`numeric`}):`an unknown day`}function r(e){let n=Date.parse(e);return Number.isFinite(n)?t(n):e}function i(t){let n=e(t),i=t.stateReason?.trim()||void 0;return n!==null&&Number.isFinite(Date.parse(n))?{kind:`dark`,since:r(n),detail:i}:i?{kind:`empty`,message:`Fleet dark. ${/[.!?…]$/.test(i)?i:`${i}.`}`}:{kind:`empty`,message:`Fleet dark.`}}function a(e){return e.kind===`dark`?{kind:`empty`,message:`No fleet runs or proposals since ${n(e.since)}.`}:e}export{a as i,e as n,i as r,n as t};
2
- //# sourceMappingURL=dark-since-DOMvtB_G.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dark-since-DOMvtB_G.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/fleet/dark-since.ts"],"sourcesContent":["/**\n * routes/verse/fleet/dark-since.ts — the ONE \"Fleet dark since …\" (3.10.1).\n *\n * 3.10.0 said it three ways: Command and Fleet took the live snapshot's\n * `lastActivityAt` (\"Sep 1\"), Growth took fleet history's `darkSince` (\"Aug\n * 18\"), and Command fell back to history whenever the live read was not dark.\n * Those are two different facts:\n *\n * dark since — autonomy is shut (no standing grant, or no daemon) and\n * the fleet last showed any sign of life then. Served once,\n * as `FleetLiveSnapshotV1.darkSince` (core/verse/\n * fleet-live-api.ts `fleetDarkSince`). Only this value may be\n * worded \"Fleet dark since …\".\n * quiet since — fleet history's `darkSince`: the last run started or\n * proposal filed. Worded \"No fleet runs or proposals since …\"\n * (`quietSinceStatus`), never \"dark\".\n *\n * Dates are the viewer's LOCAL calendar day everywhere (\"Sep 1\"), so the\n * verdict line and the chart beside it can never name different days.\n *\n * Framework-free; tested directly.\n */\nimport type { FleetLiveSnapshotV1 } from '../../../../core/fleet/fleet-types.js';\nimport type { ChartStatus } from '../../../components/charts/ChartFrame.js';\n\n/**\n * The fleet's dark-since instant, or null when the fleet is not dark. A\n * pre-3.10.1 server sends no `darkSince`; the same rule is applied to what it\n * does send.\n */\nexport function fleetDarkSince(live: FleetLiveSnapshotV1 | null | undefined): string | null {\n if (!live) return null;\n if (live.darkSince !== undefined) return live.darkSince;\n return live.state === 'dark' ? live.lastActivityAt : null;\n}\n\n/** The viewer's local calendar day for an instant, as `YYYY-MM-DD`. */\nfunction localDay(ms: number): string {\n const d = new Date(ms);\n return `${d.getFullYear()}-${String(d.getMonth() + 1).padStart(2, '0')}-${String(d.getDate()).padStart(2, '0')}`;\n}\n\n/** \"Sep 1\" — the viewer's local day for `iso`. */\nexport function darkSinceLabel(iso: string): string {\n const ms = Date.parse(iso);\n if (!Number.isFinite(ms)) return 'an unknown day';\n return new Date(ms).toLocaleDateString('en-US', { month: 'short', day: 'numeric' });\n}\n\n/**\n * `iso` as the viewer's local `YYYY-MM-DD`, for ChartFrame's dark state:\n * ChartFrame labels the day it is GIVEN (a bare ISO instant would be cut to\n * its UTC day, which an evening west of UTC turns into tomorrow).\n */\nexport function darkSinceDay(iso: string): string {\n const ms = Date.parse(iso);\n return Number.isFinite(ms) ? localDay(ms) : iso;\n}\n\n/**\n * The chart state for a DARK live fleet, from THE dark-since instant: \"Fleet\n * dark since Sep 1\" (the viewer's local day). When the server knows the fleet\n * is dark but not since when (`darkSince: null` — a fresh install, a cleared\n * ledger and journal), it says just \"Fleet dark.\", as Command's line does —\n * never \"since <today>\" from the snapshot's own `generatedAt`.\n */\nexport function fleetDarkStatus(live: FleetLiveSnapshotV1): ChartStatus {\n const since = fleetDarkSince(live);\n const detail = live.stateReason?.trim() || undefined;\n if (since !== null && Number.isFinite(Date.parse(since))) return { kind: 'dark', since: darkSinceDay(since), detail };\n if (!detail) return { kind: 'empty', message: 'Fleet dark.' };\n return { kind: 'empty', message: `Fleet dark. ${/[.!?…]$/.test(detail) ? detail : `${detail}.`}` };\n}\n\n/**\n * A chart status built over fleet HISTORY, re-worded: history's `darkSince`\n * is \"quiet since\" (the last run or proposal), so its dark state becomes a\n * plain \"No fleet runs or proposals since Aug 18.\" Every other status passes\n * through untouched.\n */\nexport function quietSinceStatus(status: ChartStatus): ChartStatus {\n if (status.kind !== 'dark') return status;\n return { kind: 'empty', message: `No fleet runs or proposals since ${darkSinceLabel(status.since)}.` };\n}\n"],"mappings":"AA8BA,SAAgB,EAAe,EAA6D,CAG1F,OAFK,EACD,EAAK,YAAc,IAAA,GAChB,EAAK,QAAU,OAAS,EAAK,eAAiB,KADZ,EAAK,UAD5B,IAGpB,CAGA,SAAS,EAAS,EAAoB,CACpC,IAAM,EAAI,IAAI,KAAK,CAAE,EACrB,MAAO,GAAG,EAAE,YAAY,EAAE,GAAG,OAAO,EAAE,SAAS,EAAI,CAAC,CAAC,CAAC,SAAS,EAAG,GAAG,EAAE,GAAG,OAAO,EAAE,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAG,GAAG,GAC/G,CAGA,SAAgB,EAAe,EAAqB,CAClD,IAAM,EAAK,KAAK,MAAM,CAAG,EAEzB,OADK,OAAO,SAAS,CAAE,EAChB,IAAI,KAAK,CAAE,CAAC,CAAC,mBAAmB,QAAS,CAAE,MAAO,QAAS,IAAK,SAAU,CAAC,EADjD,gBAEnC,CAOA,SAAgB,EAAa,EAAqB,CAChD,IAAM,EAAK,KAAK,MAAM,CAAG,EACzB,OAAO,OAAO,SAAS,CAAE,EAAI,EAAS,CAAE,EAAI,CAC9C,CASA,SAAgB,EAAgB,EAAwC,CACtE,IAAM,EAAQ,EAAe,CAAI,EAC3B,EAAS,EAAK,aAAa,KAAK,GAAK,IAAA,GAG3C,OAFI,IAAU,MAAQ,OAAO,SAAS,KAAK,MAAM,CAAK,CAAC,EAAU,CAAE,KAAM,OAAQ,MAAO,EAAa,CAAK,EAAG,QAAO,EAC/G,EACE,CAAE,KAAM,QAAS,QAAS,eAAe,UAAU,KAAK,CAAM,EAAI,EAAS,GAAG,EAAO,IAAK,EAD7E,CAAE,KAAM,QAAS,QAAS,aAAc,CAE9D,CAQA,SAAgB,EAAiB,EAAkC,CAEjE,OADI,EAAO,OAAS,OACb,CAAE,KAAM,QAAS,QAAS,oCAAoC,EAAe,EAAO,KAAK,EAAE,EAAG,EADlE,CAErC"}
@@ -1,2 +0,0 @@
1
- import{a as e,n as t,s as n}from"./index-BVxOlseC.js";import{C as r}from"./verse-model-DyCwZF-M.js";import{a as i}from"./tool-semantics-GX8ScuSH.js";var a=n(e(),1),o=[],s=(0,a.createContext)(o);function c(e){return e}function l(e){return e.replace(/\\/g,`/`).replace(/\/+$/,``).replace(/^\/private(?=\/(?:tmp|var|etc)(?:\/|$))/,``).replace(/^[A-Z](?=:)/,e=>e.toLowerCase())}function u(e,t=o){let n=l(e),r=``;for(let e of t){let t=l(e);t.length>r.length&&!/^(?:[a-z]:)?$/.test(t)&&(n===t||n.startsWith(`${t}/`))&&(r=t)}let i=e.replace(/[\\/]+$/,``);if(r){let e=n.length-r.length-1;return e>0?i.slice(i.length-e):i.slice(Math.max(i.lastIndexOf(`/`),i.lastIndexOf(`\\`))+1)}if(!/^(?:[\\/]|[A-Za-z]:[\\/])/.test(e))return e.replace(/^\.[\\/]/,``);let a=e.includes(`/`)?`/`:`\\`,s=e.replace(/^[A-Za-z]:/,``).split(/[\\/]/).filter(Boolean);return s.length>4?`…${a}${s.slice(-3).join(a)}`:e}function d(e){let t=typeof e==`object`&&e?e:null;return t&&typeof t.command!=`string`&&typeof t.cmd!=`string`?i(t)[0]??null:null}function f(){let e=(0,a.useContext)(s);return(0,a.useCallback)(t=>u(t,e),[e])}var p={live:`_live_ytrey_7`,line:`_line_ytrey_14`,pulse:`_pulse_ytrey_24`,"live-pulse":`_live-pulse_ytrey_1`,text:`_text_ytrey_34`,word:`_word_ytrey_43`,sep:`_sep_ytrey_44`,figure:`_figure_ytrey_45`,detail:`_detail_ytrey_49`,stop:`_stop_ytrey_58`,stopIcon:`_stopIcon_ytrey_75`,notice:`_notice_ytrey_82`,noticeWord:`_noticeWord_ytrey_94`,noticeText:`_noticeText_ytrey_96`},m=t();function h(e,t){for(let t=e.length-1;t>=0;--t){let n=e[t];if(n.kind===`user`)break;if(n.kind===`tool`){if(n.result===null)return{phase:`tool`,detail:r(n.input)||n.name,path:d(n.input)};break}if(n.kind===`assistant`&&n.streaming)return{phase:`writing`,detail:null};if(n.kind===`assistant`||n.kind===`thinking`)break}return t.thinking?{phase:`thinking`,detail:null}:{phase:`waiting`,detail:null}}var g={thinking:`Thinking`,tool:`Running`,writing:`Writing`,waiting:`Waiting`},_={retry:`Retrying`,preflight:`Preflight`,watchdog:`Still running`};function v(e){if(!Number.isFinite(e)||e<0)return`0s`;let t=Math.floor(e/1e3);if(t<60)return`${t}s`;let n=Math.floor(t/60);return n<60?`${n}m ${t%60}s`:`${Math.floor(n/60)}h ${n%60}m`}function y(e,t,n){let r=e.progress,i=t.phase===`tool`||t.phase===`writing`?t.phase:r?.phase??t.phase,a=r?r.elapsedMs+Math.max(0,n-r.receivedAt):e.startedAt===null?null:Math.max(0,n-e.startedAt),o=i===`tool`?t.detail??r?.tool??null:null,s=r?.tokPerSec??null,c=(i===`writing`||i===`thinking`)&&s!==null&&s>0?`${s>=10?Math.round(s):s.toFixed(1)} tok/s`:null;return{phase:i,word:g[i],elapsedMs:a,detail:o,rate:c}}var b=(0,a.memo)(function({live:e,derived:t,onStop:n,showNotice:r=!0}){let[i,o]=(0,a.useState)(()=>Date.now());(0,a.useEffect)(()=>{o(Date.now());let e=setInterval(()=>o(Date.now()),1e3);return()=>clearInterval(e)},[e.turnId]);let s=f(),c=y(e,t,i),l=c.phase===`tool`&&t.path?{...c,detail:s(t.path)}:c,u=l.detail?`${l.word}: ${l.detail}`:l.word,d=r?e.notice:null;return(0,m.jsxs)(`div`,{className:p.live,"data-phase":l.phase,children:[(0,m.jsxs)(`div`,{className:p.line,children:[(0,m.jsx)(`span`,{className:p.pulse,"aria-hidden":`true`}),(0,m.jsxs)(`span`,{className:p.text,"aria-hidden":`true`,children:[(0,m.jsx)(`span`,{className:p.word,children:l.word}),l.elapsedMs===null?null:(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:p.sep,children:`·`}),(0,m.jsx)(`span`,{className:p.figure,children:v(l.elapsedMs)})]}),l.detail?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:p.sep,children:`·`}),(0,m.jsx)(`span`,{className:p.detail,title:t.path??l.detail,children:l.detail})]}):null,l.rate?(0,m.jsxs)(m.Fragment,{children:[(0,m.jsx)(`span`,{className:p.sep,children:`·`}),(0,m.jsx)(`span`,{className:p.figure,children:l.rate})]}):null]}),(0,m.jsx)(`span`,{className:`visually-hidden`,role:`status`,children:u}),n?(0,m.jsxs)(`button`,{type:`button`,className:p.stop,onClick:n,"aria-label":`Stop this turn`,title:`Stop this turn (⌘.)`,children:[(0,m.jsx)(`span`,{className:p.stopIcon,"aria-hidden":`true`}),`Stop`]}):null]}),d?(0,m.jsxs)(`p`,{className:p.notice,"data-kind":d.kind,role:`status`,children:[(0,m.jsx)(`span`,{className:p.noticeWord,children:_[d.kind]}),(0,m.jsx)(`span`,{className:p.noticeText,children:d.message})]}):null]})}),x=new Set,S=null,C=Date.now();function w(e){return x.add(e),S===null&&(C=Date.now(),S=setInterval(()=>{C=Date.now();for(let e of[...x])e()},1e3)),()=>{x.delete(e),x.size===0&&S!==null&&(clearInterval(S),S=null)}}function T(){return C}var E=()=>()=>{},D=()=>0;function O(e=!0){let t=(0,a.useSyncExternalStore)(e?w:E,e?T:D,e?T:D);return Math.max(t,Date.now())}function k(e){if(typeof e==`number`)return Number.isFinite(e)?e:null;if(typeof e!=`string`)return null;let t=Date.parse(e);return Number.isFinite(t)?t:null}function A({since:e,className:t,label:n}){let r=k(e),i=O(r!==null);if(r===null)return null;let a=v(Math.max(0,i-r));return(0,m.jsx)(`span`,{className:t,"data-live-timer":``,"aria-hidden":!n||void 0,"aria-label":n?`${n} ${a}`:void 0,role:n?`timer`:void 0,children:a})}function j({size:e=16,children:t,...n}){return(0,m.jsx)(`svg`,{width:e,height:e,viewBox:`0 0 16 16`,fill:`none`,stroke:`currentColor`,strokeWidth:1.5,strokeLinecap:`round`,strokeLinejoin:`round`,"aria-hidden":`true`,focusable:`false`,...n,children:t})}function M(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`rect`,{x:`1.75`,y:`2.75`,width:`12.5`,height:`10.5`,rx:`1.5`}),(0,m.jsx)(`path`,{d:`m4.5 6.25 2 1.75-2 1.75M8.25 10h3`})]})}function N(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`rect`,{x:`1.75`,y:`2.75`,width:`12.5`,height:`10.5`,rx:`1.5`}),(0,m.jsx)(`path`,{d:`M1.75 5.75h12.5M4 4.25h.01M5.75 4.25h.01`})]})}function P(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`path`,{d:`M5 2.5v5M2.5 5h5M9 11h4.5`}),(0,m.jsx)(`path`,{d:`M11.5 2.5 4.5 13.5`})]})}function F(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`path`,{d:`M6.5 4h7M6.5 8h7M6.5 12h7`}),(0,m.jsx)(`path`,{d:`m2.25 4 1 1 1.5-2M2.5 8h1.75M2.5 12h1.75`})]})}function I(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`path`,{d:`m8 2 6 3-6 3-6-3 6-3Z`}),(0,m.jsx)(`path`,{d:`m2 8 6 3 6-3M2 11l6 3 6-3`})]})}function L(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`rect`,{x:`2.25`,y:`2.25`,width:`11.5`,height:`11.5`,rx:`1.5`}),(0,m.jsx)(`path`,{d:`M2.25 8h11.5`})]})}function R(e){return(0,m.jsx)(j,{...e,children:(0,m.jsx)(`path`,{d:`m4 4 8 8M12 4l-8 8`})})}function z(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`circle`,{cx:`3.5`,cy:`8`,r:`0.9`,fill:`currentColor`,stroke:`none`}),(0,m.jsx)(`circle`,{cx:`8`,cy:`8`,r:`0.9`,fill:`currentColor`,stroke:`none`}),(0,m.jsx)(`circle`,{cx:`12.5`,cy:`8`,r:`0.9`,fill:`currentColor`,stroke:`none`})]})}function B(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`path`,{d:`M9.75 2.25 13.75 6.25 11 7.5 8.5 10l.25 2.75-5-5L6.5 8 9 5.25Z`}),(0,m.jsx)(`path`,{d:`m5 11-2.75 2.75`})]})}function V(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`rect`,{x:`1.75`,y:`2.75`,width:`12.5`,height:`3`,rx:`1`}),(0,m.jsx)(`path`,{d:`M2.75 5.75v6.5a1 1 0 0 0 1 1h8.5a1 1 0 0 0 1-1v-6.5M6.5 8.5h3`})]})}function H(e){return(0,m.jsx)(j,{...e,children:(0,m.jsx)(`path`,{d:`M10.5 2.75 13.25 5.5 6 12.75H3.25V10Z`})})}function U(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`path`,{d:`M2.5 8h9M8.5 4.5 12 8l-3.5 3.5`}),(0,m.jsx)(`path`,{d:`M13.75 3v10`})]})}function W(e){return(0,m.jsxs)(j,{...e,children:[(0,m.jsx)(`rect`,{x:`5.25`,y:`5.25`,width:`8.5`,height:`8.5`,rx:`1.5`}),(0,m.jsx)(`path`,{d:`M10.75 5.25V3.75a1.5 1.5 0 0 0-1.5-1.5h-5.5a1.5 1.5 0 0 0-1.5 1.5v5.5a1.5 1.5 0 0 0 1.5 1.5h1.5`})]})}function G(e){return(0,m.jsx)(j,{...e,children:(0,m.jsx)(`path`,{d:`M2.75 4.25h10.5M6.25 4.25V2.75h3.5v1.5M4.25 4.25l.6 9h6.3l.6-9`})})}var K={terminal:M,preview:N,diff:P,tasks:F,context:I};export{U as a,H as c,A as d,b as f,f as g,c as h,K as i,L as l,s as m,R as n,z as o,h as p,W as r,B as s,V as t,G as u};
2
- //# sourceMappingURL=dock-icons-CUh8dOxJ.js.map
@@ -1,2 +0,0 @@
1
- import{a as e,s as t}from"./index-BVxOlseC.js";import{t as n}from"./viewport-nTubFCwf.js";var r=t(e(),1),i=[{id:`terminal`,label:`Terminal`,owner:`C4`,commandId:`dock.terminal`,slot:`terminal-pane`},{id:`preview`,label:`Preview`,owner:`C4`,commandId:`dock.preview`,slot:`preview-pane`},{id:`diff`,label:`Review`,owner:`C5`,commandId:`dock.diff`,slot:`diff-pane`},{id:`tasks`,label:`Tasks`,owner:`C2`,commandId:null,slot:null},{id:`context`,label:`Context`,owner:`C2`,commandId:null,slot:null}],a=i.map(e=>e.id);function o(e){return typeof e==`string`&&a.includes(e)}var s=Object.freeze({minWidth:320,maxWidthFraction:.6,defaultWidth:440,sheetBelow:n.wide,bottomSheetBelow:n.compact,bottomSheetHeightVh:75,splitRatio:Object.freeze({min:.2,max:.8,default:.5})});function c(e){return e<s.bottomSheetBelow?`bottom-sheet`:e<s.sheetBelow?`sheet`:`column`}function l(e,t){let n=typeof e==`number`&&Number.isFinite(e)?Math.round(e):s.defaultWidth,r=Math.max(s.minWidth,Math.floor(t*s.maxWidthFraction));return Math.min(r,Math.max(s.minWidth,n))}var u=`ashlr.verse.ui.v2`,d=`ashlr.verse.ui.v3`,f=Object.freeze({open:!1,width:s.defaultWidth,tabs:[],active:null,splitWith:null,splitRatio:s.splitRatio.default});function p(e){if(typeof e!=`object`||!e||Array.isArray(e))return{...f,tabs:[]};let t=e,n=[];if(Array.isArray(t.tabs))for(let e of t.tabs)o(e)&&!n.includes(e)&&n.push(e);let r=o(t.active)&&n.includes(t.active)?t.active:n[0]??null,i=o(t.splitWith)&&n.includes(t.splitWith)&&t.splitWith!==r?t.splitWith:null,a=typeof t.width==`number`&&Number.isFinite(t.width)&&t.width>=s.minWidth?Math.round(t.width):s.defaultWidth,c=typeof t.splitRatio==`number`&&Number.isFinite(t.splitRatio)?t.splitRatio:s.splitRatio.default;return{open:t.open===!0&&n.length>0,width:a,tabs:n,active:r,splitWith:i,splitRatio:Math.min(s.splitRatio.max,Math.max(s.splitRatio.min,c))}}var m={terminal:null,preview:null,diff:null},h=null,g=0,_=new Set;function v(){try{let e=localStorage.getItem(d);if(!e)return p(null);let t=JSON.parse(e);return p(t&&typeof t==`object`?t.dock:null)}catch{return p(null)}}function y(){return h===null&&(h={state:v(),requests:m}),h}function b(e){h=e;for(let e of[..._])e()}function x(e){b({...y(),state:e})}function S(e){return _.add(e),()=>_.delete(e)}function C(){return y()}function w(){return y().state}function T(e,t){let n=e.tabs.includes(t)?e.tabs:[...e.tabs,t],r=e.splitWith===t?e.active===t?null:e.active:e.splitWith;return{...e,open:!0,tabs:n,active:t,splitWith:r===t?null:r}}function E(e,t){return e.open&&(e.active===t||e.splitWith===t)?{...e,open:!1}:T(e,t)}function D(e,t){let n=e.tabs.filter(e=>e!==t),r=e.splitWith===t?null:e.splitWith,i=e.active;if(i===t){let a=e.tabs.indexOf(t);i=r??n[Math.min(a,n.length-1)]??null}return{...e,tabs:n,active:i,splitWith:r===i?null:r,open:n.length>0&&e.open}}function O(e,t){if(t===null)return{...e,splitWith:null};if(e.active===null||t===e.active)return e;let n=e.tabs.includes(t)?e.tabs:[...e.tabs,t];return{...e,open:!0,tabs:n,splitWith:t}}function k(e,t){return Number.isFinite(t)?{...e,width:Math.max(s.minWidth,Math.round(t))}:e}function A(e,t){if(!Number.isFinite(t))return e;let{min:n,max:r}=s.splitRatio;return{...e,splitRatio:Math.min(r,Math.max(n,t))}}function j(e){x(T(y().state,e))}function M(e){x(E(y().state,e))}function N(){let e=y().state;e.open?x({...e,open:!1}):e.tabs.length===0?x(T(e,`tasks`)):x({...e,open:!0,active:e.active??e.tabs[0]})}function P(){let e=y().state;e.open&&x({...e,open:!1})}function F(e){x(D(y().state,e))}function I(e){x(O(y().state,e))}function L(e){x(k(y().state,e))}function R(e){x(A(y().state,e))}function z(e){g+=1;let t=y();b({state:T(t.state,`terminal`),requests:{...t.requests,terminal:{...e,nonce:g}}})}function B(e){let t=y(),n=t.state.open?t.state.active:null;if(n===null||n===`terminal`){z(e);return}g+=1,b({state:O(t.state,`terminal`),requests:{...t.requests,terminal:{...e,nonce:g}}})}function V(e){g+=1;let t=y();b({state:T(t.state,`diff`),requests:{...t.requests,diff:{...e,nonce:g}}})}function H(){let e=y();e.requests!==m&&b({...e,requests:m})}function U(){return(0,r.useSyncExternalStore)(S,C,C)}export{i as _,j as a,l as b,B as c,I as d,S as f,s as g,U as h,w as i,R as l,M as m,P as n,V as o,N as p,F as r,z as s,H as t,L as u,d as v,c as x,u as y};
2
- //# sourceMappingURL=dock-store-B2vlxqPu.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"dock-store-B2vlxqPu.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/dock-catalog.ts","../../../../../../src/web-ui/routes/verse/dock/dock-store.ts"],"sourcesContent":["/**\n * routes/verse/shell/dock-catalog.ts — the chat dock's panes, layout rules\n * and persisted state (unit C0; SPEC-310C §3).\n *\n * The dock is C2's container; its panes belong to four units (C2 Tasks and\n * Context, C4 Terminal and Preview, C5 Review). This file is what they agree\n * on: which panes exist, which command opens each, which render through a\n * slot (slots.tsx, so the container never imports another unit's code), how\n * wide the dock may be, when it becomes a sheet, and the shape it persists.\n *\n * Pure data and pure functions — no React.\n */\nimport type { CommandId } from './command-catalog.js';\nimport { VIEWPORT_BREAKPOINTS } from './viewport.js';\n\nexport const DOCK_PANES = [\n { id: 'terminal', label: 'Terminal', owner: 'C4', commandId: 'dock.terminal', slot: 'terminal-pane' },\n { id: 'preview', label: 'Preview', owner: 'C4', commandId: 'dock.preview', slot: 'preview-pane' },\n { id: 'diff', label: 'Review', owner: 'C5', commandId: 'dock.diff', slot: 'diff-pane' },\n { id: 'tasks', label: 'Tasks', owner: 'C2', commandId: null, slot: null },\n { id: 'context', label: 'Context', owner: 'C2', commandId: null, slot: null },\n] as const satisfies readonly {\n id: string;\n label: string;\n owner: string;\n /** The catalog command that opens (and focuses) this pane; null = opened from its own affordance. */\n commandId: CommandId | null;\n /** Rendered through this slot when the pane is another unit's; null = C2's own component. */\n slot: 'terminal-pane' | 'preview-pane' | 'diff-pane' | null;\n}[];\n\nexport type DockPaneId = (typeof DOCK_PANES)[number]['id'];\nexport const DOCK_PANE_IDS: readonly DockPaneId[] = DOCK_PANES.map((p) => p.id);\n\nexport function isDockPaneId(value: unknown): value is DockPaneId {\n return typeof value === 'string' && (DOCK_PANE_IDS as readonly string[]).includes(value);\n}\n\n/**\n * Layout rules. Widths in CSS px, measured against the WINDOW, not the chat\n * column: \"resizable from 320px to 60% of the window\".\n */\nexport const DOCK_LAYOUT = Object.freeze({\n minWidth: 320,\n maxWidthFraction: 0.6,\n /** A new dock opens this wide (the 440 of the SPEC-310C shell sketch). */\n defaultWidth: 440,\n /** Below this window width the dock is a sheet over the chat, not a column. */\n sheetBelow: VIEWPORT_BREAKPOINTS.wide,\n /** Below this window width it is a bottom sheet… */\n bottomSheetBelow: VIEWPORT_BREAKPOINTS.compact,\n /** …this tall, in vh. */\n bottomSheetHeightVh: 75,\n /** The top pane's share of the height in a vertical split. */\n splitRatio: Object.freeze({ min: 0.2, max: 0.8, default: 0.5 }),\n});\n\nexport type DockPresentation = 'column' | 'sheet' | 'bottom-sheet';\n\n/** How the dock is drawn at a given window width. */\nexport function dockPresentation(windowWidth: number): DockPresentation {\n if (windowWidth < DOCK_LAYOUT.bottomSheetBelow) return 'bottom-sheet';\n if (windowWidth < DOCK_LAYOUT.sheetBelow) return 'sheet';\n return 'column';\n}\n\n/**\n * A persisted or dragged width clamped for this window. The floor wins over\n * the 60% cap on a window too narrow to honour both (it is a sheet there\n * anyway), so the result is never below minWidth.\n */\nexport function clampDockWidth(width: unknown, windowWidth: number): number {\n const n = typeof width === 'number' && Number.isFinite(width) ? Math.round(width) : DOCK_LAYOUT.defaultWidth;\n const max = Math.max(DOCK_LAYOUT.minWidth, Math.floor(windowWidth * DOCK_LAYOUT.maxWidthFraction));\n return Math.min(max, Math.max(DOCK_LAYOUT.minWidth, n));\n}\n\n// ---------------------------------------------------------------------------\n// Persisted state\n// ---------------------------------------------------------------------------\n\n/** The v2 key C1 migrates FROM (verse-ui-store.ts). */\nexport const VERSE_UI_STORAGE_KEY_V2 = 'ashlr.verse.ui.v2';\n/**\n * The v3 key (SPEC-310C §3 \"State persists in ashlr.verse.ui.v3\"). ONE blob,\n * written by C1's verse-ui-store; the dock's state is its `dock` field, read\n * back through sanitizeDockState — so two writers never race for the key.\n */\nexport const VERSE_UI_STORAGE_KEY = 'ashlr.verse.ui.v3';\n\nexport interface DockState {\n open: boolean;\n /** Last dragged width; clamp with clampDockWidth at render (it depends on the window). */\n width: number;\n /** Open panes, in tab order. */\n tabs: DockPaneId[];\n /** The pane shown (on top, when split); null only when there are no tabs. */\n active: DockPaneId | null;\n /** A second pane shown BELOW `active` (\"Preview over Terminal\"); never equal to it. */\n splitWith: DockPaneId | null;\n /** `active`'s share of the height when split. */\n splitRatio: number;\n}\n\nexport const DEFAULT_DOCK_STATE: Readonly<DockState> = Object.freeze({\n open: false,\n width: DOCK_LAYOUT.defaultWidth,\n tabs: [],\n active: null,\n splitWith: null,\n splitRatio: DOCK_LAYOUT.splitRatio.default,\n});\n\n/**\n * Read a persisted `dock` field without trusting it: unknown panes dropped,\n * duplicates collapsed, `active`/`splitWith` forced to open tabs, numbers\n * clamped. Anything unreadable falls back to the default, never throws — a\n * hand-edited or future-version blob must not take the chat down.\n */\nexport function sanitizeDockState(value: unknown): DockState {\n if (value === null || typeof value !== 'object' || Array.isArray(value)) return { ...DEFAULT_DOCK_STATE, tabs: [] };\n const raw = value as Record<string, unknown>;\n const tabs: DockPaneId[] = [];\n if (Array.isArray(raw['tabs'])) {\n for (const tab of raw['tabs']) if (isDockPaneId(tab) && !tabs.includes(tab)) tabs.push(tab);\n }\n const active: DockPaneId | null = isDockPaneId(raw['active']) && tabs.includes(raw['active']) ? raw['active'] : (tabs[0] ?? null);\n const splitWith: DockPaneId | null =\n isDockPaneId(raw['splitWith']) && tabs.includes(raw['splitWith']) && raw['splitWith'] !== active ? raw['splitWith'] : null;\n const width = typeof raw['width'] === 'number' && Number.isFinite(raw['width']) && raw['width'] >= DOCK_LAYOUT.minWidth\n ? Math.round(raw['width'])\n : DOCK_LAYOUT.defaultWidth;\n const ratio = typeof raw['splitRatio'] === 'number' && Number.isFinite(raw['splitRatio']) ? raw['splitRatio'] : DOCK_LAYOUT.splitRatio.default;\n return {\n open: raw['open'] === true && tabs.length > 0,\n width,\n tabs,\n active,\n splitWith,\n splitRatio: Math.min(DOCK_LAYOUT.splitRatio.max, Math.max(DOCK_LAYOUT.splitRatio.min, ratio)),\n };\n}\n","/**\n * routes/verse/dock/dock-store.ts — the chat dock's state and the one-shot\n * requests aimed at its panes (unit C2; contract: shell/dock-catalog.ts).\n *\n * PERSISTENCE. The dock's state belongs in `ashlr.verse.ui.v3`'s `dock`\n * field, and that blob has ONE writer — C1's verse-ui-store — so two stores\n * never race for the key (dock-catalog.ts). This store therefore never\n * writes the key. It:\n * - hydrates itself, read-only, from the v3 blob's `dock` field on first\n * read (through sanitizeDockState — a hand-edited blob cannot break the\n * chat);\n * - exposes getDockState / subscribeDockState, which C1's store folds into\n * the blob it writes (`dock: getDockState()`, re-written on change);\n * - accepts hydrateDockState(raw) when C1 prefers to push the field in.\n *\n * REQUESTS. \"Run in terminal\", a ± count opening the branch diff, Preview's\n * dev-server Start: each is a one-shot request with a nonce (slots.tsx\n * contracts) — the same request twice is two opens. They live here, not in\n * React state, because they are raised from deep inside the transcript\n * (CommandOutput) and consumed by a pane in another subtree.\n *\n * Framework-free; the React glue is useDock() at the bottom.\n */\nimport { useSyncExternalStore } from 'react';\nimport {\n DOCK_LAYOUT,\n VERSE_UI_STORAGE_KEY,\n sanitizeDockState,\n type DockPaneId,\n type DockState,\n} from '../shell/dock-catalog.js';\nimport type { DiffPaneRequest, PreviewOpenRequest, TerminalOpenRequest } from '../shell/slots.js';\n\n/**\n * A terminal request as the dock carries it. C0's TerminalOpenRequest now\n * names the Apps [Launch ▸] fields (`via`, `model`) itself, so this is a\n * plain alias — kept so TerminalPane and the Apps launcher keep one name for\n * \"what the dock hands the Terminal pane\". The server resolves the actual\n * command either way, never the page.\n */\nexport type TerminalRequest = TerminalOpenRequest;\n\nexport interface DockRequests {\n terminal: TerminalRequest | null;\n preview: PreviewOpenRequest | null;\n diff: (DiffPaneRequest & { nonce: number }) | null;\n}\n\nexport interface DockSnapshot {\n state: DockState;\n requests: DockRequests;\n}\n\nconst NO_REQUESTS: DockRequests = { terminal: null, preview: null, diff: null };\n\nlet snapshot: DockSnapshot | null = null;\nlet nonce = 0;\nconst listeners = new Set<() => void>();\n\nfunction readPersisted(): DockState {\n try {\n const raw = localStorage.getItem(VERSE_UI_STORAGE_KEY);\n if (!raw) return sanitizeDockState(null);\n const parsed = JSON.parse(raw) as { dock?: unknown } | null;\n return sanitizeDockState(parsed && typeof parsed === 'object' ? parsed.dock : null);\n } catch {\n return sanitizeDockState(null);\n }\n}\n\nfunction current(): DockSnapshot {\n if (snapshot === null) snapshot = { state: readPersisted(), requests: NO_REQUESTS };\n return snapshot;\n}\n\nfunction emit(next: DockSnapshot): void {\n snapshot = next;\n for (const listener of [...listeners]) listener();\n}\n\nfunction setState(next: DockState): void {\n emit({ ...current(), state: next });\n}\n\nexport function subscribeDockState(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function getDockSnapshot(): DockSnapshot {\n return current();\n}\n\n/** The persistable part — what C1's store writes as the v3 blob's `dock` field. */\nexport function getDockState(): DockState {\n return current().state;\n}\n\n/** C1 may push the persisted field in (on load, or when another tab wrote it). */\nexport function hydrateDockState(raw: unknown): void {\n setState(sanitizeDockState(raw));\n}\n\n/** Test seam: back to defaults with no requests; next read re-hydrates from storage. */\nexport function resetDockStore(): void {\n snapshot = null;\n nonce = 0;\n for (const listener of [...listeners]) listener();\n}\n\n// ---------------------------------------------------------------------------\n// Transitions (pure over DockState, exported for tests)\n// ---------------------------------------------------------------------------\n\n/** Open `pane` (adding its tab) and make it the visible one. */\nexport function withPaneOpen(state: DockState, pane: DockPaneId): DockState {\n const tabs = state.tabs.includes(pane) ? state.tabs : [...state.tabs, pane];\n // Opening the pane that is the split's lower half swaps it to the top.\n const splitWith = state.splitWith === pane ? (state.active !== pane ? state.active : null) : state.splitWith;\n return { ...state, open: true, tabs, active: pane, splitWith: splitWith === pane ? null : splitWith };\n}\n\n/** The pane's toggle: open & focus it, or — when it is already the visible pane — close the dock. */\nexport function withPaneToggled(state: DockState, pane: DockPaneId): DockState {\n if (state.open && (state.active === pane || state.splitWith === pane)) return { ...state, open: false };\n return withPaneOpen(state, pane);\n}\n\nexport function withTabClosed(state: DockState, pane: DockPaneId): DockState {\n const tabs = state.tabs.filter((t) => t !== pane);\n const splitWith = state.splitWith === pane ? null : state.splitWith;\n let active = state.active;\n if (active === pane) {\n // The split's lower pane moves up; otherwise the neighbour tab takes over.\n const index = state.tabs.indexOf(pane);\n active = splitWith ?? tabs[Math.min(index, tabs.length - 1)] ?? null;\n }\n return {\n ...state,\n tabs,\n active,\n splitWith: splitWith === active ? null : splitWith,\n open: tabs.length > 0 && state.open,\n };\n}\n\n/** Split `pane` BELOW the active one (\"Preview over Terminal\"); null un-splits. */\nexport function withSplit(state: DockState, pane: DockPaneId | null): DockState {\n if (pane === null) return { ...state, splitWith: null };\n if (state.active === null || pane === state.active) return state;\n const tabs = state.tabs.includes(pane) ? state.tabs : [...state.tabs, pane];\n return { ...state, open: true, tabs, splitWith: pane };\n}\n\nexport function withWidth(state: DockState, width: number): DockState {\n if (!Number.isFinite(width)) return state;\n return { ...state, width: Math.max(DOCK_LAYOUT.minWidth, Math.round(width)) };\n}\n\nexport function withSplitRatio(state: DockState, ratio: number): DockState {\n if (!Number.isFinite(ratio)) return state;\n const { min, max } = DOCK_LAYOUT.splitRatio;\n return { ...state, splitRatio: Math.min(max, Math.max(min, ratio)) };\n}\n\n// ---------------------------------------------------------------------------\n// Actions\n// ---------------------------------------------------------------------------\n\nexport function openDockPane(pane: DockPaneId): void {\n setState(withPaneOpen(current().state, pane));\n}\n\nexport function toggleDockPane(pane: DockPaneId): void {\n setState(withPaneToggled(current().state, pane));\n}\n\n/** ⌘\\ — show or hide the dock as it was; an empty dock opens on Tasks. */\nexport function toggleDock(): void {\n const state = current().state;\n if (state.open) setState({ ...state, open: false });\n else if (state.tabs.length === 0) setState(withPaneOpen(state, 'tasks'));\n else setState({ ...state, open: true, active: state.active ?? state.tabs[0]! });\n}\n\nexport function closeDock(): void {\n const state = current().state;\n if (state.open) setState({ ...state, open: false });\n}\n\nexport function closeDockTab(pane: DockPaneId): void {\n setState(withTabClosed(current().state, pane));\n}\n\nexport function splitDock(pane: DockPaneId | null): void {\n setState(withSplit(current().state, pane));\n}\n\nexport function setDockWidth(width: number): void {\n setState(withWidth(current().state, width));\n}\n\nexport function setDockSplitRatio(ratio: number): void {\n setState(withSplitRatio(current().state, ratio));\n}\n\n/** Open the Terminal pane with a request (a tab at a root, a pasted command, an app launch). */\nexport function requestTerminal(request: Omit<TerminalRequest, 'nonce'>): void {\n nonce += 1;\n const snap = current();\n emit({ state: withPaneOpen(snap.state, 'terminal'), requests: { ...snap.requests, terminal: { ...request, nonce } } });\n}\n\n/**\n * The same request, but with Terminal as the LOWER half of a split under the\n * pane that is showing (Preview's dev-server Start: the page stays on top and\n * appears when its port answers, the server's output runs underneath — the\n * \"Preview over Terminal\" layout). With nothing showing, or when Terminal is\n * the pane on top, it is a plain open. In the bottom sheet the split's lower\n * pane is mounted but hidden, so the request still runs.\n */\nexport function requestTerminalBelow(request: Omit<TerminalRequest, 'nonce'>): void {\n const snap = current();\n const top = snap.state.open ? snap.state.active : null;\n if (top === null || top === 'terminal') {\n requestTerminal(request);\n return;\n }\n nonce += 1;\n emit({ state: withSplit(snap.state, 'terminal'), requests: { ...snap.requests, terminal: { ...request, nonce } } });\n}\n\nexport function requestPreview(request: Omit<PreviewOpenRequest, 'nonce'>): void {\n nonce += 1;\n const snap = current();\n emit({ state: withPaneOpen(snap.state, 'preview'), requests: { ...snap.requests, preview: { ...request, nonce } } });\n}\n\nexport function requestDiff(request: DiffPaneRequest): void {\n nonce += 1;\n const snap = current();\n emit({ state: withPaneOpen(snap.state, 'diff'), requests: { ...snap.requests, diff: { ...request, nonce } } });\n}\n\n/**\n * Requests are per chat: switching chats must not replay the last chat's\n * terminal paste. Callers clear on a SWITCH only — never on the Chat\n * section's first mount, which is exactly when an Apps [Launch ▸] (raised on\n * another surface, then `setVerseSection('chat')`) is waiting to be served.\n */\nexport function clearDockRequests(): void {\n const snap = current();\n if (snap.requests === NO_REQUESTS) return;\n emit({ ...snap, requests: NO_REQUESTS });\n}\n\nexport function useDock(): DockSnapshot {\n return useSyncExternalStore(subscribeDockState, getDockSnapshot, getDockSnapshot);\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{g as e,s as t}from"./format-BkWdOQDL.js";function n(e){return typeof e==`object`&&e&&!Array.isArray(e)?e:null}function r(e,t){let n=e[t];return typeof n==`string`&&n.length>0?n:null}function i(e,t){let n=e[t];return typeof n==`number`&&Number.isFinite(n)?n:null}function a(e,t){let n=i(e,t);return n===null?null:Math.max(0,Math.round(n))}function o(e,t){let n=e[t];return typeof n==`boolean`?n:null}function s(e,t){let n=e[t];return Array.isArray(n)?n.filter(e=>typeof e==`string`):[]}var c=[`llama-server`,`ollama`,`vllm`,`unknown`],l=[`running`,`starting`,`stopping`,`stopped`,`unknown`],u=[`queued`,`running`,`finishing`],d=[`off`,`config`,`env`,`config+env`,`latch`,`unknown`];function f(e,t,n,r){let i=e[t];return typeof i==`string`&&n.includes(i)?i:r}function p(e){let t=n(e);return t?{capable:o(t,`capable`),refusal:r(t,`refusal`),slots:a(t,`slots`)}:{capable:null,refusal:null,slots:null}}var m={up:`running`,down:`stopped`,loading:`starting`,unknown:`unknown`};function h(e){let t=e.state;if(typeof t!=`string`||!(t in m))return null;let i=n(e.slots),s=r(e,`host`),c=a(e,`port`),l=i?a(i,`configured`):null,u=i?a(i,`busy`):null,d=i?r(i,`source`):null,f=d!==null&&d!==`unknown`,p=f?l:null,h=r(e,`parallelRefusal`),_=r(e,`runtimeKind`),v=a(e,`contextPerSlot`),y=a(e,`contextTotal`);return{kind:_===`ollama`?`ollama`:_===`unknown`?`unknown`:`llama-server`,state:m[t]??`unknown`,endpoint:s!==null&&c!==null?`${s}:${c}`:r(e,`origin`)??null,model:g(r(e,`modelName`))??g(r(e,`model`)),slotsTotal:p,slotsBusy:f?u:null,contextTokens:v??(p!==null&&p>0&&y!==null&&y>0?Math.floor(y/p):null),startedAt:r(e,`startedAt`),parallel:{capable:h===null?f&&p!==null?!0:null:!1,refusal:h,slots:p},reason:r(e,`lastError`),supervised:o(e,`managed`)??!1,sampledAt:r(e,`checkedAt`)}}function g(e){if(e===null||e.length===0)return null;let t=e.split(`/`).pop()??e;return t.length===0||/^sha256[-:][0-9a-f]{16,}$/i.test(t)?null:t}function _(e){let t=n(e);if(!t)return null;if(!(`kind`in t)&&`slots`in t&&`state`in t){let e=h(t);if(e!==null)return e}return{kind:f(t,`kind`,c,`unknown`),state:f(t,`state`,l,`unknown`),endpoint:r(t,`endpoint`),model:r(t,`model`),slotsTotal:a(t,`slotsTotal`),slotsBusy:a(t,`slotsBusy`),contextTokens:a(t,`contextTokens`),startedAt:r(t,`startedAt`),parallel:p(t.parallel),reason:r(t,`reason`),supervised:o(t,`supervised`)??!1,sampledAt:r(t,`sampledAt`)}}function v(e){let t=n(e);if(!t)return null;let i=r(t,`id`);return i===null?null:{id:i,task:r(t,`task`),repo:r(t,`repo`),engine:r(t,`engine`),model:r(t,`model`),state:f(t,`state`,u,`running`),startedAt:r(t,`startedAt`),slot:a(t,`slot`)}}function y(e){let t=n(e);return t?{agents:(Array.isArray(t.agents)?t.agents:[]).map(v).filter(e=>e!==null),queueDepth:a(t,`queueDepth`),slotsTotal:a(t,`slotsTotal`),slotsBusy:a(t,`slotsBusy`),notes:s(t,`notes`),sampledAt:r(t,`sampledAt`)}:null}function b(e){let t=n(e);if(!t)return null;let i=r(t,`engine`);return i===null?null:{engine:i,reason:r(t,`reason`)??`The dispatcher refuses this engine while local-only is on.`}}var x=new Set([`env`,`config+env`,`latch`,`unknown`]);function S(e){let t=n(e);if(!t)return null;let i=Array.isArray(t.refuses)?t.refuses:[],a=f(t,`source`,d,`unknown`);return{enabled:o(t,`enabled`)??!1,source:a,refuses:i.map(b).filter(e=>e!==null),mutable:x.has(a)?!1:o(t,`mutable`)??!1,detail:r(t,`detail`),sampledAt:r(t,`sampledAt`)??r(t,`checkedAt`)}}function C(e){switch(e){case`llama-server`:return`llama-server`;case`ollama`:return`Ollama`;case`vllm`:return`vLLM`;default:return`the serving runtime`}}function w(e){if(e===null)return{verdict:`unknown`,effectiveConcurrency:null,configuredSlots:null,overstated:!1,headline:`No serving runtime reported`,detail:`Nothing answered for the serving runtime, so how many agents can run at once is unknown. That is a missing reading, not an idle machine.`,tone:`unknown`};let t=e.slotsTotal??e.parallel.slots,n=C(e.kind);if(e.state!==`running`)return{verdict:`offline`,effectiveConcurrency:null,configuredSlots:t,overstated:!1,headline:e.state===`stopped`?`Not serving`:`Serving runtime is ${e.state}`,detail:e.state===`stopped`?`${n} is not running, so no local agent can take a turn. Start it before dispatching a fleet.`:`${n} is ${e.state}; capacity is not settled until it reports running.`,tone:e.state===`stopped`?`neutral`:`warning`};if(e.parallel.capable===!1){let e=t!==null&&t>1;return{verdict:`serialized`,effectiveConcurrency:1,configuredSlots:t,overstated:e,headline:`${n} serializes requests`,detail:e?`${n} has ${t} slots configured but runs one request at a time for this model, so the real capacity is one agent. The other ${t-1} would queue, and a queue looks like slowness rather than a wait.`:`${n} runs one request at a time for this model. A second agent waits for the first to finish.`,tone:`danger`}}return e.parallel.capable===null?{verdict:`unknown`,effectiveConcurrency:null,configuredSlots:t,overstated:!1,headline:`Batching not confirmed`,detail:`${n} is running${t===null?``:` with ${t} slots configured`}, but it has not reported whether it batches concurrent requests for this model. Until it does, this panel will not quote a concurrency it cannot stand behind.`,tone:`unknown`}:t===null?{verdict:`batched`,effectiveConcurrency:null,configuredSlots:null,overstated:!1,headline:`${n} batches concurrent requests`,detail:`${n} batches, but reported no slot count, so the ceiling on concurrent agents is unknown.`,tone:`unknown`}:{verdict:`batched`,effectiveConcurrency:t,configuredSlots:t,overstated:!1,headline:`${t} agent${t===1?``:`s`} in parallel`,detail:`${n} batches across ${t} slot${t===1?``:`s`} sharing one copy of the weights, so ${t} agent${t===1?``:`s`} can be mid-turn at once.`,tone:`success`}}var T=[{runtime:`Ollama`,perRequestSeconds:[3.7,7.6,11.4,15.2],wallSeconds:15.2,verdict:`staggered — the requests queued`},{runtime:`llama-server`,perRequestSeconds:[8.6,8.9,9,9],wallSeconds:9.1,verdict:`together — the requests batched`}];function E(t,n){if(t===null||n===null||n<=0)return{busy:t,total:n,percent:null,percentText:null,saturated:!1,label:t===null?`Slot occupancy is not reported.`:`${t} in flight; the number of slots is not known, so occupancy cannot be drawn.`};let r=Math.min(t,n)/n*100,i=Math.round(r),a=t>=n;return{busy:t,total:n,percent:i,percentText:e(r),saturated:a,label:a?`All ${n} slot${n===1?``:`s`} busy — new turns wait for one to free up.`:`${t} of ${n} slot${n===1?``:`s`} busy.`}}function D(e,t,n){if(e===null)return{state:`unknown`,headline:`Fleet not reported`,detail:`No fleet snapshot answered, so what is in flight cannot be listed. That is a missing reading, not an empty fleet.`,tone:`unknown`};let r=e.agents.filter(e=>e.state!==`queued`).length,i=e.queueDepth??e.agents.filter(e=>e.state===`queued`).length;return i>0?{state:`queued`,headline:`${i} waiting for a slot`,detail:n.verdict===`serialized`?`${r} turn${r===1?``:`s`} in flight and ${i} queued. This runtime serializes, so the queue drains one at a time — the wait is a wait, not slow inference.`:`${r} turn${r===1?``:`s`} in flight and ${i} queued behind ${t.total===null?`the available slots`:`${t.total} slots`}. Queued turns have not started; their wall time is queueing, not work.`,tone:`warning`}:r===0?{state:`idle`,headline:`Nothing in flight`,detail:`No agent is mid-turn. The fleet is idle, not stuck.`,tone:`neutral`}:t.saturated?{state:`saturated`,headline:`All slots busy · ${r} in flight`,detail:`Every slot is working and nothing is queued behind them. The next turn will wait, but none is waiting yet.`,tone:`running`}:{state:`working`,headline:`${r} in flight`,detail:t.label,tone:`running`}}var O=`Refused: local-only is on and this engine is not local.`;function k(e,t){let n=t.filter(e=>e.engine!==`local`),r=t.filter(e=>e.engine===`local`),i=new Map;for(let t of e?.refuses??[])i.set(t.engine,t.reason);return{blocked:n,allowed:r,refusalFor:e=>i.get(e)??O,summary:t.length===0?`No seats are configured, so there is nothing for this policy to block yet.`:n.length===0?`Every one of your ${t.length} seat${t.length===1?``:`s`} is local, so this policy would block nothing today.`:`${n.length} of ${t.length} seat${t.length===1?``:`s`} would become unreachable; ${r.length} local seat${r.length===1?``:`s`} would keep working.`}}function A(e){if(e===null)return null;if(e.detail!==null)return e.detail;switch(e.source){case`env`:case`config+env`:return`This policy is pinned by an environment variable on the server process, so it cannot be changed from here — restart the server without it to take the switch back.`;case`latch`:return`This process already observed a persisted local-only and has pinned it for its own lifetime, so turning it off takes effect for new dispatches but not for the seams that latched. Restart the server to clear it.`;case`config`:return`Stored in the hub config and applied on the next dispatch.`;case`off`:return`Not configured; cloud engines are reachable.`;default:return`The server did not say where this setting came from.`}}function j(e,n){if(!e)return`—`;let r=Date.parse(e);return Number.isNaN(r)?`—`:t(Math.max(0,n-r))}function M(e,n){if(!e)return`—`;let r=Date.parse(e);return Number.isNaN(r)?`—`:`up ${t(Math.max(0,n-r))}`}function N(e){return e===null||!Number.isFinite(e)?`—`:e>=1024?`${Math.round(e/1024)}k`:String(e)}function P(e){let t={running:0,finishing:1,queued:2};return[...e].sort((e,n)=>{let r=t[e.state]-t[n.state];if(r!==0)return r;let i=e.startedAt?Date.parse(e.startedAt):NaN,a=n.startedAt?Date.parse(n.startedAt):NaN;return Number.isNaN(i)&&Number.isNaN(a)?e.id.localeCompare(n.id):Number.isNaN(i)?1:Number.isNaN(a)?-1:i-a})}export{M as a,P as c,_ as d,w as f,N as i,y as l,E as m,j as n,k as o,C as p,D as r,A as s,T as t,S as u};
2
- //# sourceMappingURL=fleet-model-7i-FbzKI.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fleet-model-7i-FbzKI.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/autonomy/fleet-model.ts"],"sourcesContent":["/**\n * routes/verse/autonomy/fleet-model.ts — every derivation the local-fleet\n * surfaces make, as pure functions. No React, no I/O, so the rules that decide\n * what the operator is told are unit-testable without a DOM.\n *\n * The one rule this file exists to enforce:\n *\n * **A concurrency number the runtime will not honour is a lie, and the UI\n * must print the truth instead of the configuration.**\n *\n * That is not a hypothetical. Measured on this machine (docs/LOCAL-FLEET.md),\n * four concurrent Qwen3.8 requests to Ollama returned at 3.7 / 7.6 / 11.4 /\n * 15.2s — a four-second stagger, which is a queue. The same weights on\n * llama-server returned at 8.6 / 8.9 / 9.0 / 9.0s: continuous batching across\n * four slots sharing one 27 GB copy. Ollama's log calls it a refusal\n * (`model architecture does not currently support parallel requests`) and\n * `OLLAMA_NUM_PARALLEL` does not move it.\n *\n * So `runtimeCapacity()` never reports `slotsTotal` as capacity unless the\n * runtime says it batches. When a runtime that serializes is configured with\n * four slots, the capacity is ONE and `overstated` is true, and the panel says\n * so in words. A queue that looks like slowness is the exact failure this\n * surface is here to prevent.\n *\n * The bodies these functions narrow come from routes that are landing in\n * parallel (see fleet-contract.ts), so everything is projected STRUCTURALLY\n * rather than cast: a field-name drift degrades to an honest \"unknown\" at\n * render time instead of throwing.\n */\nimport { UNKNOWN, formatDuration, percentText } from './format.js';\nimport type {\n FleetAgent,\n FleetAgentState,\n FleetSnapshot,\n LocalOnlyPolicy,\n LocalOnlyRefusal,\n LocalOnlySource,\n ServingRuntimeKind,\n ServingRuntimeParallelism,\n ServingRuntimeSnapshot,\n ServingRuntimeState,\n} from './fleet-contract.js';\n\n// ---------------------------------------------------------------------------\n// Structural narrowing\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\n/** A count that is meaningful at zero — so 0 stays 0 and absent stays null. */\nfunction count(source: Record<string, unknown>, key: string): number | null {\n const v = num(source, key);\n return v === null ? null : Math.max(0, Math.round(v));\n}\n\nfunction bool(source: Record<string, unknown>, key: string): boolean | null {\n const v = source[key];\n return typeof v === 'boolean' ? v : null;\n}\n\nfunction strings(source: Record<string, unknown>, key: string): string[] {\n const v = source[key];\n return Array.isArray(v) ? v.filter((entry): entry is string => typeof entry === 'string') : [];\n}\n\nconst RUNTIME_KINDS: readonly ServingRuntimeKind[] = ['llama-server', 'ollama', 'vllm', 'unknown'];\nconst RUNTIME_STATES: readonly ServingRuntimeState[] = [\n 'running',\n 'starting',\n 'stopping',\n 'stopped',\n 'unknown',\n];\nconst AGENT_STATES: readonly FleetAgentState[] = ['queued', 'running', 'finishing'];\nconst LOCAL_ONLY_SOURCES: readonly LocalOnlySource[] = [\n 'off',\n 'config',\n 'env',\n 'config+env',\n 'latch',\n 'unknown',\n];\n\nfunction oneOf<T extends string>(\n source: Record<string, unknown>,\n key: string,\n allowed: readonly T[],\n fallback: T,\n): T {\n const v = source[key];\n return typeof v === 'string' && (allowed as readonly string[]).includes(v) ? (v as T) : fallback;\n}\n\nfunction projectParallelism(raw: unknown): ServingRuntimeParallelism {\n const r = record(raw);\n if (!r) return { capable: null, refusal: null, slots: null };\n return { capable: bool(r, 'capable'), refusal: str(r, 'refusal'), slots: count(r, 'slots') };\n}\n\n/**\n * Owner R's `LlamaRuntimeSnapshot` (`src/core/local-runtime/llama/types.ts`)\n * spells the same facts differently, and the route that serves it is not\n * written yet — so rather than betting on one envelope, this reads both.\n *\n * The mapping, with the two judgement calls stated:\n *\n * - `state: 'up' | 'down' | 'loading' | 'unknown'` → running / stopped /\n * starting / unknown.\n * - `contextPerSlot` wins over `contextTotal`. `-c 65536 --parallel 4` gives\n * each slot 16k, and the number an agent's turn actually runs in is the\n * per-slot one. Quoting the total would overstate every agent's context\n * fourfold — the same class of error as quoting slots as concurrency.\n * - `managed` → `supervised`. R is explicit that an unmanaged server may be\n * adopted but is \"never killed on a guess\", which is exactly the condition\n * under which this panel must not offer a stop button.\n */\nconst LLAMA_STATE: Readonly<Record<string, ServingRuntimeState>> = {\n up: 'running',\n down: 'stopped',\n loading: 'starting',\n unknown: 'unknown',\n};\n\nfunction projectLlamaShape(r: Record<string, unknown>): ServingRuntimeSnapshot | null {\n const rawState = r['state'];\n if (typeof rawState !== 'string' || !(rawState in LLAMA_STATE)) return null;\n const slots = record(r['slots']);\n const host = str(r, 'host');\n const port = count(r, 'port');\n const configured = slots ? count(slots, 'configured') : null;\n const busy = slots ? count(slots, 'busy') : null;\n // `slots.source` is R's own trust marker: 'unknown' means \"do not trust a\n // number\", so a slot count carrying it is dropped rather than quoted.\n const slotSource = slots ? str(slots, 'source') : null;\n const trusted = slotSource !== null && slotSource !== 'unknown';\n const total = trusted ? configured : null;\n\n const refusal = str(r, 'parallelRefusal');\n const identity = str(r, 'runtimeKind');\n const contextPerSlot = count(r, 'contextPerSlot');\n const contextTotal = count(r, 'contextTotal');\n\n return {\n // IDENTIFIED where the producer says so. A base URL pointed at Ollama's\n // /v1 answers /v1/models — enough to keep the engine routable — while\n // 404ing /health and /props, and asserting 'llama-server' for it would\n // hide the one fact that matters: that runtime serialises this model.\n kind: identity === 'ollama' ? 'ollama' : identity === 'unknown' ? 'unknown' : 'llama-server',\n state: LLAMA_STATE[rawState] ?? 'unknown',\n endpoint: host !== null && port !== null ? `${host}:${port}` : (str(r, 'origin') ?? null),\n // A digest is not a name. `modelName` falls back to `model_path`'s basename\n // at the producer, which for a blob out of Ollama's content-addressed store\n // is `sha256-…`: it identifies the machine's storage layout and names\n // nothing. Null renders as \"unknown\", which is the honest answer.\n model: humaneModelName(str(r, 'modelName')) ?? humaneModelName(str(r, 'model')),\n slotsTotal: total,\n slotsBusy: trusted ? busy : null,\n // PER-SLOT, or nothing. `-c 65536 --parallel 4` gives each agent 16k, so\n // the `-c` total is usable only divided by a slot count we trust.\n contextTokens:\n contextPerSlot ??\n (total !== null && total > 0 && contextTotal !== null && contextTotal > 0\n ? Math.floor(contextTotal / total)\n : null),\n startedAt: str(r, 'startedAt'),\n parallel: {\n // llama-server's slots ARE its continuous-batching slots: a count read\n // back off the live server (`/props.total_slots`, `/slots`) is a count\n // of requests it will run at the same time, which is what the\n // measurement in docs/LOCAL-FLEET.md showed. An untrusted or absent\n // reading claims nothing — `null`, not `true`.\n capable: refusal !== null ? false : trusted && total !== null ? true : null,\n // The runtime's own words when it refuses, carried verbatim as evidence.\n refusal,\n slots: total,\n },\n reason: str(r, 'lastError'),\n supervised: bool(r, 'managed') ?? false,\n sampledAt: str(r, 'checkedAt'),\n };\n}\n\n/** A displayable model name, or null for an absent or digest-shaped one. */\nfunction humaneModelName(raw: string | null): string | null {\n if (raw === null || raw.length === 0) return null;\n const base = raw.split('/').pop() ?? raw;\n if (base.length === 0) return null;\n if (/^sha256[-:][0-9a-f]{16,}$/i.test(base)) return null;\n return base;\n}\n\nexport function projectServingRuntime(raw: unknown): ServingRuntimeSnapshot | null {\n const r = record(raw);\n if (!r) return null;\n // A body already in this surface's own shape wins; otherwise try owner R's.\n if (!('kind' in r) && 'slots' in r && 'state' in r) {\n const llama = projectLlamaShape(r);\n if (llama !== null) return llama;\n }\n return {\n kind: oneOf(r, 'kind', RUNTIME_KINDS, 'unknown'),\n state: oneOf(r, 'state', RUNTIME_STATES, 'unknown'),\n endpoint: str(r, 'endpoint'),\n model: str(r, 'model'),\n slotsTotal: count(r, 'slotsTotal'),\n slotsBusy: count(r, 'slotsBusy'),\n contextTokens: count(r, 'contextTokens'),\n startedAt: str(r, 'startedAt'),\n parallel: projectParallelism(r['parallel']),\n reason: str(r, 'reason'),\n // A runtime this server cannot supervise must not be offered buttons, so\n // an unreported flag reads as NOT supervised. The conservative default is\n // \"no controls\" rather than controls that 404 on the first click.\n supervised: bool(r, 'supervised') ?? false,\n sampledAt: str(r, 'sampledAt'),\n };\n}\n\nfunction projectAgent(raw: unknown): FleetAgent | null {\n const r = record(raw);\n if (!r) return null;\n const id = str(r, 'id');\n if (id === null) return null;\n return {\n id,\n task: str(r, 'task'),\n repo: str(r, 'repo'),\n engine: str(r, 'engine'),\n model: str(r, 'model'),\n state: oneOf(r, 'state', AGENT_STATES, 'running'),\n startedAt: str(r, 'startedAt'),\n slot: count(r, 'slot'),\n };\n}\n\nexport function projectFleet(raw: unknown): FleetSnapshot | null {\n const r = record(raw);\n if (!r) return null;\n const rawAgents = Array.isArray(r['agents']) ? (r['agents'] as unknown[]) : [];\n return {\n agents: rawAgents.map(projectAgent).filter((a): a is FleetAgent => a !== null),\n queueDepth: count(r, 'queueDepth'),\n slotsTotal: count(r, 'slotsTotal'),\n slotsBusy: count(r, 'slotsBusy'),\n notes: strings(r, 'notes'),\n sampledAt: str(r, 'sampledAt'),\n };\n}\n\nfunction projectRefusal(raw: unknown): LocalOnlyRefusal | null {\n const r = record(raw);\n if (!r) return null;\n const engine = str(r, 'engine');\n if (engine === null) return null;\n return { engine, reason: str(r, 'reason') ?? 'The dispatcher refuses this engine while local-only is on.' };\n}\n\n/**\n * `source` is carried through as the resolver's own value — it is no longer\n * flattened onto a smaller union here.\n *\n * The flattening this replaced mapped `'latch'` onto `'config'`, which tells\n * an operator the mode is stored in the config and editable when in fact the\n * process has pinned it for its own lifetime. Only the separate `mutable`\n * flag kept that from reaching the screen as a working switch that silently\n * does nothing. An unrecognised value lands on `'unknown'`, which makes no\n * claim at all.\n */\n/** Sources that pin the mode to this server process, whatever the config says. */\nconst PINNED_SOURCES: ReadonlySet<LocalOnlySource> = new Set<LocalOnlySource>([\n 'env',\n 'config+env',\n 'latch',\n 'unknown',\n]);\n\nexport function projectLocalOnly(raw: unknown): LocalOnlyPolicy | null {\n const r = record(raw);\n if (!r) return null;\n const rawRefusals = Array.isArray(r['refuses']) ? (r['refuses'] as unknown[]) : [];\n const source = oneOf(r, 'source', LOCAL_ONLY_SOURCES, 'unknown');\n return {\n // An unreported `enabled` is NOT \"on\": claiming cloud is unreachable when\n // the server never said so is the one error this policy cannot afford.\n enabled: bool(r, 'enabled') ?? false,\n source,\n refuses: rawRefusals.map(projectRefusal).filter((x): x is LocalOnlyRefusal => x !== null),\n // A policy pinned by the server's own process — an env var, or a latch\n // this process already took — is never editable from here, whatever the\n // body claims: a write would be silently overridden on the next read.\n // `'unknown'` is treated as pinned too, because offering a switch for a\n // policy this client cannot identify is the more expensive mistake.\n mutable: PINNED_SOURCES.has(source) ? false : (bool(r, 'mutable') ?? false),\n detail: str(r, 'detail'),\n sampledAt: str(r, 'sampledAt') ?? str(r, 'checkedAt'),\n };\n}\n\n// ---------------------------------------------------------------------------\n// The capacity verdict — the point of this whole file\n// ---------------------------------------------------------------------------\n\nexport type CapacityVerdict = 'batched' | 'serialized' | 'unknown' | 'offline';\n\nexport interface RuntimeCapacity {\n verdict: CapacityVerdict;\n /**\n * How many agents can genuinely be in flight at once. `null` means it\n * cannot be known from this reading — which is NOT the same as 0 and must\n * never render as a number.\n */\n effectiveConcurrency: number | null;\n /** What the runtime was configured with, honoured or not. */\n configuredSlots: number | null;\n /**\n * True when the configured slot count is larger than what the runtime will\n * actually run in parallel. While this is true, the configured number must\n * not be presented as capacity anywhere on the screen.\n */\n overstated: boolean;\n headline: string;\n detail: string;\n tone: 'success' | 'warning' | 'danger' | 'neutral' | 'unknown';\n}\n\n/** Human name for a runtime, used in sentences. */\nexport function runtimeLabel(kind: ServingRuntimeKind): string {\n switch (kind) {\n case 'llama-server':\n return 'llama-server';\n case 'ollama':\n return 'Ollama';\n case 'vllm':\n return 'vLLM';\n default:\n return 'the serving runtime';\n }\n}\n\nexport function runtimeCapacity(runtime: ServingRuntimeSnapshot | null): RuntimeCapacity {\n if (runtime === null) {\n return {\n verdict: 'unknown',\n effectiveConcurrency: null,\n configuredSlots: null,\n overstated: false,\n headline: 'No serving runtime reported',\n detail:\n 'Nothing answered for the serving runtime, so how many agents can run at once is unknown. That is a missing reading, not an idle machine.',\n tone: 'unknown',\n };\n }\n\n const configured = runtime.slotsTotal ?? runtime.parallel.slots;\n const name = runtimeLabel(runtime.kind);\n\n if (runtime.state !== 'running') {\n return {\n verdict: 'offline',\n effectiveConcurrency: null,\n configuredSlots: configured,\n overstated: false,\n headline: runtime.state === 'stopped' ? 'Not serving' : `Serving runtime is ${runtime.state}`,\n detail:\n runtime.state === 'stopped'\n ? `${name} is not running, so no local agent can take a turn. Start it before dispatching a fleet.`\n : `${name} is ${runtime.state}; capacity is not settled until it reports running.`,\n tone: runtime.state === 'stopped' ? 'neutral' : 'warning',\n };\n }\n\n if (runtime.parallel.capable === false) {\n // The measured case. The configured number is real — it is simply not a\n // concurrency, and printing it as one is the failure mode this exists for.\n const overstated = configured !== null && configured > 1;\n return {\n verdict: 'serialized',\n effectiveConcurrency: 1,\n configuredSlots: configured,\n overstated,\n headline: `${name} serializes requests`,\n detail: overstated\n ? `${name} has ${configured} slots configured but runs one request at a time for this model, so the real capacity is one agent. The other ${configured - 1} would queue, and a queue looks like slowness rather than a wait.`\n : `${name} runs one request at a time for this model. A second agent waits for the first to finish.`,\n tone: 'danger',\n };\n }\n\n if (runtime.parallel.capable === null) {\n return {\n verdict: 'unknown',\n effectiveConcurrency: null,\n configuredSlots: configured,\n overstated: false,\n headline: 'Batching not confirmed',\n detail: `${name} is running${\n configured === null ? '' : ` with ${configured} slots configured`\n }, but it has not reported whether it batches concurrent requests for this model. Until it does, this panel will not quote a concurrency it cannot stand behind.`,\n tone: 'unknown',\n };\n }\n\n if (configured === null) {\n return {\n verdict: 'batched',\n effectiveConcurrency: null,\n configuredSlots: null,\n overstated: false,\n headline: `${name} batches concurrent requests`,\n detail: `${name} batches, but reported no slot count, so the ceiling on concurrent agents is unknown.`,\n tone: 'unknown',\n };\n }\n\n return {\n verdict: 'batched',\n effectiveConcurrency: configured,\n configuredSlots: configured,\n overstated: false,\n headline: `${configured} agent${configured === 1 ? '' : 's'} in parallel`,\n detail: `${name} batches across ${configured} slot${\n configured === 1 ? '' : 's'\n } sharing one copy of the weights, so ${configured} agent${\n configured === 1 ? '' : 's'\n } can be mid-turn at once.`,\n tone: 'success',\n };\n}\n\n/**\n * The measured comparison, kept as data so the panel renders it as evidence\n * rather than as an assertion in prose. Source: docs/LOCAL-FLEET.md, four\n * concurrent requests against the same Qwen3.8 GGUF on this machine.\n */\nexport interface ConcurrencyEvidenceRow {\n runtime: string;\n /** Per-request completion times, in seconds, in the order they returned. */\n perRequestSeconds: readonly number[];\n wallSeconds: number;\n verdict: string;\n}\n\nexport const CONCURRENCY_EVIDENCE: readonly ConcurrencyEvidenceRow[] = [\n {\n runtime: 'Ollama',\n perRequestSeconds: [3.7, 7.6, 11.4, 15.2],\n wallSeconds: 15.2,\n verdict: 'staggered — the requests queued',\n },\n {\n runtime: 'llama-server',\n perRequestSeconds: [8.6, 8.9, 9.0, 9.0],\n wallSeconds: 9.1,\n verdict: 'together — the requests batched',\n },\n] as const;\n\n// ---------------------------------------------------------------------------\n// Utilisation\n// ---------------------------------------------------------------------------\n\nexport interface SlotUtilisation {\n busy: number | null;\n total: number | null;\n /** 0–100, or null when either half is unknown. */\n percent: number | null;\n /** The share in words, by the one percent rule (\"<1%\", \"99%\"); null when unknown. */\n percentText: string | null;\n /** Every slot is taken: the next turn waits. */\n saturated: boolean;\n /** One line, safe to render on its own. */\n label: string;\n}\n\n/**\n * Slot occupancy.\n *\n * `total` is the EFFECTIVE concurrency, not the configured slot count — on a\n * runtime that serializes, one busy slot out of four configured is full, and\n * drawing it as 25% would tell the operator there is room when there is none.\n */\nexport function slotUtilisation(busy: number | null, effectiveTotal: number | null): SlotUtilisation {\n if (busy === null || effectiveTotal === null || effectiveTotal <= 0) {\n return {\n busy,\n total: effectiveTotal,\n percent: null,\n percentText: null,\n saturated: false,\n label:\n busy === null\n ? 'Slot occupancy is not reported.'\n : `${busy} in flight; the number of slots is not known, so occupancy cannot be drawn.`,\n };\n }\n const clamped = Math.min(busy, effectiveTotal);\n const share = (clamped / effectiveTotal) * 100;\n const percent = Math.round(share);\n const saturated = busy >= effectiveTotal;\n return {\n busy,\n total: effectiveTotal,\n percent,\n percentText: percentText(share),\n saturated,\n label: saturated\n ? `All ${effectiveTotal} slot${effectiveTotal === 1 ? '' : 's'} busy — new turns wait for one to free up.`\n : `${busy} of ${effectiveTotal} slot${effectiveTotal === 1 ? '' : 's'} busy.`,\n };\n}\n\n/**\n * What the operator is actually waiting on.\n *\n * Saturation alone is not bad news — a fleet at full occupancy is a fleet\n * working. Saturation WITH a queue is the thing to say plainly, because from\n * the outside it is indistinguishable from the machine being slow.\n */\nexport interface FleetPressure {\n state: 'idle' | 'working' | 'saturated' | 'queued' | 'unknown';\n headline: string;\n detail: string;\n tone: 'success' | 'running' | 'warning' | 'neutral' | 'unknown';\n}\n\nexport function fleetPressure(\n fleet: FleetSnapshot | null,\n utilisation: SlotUtilisation,\n capacity: RuntimeCapacity,\n): FleetPressure {\n if (fleet === null) {\n return {\n state: 'unknown',\n headline: 'Fleet not reported',\n detail:\n 'No fleet snapshot answered, so what is in flight cannot be listed. That is a missing reading, not an empty fleet.',\n tone: 'unknown',\n };\n }\n\n const running = fleet.agents.filter((a) => a.state !== 'queued').length;\n const queued = fleet.queueDepth ?? fleet.agents.filter((a) => a.state === 'queued').length;\n\n if (queued > 0) {\n return {\n state: 'queued',\n headline: `${queued} waiting for a slot`,\n detail:\n capacity.verdict === 'serialized'\n ? `${running} turn${running === 1 ? '' : 's'} in flight and ${queued} queued. This runtime serializes, so the queue drains one at a time — the wait is a wait, not slow inference.`\n : `${running} turn${running === 1 ? '' : 's'} in flight and ${queued} queued behind ${\n utilisation.total === null ? 'the available slots' : `${utilisation.total} slots`\n }. Queued turns have not started; their wall time is queueing, not work.`,\n tone: 'warning',\n };\n }\n\n if (running === 0) {\n return {\n state: 'idle',\n headline: 'Nothing in flight',\n detail: 'No agent is mid-turn. The fleet is idle, not stuck.',\n tone: 'neutral',\n };\n }\n\n if (utilisation.saturated) {\n return {\n state: 'saturated',\n headline: `All slots busy · ${running} in flight`,\n detail: `Every slot is working and nothing is queued behind them. The next turn will wait, but none is waiting yet.`,\n tone: 'running',\n };\n }\n\n return {\n state: 'working',\n headline: `${running} in flight`,\n detail: utilisation.label,\n tone: 'running',\n };\n}\n\n// ---------------------------------------------------------------------------\n// Local-only impact\n// ---------------------------------------------------------------------------\n\nexport interface SeatLike {\n id: string;\n engine: string;\n label: string;\n}\n\nexport interface LocalOnlyImpact {\n /** Seats that become unreachable while the policy is on. */\n blocked: SeatLike[];\n /** Seats unaffected — the local ones. */\n allowed: SeatLike[];\n /** The named refusal per blocked engine, from the server when it sent one. */\n refusalFor: (engine: string) => string;\n /** One line summarising the blast radius against the CURRENT seat roster. */\n summary: string;\n}\n\nconst DEFAULT_REFUSAL = 'Refused: local-only is on and this engine is not local.';\n\n/**\n * What local-only would block, measured against the seats that actually exist\n * on this machine right now.\n *\n * Deliberately computed from the live roster rather than from a fixed list of\n * cloud engines: the sentence \"this would block 3 of your 5 seats\" is only\n * trustworthy if the 5 is the operator's own number.\n */\nexport function localOnlyImpact(\n policy: LocalOnlyPolicy | null,\n seats: readonly SeatLike[],\n): LocalOnlyImpact {\n const blocked = seats.filter((s) => s.engine !== 'local');\n const allowed = seats.filter((s) => s.engine === 'local');\n const byEngine = new Map<string, string>();\n for (const refusal of policy?.refuses ?? []) byEngine.set(refusal.engine, refusal.reason);\n\n const summary =\n seats.length === 0\n ? 'No seats are configured, so there is nothing for this policy to block yet.'\n : blocked.length === 0\n ? `Every one of your ${seats.length} seat${seats.length === 1 ? '' : 's'} is local, so this policy would block nothing today.`\n : `${blocked.length} of ${seats.length} seat${seats.length === 1 ? '' : 's'} would become unreachable; ${allowed.length} local seat${allowed.length === 1 ? '' : 's'} would keep working.`;\n\n return {\n blocked,\n allowed,\n refusalFor: (engine: string) => byEngine.get(engine) ?? DEFAULT_REFUSAL,\n summary,\n };\n}\n\n/** Where the policy came from, as a sentence an operator can act on. */\nexport function localOnlySourceNote(policy: LocalOnlyPolicy | null): string | null {\n if (policy === null) return null;\n // The policy's own sentence, when it wrote one. It knows things this client\n // does not — e.g. that an env var tried and failed to clear a persisted\n // local-only — and a template would erase exactly that.\n if (policy.detail !== null) return policy.detail;\n switch (policy.source) {\n case 'env':\n case 'config+env':\n return 'This policy is pinned by an environment variable on the server process, so it cannot be changed from here — restart the server without it to take the switch back.';\n case 'latch':\n return 'This process already observed a persisted local-only and has pinned it for its own lifetime, so turning it off takes effect for new dispatches but not for the seams that latched. Restart the server to clear it.';\n case 'config':\n return 'Stored in the hub config and applied on the next dispatch.';\n case 'off':\n return 'Not configured; cloud engines are reachable.';\n default:\n return 'The server did not say where this setting came from.';\n }\n}\n\n// ---------------------------------------------------------------------------\n// Small formatters\n// ---------------------------------------------------------------------------\n\n/** \"4m 12s\" since an ISO instant, against a live clock. Absent stays absent. */\nexport function elapsedSince(iso: string | null, now: number): string {\n if (!iso) return UNKNOWN;\n const at = Date.parse(iso);\n if (Number.isNaN(at)) return UNKNOWN;\n return formatDuration(Math.max(0, now - at));\n}\n\n/** Uptime for the runtime header. Same rules, different words. */\nexport function formatUptime(startedAt: string | null, now: number): string {\n if (!startedAt) return UNKNOWN;\n const at = Date.parse(startedAt);\n if (Number.isNaN(at)) return UNKNOWN;\n return `up ${formatDuration(Math.max(0, now - at))}`;\n}\n\n/**\n * Context windows are quoted in powers of two everywhere the operator has\n * seen them (65536 is \"64k\"), so the divisor is 1024. Matching\n * `usage/local-model.ts`'s `formatContext` on purpose: two spellings of the\n * same number across two panels is how a UI starts to feel untrustworthy.\n */\nexport function formatContextTokens(tokens: number | null): string {\n if (tokens === null || !Number.isFinite(tokens)) return UNKNOWN;\n if (tokens >= 1024) return `${Math.round(tokens / 1024)}k`;\n return String(tokens);\n}\n\n/** Agent rows, ordered so the reader's first question is answered first. */\nexport function orderAgents(agents: readonly FleetAgent[]): FleetAgent[] {\n const rank: Record<FleetAgentState, number> = { running: 0, finishing: 1, queued: 2 };\n return [...agents].sort((a, b) => {\n const byState = rank[a.state] - rank[b.state];\n if (byState !== 0) return byState;\n // Longest-running first: the one most likely to be stuck is the one an\n // operator scanning this table is looking for.\n const at = a.startedAt ? Date.parse(a.startedAt) : Number.NaN;\n const bt = b.startedAt ? Date.parse(b.startedAt) : Number.NaN;\n if (Number.isNaN(at) && Number.isNaN(bt)) return a.id.localeCompare(b.id);\n if (Number.isNaN(at)) return 1;\n if (Number.isNaN(bt)) return -1;\n return at - bt;\n });\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{a as e,s as t}from"./index-BVxOlseC.js";import{D as n,F as r,U as i,c as a,l as o,m as s,o as c}from"./global-oEl9Qj8u.js";import{n as l,t as u}from"./control-queries-CmgBgKV7.js";import{d,l as f,u as p}from"./fleet-model-7i-FbzKI.js";var m=t(e(),1),h=`verse-runtime`,g=`verse-fleet`,_=`verse-local-only`;function v(e,t){return t instanceof c?t.status===404?`This server does not expose ${e}, so this panel has no source. It is a missing route, not an idle machine.`:`${e} answered HTTP ${t.status}.`:`${e} could not be reached.`}function y(e,t){return async n=>{try{let r=t(await a(e,n));return r===null?{value:null,available:!0,reason:`${e} answered in a shape this client does not recognise, so nothing is shown rather than guessed.`}:{value:r,available:!0,reason:null}}catch(t){if(t instanceof c&&t.status===401||t instanceof DOMException&&t.name===`AbortError`)throw t;return{value:null,available:!1,reason:v(e,t)}}}}var b={key:h,fetch:y(`/api/verse/runtime`,d)},x={key:g,fetch:y(`/api/verse/fleet`,f)},S={key:_,fetch:y(`/api/verse/local-only`,p)};async function C(e,t){let i=n();if(!i)throw new l;let a=await o(e,t,i);return r(),a}async function w(e){let t=await C(`/api/verse/runtime`,{action:e});return i(h),i(g),i(u),t}async function T(e){let t=await C(`/api/verse/local-only`,{enabled:e});return i(_),i(u),t}var E=4e3;function D(e=E){let t=s(b),n=s(x);(0,m.useEffect)(()=>{let r=null,i=()=>{t(),n()},a=()=>{r===null&&(r=setInterval(i,e))},o=()=>{r!==null&&(clearInterval(r),r=null)},s=()=>{if(document.visibilityState===`hidden`){o();return}i(),a()};return document.visibilityState!==`hidden`&&a(),document.addEventListener(`visibilitychange`,s),()=>{o(),document.removeEventListener(`visibilitychange`,s)}},[e,t,n])}export{b as a,w as i,x as n,T as o,S as r,D as s,g as t};
2
- //# sourceMappingURL=fleet-queries-DzGoqq8X.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"fleet-queries-DzGoqq8X.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/autonomy/fleet-queries.ts"],"sourcesContent":["/**\n * routes/verse/autonomy/fleet-queries.ts — the reads and writes behind the\n * local-fleet surfaces: `GET/POST /api/verse/runtime`,\n * `GET/POST /api/verse/local-only`, and `GET /api/verse/fleet`.\n *\n * Same contract as control-queries.ts — reads are QueryDefs consumed through\n * useQuery, writes go through the mutation-token gate and invalidate exactly\n * the keys they affect — with two differences that both come from these three\n * routes landing in parallel with this surface (owners R, L, F):\n *\n * 1. **The reads do not throw on absence.** A server without these routes\n * answers 404, and a 404 means \"this panel has no source yet\", not\n * \"Autonomy is broken\". The panels render a designed degraded state from\n * `OptionalFleetRead.reason`. 401 still propagates: an expired read\n * session is an unauthorized state for the whole surface.\n * 2. **The bodies are narrowed structurally, not cast.** `fleet-model.ts`\n * projects every field, so a name drift between the route and this client\n * degrades to \"unknown\" rather than throwing at render time.\n *\n * Polling: the fleet and the runtime are the two things on this screen that\n * change while nobody clicks anything, and neither has an SSE event yet, so\n * `useFleetPolling` re-reads them on an interval — pausing while the tab is\n * hidden, because a background tab polling a runtime probe is pure waste.\n */\nimport { useEffect } from 'react';\nimport { ApiError, apiGet, apiPost } from '../../../data/client.js';\nimport { getMutationToken, touchMutationHold } from '../../../data/auth-store.js';\nimport { invalidate } from '../../../data/cache.js';\nimport type { QueryDef } from '../../../data/queries.js';\nimport { useRefetch } from '../../../data/hooks.js';\nimport { VERSE_CONTROL_KEY, VerseControlLockedError } from './control-queries.js';\nimport type {\n FleetSnapshot,\n LocalOnlyPolicy,\n LocalOnlyUpdateResult,\n OptionalFleetRead,\n RuntimeAction,\n RuntimeActionResult,\n ServingRuntimeSnapshot,\n} from './fleet-contract.js';\nimport { projectFleet, projectLocalOnly, projectServingRuntime } from './fleet-model.js';\n\nexport const VERSE_RUNTIME_KEY = 'verse-runtime';\nexport const VERSE_FLEET_KEY = 'verse-fleet';\nexport const VERSE_LOCAL_ONLY_KEY = 'verse-local-only';\n\nfunction describeAbsence(path: string, err: unknown): string {\n if (err instanceof ApiError) {\n if (err.status === 404) {\n return `This server does not expose ${path}, so this panel has no source. It is a missing route, not an idle machine.`;\n }\n return `${path} answered HTTP ${err.status}.`;\n }\n return `${path} could not be reached.`;\n}\n\n/**\n * One optional read, projected. `value` is null both when the route was absent\n * and when it answered something this client could not narrow — `available`\n * and `reason` are what tell the two apart.\n */\nfunction optionalRead<T>(\n path: string,\n project: (raw: unknown) => T | null,\n): (signal?: AbortSignal) => Promise<OptionalFleetRead<T>> {\n return async (signal) => {\n try {\n const raw = await apiGet<unknown>(path, signal);\n const value = project(raw);\n if (value === null) {\n return {\n value: null,\n available: true,\n reason: `${path} answered in a shape this client does not recognise, so nothing is shown rather than guessed.`,\n };\n }\n return { value, 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 { value: null, available: false, reason: describeAbsence(path, err) };\n }\n };\n}\n\n/** GET /api/verse/runtime — is the serving runtime up, and what can it do. */\nexport const servingRuntimeQuery: QueryDef<OptionalFleetRead<ServingRuntimeSnapshot>> = {\n key: VERSE_RUNTIME_KEY,\n fetch: optionalRead('/api/verse/runtime', projectServingRuntime),\n};\n\n/** GET /api/verse/fleet — the agents in flight right now. */\nexport const fleetQuery: QueryDef<OptionalFleetRead<FleetSnapshot>> = {\n key: VERSE_FLEET_KEY,\n fetch: optionalRead('/api/verse/fleet', projectFleet),\n};\n\n/** GET /api/verse/local-only — the refusal policy and what it refuses. */\nexport const localOnlyQuery: QueryDef<OptionalFleetRead<LocalOnlyPolicy>> = {\n key: VERSE_LOCAL_ONLY_KEY,\n fetch: optionalRead('/api/verse/local-only', projectLocalOnly),\n};\n\n// ---------------------------------------------------------------------------\n// Writes\n// ---------------------------------------------------------------------------\n\nasync function post<T>(path: string, body: unknown): Promise<T> {\n const token = getMutationToken();\n if (!token) throw new VerseControlLockedError();\n const result = await apiPost<T>(path, body, token);\n touchMutationHold();\n return result;\n}\n\n/**\n * Start / stop / restart the serving runtime.\n *\n * Every one of these changes what the fleet can do, so all three fleet keys\n * and the control snapshot are invalidated together — a restarted runtime\n * with a stale slot count beside it is exactly the disagreement this surface\n * exists to prevent.\n */\nexport async function runRuntimeAction(action: RuntimeAction): Promise<RuntimeActionResult> {\n const result = await post<RuntimeActionResult>('/api/verse/runtime', { action });\n invalidate(VERSE_RUNTIME_KEY);\n invalidate(VERSE_FLEET_KEY);\n invalidate(VERSE_CONTROL_KEY);\n return result;\n}\n\n/** Turn the local-only refusal on or off. */\nexport async function setLocalOnly(enabled: boolean): Promise<LocalOnlyUpdateResult> {\n const result = await post<LocalOnlyUpdateResult>('/api/verse/local-only', { enabled });\n invalidate(VERSE_LOCAL_ONLY_KEY);\n invalidate(VERSE_CONTROL_KEY);\n return result;\n}\n\n// ---------------------------------------------------------------------------\n// Polling\n// ---------------------------------------------------------------------------\n\n/** Fast enough that \"is it working\" is answered live; slow enough to be free. */\nexport const FLEET_POLL_MS = 4000;\n\n/**\n * Keep the runtime and fleet reads live while this section is mounted and the\n * tab is visible.\n *\n * Both routes probe a local process, so this is cheap — but only while someone\n * is looking. `visibilitychange` stops the timer when the tab is hidden and\n * takes one immediate reading when it comes back, so a fleet view returned to\n * after lunch is current on the first frame rather than up to an interval old.\n */\nexport function useFleetPolling(intervalMs: number = FLEET_POLL_MS): void {\n const refetchRuntime = useRefetch(servingRuntimeQuery);\n const refetchFleet = useRefetch(fleetQuery);\n\n useEffect(() => {\n let timer: ReturnType<typeof setInterval> | null = null;\n\n const tick = (): void => {\n refetchRuntime();\n refetchFleet();\n };\n\n const start = (): void => {\n if (timer !== null) return;\n timer = setInterval(tick, intervalMs);\n };\n\n const stop = (): void => {\n if (timer === null) return;\n clearInterval(timer);\n timer = null;\n };\n\n const onVisibility = (): void => {\n if (document.visibilityState === 'hidden') {\n stop();\n return;\n }\n tick();\n start();\n };\n\n if (document.visibilityState !== 'hidden') start();\n document.addEventListener('visibilitychange', onVisibility);\n return () => {\n stop();\n document.removeEventListener('visibilitychange', onVisibility);\n };\n }, [intervalMs, refetchRuntime, refetchFleet]);\n}\n"],"mappings":"iQA0Ca,EAAoB,gBACpB,EAAkB,cAClB,EAAuB,mBAEpC,SAAS,EAAgB,EAAc,EAAsB,CAO3D,OANI,aAAe,EACb,EAAI,SAAW,IACV,+BAA+B,EAAK,4EAEtC,GAAG,EAAK,iBAAiB,EAAI,OAAO,GAEtC,GAAG,EAAK,uBACjB,CAOA,SAAS,EACP,EACA,EACyD,CACzD,OAAO,KAAO,IAAW,CACvB,GAAI,CAEF,IAAM,EAAQ,EAAQ,MADJ,EAAgB,EAAM,CAAM,CACrB,EAQzB,OAPI,IAAU,KACL,CACL,MAAO,KACP,UAAW,GACX,OAAQ,GAAG,EAAK,8FAClB,EAEK,CAAE,QAAO,UAAW,GAAM,OAAQ,IAAK,CAChD,OAAS,EAAK,CAEZ,GADI,aAAe,GAAY,EAAI,SAAW,KAC1C,aAAe,cAAgB,EAAI,OAAS,aAAc,MAAM,EACpE,MAAO,CAAE,MAAO,KAAM,UAAW,GAAO,OAAQ,EAAgB,EAAM,CAAG,CAAE,CAC7E,CACF,CACF,CAGA,IAAa,EAA2E,CACtF,IAAK,EACL,MAAO,EAAa,qBAAsB,CAAqB,CACjE,EAGa,EAAyD,CACpE,IAAK,EACL,MAAO,EAAa,mBAAoB,CAAY,CACtD,EAGa,EAA+D,CAC1E,IAAK,EACL,MAAO,EAAa,wBAAyB,CAAgB,CAC/D,EAMA,eAAe,EAAQ,EAAc,EAA2B,CAC9D,IAAM,EAAQ,EAAiB,EAC/B,GAAI,CAAC,EAAO,MAAM,IAAI,EACtB,IAAM,EAAS,MAAM,EAAW,EAAM,EAAM,CAAK,EAEjD,OADA,EAAkB,EACX,CACT,CAUA,eAAsB,EAAiB,EAAqD,CAC1F,IAAM,EAAS,MAAM,EAA0B,qBAAsB,CAAE,QAAO,CAAC,EAI/E,OAHA,EAAW,CAAiB,EAC5B,EAAW,CAAe,EAC1B,EAAW,CAAiB,EACrB,CACT,CAGA,eAAsB,EAAa,EAAkD,CACnF,IAAM,EAAS,MAAM,EAA4B,wBAAyB,CAAE,SAAQ,CAAC,EAGrF,OAFA,EAAW,CAAoB,EAC/B,EAAW,CAAiB,EACrB,CACT,CAOA,IAAa,EAAgB,IAW7B,SAAgB,EAAgB,EAAqB,EAAqB,CACxE,IAAM,EAAiB,EAAW,CAAmB,EAC/C,EAAe,EAAW,CAAU,GAE1C,EAAA,EAAA,UAAA,KAAgB,CACd,IAAI,EAA+C,KAE7C,MAAmB,CACvB,EAAe,EACf,EAAa,CACf,EAEM,MAAoB,CACpB,IAAU,OACd,EAAQ,YAAY,EAAM,CAAU,EACtC,EAEM,MAAmB,CACnB,IAAU,OACd,cAAc,CAAK,EACnB,EAAQ,KACV,EAEM,MAA2B,CAC/B,GAAI,SAAS,kBAAoB,SAAU,CACzC,EAAK,EACL,MACF,CACA,EAAK,EACL,EAAM,CACR,EAIA,OAFI,SAAS,kBAAoB,UAAU,EAAM,EACjD,SAAS,iBAAiB,mBAAoB,CAAY,MAC7C,CACX,EAAK,EACL,SAAS,oBAAoB,mBAAoB,CAAY,CAC/D,CACF,EAAG,CAAC,EAAY,EAAgB,CAAY,CAAC,CAC/C"}
@@ -1,2 +0,0 @@
1
- import{n as e,r as t}from"./format-DKrNjdwD.js";import{E as n}from"./VerseConsoleApp-DTjDpGCd.js";import{d as r,g as i}from"./verse-model-DyCwZF-M.js";function a(e,t){if(!e)return null;for(let n of e)if(n.seatId===t)return n;return null}function o(e,t=Date.now()){if(typeof e!=`string`||e.length===0)return null;let n=Date.parse(e);if(!Number.isFinite(n))return null;let r=new Date(n),i=r.toLocaleTimeString([],{hour:`numeric`,minute:`2-digit`});return new Date(t).toDateString()===r.toDateString()?`today ${i}`:n>t&&n-t<5184e5?`${r.toLocaleDateString([],{weekday:`short`})} ${i}`:`${r.toLocaleDateString([],{month:`short`,day:`numeric`})}, ${i}`}function s(e){return(e.capacity?.binding??null)?.resetDescription??null}function c(e,t,n=Date.now()){let r=null,i=null;if(t!==null)(t.connection===`signed-out`||t.connection===`exhausted`)&&(r=t.connection,i=t.resetAt);else if(e.engine!==`local`){let t=e.capacity?.usability;(t===`signed-out`||t===`exhausted`)&&(r=t,i=t===`exhausted`?e.capacity?.binding?.resetsAt??null:null)}if(r===null)return null;if(r===`signed-out`)return{connection:r,resetAt:null,reason:`${e.label} is signed out — reconnect it to use this seat.`};let a=o(i,n),c=a===null?s(e):null,l=a===null?c===null?``:` — ${c}`:` — resets ${a}`;return{connection:r,resetAt:i,reason:`${e.label} is out of usage${l}.`}}function l(e){return e.models.some(e=>!e.unavailableReason)}function u(e){return e.engine===`local`?2:e.capacity?.usability===`ready`?0:1}function d(e){let t=e.capacity?.binding?.usedPercent;return typeof t==`number`&&Number.isFinite(t)?t:101}function f(e,t,n){return!(!l(e)||e.health.state===`unavailable`||c(e,t,n)!==null||e.engine===`local`&&t!==null&&t.connection===`unknown`&&t.reasons.length>0)}function p(e,t,n,r=Date.now()){let i=t.find(t=>t.id===e)??null,o=t.map((e,t)=>({seat:e,index:t})).filter(({seat:t})=>t.id!==e&&f(t,a(n,t.id),r));return o.sort((e,t)=>{let n=u(e.seat)-u(t.seat);if(n!==0)return n;if(i!==null){let n=e.seat.engine===i.engine?0:1,r=t.seat.engine===i.engine?0:1;if(n!==r)return n-r}let r=d(e.seat)-d(t.seat);return r===0?e.index-t.index:r}),o.slice(0,5).map(({seat:e})=>e.id)}function m(e){return typeof e!=`number`||!Number.isFinite(e)?`—`:e>0&&e<.01?`<1%`:t(e)}function h(e){return n(e)}var g=/\b\d{4}-\d{2}-\d{2}T\d{2}:\d{2}(?::\d{2}(?:\.\d{1,9})?)?(?:Z|[+-]\d{2}:?\d{2})?(?![\w:])/g,_=String.raw`[\p{L}\p{N}%…)\]"'’”\x60]`,v=RegExp(`(${_})\\.{1,2}\\s*;`,`gu`),y=RegExp(`(${_})\\.\\.(?=\\s|$)`,`gu`);function b(e,t=Date.now()){return e.replace(g,e=>o(e,t)??e).replace(v,`$1;`).replace(y,`$1.`)}function x(e){let t=e.trim();return t.endsWith(`...`)||t.endsWith(`…`)?t:t.replace(/\.+$/,``)}function S(e){return r(e)?i(e):e}function C(e){return typeof e!=`number`||!Number.isFinite(e)?`—`:`$${e.toFixed(2)}`}function w(e){return typeof e!=`number`||!Number.isFinite(e)?`—`:String(e)}function T(e){let t=Math.max(0,Math.round(e/1e3));if(t<60)return`${t}s`;let n=Math.floor(t/60),r=t%60;return n<60?`${n}m ${String(r).padStart(2,`0`)}s`:`${Math.floor(n/60)}h ${String(n%60).padStart(2,`0`)}m`}function E(e){if(!e)return`—`;let t=Date.parse(e);if(Number.isNaN(t))return`—`;let n=Math.max(0,Math.round((Date.now()-t)/1e3));if(n<60)return`${n}s`;let r=Math.round(n/60);if(r<60)return`${r}m`;let i=Math.round(r/60);return i<24?`${i}h`:`${Math.round(i/24)}d`}function D(e){let t=E(e);return t===`—`?`—`:`${t} ago`}function O(e=new Date){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}function k(e,t=new Date){return e===O(t)||e===t.toISOString().slice(0,10)}function A(e,t=new Date){if(!e)return`—`;let n=Date.parse(e);if(Number.isNaN(n))return`—`;let r=new Date(n),i=r.toLocaleTimeString(void 0,{hour:`2-digit`,minute:`2-digit`,second:`2-digit`});return O(r)===O(t)?i:`${r.toLocaleDateString(void 0,{month:`short`,day:`numeric`})} ${i}`}function j(e){return typeof e!=`number`||!Number.isFinite(e)||e<=0?`—`:`every ${T(e).replace(/ 00[ms]$/,``)}`}var M=70;function N(t,n,r,i=new Date){let a=typeof t==`number`&&Number.isFinite(t)?Math.max(0,t):null,o=typeof n==`number`&&Number.isFinite(n)?n:null,s=typeof r==`string`&&!k(r,i);if(o===0)return{state:`stopped`,percent:100,label:`${C(a)} spent today · budget $0.00`,note:`Daily budget is 0 — the loop is stopped, not unlimited.`};if(s)return{state:`unknown`,percent:null,label:`— spent today · budget ${C(o)}`,note:`Nothing has been recorded today — the last ledger day is ${e(r)}.`};if(o===null||a===null)return{state:`unknown`,percent:null,label:o===null?`${C(a)} spent today · budget —`:`— spent today · budget ${C(o)}`,note:o===null?`Daily budget is not configured.`:`Today's spend is not observable right now.`};let c=a/o*100,l=Math.min(100,Math.round(c)),u=c>=100?`over`:c>=M?`warn`:`ok`;return{state:u,percent:l,label:`${C(a)} of ${C(o)} today · ${h(a/o*100)}`,note:u===`over`?`Daily budget reached — the loop idles until the date rolls over.`:u===`warn`?`${C(o-a)} left before the loop idles today.`:`${C(o-a)} left today.`}}function P(e,t){if(!e)return null;let n=Date.parse(e);return Number.isNaN(n)||typeof t!=`number`||!Number.isFinite(t)||t<=0?null:n+t}function F(e,t){if(e===null)return`—`;let n=e-t;return n>1e3?`in ${T(n)}`:n>-1e3?`due now`:`overdue by ${T(-n)}`}function I(e){if(!e)return{label:`no tick recorded`,tone:`unknown`};switch(e){case`ok`:return{label:`ok`,tone:`success`};case`kill-switch`:return{label:`refused — emergency stop engaged`,tone:`danger`};case`budget-exhausted`:return{label:`stopped — daily budget spent`,tone:`warning`};case`no-enrolled-repos`:return{label:`nothing to do — no repos enrolled`,tone:`warning`};case`no-backlog`:return{label:`nothing to do — backlog empty`,tone:`neutral`};case`dry-run`:return{label:`dry run`,tone:`neutral`};default:return{label:e,tone:`neutral`}}}export{S as _,E as a,p as b,j as c,C as d,m as f,h as g,P as h,I as i,D as l,O as m,N as n,w as o,k as p,F as r,T as s,x as t,A as u,b as v,c as x,o as y};
2
- //# sourceMappingURL=format-BkWdOQDL.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"format-BkWdOQDL.js","names":[],"sources":["../../../../../../src/core/verse/seat-readiness.ts","../../../../../../src/web-ui/routes/verse/autonomy/format.ts"],"sourcesContent":["/**\n * core/verse/seat-readiness.ts — \"can this seat run a turn right now, and if\n * not, where else can the operator go?\" (V3.10, unit A2).\n *\n * PURE and BROWSER-SAFE on purpose: the engine's admission gate\n * (`getSeatReadiness` in core/verse/seats.ts) and the Composer's block\n * (web-ui/routes/verse/health/ComposerSeatBlock.tsx) must give the SAME\n * answer, with the SAME ranked alternatives, or the UI would offer a seat the\n * server then refuses. One implementation, imported by both. Type-only\n * imports and `Intl` only — no node: modules.\n *\n * ── WHAT BLOCKS A SEAT ─────────────────────────────────────────────────────\n * Only POSITIVE evidence that a turn would fail at the provider:\n * - `signed-out` — the CLI said so (status command or the live collector).\n * - `exhausted` — every window that carried a reading is spent and no\n * Codex credit balance remains (`seatUsability` in seats.ts;\n * a spent per-model window beside a healthy account-wide\n * one is `tight`, not exhausted).\n * `unknown`, `expiring` and `binary-skew` are WARNINGS, never refusals: an\n * admission gate that refused on \"we could not read it\" would lock Mason out\n * of his own seats every time a probe hiccuped (docs/VERSE-TELEMETRY-V2.md —\n * no signal is not a verdict).\n *\n * ── HOW ALTERNATIVES ARE RANKED ────────────────────────────────────────────\n * (research r2/accounts.md, recommendation 4): other subscription seats with\n * measured headroom first, then subscription seats whose headroom is tight or\n * unread, then local models (free, always last because they are the weakest).\n * Inside a tier the SAME ENGINE leads (a Codex user blocked on one account most\n * likely wants the other Codex account), then the lower binding-window\n * percentage, then discovery order. A seat with no runnable model, a local\n * seat whose runtime is not answering, or a seat that is itself blocked is\n * never offered.\n */\nimport type { SeatConnection, SeatHealthReport, SeatReadiness } from './health-types.js';\nimport type { VerseSeat } from './types.js';\n\n/** The only connections that refuse a turn. Everything else is a warning. */\nexport const SEAT_BLOCKING_CONNECTIONS: ReadonlySet<SeatConnection> = new Set<SeatConnection>(['signed-out', 'exhausted']);\n\n/** At most this many alternatives are offered — a list, not a directory. */\nexport const SEAT_MAX_ALTERNATIVES = 5;\n\nexport interface SeatBlock {\n connection: 'signed-out' | 'exhausted';\n /** One plain sentence naming the seat and the fact (\"Personal Codex is out of usage — resets Fri 2:25 PM.\"). */\n reason: string;\n /** Machine-readable reset instant, when the provider gave one. */\n resetAt: string | null;\n}\n\nfunction reportFor(reports: readonly SeatHealthReport[] | null | undefined, seatId: string): SeatHealthReport | null {\n if (!reports) return null;\n for (const report of reports) if (report.seatId === seatId) return report;\n return null;\n}\n\n/**\n * A reset instant as a short local phrase (\"Fri 2:25 PM\", \"Sep 30, 2:25 PM\"),\n * or null when `iso` is not a valid instant. Only a MACHINE-READABLE instant\n * is ever formatted — Claude's prose reset never reaches this function.\n */\nexport function describeResetAt(iso: string | null | undefined, now: number = Date.now()): string | null {\n if (typeof iso !== 'string' || iso.length === 0) return null;\n const at = Date.parse(iso);\n if (!Number.isFinite(at)) return null;\n const date = new Date(at);\n const time = date.toLocaleTimeString([], { hour: 'numeric', minute: '2-digit' });\n if (new Date(now).toDateString() === date.toDateString()) return `today ${time}`;\n // Within the coming week the weekday is the clearest name for a day.\n if (at > now && at - now < 6 * 24 * 60 * 60 * 1000) {\n return `${date.toLocaleDateString([], { weekday: 'short' })} ${time}`;\n }\n return `${date.toLocaleDateString([], { month: 'short', day: 'numeric' })}, ${time}`;\n}\n\n/** The provider's own reset wording for the seat's binding window (Claude publishes prose only). */\nfunction bindingResetDescription(seat: VerseSeat): string | null {\n const binding = seat.capacity?.binding ?? null;\n return binding?.resetDescription ?? null;\n}\n\n/**\n * Why `seat` cannot take a turn, or null when nothing positively blocks it.\n *\n * The health report (sweep + live telemetry) wins when present; without one\n * the seat's own `capacity.usability` — which is on every native seat the\n * server serves — is the fallback, so the seat picker can mark a blocked seat\n * before the health endpoint has ever been read.\n */\nexport function seatBlock(\n seat: VerseSeat,\n report: SeatHealthReport | null,\n now: number = Date.now(),\n): SeatBlock | null {\n let connection: SeatBlock['connection'] | null = null;\n let resetAt: string | null = null;\n if (report !== null) {\n if (report.connection === 'signed-out' || report.connection === 'exhausted') {\n connection = report.connection;\n resetAt = report.resetAt;\n }\n } else if (seat.engine !== 'local') {\n const usability = seat.capacity?.usability;\n if (usability === 'signed-out' || usability === 'exhausted') {\n connection = usability;\n resetAt = usability === 'exhausted' ? seat.capacity?.binding?.resetsAt ?? null : null;\n }\n }\n if (connection === null) return null;\n if (connection === 'signed-out') {\n return { connection, resetAt: null, reason: `${seat.label} is signed out — reconnect it to use this seat.` };\n }\n const when = describeResetAt(resetAt, now);\n const prose = when === null ? bindingResetDescription(seat) : null;\n const tail = when !== null ? ` — resets ${when}` : prose !== null ? ` — ${prose}` : '';\n return { connection, resetAt, reason: `${seat.label} is out of usage${tail}.` };\n}\n\nfunction hasRunnableModel(seat: VerseSeat): boolean {\n return seat.models.some((model) => !model.unavailableReason);\n}\n\n/** 0 = subscription seat with measured headroom, 1 = tight/unread subscription seat, 2 = local. */\nfunction tier(seat: VerseSeat): number {\n if (seat.engine === 'local') return 2;\n return seat.capacity?.usability === 'ready' ? 0 : 1;\n}\n\nfunction bindingPercent(seat: VerseSeat): number {\n const used = seat.capacity?.binding?.usedPercent;\n // Unread sorts after every reading: no signal is not \"0% used\".\n return typeof used === 'number' && Number.isFinite(used) ? used : 101;\n}\n\n/** Can `seat` be offered as somewhere else to go? */\nfunction offerable(seat: VerseSeat, report: SeatHealthReport | null, now: number): boolean {\n if (!hasRunnableModel(seat)) return false;\n if (seat.health.state === 'unavailable') return false;\n if (seatBlock(seat, report, now) !== null) return false;\n // A local seat is only worth offering while its runtime answers. `unknown`\n // with reasons is the sweep saying Ollama did not respond.\n if (seat.engine === 'local' && report !== null && report.connection === 'unknown' && report.reasons.length > 0) {\n return false;\n }\n return true;\n}\n\n/** Ranked ids of seats that could take the turn instead of `seatId` (see the file header). */\nexport function rankSeatAlternatives(\n seatId: string,\n seats: readonly VerseSeat[],\n reports: readonly SeatHealthReport[] | null | undefined,\n now: number = Date.now(),\n): string[] {\n const blocked = seats.find((seat) => seat.id === seatId) ?? null;\n const candidates = seats\n .map((seat, index) => ({ seat, index }))\n .filter(({ seat }) => seat.id !== seatId && offerable(seat, reportFor(reports, seat.id), now));\n candidates.sort((a, b) => {\n const byTier = tier(a.seat) - tier(b.seat);\n if (byTier !== 0) return byTier;\n if (blocked !== null) {\n const sameA = a.seat.engine === blocked.engine ? 0 : 1;\n const sameB = b.seat.engine === blocked.engine ? 0 : 1;\n if (sameA !== sameB) return sameA - sameB;\n }\n const byUse = bindingPercent(a.seat) - bindingPercent(b.seat);\n if (byUse !== 0) return byUse;\n return a.index - b.index;\n });\n return candidates.slice(0, SEAT_MAX_ALTERNATIVES).map(({ seat }) => seat.id);\n}\n\n/**\n * The admission answer for one seat. A seat that is not in `seats` at all is\n * reported READY with no reason: the readiness layer has no evidence about\n * it, and \"seat not found\" is the engine's own error to raise.\n */\nexport function seatReadiness(\n seatId: string,\n seats: readonly VerseSeat[],\n reports: readonly SeatHealthReport[] | null | undefined,\n now: number = Date.now(),\n): SeatReadiness {\n const seat = seats.find((candidate) => candidate.id === seatId) ?? null;\n if (seat === null) return { seatId, ready: true, reason: null, alternatives: [] };\n const block = seatBlock(seat, reportFor(reports, seatId), now);\n if (block === null) return { seatId, ready: true, reason: null, alternatives: [] };\n return { seatId, ready: false, reason: block.reason, alternatives: rankSeatAlternatives(seatId, seats, reports, now) };\n}\n","/**\n * routes/verse/autonomy/format.ts — the small pure functions the cockpit's\n * numerals go through. Kept framework-free so they unit-test without a DOM,\n * and kept in ONE place so \"unknown\" never renders as 0 in one panel and as\n * an em-dash in the next.\n *\n * The rule every function here obeys: absent is not zero. A null spend is\n * \"—\", a null budget is \"not configured\", and a budget of exactly 0 is\n * \"stopped\" — which is the single most misread number in the whole product.\n */\nimport { describeResetAt } from '../../../../core/verse/seat-readiness.js';\nimport { formatDayLabel, formatPercent } from '../../../components/charts/format.js';\nimport { isAbsolutePath, projectName } from '../verse-model.js';\nimport { usedPercentText } from '../percent-text.js';\n\n/** What we render when a value genuinely is not known. */\nexport const UNKNOWN = '—';\n\n/**\n * A share as a whole percentage — \"18%\" — except a non-zero share under one\n * percent, which reads \"<1%\". One precision per panel: \"0%\" for a sliver of\n * real spend or progress would state that nothing happened.\n */\nexport function formatWholePercent(fraction: number | null | undefined): string {\n if (typeof fraction !== 'number' || !Number.isFinite(fraction)) return UNKNOWN;\n if (fraction > 0 && fraction < 0.01) return '<1%';\n return formatPercent(fraction);\n}\n\n/**\n * THE ONE PERCENT RULE — a measured share of a window (or of anything capped\n * at 100), printed the same way on every panel: a whole percent, except that a\n * real reading under 1% is \"<1%\" (never \"0%\", which would read as \"untouched\")\n * and one just short of 100 is \"99%\" (never a rounded \"100%\", which would read\n * as \"spent\"). `used` is 0–100 and is clamped; not a number is \"—\".\n *\n * Every place that prints a used percent goes through this — a bar reading\n * \"99%\" beside a summary reading \"100% of 5-hour window used\" is one seat\n * described two ways. Bar WIDTHS stay numeric; only the words use this.\n */\nexport function percentText(used: number): string {\n return usedPercentText(used);\n}\n\n/** An ISO-8601 instant (a date WITH a time) anywhere inside a sentence. */\nconst ISO_INSTANT_IN_TEXT = /\\b\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}(?::\\d{2}(?:\\.\\d{1,9})?)?(?:Z|[+-]\\d{2}:?\\d{2})?(?![\\w:])/g;\n\n/**\n * What may end a sentence right before its full stop: a letter, a digit, a\n * percent sign, an ellipsis, or a closing quote / bracket / backtick. NOT a\n * dot, a slash or a space — so a path segment (`../x`, `cd ..;`) never looks\n * like doubled punctuation.\n */\nconst SENTENCE_END = String.raw`[\\p{L}\\p{N}%…)\\]\"'’”\\x60]`;\n/** \"failed.; next\" / \"failed..; next\" → \"failed; next\". */\nconst STOP_BEFORE_SEMICOLON = new RegExp(`(${SENTENCE_END})\\\\.{1,2}\\\\s*;`, 'gu');\n/**\n * \"failed.. Next\" / \"exhausted..\" → one stop. The pair must be FOLLOWED by\n * whitespace or the end, so a git range (`a1b2c3d..e4f5a6b`, `HEAD~1..HEAD`)\n * and a traversal (`x/../y`) pass through untouched; a third dot (`...`) is\n * an ellipsis, not a doubled stop.\n */\nconst DOUBLED_STOP = new RegExp(`(${SENTENCE_END})\\\\.\\\\.(?=\\\\s|$)`, 'gu');\n\n/**\n * Server prose made fit to print: every ISO instant becomes the viewer's\n * local time (\"today 11:46 PM\", \"Fri 11:46 PM\", \"Sep 26, 11:46 PM\" — the\n * wording `describeResetAt` gives resets everywhere else), and the \".;\" / \"..\"\n * that a sentence joined onto another sentence leaves behind is collapsed.\n *\n * For text the server wrote for a person (`ApiError.detail`, action notes,\n * audit summaries, fleet notes): it is shown verbatim otherwise. That matters\n * on the trust surfaces this runs on (approval summaries, the audit trail):\n * a `../../.ssh/authorized_keys` rewritten to `././.ssh/…` would hide the very\n * traversal the operator is deciding about, so only sentence punctuation is\n * ever touched.\n */\nexport function tidyProse(text: string, now: number = Date.now()): string {\n return text\n .replace(ISO_INSTANT_IN_TEXT, (iso) => describeResetAt(iso, now) ?? iso)\n .replace(STOP_BEFORE_SEMICOLON, '$1;')\n .replace(DOUBLED_STOP, '$1.');\n}\n\n/**\n * A sentence ready to be embedded in another one: trimmed, with its own\n * closing period dropped so \"… unavailable: quota exhausted.\" does not become\n * \"quota exhausted..\". An ellipsis is kept — it is not a full stop.\n */\nexport function asClause(text: string): string {\n const trimmed = text.trim();\n if (trimmed.endsWith('...') || trimmed.endsWith('…')) return trimmed;\n return trimmed.replace(/\\.+$/, '');\n}\n\n/**\n * What a repo cell shows: the folder's own name for an absolute checkout path\n * (the full path belongs in the cell's `title`), and a `owner/name` slug or a\n * bare name as it came — cutting a slug to its last segment would drop the\n * owner, which is half of what identifies it.\n */\nexport function repoDisplayName(repo: string): string {\n return isAbsolutePath(repo) ? projectName(repo) : repo;\n}\n\nexport function formatUsd(value: number | null | undefined): string {\n if (typeof value !== 'number' || !Number.isFinite(value)) return UNKNOWN;\n return `$${value.toFixed(2)}`;\n}\n\nexport function formatCount(value: number | null | undefined): string {\n if (typeof value !== 'number' || !Number.isFinite(value)) return UNKNOWN;\n return String(value);\n}\n\n/** \"4m 12s\" / \"1h 06m\" / \"12s\" — for durations and countdowns alike. */\nexport function formatDuration(ms: number): string {\n const total = Math.max(0, Math.round(ms / 1000));\n if (total < 60) return `${total}s`;\n const minutes = Math.floor(total / 60);\n const seconds = total % 60;\n if (minutes < 60) return `${minutes}m ${String(seconds).padStart(2, '0')}s`;\n const hours = Math.floor(minutes / 60);\n return `${hours}h ${String(minutes % 60).padStart(2, '0')}m`;\n}\n\n/** Compact age for dense table cells: \"42s\", \"7m\", \"3h\", \"5d\". */\nexport function formatAge(iso: string | null | undefined): string {\n if (!iso) return UNKNOWN;\n const ms = Date.parse(iso);\n if (Number.isNaN(ms)) return UNKNOWN;\n const seconds = Math.max(0, Math.round((Date.now() - ms) / 1000));\n if (seconds < 60) return `${seconds}s`;\n const minutes = Math.round(seconds / 60);\n if (minutes < 60) return `${minutes}m`;\n const hours = Math.round(minutes / 60);\n if (hours < 24) return `${hours}h`;\n return `${Math.round(hours / 24)}d`;\n}\n\nexport function formatRelative(iso: string | null | undefined): string {\n const age = formatAge(iso);\n return age === UNKNOWN ? UNKNOWN : `${age} ago`;\n}\n\n/** Local wall-clock time, for the audit table's second column. */\nexport function formatClock(iso: string | null | undefined): string {\n if (!iso) return UNKNOWN;\n const ms = Date.parse(iso);\n if (Number.isNaN(ms)) return UNKNOWN;\n return new Date(ms).toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n}\n\n/** The viewer's local calendar day as `YYYY-MM-DD` — NOT the UTC slice. */\nexport function localDateKey(at: Date = new Date()): string {\n const y = at.getFullYear();\n const m = String(at.getMonth() + 1).padStart(2, '0');\n const d = String(at.getDate()).padStart(2, '0');\n return `${y}-${m}-${d}`;\n}\n\n/**\n * Is `todayDate` still the current ledger day?\n *\n * The daemon stamps it in UTC (`resetDayIfNeeded` in core/daemon/state.ts is\n * `new Date().toISOString().slice(0, 10)`) but the operator reads the screen\n * in local time, and the two disagree for part of every day at any offset but\n * zero. Comparing against the local day alone would announce \"nothing has been\n * recorded today\" every evening west of UTC — a false alarm on the meter whose\n * whole purpose is to be trustworthy.\n *\n * So either spelling counts as current. That is deliberately conservative: it\n * can call a day current for a few hours after the UTC rollover, and it will\n * never call a genuinely current day stale. The case this exists for is a\n * ledger day weeks old, which neither spelling matches.\n */\nexport function isCurrentLedgerDay(todayDate: string, now: Date = new Date()): boolean {\n return todayDate === localDateKey(now) || todayDate === now.toISOString().slice(0, 10);\n}\n\n/**\n * Time-of-day for a row from today; date + time for anything older.\n *\n * `formatClock` alone is only honest inside a single-day window, and the\n * tables that use it are not one: the audit trail defaults to 200 rows and\n * offers 500, which on a real machine spans days. Two rows reading \"03:12:44\"\n * could be last night and last week, and the only date was in a hover title\n * that a touch viewport never fires.\n */\nexport function formatStamp(iso: string | null | undefined, now: Date = new Date()): string {\n if (!iso) return UNKNOWN;\n const ms = Date.parse(iso);\n if (Number.isNaN(ms)) return UNKNOWN;\n const at = new Date(ms);\n const clock = at.toLocaleTimeString(undefined, { hour: '2-digit', minute: '2-digit', second: '2-digit' });\n if (localDateKey(at) === localDateKey(now)) return clock;\n const day = at.toLocaleDateString(undefined, { month: 'short', day: 'numeric' });\n return `${day} ${clock}`;\n}\n\n/** Human tick interval, e.g. \"every 15m\". */\nexport function formatInterval(intervalMs: number | null | undefined): string {\n if (typeof intervalMs !== 'number' || !Number.isFinite(intervalMs) || intervalMs <= 0) return UNKNOWN;\n // A configured interval is a round number far more often than not; \"every\n // 15m\" reads better than \"every 15m 00s\" and loses nothing when it isn't.\n return `every ${formatDuration(intervalMs).replace(/ 00[ms]$/, '')}`;\n}\n\nexport type BudgetState = 'stopped' | 'unknown' | 'ok' | 'warn' | 'over';\n\nexport interface BudgetMeter {\n state: BudgetState;\n /** 0-100, clamped. Null when there is nothing honest to draw. */\n percent: number | null;\n /** One line: \"$4.50 of $25.00 today · 18%\". */\n label: string;\n /** The plain-language verdict shown next to the meter. */\n note: string;\n}\n\nconst BUDGET_WARN_PERCENT = 70;\n\n/**\n * Today's spend against the configured daily cap, as ONE line.\n *\n * A cap of exactly 0 is the contract's guard rail: it means the loop is\n * stopped, and it must never render as an empty (i.e. \"plenty left\") meter.\n *\n * `todayDate` is the ledger day `spend.todayUsd` was counted for. It is NOT\n * optional decoration: the daemon writes the figure once per day and leaves it\n * there, so a machine that last ticked three weeks ago answers\n * `{todayUsd: 0, todayDate: \"2026-09-01\"}`. Rendering that as \"$0.00 of $50.00\n * today\" is a fabricated statement about today on the one number an operator\n * checks before walking away from an autonomous loop. Pass `null` only when\n * the source genuinely has no date to offer (the legacy daemon observation).\n */\nexport function budgetMeter(\n spentUsd: number | null | undefined,\n capUsd: number | null | undefined,\n todayDate?: string | null,\n now: Date = new Date(),\n): BudgetMeter {\n const spend = typeof spentUsd === 'number' && Number.isFinite(spentUsd) ? Math.max(0, spentUsd) : null;\n const cap = typeof capUsd === 'number' && Number.isFinite(capUsd) ? capUsd : null;\n // A cap of 0 is a statement about configuration, not about the ledger, so\n // it still reads true on a stale day and is checked first.\n const stale = typeof todayDate === 'string' && !isCurrentLedgerDay(todayDate, now);\n\n if (cap === 0) {\n return {\n state: 'stopped',\n percent: 100,\n label: `${formatUsd(spend)} spent today · budget $0.00`,\n note: 'Daily budget is 0 — the loop is stopped, not unlimited.',\n };\n }\n if (stale) {\n return {\n state: 'unknown',\n percent: null,\n label: `${UNKNOWN} spent today · budget ${formatUsd(cap)}`,\n // \"Sep 1\", not \"2026-09-01\": the ledger day is a calendar date, so it is\n // read as one (formatDayLabel parses it in UTC and cannot shift a day).\n note: `Nothing has been recorded today — the last ledger day is ${formatDayLabel(todayDate)}.`,\n };\n }\n if (cap === null || spend === null) {\n return {\n state: 'unknown',\n percent: null,\n label: cap === null ? `${formatUsd(spend)} spent today · budget ${UNKNOWN}` : `${UNKNOWN} spent today · budget ${formatUsd(cap)}`,\n note: cap === null ? 'Daily budget is not configured.' : \"Today's spend is not observable right now.\",\n };\n }\n\n const raw = (spend / cap) * 100;\n const percent = Math.min(100, Math.round(raw));\n const state: BudgetState = raw >= 100 ? 'over' : raw >= BUDGET_WARN_PERCENT ? 'warn' : 'ok';\n return {\n state,\n percent,\n // The text follows the one percent rule (\"<1%\", \"99%\" short of the cap); `percent` (the bar) stays numeric.\n label: `${formatUsd(spend)} of ${formatUsd(cap)} today · ${percentText((spend / cap) * 100)}`,\n note:\n state === 'over'\n ? 'Daily budget reached — the loop idles until the date rolls over.'\n : state === 'warn'\n ? `${formatUsd(cap - spend)} left before the loop idles today.`\n : `${formatUsd(cap - spend)} left today.`,\n };\n}\n\n/** Epoch ms of the next expected tick, or null when it cannot be derived. */\nexport function nextTickAt(lastTickAt: string | null | undefined, intervalMs: number | null | undefined): number | null {\n if (!lastTickAt) return null;\n const last = Date.parse(lastTickAt);\n if (Number.isNaN(last)) return null;\n if (typeof intervalMs !== 'number' || !Number.isFinite(intervalMs) || intervalMs <= 0) return null;\n return last + intervalMs;\n}\n\n/** \"in 4m 12s\" / \"due now\" / \"overdue by 2m 03s\". */\nexport function countdownLabel(nextAt: number | null, now: number): string {\n if (nextAt === null) return UNKNOWN;\n const delta = nextAt - now;\n if (delta > 1000) return `in ${formatDuration(delta)}`;\n if (delta > -1000) return 'due now';\n return `overdue by ${formatDuration(-delta)}`;\n}\n\n/** Last tick outcome, phrased the way a person would say it out loud. */\nexport function describeTickOutcome(reason: string | null | undefined): { label: string; tone: 'success' | 'warning' | 'danger' | 'neutral' | 'unknown' } {\n if (!reason) return { label: 'no tick recorded', tone: 'unknown' };\n switch (reason) {\n case 'ok':\n return { label: 'ok', tone: 'success' };\n case 'kill-switch':\n return { label: 'refused — emergency stop engaged', tone: 'danger' };\n case 'budget-exhausted':\n return { label: 'stopped — daily budget spent', tone: 'warning' };\n case 'no-enrolled-repos':\n return { label: 'nothing to do — no repos enrolled', tone: 'warning' };\n case 'no-backlog':\n return { label: 'nothing to do — backlog empty', tone: 'neutral' };\n case 'dry-run':\n return { label: 'dry run', tone: 'neutral' };\n default:\n return { label: reason, tone: 'neutral' };\n }\n}\n"],"mappings":"uJAkDA,SAAS,EAAU,EAAyD,EAAyC,CACnH,GAAI,CAAC,EAAS,OAAO,KACrB,IAAK,IAAM,KAAU,EAAS,GAAI,EAAO,SAAW,EAAQ,OAAO,EACnE,OAAO,IACT,CAOA,SAAgB,EAAgB,EAAgC,EAAc,KAAK,IAAI,EAAkB,CACvG,GAAI,OAAO,GAAQ,UAAY,EAAI,SAAW,EAAG,OAAO,KACxD,IAAM,EAAK,KAAK,MAAM,CAAG,EACzB,GAAI,CAAC,OAAO,SAAS,CAAE,EAAG,OAAO,KACjC,IAAM,EAAO,IAAI,KAAK,CAAE,EAClB,EAAO,EAAK,mBAAmB,CAAC,EAAG,CAAE,KAAM,UAAW,OAAQ,SAAU,CAAC,EAM/E,OALI,IAAI,KAAK,CAAG,CAAC,CAAC,aAAa,IAAM,EAAK,aAAa,EAAU,SAAS,IAEtE,EAAK,GAAO,EAAK,EAAM,OAClB,GAAG,EAAK,mBAAmB,CAAC,EAAG,CAAE,QAAS,OAAQ,CAAC,EAAE,GAAG,IAE1D,GAAG,EAAK,mBAAmB,CAAC,EAAG,CAAE,MAAO,QAAS,IAAK,SAAU,CAAC,EAAE,IAAI,GAChF,CAGA,SAAS,EAAwB,EAAgC,CAE/D,OADgB,EAAK,UAAU,SAAW,KAAA,EAC1B,kBAAoB,IACtC,CAUA,SAAgB,EACd,EACA,EACA,EAAc,KAAK,IAAI,EACL,CAClB,IAAI,EAA6C,KAC7C,EAAyB,KAC7B,GAAI,IAAW,MACT,EAAO,aAAe,cAAgB,EAAO,aAAe,eAC9D,EAAa,EAAO,WACpB,EAAU,EAAO,cAEd,GAAI,EAAK,SAAW,QAAS,CAClC,IAAM,EAAY,EAAK,UAAU,WAC7B,IAAc,cAAgB,IAAc,eAC9C,EAAa,EACb,EAAU,IAAc,YAAc,EAAK,UAAU,SAAS,UAAY,KAAO,KAErF,CACA,GAAI,IAAe,KAAM,OAAO,KAChC,GAAI,IAAe,aACjB,MAAO,CAAE,aAAY,QAAS,KAAM,OAAQ,GAAG,EAAK,MAAM,gDAAiD,EAE7G,IAAM,EAAO,EAAgB,EAAS,CAAG,EACnC,EAAQ,IAAS,KAAO,EAAwB,CAAI,EAAI,KACxD,EAAO,IAAS,KAA6B,IAAU,KAAuB,GAAhB,MAAM,IAA7C,aAAa,IAC1C,MAAO,CAAE,aAAY,UAAS,OAAQ,GAAG,EAAK,MAAM,kBAAkB,EAAK,EAAG,CAChF,CAEA,SAAS,EAAiB,EAA0B,CAClD,OAAO,EAAK,OAAO,KAAM,GAAU,CAAC,EAAM,iBAAiB,CAC7D,CAGA,SAAS,EAAK,EAAyB,CAErC,OADI,EAAK,SAAW,QAAgB,EAC7B,EAAK,UAAU,YAAc,QAAU,EAAI,CACpD,CAEA,SAAS,EAAe,EAAyB,CAC/C,IAAM,EAAO,EAAK,UAAU,SAAS,YAErC,OAAO,OAAO,GAAS,UAAY,OAAO,SAAS,CAAI,EAAI,EAAO,GACpE,CAGA,SAAS,EAAU,EAAiB,EAAiC,EAAsB,CASzF,MAHA,EALI,CAAC,EAAiB,CAAI,GACtB,EAAK,OAAO,QAAU,eACtB,EAAU,EAAM,EAAQ,CAAG,IAAM,MAGjC,EAAK,SAAW,SAAW,IAAW,MAAQ,EAAO,aAAe,WAAa,EAAO,QAAQ,OAAS,EAI/G,CAGA,SAAgB,EACd,EACA,EACA,EACA,EAAc,KAAK,IAAI,EACb,CACV,IAAM,EAAU,EAAM,KAAM,GAAS,EAAK,KAAO,CAAM,GAAK,KACtD,EAAa,EAChB,KAAK,EAAM,KAAW,CAAE,OAAM,OAAM,EAAE,CAAC,CACvC,QAAQ,CAAE,UAAW,EAAK,KAAO,GAAU,EAAU,EAAM,EAAU,EAAS,EAAK,EAAE,EAAG,CAAG,CAAC,EAa/F,OAZA,EAAW,MAAM,EAAG,IAAM,CACxB,IAAM,EAAS,EAAK,EAAE,IAAI,EAAI,EAAK,EAAE,IAAI,EACzC,GAAI,IAAW,EAAG,OAAO,EACzB,GAAI,IAAY,KAAM,CACpB,IAAM,EAAQ,EAAE,KAAK,SAAW,EAAQ,OAAS,EAAI,EAC/C,EAAQ,EAAE,KAAK,SAAW,EAAQ,OAAS,EAAI,EACrD,GAAI,IAAU,EAAO,OAAO,EAAQ,CACtC,CACA,IAAM,EAAQ,EAAe,EAAE,IAAI,EAAI,EAAe,EAAE,IAAI,EAE5D,OADI,IAAU,EACP,EAAE,MAAQ,EAAE,MADK,CAE1B,CAAC,EACM,EAAW,MAAM,EAAA,CAAwB,CAAC,CAAC,KAAK,CAAE,UAAW,EAAK,EAAE,CAC7E,CCpJA,SAAgB,EAAmB,EAA6C,CAG9E,OAFI,OAAO,GAAa,UAAY,CAAC,OAAO,SAAS,CAAQ,EAAG,IAC5D,EAAW,GAAK,EAAW,IAAa,MACrC,EAAc,CAAQ,CAC/B,CAaA,SAAgB,EAAY,EAAsB,CAChD,OAAO,EAAgB,CAAI,CAC7B,CAGA,IAAM,EAAsB,4FAQtB,EAAe,OAAO,GAAG,4BAEzB,EAA4B,OAAO,IAAI,EAAa,gBAAiB,IAAI,EAOzE,EAAmB,OAAO,IAAI,EAAa,kBAAmB,IAAI,EAexE,SAAgB,EAAU,EAAc,EAAc,KAAK,IAAI,EAAW,CACxE,OAAO,EACJ,QAAQ,EAAsB,GAAQ,EAAgB,EAAK,CAAG,GAAK,CAAG,CAAC,CACvE,QAAQ,EAAuB,KAAK,CAAC,CACrC,QAAQ,EAAc,KAAK,CAChC,CAOA,SAAgB,EAAS,EAAsB,CAC7C,IAAM,EAAU,EAAK,KAAK,EAE1B,OADI,EAAQ,SAAS,KAAK,GAAK,EAAQ,SAAS,GAAG,EAAU,EACtD,EAAQ,QAAQ,OAAQ,EAAE,CACnC,CAQA,SAAgB,EAAgB,EAAsB,CACpD,OAAO,EAAe,CAAI,EAAI,EAAY,CAAI,EAAI,CACpD,CAEA,SAAgB,EAAU,EAA0C,CAElE,OADI,OAAO,GAAU,UAAY,CAAC,OAAO,SAAS,CAAK,EAAG,IACnD,IAAI,EAAM,QAAQ,CAAC,GAC5B,CAEA,SAAgB,EAAY,EAA0C,CAEpE,OADI,OAAO,GAAU,UAAY,CAAC,OAAO,SAAS,CAAK,EAAG,IACnD,OAAO,CAAK,CACrB,CAGA,SAAgB,EAAe,EAAoB,CACjD,IAAM,EAAQ,KAAK,IAAI,EAAG,KAAK,MAAM,EAAK,GAAI,CAAC,EAC/C,GAAI,EAAQ,GAAI,MAAO,GAAG,EAAM,GAChC,IAAM,EAAU,KAAK,MAAM,EAAQ,EAAE,EAC/B,EAAU,EAAQ,GAGxB,OAFI,EAAU,GAAW,GAAG,EAAQ,IAAI,OAAO,CAAO,CAAC,CAAC,SAAS,EAAG,GAAG,EAAE,GAElE,GADO,KAAK,MAAM,EAAU,EACzB,EAAM,IAAI,OAAO,EAAU,EAAE,CAAC,CAAC,SAAS,EAAG,GAAG,EAAE,EAC5D,CAGA,SAAgB,EAAU,EAAwC,CAChE,GAAI,CAAC,EAAK,MAAA,IACV,IAAM,EAAK,KAAK,MAAM,CAAG,EACzB,GAAI,OAAO,MAAM,CAAE,EAAG,MAAA,IACtB,IAAM,EAAU,KAAK,IAAI,EAAG,KAAK,OAAO,KAAK,IAAI,EAAI,GAAM,GAAI,CAAC,EAChE,GAAI,EAAU,GAAI,MAAO,GAAG,EAAQ,GACpC,IAAM,EAAU,KAAK,MAAM,EAAU,EAAE,EACvC,GAAI,EAAU,GAAI,MAAO,GAAG,EAAQ,GACpC,IAAM,EAAQ,KAAK,MAAM,EAAU,EAAE,EAErC,OADI,EAAQ,GAAW,GAAG,EAAM,GACzB,GAAG,KAAK,MAAM,EAAQ,EAAE,EAAE,EACnC,CAEA,SAAgB,EAAe,EAAwC,CACrE,IAAM,EAAM,EAAU,CAAG,EACzB,OAAO,IAAA,IAAA,IAA4B,GAAG,EAAI,KAC5C,CAWA,SAAgB,EAAa,EAAW,IAAI,KAAgB,CAI1D,MAAO,GAHG,EAAG,YAGH,EAAE,GAFF,OAAO,EAAG,SAAS,EAAI,CAAC,CAAC,CAAC,SAAS,EAAG,GAEjC,EAAE,GADP,OAAO,EAAG,QAAQ,CAAC,CAAC,CAAC,SAAS,EAAG,GACvB,GACtB,CAiBA,SAAgB,EAAmB,EAAmB,EAAY,IAAI,KAAiB,CACrF,OAAO,IAAc,EAAa,CAAG,GAAK,IAAc,EAAI,YAAY,CAAC,CAAC,MAAM,EAAG,EAAE,CACvF,CAWA,SAAgB,EAAY,EAAgC,EAAY,IAAI,KAAgB,CAC1F,GAAI,CAAC,EAAK,MAAA,IACV,IAAM,EAAK,KAAK,MAAM,CAAG,EACzB,GAAI,OAAO,MAAM,CAAE,EAAG,MAAA,IACtB,IAAM,EAAK,IAAI,KAAK,CAAE,EAChB,EAAQ,EAAG,mBAAmB,IAAA,GAAW,CAAE,KAAM,UAAW,OAAQ,UAAW,OAAQ,SAAU,CAAC,EAGxG,OAFI,EAAa,CAAE,IAAM,EAAa,CAAG,EAAU,EAE5C,GADK,EAAG,mBAAmB,IAAA,GAAW,CAAE,MAAO,QAAS,IAAK,SAAU,CACpE,EAAI,GAAG,GACnB,CAGA,SAAgB,EAAe,EAA+C,CAI5E,OAHI,OAAO,GAAe,UAAY,CAAC,OAAO,SAAS,CAAU,GAAK,GAAc,EAAG,IAGhF,SAAS,EAAe,CAAU,CAAC,CAAC,QAAQ,WAAY,EAAE,GACnE,CAcA,IAAM,EAAsB,GAgB5B,SAAgB,EACd,EACA,EACA,EACA,EAAY,IAAI,KACH,CACb,IAAM,EAAQ,OAAO,GAAa,UAAY,OAAO,SAAS,CAAQ,EAAI,KAAK,IAAI,EAAG,CAAQ,EAAI,KAC5F,EAAM,OAAO,GAAW,UAAY,OAAO,SAAS,CAAM,EAAI,EAAS,KAGvE,EAAQ,OAAO,GAAc,UAAY,CAAC,EAAmB,EAAW,CAAG,EAEjF,GAAI,IAAQ,EACV,MAAO,CACL,MAAO,UACP,QAAS,IACT,MAAO,GAAG,EAAU,CAAK,EAAE,6BAC3B,KAAM,yDACR,EAEF,GAAI,EACF,MAAO,CACL,MAAO,UACP,QAAS,KACT,MAAO,0BAAmC,EAAU,CAAG,IAGvD,KAAM,4DAA4D,EAAe,CAAS,EAAE,EAC9F,EAEF,GAAI,IAAQ,MAAQ,IAAU,KAC5B,MAAO,CACL,MAAO,UACP,QAAS,KACT,MAAO,IAAQ,KAAO,GAAG,EAAU,CAAK,EAAE,yBAAoC,0BAAmC,EAAU,CAAG,IAC9H,KAAM,IAAQ,KAAO,kCAAoC,4CAC3D,EAGF,IAAM,EAAO,EAAQ,EAAO,IACtB,EAAU,KAAK,IAAI,IAAK,KAAK,MAAM,CAAG,CAAC,EACvC,EAAqB,GAAO,IAAM,OAAS,GAAO,EAAsB,OAAS,KACvF,MAAO,CACL,QACA,UAEA,MAAO,GAAG,EAAU,CAAK,EAAE,MAAM,EAAU,CAAG,EAAE,WAAW,EAAa,EAAQ,EAAO,GAAG,IAC1F,KACE,IAAU,OACN,mEACA,IAAU,OACR,GAAG,EAAU,EAAM,CAAK,EAAE,oCAC1B,GAAG,EAAU,EAAM,CAAK,EAAE,aACpC,CACF,CAGA,SAAgB,EAAW,EAAuC,EAAsD,CACtH,GAAI,CAAC,EAAY,OAAO,KACxB,IAAM,EAAO,KAAK,MAAM,CAAU,EAGlC,OAFI,OAAO,MAAM,CAAI,GACjB,OAAO,GAAe,UAAY,CAAC,OAAO,SAAS,CAAU,GAAK,GAAc,EAAU,KACvF,EAAO,CAChB,CAGA,SAAgB,EAAe,EAAuB,EAAqB,CACzE,GAAI,IAAW,KAAM,MAAA,IACrB,IAAM,EAAQ,EAAS,EAGvB,OAFI,EAAQ,IAAa,MAAM,EAAe,CAAK,IAC/C,EAAQ,KAAc,UACnB,cAAc,EAAe,CAAC,CAAK,GAC5C,CAGA,SAAgB,EAAoB,EAAsH,CACxJ,GAAI,CAAC,EAAQ,MAAO,CAAE,MAAO,mBAAoB,KAAM,SAAU,EACjE,OAAQ,EAAR,CACE,IAAK,KACH,MAAO,CAAE,MAAO,KAAM,KAAM,SAAU,EACxC,IAAK,cACH,MAAO,CAAE,MAAO,mCAAoC,KAAM,QAAS,EACrE,IAAK,mBACH,MAAO,CAAE,MAAO,+BAAgC,KAAM,SAAU,EAClE,IAAK,oBACH,MAAO,CAAE,MAAO,oCAAqC,KAAM,SAAU,EACvE,IAAK,aACH,MAAO,CAAE,MAAO,gCAAiC,KAAM,SAAU,EACnE,IAAK,UACH,MAAO,CAAE,MAAO,UAAW,KAAM,SAAU,EAC7C,QACE,MAAO,CAAE,MAAO,EAAQ,KAAM,SAAU,CAC5C,CACF"}
@@ -1,2 +0,0 @@
1
- import{a as e,n as t,r as n,s as r}from"./index-BVxOlseC.js";var i=r(e(),1),a={data:void 0,error:void 0,status:`idle`,updatedAt:null},o=new Map,s=0,c=[],l=0,u=0;function ee(){--s;let e=c.shift();e&&e()}function te(e){let t=()=>{let t=u;s+=1,s>l&&(l=s);let n=()=>{t===u&&ee()},r;try{r=e()}catch(e){return n(),Promise.reject(e instanceof Error?e:Error(String(e)))}return r.then(e=>(n(),e),e=>{throw n(),e})};return s<4?t():new Promise((e,n)=>{c.push(()=>{t().then(e,n)})})}function ne(){u+=1,s=0,l=0;for(let e of c.splice(0))e()}function re(){return{active:s,queued:c.length,peak:l}}function d(e){let t=o.get(e);return t||(t={snapshot:a,inFlight:null,fetcher:null,subscribers:new Set,issued:0,issuedAt:0,applied:0},o.set(e,t)),t}function f(e,t){e.snapshot={...e.snapshot,...t}}function p(e){let t=o.get(e);if(t)for(let e of t.subscribers)e()}function m(e,t){if(Object.is(e,t))return!0;if(typeof e!=typeof t||e===null||t===null||typeof e!=`object`||Array.isArray(e)!==Array.isArray(t))return!1;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>m(e,t[n]));let n=e,r=t,i=Object.keys(n);return i.length===Object.keys(r).length&&i.every(e=>Object.prototype.hasOwnProperty.call(r,e)&&m(n[e],r[e]))}function ie(e,t){let n=d(e);return n.subscribers.add(t),()=>{n.subscribers.delete(t)}}function ae(e){return d(e).snapshot}function oe(e,t){return e.snapshot.updatedAt===null||e.snapshot.status===`error`?!1:Date.now()-e.snapshot.updatedAt<t}function se(e,t){return e.inFlight===null?!1:t.joinWindowMs===void 0||Date.now()-e.issuedAt<t.joinWindowMs}function ce(e,t,n){let r=d(e);if(r.fetcher=t,!n.force){if(se(r,n))return r.inFlight;if(n.maxAgeMs!==void 0&&oe(r,n.maxAgeMs))return Promise.resolve()}let i=r.issued+=1;r.issuedAt=Date.now(),f(r,{status:r.snapshot.data===void 0?`loading`:`refreshing`}),p(e);let a=te(t).then(e=>{if(i<r.applied)return;r.applied=i;let t=r.snapshot.data!==void 0&&m(r.snapshot.data,e);f(r,{data:t?r.snapshot.data:e,error:void 0,status:`success`,updatedAt:Date.now()})}).catch(e=>{i<r.applied||(r.applied=i,f(r,{error:e instanceof Error?e:Error(String(e)),status:`error`}))}).finally(()=>{r.issued===i&&(r.inFlight=null),p(e)});return r.inFlight=a,a}function le(e,t){return ce(e,t,{})}function ue(e,t,n){return ce(e,t,{maxAgeMs:n})}function h(e,t,n=!1){return ce(e,t,n?{force:!0}:{joinWindowMs:250})}function g(e){let t=o.get(e);t&&t.fetcher&&le(e,t.fetcher)}function _(e){for(let t of o.keys())t.startsWith(e)&&g(t)}function de(e){for(let[t,n]of o)n.subscribers.size>0&&t.startsWith(e)&&g(t)}function fe(e,t){t.snapshot=a,t.fetcher=null,t.inFlight=null,t.issued+=1,t.applied=t.issued,p(e)}function pe(){ne();for(let[e,t]of[...o]){if(t.subscribers.size===0){o.delete(e);continue}fe(e,t)}}var v=`ashlr.verse.drafts.v1`,y=`ashlr.verse.sent.v1`,me=40,b=65536;function x(e,t){let n={};try{let r=localStorage.getItem(e),i=r?JSON.parse(r):null;if(i&&typeof i==`object`&&!Array.isArray(i))for(let[e,r]of Object.entries(i)){let i=t(r);i!==null&&(n[e]=i)}}catch{}return n}function S(e,t){let n=Object.keys(t);for(let e of n.slice(0,Math.max(0,n.length-me)))delete t[e];try{return localStorage.setItem(e,JSON.stringify(t)),!0}catch{return!1}}var he=e=>typeof e==`string`&&e.length>0?e.slice(0,b):null,ge=e=>{if(!Array.isArray(e))return null;let t=e.filter(e=>typeof e==`string`&&e.length>0).slice(-25).map(e=>e.slice(0,b));return t.length>0?t:null},C=new Map;function _e(e){if(!e)return``;let t=C.get(e);return t===void 0?x(v,he)[e]??``:t}function ve(e,t){if(!e)return;let n=t.trim().length>0?t.slice(0,b):``,r=x(v,he);if(delete r[e],n&&(r[e]=n),C.delete(e),!S(v,r)){C.set(e,n);for(let e of[...C.keys()].slice(0,Math.max(0,C.size-me)))C.delete(e)}}function ye(e){return e?x(y,ge)[e]??[]:[]}function be(e,t){if(!e||t.trim().length===0)return;let n=x(y,ge),r=n[e]??[];delete n[e],n[e]=(r[r.length-1]===t?r:[...r,t.slice(0,b)]).slice(-25),S(y,n)}function xe(e){if(e){C.delete(e);for(let[t,n]of[[v,he],[y,ge]]){let r=x(t,n);e in r&&(delete r[e],S(t,r))}}}function Se(){C.clear();for(let e of[v,y])try{localStorage.removeItem(e)}catch{}}var Ce=`ashlr.readClientProof.v1`,we=/^[a-f0-9]{64}$/,Te=12e5;function Ee(){let e=new Uint8Array(32);return crypto.getRandomValues(e),Array.from(e,e=>e.toString(16).padStart(2,`0`)).join(``)}function De(){try{let e=sessionStorage.getItem(Ce);if(e&&we.test(e))return e}catch{}let e=Ee();try{sessionStorage.setItem(Ce,e)}catch{}return e}var Oe=De(),w=null,T=null,ke=!1,E=null,D=null,O=null,k={phase:`checking`,checked:!1,mutationTokenHeldUntil:null},A=new Set;function Ae(){for(let e of A)e()}function j(e){k={...k,...e},Ae()}function M(e){return A.add(e),()=>A.delete(e)}function N(){return k}function P(){return Oe}async function F(e){let t=e.trim();if(!/^[a-f0-9]{64}$/.test(t))throw Error(`That does not look like a read token — expected 64 hex characters.`);let n=await fetch(`/api/session`,{method:`POST`,credentials:`same-origin`,headers:{"x-ashlr-token":t,"x-ashlr-read-client":Oe}});if(n.status===204){E=t,j({phase:`authenticated`,checked:!0});return}throw n.status===401?Error(`Server rejected that token. Double-check the read token printed by this server at startup.`):Error(`Unexpected response establishing session (HTTP ${n.status}).`)}async function je(){try{await fetch(`/api/session`,{method:`DELETE`,credentials:`same-origin`,headers:{"x-ashlr-read-client":Oe}})}catch{}E=null,O=null,I()}function I(){B(),pe(),Se(),j({phase:`unauthenticated`,checked:!0})}function L(){if(k.phase===`authenticated`){if(E){Me();return}I()}}function Me(){if(D)return D;let e=E;return e?(D=(async()=>{try{return await F(e),de(``),!0}catch{return E=null,O=null,I(),!1}finally{D=null}})(),D):Promise.resolve(!1)}function Ne(e){j({phase:e?`authenticated`:`unauthenticated`,checked:!0})}function Pe(){let e=window.__ASHLR_TOKENS__;if(e&&typeof e==`object`){try{delete window.__ASHLR_TOKENS__}catch{window.__ASHLR_TOKENS__=void 0}typeof e.readToken==`string`&&(O={readToken:e.readToken,...typeof e.token==`string`?{token:e.token}:{}})}return O?{...O}:null}async function Fe(){let e=Pe();if(!e)return!1;try{await F(e.readToken)}catch{return O=null,!1}return e.token&&/^[a-f0-9]{64}$/.test(e.token.trim())&&R(e.token.trim(),{host:!0}),!0}function Ie(){return w}function Le(){return w!==null}function Re(){T&&clearTimeout(T),T=setTimeout(()=>{ke&&w!==null?z():B()},Te)}function R(e,t={}){w=e,ke=t.host===!0,j({mutationTokenHeldUntil:Date.now()+Te}),Re()}function z(){w!==null&&(j({mutationTokenHeldUntil:Date.now()+Te}),Re())}function B(){w=null,ke=!1,T&&=(clearTimeout(T),null),j({mutationTokenHeldUntil:null})}var ze=[`runs`,`swarms`,`inbox`,`daemon`,`daemon-observation`,`fleet-activity-ping`,`fleet-activity-observation`,`snapshot`,`session-expired`],Be={runs:[`runs`],swarms:[`swarms`],inbox:[`inbox`],daemon:[`daemon`,`control-snapshot`,`verse-control`,`verse-usage-control`,`verse-caps`],"daemon-observation":[`daemon`,`control-snapshot`,`verse-control`,`verse-usage-control`,`verse-caps`],"fleet-activity-ping":[`fleet-activity`,`fleet`],"fleet-activity-observation":[`fleet-activity`,`fleet`],snapshot:[`dashboard-snapshot`,`agent-os-snapshot`],"session-expired":[]},Ve=new Map,V=null,H=null,U=0;function He(){return Math.min(1e3*2**U,15e3)}function W(){V&&=(V.close(),null),H&&=(clearTimeout(H),null)}function Ue(){H||=setTimeout(()=>{H=null,U+=1,We()},He())}function We(){if(n()){W();return}if(N().phase!==`authenticated`)return;W();let e=`/api/events?client=${encodeURIComponent(P())}`,t=new EventSource(e,{withCredentials:!0});V=t,t.onopen=()=>{U=0};for(let e of ze)t.addEventListener(e,t=>{let n=t,r;try{r=JSON.parse(n.data)}catch{r=void 0}for(let t of Be[e])g(t);e===`inbox`&&(_(`inbox-list:`),_(`proposal-detail-`)),e===`session-expired`&&L();let i=Ve.get(e);if(i)for(let e of i)e(r)});t.onerror=()=>{t.close(),V===t&&(V=null),N().phase===`authenticated`&&Ue()}}M(()=>{N().phase===`authenticated`?(U=0,We()):W()});var Ge=`ashlr.theme.v1`;function Ke(e){let t=document.documentElement;e===`system`?t.removeAttribute(`data-theme`):t.setAttribute(`data-theme`,e)}function qe(){try{let e=localStorage.getItem(Ge);if(e===`light`||e===`dark`||e===`system`)return e}catch{}return`system`}var G=qe();Ke(G);var Je=new Set;function Ye(){for(let e of Je)e()}function Xe(e){return Je.add(e),()=>Je.delete(e)}function K(){return G}function q(e){G=e,Ke(G);try{localStorage.setItem(Ge,G)}catch{}Ye()}function Ze(){q(G===`system`?`light`:G===`light`?`dark`:`system`)}var Qe=`ashlr.verse.appearance.v1`,$e=30,et=78,J={h:245,s:72,l:58},tt=[{id:`indigo`,label:`Indigo`,h:245,s:72,l:58},{id:`blue`,label:`Blue`,h:212,s:80,l:50},{id:`cyan`,label:`Cyan`,h:190,s:80,l:40},{id:`teal`,label:`Teal`,h:168,s:70,l:38},{id:`green`,label:`Green`,h:145,s:60,l:38},{id:`amber`,label:`Amber`,h:38,s:80,l:42},{id:`rose`,label:`Rose`,h:348,s:72,l:50},{id:`violet`,label:`Violet`,h:278,s:66,l:55}];function nt(){try{return typeof window<`u`&&typeof window.matchMedia==`function`&&window.matchMedia(`(prefers-reduced-motion: reduce)`).matches}catch{return!1}}function rt(){return{theme:`system`,accentH:J.h,accentS:J.s,accentL:J.l,density:`comfortable`,uiScale:`default`,displayFont:`grotesk`,radius:`default`,motion:`system`,reduceMotion:nt()}}function it(e){return e===`system`||e===`reduce`||e===`full`}function at(e){return e===`reduce`||e!==`full`&&nt()}var ot=(e,t,n)=>Math.min(n,Math.max(t,e));function st(e){return e===`comfortable`||e===`compact`}function ct(e){return e==="default"||e===`large`||e===`xlarge`}function lt(e){return e===`grotesk`||e===`ui`||e===`mono`}function ut(e){return e===`sharp`||e==="default"||e===`soft`}function dt(e,t){let n={...e,...t},r=t.reduceMotion,i=it(t.motion)?t.motion:typeof r==`boolean`?r?`reduce`:`full`:it(e.motion)?e.motion:`system`;return{theme:n.theme===`light`||n.theme===`dark`?n.theme:`system`,accentH:Number.isFinite(n.accentH)?(Math.round(n.accentH)%360+360)%360:J.h,accentS:Number.isFinite(n.accentS)?ot(Math.round(n.accentS),0,100):J.s,accentL:Number.isFinite(n.accentL)?ot(Math.round(n.accentL),$e,et):J.l,density:st(n.density)?n.density:`comfortable`,uiScale:ct(n.uiScale)?n.uiScale:`default`,displayFont:lt(n.displayFont)?n.displayFont:`grotesk`,radius:ut(n.radius)?n.radius:`default`,motion:i,reduceMotion:at(i)}}function ft(){let e=rt(),t={};try{let e=localStorage.getItem(Qe);if(e){let n=JSON.parse(e);n&&typeof n==`object`&&(t=n)}}catch{}let{reduceMotion:n,...r}=t;return dt(e,{...r,theme:K()})}function pt(e){try{let{theme:t,reduceMotion:n,...r}=e;localStorage.setItem(Qe,JSON.stringify(r))}catch{}}var mt={grotesk:null,ui:`var(--font-ui)`,mono:`var(--font-mono)`};function ht(e){if(typeof document>`u`)return;let t=document.documentElement;t.style.setProperty(`--accent-h`,String(e.accentH)),t.style.setProperty(`--accent-s`,`${e.accentS}%`),t.style.setProperty(`--accent-l`,`${e.accentL}%`);let n=mt[e.displayFont];n===null?t.style.removeProperty(`--font-display`):t.style.setProperty(`--font-display`,n),t.setAttribute(`data-density`,e.density),t.setAttribute(`data-ui-scale`,e.uiScale),t.setAttribute(`data-radius`,e.radius),e.motion===`system`?t.removeAttribute(`data-motion`):t.setAttribute(`data-motion`,e.motion)}var Y=ft();ht(Y);var X=new Set;function gt(){for(let e of X)e()}Xe(()=>{Y.theme!==K()&&(Y={...Y,theme:K()},gt())});function _t(e){return X.add(e),()=>X.delete(e)}function vt(){return Y}function yt(e){let t=dt(Y,e),n=t.theme!==Y.theme;Y=t,ht(Y),pt(Y),n&&q(Y.theme),gt()}function bt(){try{localStorage.removeItem(Qe)}catch{}Y=rt(),ht(Y),q(`system`),gt()}function xt(e=Y){let t=rt();return e.theme===t.theme&&e.accentH===t.accentH&&e.accentS===t.accentS&&e.accentL===t.accentL&&e.density===t.density&&e.uiScale===t.uiScale&&e.displayFont===t.displayFont&&e.radius===t.radius&&e.motion===t.motion}function St(e=Y){return tt.find(t=>t.h===e.accentH&&t.s===e.accentS&&t.l===e.accentL)??null}var Ct={min:$e,max:et};function wt(e,t){let n=t?.freshMs??1e4,r=(0,i.useSyncExternalStore)((0,i.useCallback)(t=>ie(e.key,t),[e.key]),()=>ae(e.key),()=>ae(e.key));return(0,i.useEffect)(()=>{ue(e.key,()=>e.fetch(),n)},[e.key,n]),r}function Tt(e){return(0,i.useCallback)(()=>{h(e.key,()=>e.fetch())},[e])}function Et(e){return(0,i.useCallback)(()=>{h(e.key,()=>e.fetch(),!0)},[e])}function Dt(){return(0,i.useSyncExternalStore)(M,()=>N().phase,()=>N().phase)}function Ot(){let e=(0,i.useSyncExternalStore)(M,()=>N().mutationTokenHeldUntil,()=>N().mutationTokenHeldUntil);return{hasHold:Le(),token:Ie(),heldUntil:e,setToken:R,touch:z,clear:B}}function kt(){return{theme:(0,i.useSyncExternalStore)(Xe,K,K),set:q,cycle:Ze}}function At(){return{appearance:(0,i.useSyncExternalStore)(_t,vt,vt),set:yt,reset:bt}}var Z=class extends Error{status;path;detail;code;constructor(e,t,n,r=null,i=null){super(e),this.status=t,this.path=n,this.detail=r,this.code=i,this.name=`ApiError`}},jt=class extends Z{constructor(e){super(`This server was started without --allow-dispatch, so mutations are disabled.`,404,e),this.name=`DispatchDisabledError`}};async function Mt(e,t){let n=await fetch(e,{method:`GET`,credentials:`same-origin`,headers:{"x-ashlr-read-client":P()},signal:t});if(n.status===401)throw L(),new Z(`Read session expired.`,401,e);if(!n.ok)throw new Z(`GET ${e} failed (HTTP ${n.status}).`,n.status,e);return await n.json()}async function Nt(e,t,n,r){let i=await fetch(e,{method:`POST`,credentials:`same-origin`,headers:{"Content-Type":`application/json`,"x-ashlr-token":n},body:JSON.stringify(t??{}),signal:r});if(i.status===401)throw new Z(`Mutation token was rejected.`,401,e);if(!i.ok){let{detail:t,code:n}=await Pt(i);throw i.status===404&&n===null?new jt(e):new Z(`POST ${e} failed (HTTP ${i.status})${t?`: ${t}`:``}.`,i.status,e,t||null,n)}if(i.status!==204)return await i.json()}async function Pt(e){try{let t=await e.json();return{detail:typeof t.error==`string`&&t.error?t.error:typeof t.note==`string`?t.note:``,code:typeof t.code==`string`&&t.code?t.code:null}}catch{return{detail:``,code:null}}}var Q={grid:`_grid_x7p2y_1`,card:`_card_x7p2y_10`,title:`_title_x7p2y_19`,stat:`_stat_x7p2y_25`,caption:`_caption_x7p2y_31`,line:`_line_x7p2y_37`,row:`_row_x7p2y_42`,cell:`_cell_x7p2y_51`},$=t();function Ft({width:e=`100%`}){return(0,$.jsx)(`div`,{className:`skeleton ${Q.line}`,style:{width:e}})}function It(){return(0,$.jsxs)(`div`,{className:Q.card,children:[(0,$.jsx)(`div`,{className:`skeleton ${Q.title}`}),(0,$.jsx)(`div`,{className:`skeleton ${Q.stat}`}),(0,$.jsx)(`div`,{className:`skeleton ${Q.caption}`})]})}function Lt(){return(0,$.jsxs)(`div`,{className:Q.row,children:[(0,$.jsx)(`div`,{className:`skeleton ${Q.cell}`,style:{width:`18%`}}),(0,$.jsx)(`div`,{className:`skeleton ${Q.cell}`,style:{width:`38%`}}),(0,$.jsx)(`div`,{className:`skeleton ${Q.cell}`,style:{width:`14%`}}),(0,$.jsx)(`div`,{className:`skeleton ${Q.cell}`,style:{width:`10%`}})]})}function Rt({count:e=4}){return(0,$.jsx)(`div`,{className:Q.grid,children:Array.from({length:e},(e,t)=>(0,$.jsx)(It,{},t))})}var zt={skipLink:`_skipLink_1uply_1`};function Bt(){return(0,$.jsx)(`button`,{type:`button`,className:zt.skipLink,onClick:()=>{let e=document.getElementById(`main-content`);e?.focus(),e?.scrollIntoView({block:`start`})},children:`Skip to content`})}export{Ne as A,ve as B,B as C,Ie as D,N as E,z as F,re as G,ae as H,xe as I,ie as J,h as K,_e as L,L as M,R as N,P as O,M as P,ye as R,Fe as S,F as T,g as U,ue as V,_ as W,Ct as _,Lt as a,St as b,Mt as c,Dt as d,Ot as f,kt as g,Et as h,Ft as i,Me as j,Le as k,Nt as l,Tt as m,It as n,Z as o,wt as p,le as q,Rt as r,jt as s,Bt as t,At as u,tt as v,je as w,Ze as x,xt as y,be as z};
2
- //# sourceMappingURL=global-oEl9Qj8u.js.map
@@ -1,3 +0,0 @@
1
- const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/ConfirmDialog-DLrLKM0c.js","assets/index-BVxOlseC.js","assets/Dialog-BS9Dxi3G.js","assets/focus-trap-HtcoXeEq.js","assets/Dialog-tQ8kFulD.css","assets/ConfirmDialog-Dx15x0Ho.css","assets/MutationTokenDialog-mxrw0Yvy.js","assets/global-oEl9Qj8u.js","assets/global-BlI2BYa1.css","assets/MutationTokenDialog-CrfJ0PdD.css"])))=>i.map(i=>d[i]);
2
- import{a as e,n as t,s as n,t as r}from"./index-BVxOlseC.js";import{k as i,o as a,s as o}from"./global-oEl9Qj8u.js";import{t as s}from"./preloaded-Cwf9rsnZ.js";var c=n(e(),1),l=t(),u=s(()=>r(()=>import(`./ConfirmDialog-DLrLKM0c.js`).then(e=>e.n).then(e=>e.ConfirmDialog),__vite__mapDeps([0,1,2,3,4,5]))).Slot,d=s(()=>r(()=>import(`./MutationTokenDialog-mxrw0Yvy.js`).then(e=>e.n).then(e=>e.MutationTokenDialog),__vite__mapDeps([6,1,7,8,2,3,4,9]))).Slot,f={request:null,phase:`confirm`,error:null},p=f,m=new Set;function h(e){p=e;for(let e of[...m])e()}function g(e){return p.request?!1:e.skipConfirm?(e.token&&!i()?h({request:e,phase:`token`,error:null}):y(e),!0):(h({request:e,phase:`confirm`,error:null}),!0)}function _(){return p.request!==null}function v(e){return e instanceof o?"This server was started without dispatch, so actions are unavailable. Run `ashlr verse` to act.":e instanceof a?e.status===401?"The mutation token was rejected. Unlock again with the token `ashlr verse` printed.":e.status===409?e.detail??`Something changed underneath this action. Refresh and try again.`:e.detail??`The server refused (HTTP ${e.status}).`:e instanceof Error&&e.message?e.message:`Something went wrong.`}async function y(e){h({request:e,phase:`running`,error:null});try{await e.run(),h(f),e.onDone?.()}catch(t){let n=v(t);h(e.skipConfirm?f:{request:e,phase:`confirm`,error:n}),e.onError?.(n)}}function b(){let{request:e}=p;if(e&&p.phase!==`running`){if(e.token&&!i()){h({request:e,phase:`token`,error:null});return}y(e)}}function x(){p.phase!==`running`&&h(f)}function S(){let{request:e}=p;e&&(i()?y(e):h(f))}function C(e){return m.add(e),()=>m.delete(e)}function w(){return(0,c.useSyncExternalStore)(C,()=>p,()=>p)}function T(){let{request:e,phase:t,error:n}=w();return e?(0,l.jsxs)(c.Suspense,{fallback:null,children:[(0,l.jsx)(u,{open:t!==`token`&&!e.skipConfirm,onClose:x,title:e.title,body:e.body,confirmLabel:n?`Try again`:e.confirmLabel,destructive:e.destructive,busy:t===`running`,error:n,onConfirm:b}),(0,l.jsx)(d,{open:t===`token`,onClose:S,reason:e.tokenReason??`This action changes state on this machine and requires the dispatch token.`,tokenHelp:`the mutation token ashlr verse printed`})]}):null}export{g as i,v as n,_ as r,T as t};
3
- //# sourceMappingURL=guarded-action-OzqcPjmh.js.map
@@ -1 +0,0 @@
1
- {"version":3,"mappings":";qLA2CM,EAHsB,YACpB,OAAO,8BAA+B,cAAC,KAAM,GAAM,EAAE,aAAa,iCAEpD,EAAoB,KAIpC,EAHoB,YAClB,OAAO,oCAAkD,cAAC,KAAM,GAAM,EAAE,mBAAmB,qCAEvE,EAAkB,KAoCxC,EAAmB,CAAE,QAAS,KAAM,MAAO,UAAW,MAAO,IAAK,EACpE,EAAoB,EAClB,EAAY,IAAI,IAEtB,SAAS,EAAI,EAAwB,CACnC,EAAQ,EACR,IAAK,IAAM,IAAK,CAAC,GAAG,CAAS,EAAG,EAAE,CACpC,CAGA,SAAgB,EAAe,EAAkC,CAQ/D,OAPI,EAAM,QAAgB,GACtB,EAAQ,aACN,EAAQ,OAAS,CAAC,EAAgB,EAAG,EAAI,CAAE,UAAS,MAAO,QAAS,MAAO,IAAK,CAAC,EAChF,EAAa,CAAO,EAClB,KAET,EAAI,CAAE,UAAS,MAAO,UAAW,MAAO,IAAK,CAAC,EACvC,GACT,CAEA,SAAgB,GAAuB,CACrC,OAAO,EAAM,UAAY,IAC3B,CAQA,SAAgB,EAAoB,EAAsB,CAOxD,OANI,aAAe,EAA8B,kGAC7C,aAAe,EACb,EAAI,SAAW,IAAY,sFAC3B,EAAI,SAAW,IAAY,EAAI,QAAU,mEACtC,EAAI,QAAU,4BAA4B,EAAI,OAAO,IAEvD,aAAe,OAAS,EAAI,QAAU,EAAI,QAAU,uBAC7D,CAEA,eAAe,EAAQ,EAAwC,CAC7D,EAAI,CAAE,UAAS,MAAO,UAAW,MAAO,IAAK,CAAC,EAC9C,GAAI,CACF,MAAM,EAAQ,IAAI,EAClB,EAAI,CAAI,EACR,EAAQ,SAAS,CACnB,OAAS,EAAK,CACZ,IAAM,EAAU,EAAoB,CAAG,EACvC,EAAI,EAAQ,YAAc,EAAO,CAAE,UAAS,MAAO,UAAW,MAAO,CAAQ,CAAC,EAC9E,EAAQ,UAAU,CAAO,CAC3B,CACF,CAEA,SAAS,GAAgB,CACvB,GAAM,CAAE,WAAY,EAChB,GAAC,GAAW,EAAM,QAAU,UAChC,IAAI,EAAQ,OAAS,CAAC,EAAgB,EAAG,CACvC,EAAI,CAAE,UAAS,MAAO,QAAS,MAAO,IAAK,CAAC,EAC5C,MACF,CACA,EAAa,CAAO,CADpB,CAEF,CAEA,SAAS,GAAe,CAClB,EAAM,QAAU,WACpB,EAAI,CAAI,CACV,CAEA,SAAS,GAAoB,CAC3B,GAAM,CAAE,WAAY,EACf,IAGD,EAAgB,EAAG,EAAa,CAAO,EACtC,EAAI,CAAI,EACf,CAEA,SAAS,EAAU,EAAkC,CAEnD,OADA,EAAU,IAAI,CAAQ,MACT,EAAU,OAAO,CAAQ,CACxC,CAEA,SAAgB,GAA4B,CAC1C,SAAO,wBAAqB,MAAiB,MAAa,CAAK,CACjE,CAGA,SAAgB,GAAY,CAC1B,GAAM,CAAE,UAAS,QAAO,SAAU,EAAc,EAEhD,OADK,GAEH,UAAC,WAAD,CAAU,SAAU,KAApB,WACE,SAAC,EAAD,CACE,KAAM,IAAU,SAAW,CAAC,EAAQ,YACpC,QAAS,EACT,MAAO,EAAQ,MACf,KAAM,EAAQ,KACd,aAAc,EAAQ,YAAc,EAAQ,aAC5C,YAAa,EAAQ,YACrB,KAAM,IAAU,UACT,QACP,UAAW,CACZ,IACD,SAAC,EAAD,CACE,KAAM,IAAU,QAChB,QAAS,EACT,OAAQ,EAAQ,aAAe,6EAC/B,UAAU,wCACX,EACO,IApBS,IAsBvB","names":[],"ignoreList":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/guarded-action.tsx"],"sourcesContent":["/**\n * routes/verse/shell/guarded-action.tsx — confirmation FIRST, then the\n * mutation token, then the action (unit C1; SPEC-310C §1 \"Guarded actions ask\n * for confirmation, then the mutation token\").\n *\n * The palette and the drawer's single-letter keys are the fastest way to do\n * anything in Verse, which is exactly why they must not be a shortcut around\n * the confirm step the regular UI requires. Every guarded path — a catalog\n * command with a `guard`, a Needs-you approve / reject / veto — goes through\n * ONE host, so the order can never differ between two entry points:\n *\n * confirm ──Cancel──▶ nothing happened\n * │ Confirm\n * ├─ token needed and not held ─▶ MutationTokenDialog ──Cancel──▶ nothing\n * │ │ unlocked\n * ▼ ▼\n * running (the confirm dialog shows \"Working…\")\n * ├─ ok ─▶ closed (the caller's own onDone decides the toast)\n * └─ error ─▶ back to confirm, with the sentence; Confirm retries\n *\n * Why confirm before token (the old ApprovalDetail asked for the token\n * first): an operator who presses A by mistake should be able to back out at\n * the FIRST prompt, which should describe what is about to happen — not a\n * prompt asking for a secret.\n */\nimport { Suspense, useSyncExternalStore, type ComponentProps, type ReactNode } from 'react';\nimport type { MutationTokenDialog as MutationTokenDialogComponent } from '../../../components/auth/MutationTokenDialog.js';\nimport { hasMutationHold } from '../../../data/auth-store.js';\nimport { ApiError, DispatchDisabledError } from '../../../data/client.js';\nimport type { ConfirmDialog as ConfirmDialogComponent } from '../../inbox/ConfirmDialog.js';\nimport { preloadedLazy } from './preloaded.js';\n\n/**\n * The two dialogs are preloaded, not static imports: GuardHost is mounted by\n * the shell at first paint but draws nothing until a guarded action starts,\n * and the dialogs (with the dialog primitive and its focus trap) were ~4 KB\n * of chat first-paint critical JS. Their download starts when this module\n * evaluates, so the first guarded action finds them in and they mount in the\n * same render that opens them.\n */\nconst ConfirmDialogModule = preloadedLazy<ComponentProps<typeof ConfirmDialogComponent>>(\n () => import('../../inbox/ConfirmDialog.js').then((m) => m.ConfirmDialog),\n);\nconst ConfirmDialog = ConfirmDialogModule.Slot;\nconst TokenDialogModule = preloadedLazy<ComponentProps<typeof MutationTokenDialogComponent>>(\n () => import('../../../components/auth/MutationTokenDialog.js').then((m) => m.MutationTokenDialog),\n);\nconst MutationTokenDialog = TokenDialogModule.Slot;\n\n/** Resolves once both dialogs are in (tests await it; the app never needs to). */\nexport function preloadGuardDialogs(): Promise<unknown> {\n return Promise.all([ConfirmDialogModule.ready(), TokenDialogModule.ready()]);\n}\n\nexport interface GuardedRequest {\n title: string;\n body: ReactNode;\n confirmLabel: string;\n destructive: boolean;\n /** Ask for the mutation token before running (every server write does). */\n token: boolean;\n /** Why the token is needed, in the token dialog's own words. */\n tokenReason?: string;\n run: () => Promise<void>;\n /**\n * For actions the regular UI does not confirm either (Mark read, Reconnect\n * with no item copy): straight to the token (if needed), then run; a\n * failure goes to `onError` only, since there is no dialog to show it in.\n */\n skipConfirm?: boolean;\n onDone?: () => void;\n /** Called with the sentence when the run fails (after the dialog shows it). */\n onError?: (message: string) => void;\n}\n\ntype Phase = 'confirm' | 'token' | 'running';\n\ninterface GuardState {\n request: GuardedRequest | null;\n phase: Phase;\n error: string | null;\n}\n\nconst IDLE: GuardState = { request: null, phase: 'confirm', error: null };\nlet state: GuardState = IDLE;\nconst listeners = new Set<() => void>();\n\nfunction set(next: GuardState): void {\n state = next;\n for (const l of [...listeners]) l();\n}\n\n/** Start a guarded action. A second request while one is open replaces nothing: it is ignored. */\nexport function requestGuarded(request: GuardedRequest): boolean {\n if (state.request) return false;\n if (request.skipConfirm) {\n if (request.token && !hasMutationHold()) set({ request, phase: 'token', error: null });\n else void execute(request);\n return true;\n }\n set({ request, phase: 'confirm', error: null });\n return true;\n}\n\nexport function isGuardOpen(): boolean {\n return state.request !== null;\n}\n\n/** Test hygiene. */\nexport function resetGuard(): void {\n set(IDLE);\n}\n\n/** Operator language for a failed write — never a stack, never a path. */\nexport function describeActionError(err: unknown): string {\n if (err instanceof DispatchDisabledError) return 'This server was started without dispatch, so actions are unavailable. Run `ashlr verse` to act.';\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.status === 409) return err.detail ?? 'Something changed underneath this action. Refresh and try again.';\n return err.detail ?? `The server refused (HTTP ${err.status}).`;\n }\n return err instanceof Error && err.message ? err.message : 'Something went wrong.';\n}\n\nasync function execute(request: GuardedRequest): Promise<void> {\n set({ request, phase: 'running', error: null });\n try {\n await request.run();\n set(IDLE);\n request.onDone?.();\n } catch (err) {\n const message = describeActionError(err);\n set(request.skipConfirm ? IDLE : { request, phase: 'confirm', error: message });\n request.onError?.(message);\n }\n}\n\nfunction confirm(): void {\n const { request } = state;\n if (!request || state.phase === 'running') return;\n if (request.token && !hasMutationHold()) {\n set({ request, phase: 'token', error: null });\n return;\n }\n void execute(request);\n}\n\nfunction cancel(): void {\n if (state.phase === 'running') return;\n set(IDLE);\n}\n\nfunction tokenClosed(): void {\n const { request } = state;\n if (!request) return;\n // MutationTokenDialog closes synchronously after storing the token, so a\n // live read says whether this close was \"unlocked\" or \"cancelled\".\n if (hasMutationHold()) void execute(request);\n else set(IDLE);\n}\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener);\n return () => listeners.delete(listener);\n}\n\nexport function useGuardState(): GuardState {\n return useSyncExternalStore(subscribe, () => state, () => state);\n}\n\n/** Mounted once by the shell. */\nexport function GuardHost() {\n const { request, phase, error } = useGuardState();\n if (!request) return null;\n return (\n <Suspense fallback={null}>\n <ConfirmDialog\n open={phase !== 'token' && !request.skipConfirm}\n onClose={cancel}\n title={request.title}\n body={request.body}\n confirmLabel={error ? 'Try again' : request.confirmLabel}\n destructive={request.destructive}\n busy={phase === 'running'}\n error={error}\n onConfirm={confirm}\n />\n <MutationTokenDialog\n open={phase === 'token'}\n onClose={tokenClosed}\n reason={request.tokenReason ?? 'This action changes state on this machine and requires the dispatch token.'}\n tokenHelp=\"the mutation token ashlr verse printed\"\n />\n </Suspense>\n );\n}\n"],"file":"guarded-action-OzqcPjmh.js"}
@@ -1,2 +0,0 @@
1
- import{n as e}from"./index-BVxOlseC.js";var t=e();function n({size:e=16,title:n,children:r,...i}){return(0,t.jsxs)(`svg`,{width:e,height:e,viewBox:`0 0 16 16`,fill:`none`,stroke:`currentColor`,strokeWidth:1.5,strokeLinecap:`round`,strokeLinejoin:`round`,focusable:`false`,...n?{role:`img`}:{"aria-hidden":!0},...i,children:[n?(0,t.jsx)(`title`,{children:n}):null,r]})}var r=e=>(0,t.jsx)(n,{...e,children:(0,t.jsx)(`path`,{d:`M2.5 11.5V4.25A1.75 1.75 0 0 1 4.25 2.5h7.5a1.75 1.75 0 0 1 1.75 1.75v4.5a1.75 1.75 0 0 1-1.75 1.75H5.5L2.5 13.5v-2Z`})}),i=e=>(0,t.jsxs)(n,{...e,children:[(0,t.jsx)(`path`,{d:`M2 9.5 3.6 3.4A1.5 1.5 0 0 1 5.05 2.3h5.9a1.5 1.5 0 0 1 1.45 1.1L14 9.5`}),(0,t.jsx)(`path`,{d:`M2 9.5h3l.8 1.6h4.4l.8-1.6h3v2.6A1.9 1.9 0 0 1 12.1 14H3.9A1.9 1.9 0 0 1 2 12.1V9.5Z`})]}),a=e=>(0,t.jsxs)(n,{...e,children:[(0,t.jsx)(`path`,{d:`M2.2 11.5a6.4 6.4 0 1 1 11.6 0`}),(0,t.jsx)(`path`,{d:`M8 11 10.8 6.6`}),(0,t.jsx)(`circle`,{cx:`8`,cy:`11.6`,r:`0.9`,fill:`currentColor`,stroke:`none`})]}),o=e=>(0,t.jsxs)(n,{...e,children:[(0,t.jsx)(`path`,{d:`M2.5 4.5h4M9.5 4.5h4M2.5 11.5h2M7.5 11.5h6`}),(0,t.jsx)(`circle`,{cx:`8`,cy:`4.5`,r:`1.6`}),(0,t.jsx)(`circle`,{cx:`6`,cy:`11.5`,r:`1.6`})]});export{o as a,i,r as n,a as r,n as t};
2
- //# sourceMappingURL=icon-base-DvM1eI5V.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"icon-base-DvM1eI5V.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/icon-base.tsx"],"sourcesContent":["/**\n * components/primitives/icon-base.tsx — the icon geometry (16px box, 1.5px\n * stroke, round caps/joins, currentColor) and the few glyphs the Verse rail\n * draws at first paint. Everything here is re-exported by icons.tsx, which\n * remains the console's icon set and the import site for everyone else.\n *\n * WHY SPLIT: icons.tsx holds every glyph any surface uses, and the rail is on\n * the chat first-paint path; importing it there put the whole set (~4 KB) in\n * the chat first-paint critical JS (SPEC-310A §1). Add a glyph here only when\n * a first-paint module draws it.\n *\n * Every icon is decorative by default (`aria-hidden`); pass `title` only when\n * the icon is the sole carrier of meaning (it then becomes `role=\"img\"`).\n */\nimport type { ReactNode, SVGProps } from 'react';\n\nexport interface IconProps extends Omit<SVGProps<SVGSVGElement>, 'children' | 'viewBox'> {\n /** Edge length in px. Defaults to 16 — the design language's icon size. */\n size?: number;\n /** Accessible name. Omit for decorative icons (the default). */\n title?: string;\n}\n\nexport function Icon({ size = 16, title, children, ...rest }: IconProps & { children: ReactNode }) {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 16 16\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.5}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n focusable=\"false\"\n {...(title ? { role: 'img' } : { 'aria-hidden': true })}\n {...rest}\n >\n {title ? <title>{title}</title> : null}\n {children}\n </svg>\n );\n}\n\n/** Chat — the transcript section. */\nexport const IconChat = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M2.5 11.5V4.25A1.75 1.75 0 0 1 4.25 2.5h7.5a1.75 1.75 0 0 1 1.75 1.75v4.5a1.75 1.75 0 0 1-1.75 1.75H5.5L2.5 13.5v-2Z\" />\n </Icon>\n);\n\n/** Inbox — approvals. */\nexport const IconInbox = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M2 9.5 3.6 3.4A1.5 1.5 0 0 1 5.05 2.3h5.9a1.5 1.5 0 0 1 1.45 1.1L14 9.5\" />\n <path d=\"M2 9.5h3l.8 1.6h4.4l.8-1.6h3v2.6A1.9 1.9 0 0 1 12.1 14H3.9A1.9 1.9 0 0 1 2 12.1V9.5Z\" />\n </Icon>\n);\n\n/** Gauge — usage / spend. */\nexport const IconGauge = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M2.2 11.5a6.4 6.4 0 1 1 11.6 0\" />\n <path d=\"M8 11 10.8 6.6\" />\n <circle cx=\"8\" cy=\"11.6\" r=\"0.9\" fill=\"currentColor\" stroke=\"none\" />\n </Icon>\n);\n\n/** Sliders — settings. */\nexport const IconSliders = (p: IconProps) => (\n <Icon {...p}>\n <path d=\"M2.5 4.5h4M9.5 4.5h4M2.5 11.5h2M7.5 11.5h6\" />\n <circle cx=\"8\" cy=\"4.5\" r=\"1.6\" />\n <circle cx=\"6\" cy=\"11.5\" r=\"1.6\" />\n </Icon>\n);\n"],"mappings":"kDAuBA,SAAgB,EAAK,CAAE,OAAO,GAAI,QAAO,WAAU,GAAG,GAA6C,CACjG,OACE,EAAA,EAAA,KAAA,CAAC,MAAD,CACE,MAAO,EACP,OAAQ,EACR,QAAQ,YACR,KAAK,OACL,OAAO,eACP,YAAa,IACb,cAAc,QACd,eAAe,QACf,UAAU,QACV,GAAK,EAAQ,CAAE,KAAM,KAAM,EAAI,CAAE,cAAe,EAAK,EACrD,GAAI,EAXN,SAAA,CAaG,GAAQ,EAAA,EAAA,IAAA,CAAC,QAAD,CAAA,SAAQ,CAAa,CAAA,EAAI,KACjC,CACE,GAET,CAGA,IAAa,EAAY,IACvB,EAAA,EAAA,IAAA,CAAC,EAAD,CAAM,GAAI,EACR,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,sHAAwH,CAAA,CAC5H,CAAA,EAIK,EAAa,IACxB,EAAA,EAAA,KAAA,CAAC,EAAD,CAAM,GAAI,EAAV,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,yEAA2E,CAAA,GACnF,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,sFAAwF,CAAA,CAC5F,IAIK,EAAa,IACxB,EAAA,EAAA,KAAA,CAAC,EAAD,CAAM,GAAI,EAAV,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,gCAAkC,CAAA,GAC1C,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,gBAAkB,CAAA,GAC1B,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,GAAG,IAAI,GAAG,OAAO,EAAE,MAAM,KAAK,eAAe,OAAO,MAAQ,CAAA,CAChE,IAIK,EAAe,IAC1B,EAAA,EAAA,KAAA,CAAC,EAAD,CAAM,GAAI,EAAV,SAAA,EACE,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,EAAE,4CAA8C,CAAA,GACtD,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,GAAG,IAAI,GAAG,MAAM,EAAE,KAAO,CAAA,GACjC,EAAA,EAAA,IAAA,CAAC,SAAD,CAAQ,GAAG,IAAI,GAAG,OAAO,EAAE,KAAO,CAAA,CAC9B"}
@@ -1,2 +0,0 @@
1
- import{n as e}from"./index-BVxOlseC.js";import{t}from"./icon-base-DvM1eI5V.js";var n=e(),r=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`rect`,{x:`4.5`,y:`4.5`,width:`7`,height:`7`,rx:`1.5`}),(0,n.jsx)(`path`,{d:`M6.5 1.5v3M9.5 1.5v3M6.5 11.5v3M9.5 11.5v3M1.5 6.5h3M1.5 9.5h3M11.5 6.5h3M11.5 9.5h3`})]}),i=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`path`,{d:`m3 8.5 3.2 3.2L13 5`})}),a=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`circle`,{cx:`8`,cy:`8`,r:`6`}),(0,n.jsx)(`path`,{d:`m5.2 8.2 1.9 1.9 3.7-4`})]}),o=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`path`,{d:`m4 4 8 8M12 4l-8 8`})}),s=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`path`,{d:`M5.5 3.4 12 8l-6.5 4.6V3.4Z`})}),c=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`rect`,{x:`4`,y:`4`,width:`8`,height:`8`,rx:`1.2`})}),l=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`path`,{d:`M8 2.6 14.2 13H1.8L8 2.6Z`}),(0,n.jsx)(`path`,{d:`M8 6.6v3`}),(0,n.jsx)(`circle`,{cx:`8`,cy:`11.3`,r:`0.75`,fill:`currentColor`,stroke:`none`})]}),u=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`circle`,{cx:`8`,cy:`8`,r:`6`}),(0,n.jsx)(`path`,{d:`M8 7.4v3.4`}),(0,n.jsx)(`circle`,{cx:`8`,cy:`5.4`,r:`0.75`,fill:`currentColor`,stroke:`none`})]}),d=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`path`,{d:`M8 3.2v9.6M3.2 8h9.6`})}),f=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`circle`,{cx:`7.2`,cy:`7.2`,r:`4.2`}),(0,n.jsx)(`path`,{d:`m10.4 10.4 3.1 3.1`})]}),p=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`rect`,{x:`5.5`,y:`5.5`,width:`8`,height:`8`,rx:`1.5`}),(0,n.jsx)(`path`,{d:`M10.5 3.5a1.5 1.5 0 0 0-1.5-1.5H4A1.5 1.5 0 0 0 2.5 3.5v5A1.5 1.5 0 0 0 4 10`})]}),m=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`path`,{d:`m4 6.2 4 4 4-4`})}),h=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`path`,{d:`m6.2 4 4 4-4 4`})}),g=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`path`,{d:`M14 2 7.2 8.8M14 2l-4.4 12-2.4-5.2L2 6.4 14 2Z`})}),_=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`path`,{d:`M9.5 2.5H13.5v4M13.5 2.5 7.8 8.2`}),(0,n.jsx)(`path`,{d:`M12.5 9.6v2.9a1.5 1.5 0 0 1-1.5 1.5H3.5A1.5 1.5 0 0 1 2 12.5V5a1.5 1.5 0 0 1 1.5-1.5h2.9`})]}),v=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`path`,{d:`M13.2 7.2a5.2 5.2 0 1 0-.7 3.5`}),(0,n.jsx)(`path`,{d:`M13.5 3.4v3.9h-3.9`})]}),y=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`rect`,{x:`3`,y:`7`,width:`10`,height:`6.5`,rx:`1.5`}),(0,n.jsx)(`path`,{d:`M5.5 7V5.2a2.5 2.5 0 0 1 5 0V7`})]}),b=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`circle`,{cx:`8`,cy:`8`,r:`3.1`}),(0,n.jsx)(`path`,{d:`M8 1.5v1.6M8 12.9v1.6M1.5 8h1.6M12.9 8h1.6M3.4 3.4l1.1 1.1M11.5 11.5l1.1 1.1M12.6 3.4l-1.1 1.1M4.5 11.5l-1.1 1.1`})]}),x=e=>(0,n.jsx)(t,{...e,children:(0,n.jsx)(`path`,{d:`M13 9.8A5.6 5.6 0 0 1 6.2 3a5.6 5.6 0 1 0 6.8 6.8Z`})}),S=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`rect`,{x:`1.8`,y:`2.8`,width:`12.4`,height:`8.4`,rx:`1.5`}),(0,n.jsx)(`path`,{d:`M5.8 14h4.4M8 11.2V14`})]}),C=e=>(0,n.jsxs)(t,{...e,children:[(0,n.jsx)(`rect`,{x:`1.5`,y:`4`,width:`13`,height:`8`,rx:`1.5`}),(0,n.jsx)(`path`,{d:`M4.2 6.6h.01M6.8 6.6h.01M9.4 6.6h.01M12 6.6h.01M4.2 9.4h.01M12 9.4h.01M6.4 9.4h3.2`})]});export{f as _,h as a,b,_ as c,y as d,S as f,v as g,d as h,m as i,u as l,s as m,i as n,p as o,x as p,a as r,r as s,l as t,C as u,g as v,o as x,c as y};
2
- //# sourceMappingURL=icons-DEQa2rTx.js.map