@ashlr/hub 3.11.3 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (558) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +44 -18
  3. package/dist/authority-surface.json +74 -59
  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/trust-roots.js +7 -1
  14. package/dist/core/authority/trust-roots.js.map +1 -1
  15. package/dist/core/authority/types.d.ts +2 -2
  16. package/dist/core/cloud/cloud-api.js +1 -1
  17. package/dist/core/cloud/cloud-api.js.map +1 -1
  18. package/dist/core/cloud/delivery-contract.d.ts +1 -1
  19. package/dist/core/cloud/delivery-contract.js +25 -15
  20. package/dist/core/cloud/delivery-contract.js.map +1 -1
  21. package/dist/core/cloud/store.js +6 -0
  22. package/dist/core/cloud/store.js.map +1 -1
  23. package/dist/core/cloud/tracker.d.ts +2 -0
  24. package/dist/core/cloud/tracker.js +140 -37
  25. package/dist/core/cloud/tracker.js.map +1 -1
  26. package/dist/core/cloud/types.d.ts +9 -1
  27. package/dist/core/cloud/types.js.map +1 -1
  28. package/dist/core/comms/dispatch.d.ts +5 -0
  29. package/dist/core/comms/dispatch.js +12 -1
  30. package/dist/core/comms/dispatch.js.map +1 -1
  31. package/dist/core/comms/requests.d.ts +27 -1
  32. package/dist/core/comms/requests.js +50 -1
  33. package/dist/core/comms/requests.js.map +1 -1
  34. package/dist/core/daemon/loop.d.ts +14 -0
  35. package/dist/core/daemon/loop.js +35 -0
  36. package/dist/core/daemon/loop.js.map +1 -1
  37. package/dist/core/fabric/claude-usage.js +23 -1
  38. package/dist/core/fabric/claude-usage.js.map +1 -1
  39. package/dist/core/fleet/dispatch-router.d.ts +7 -0
  40. package/dist/core/fleet/dispatch-router.js +4 -1
  41. package/dist/core/fleet/dispatch-router.js.map +1 -1
  42. package/dist/core/fleet/tick-hooks-live.d.ts +5 -1
  43. package/dist/core/fleet/tick-hooks-live.js +10 -1
  44. package/dist/core/fleet/tick-hooks-live.js.map +1 -1
  45. package/dist/core/local-runtime/llama/config.d.ts +14 -0
  46. package/dist/core/local-runtime/llama/config.js +20 -2
  47. package/dist/core/local-runtime/llama/config.js.map +1 -1
  48. package/dist/core/local-runtime/llama/process.d.ts +19 -0
  49. package/dist/core/local-runtime/llama/process.js +67 -17
  50. package/dist/core/local-runtime/llama/process.js.map +1 -1
  51. package/dist/core/local-runtime/llama/supervisor.js +14 -3
  52. package/dist/core/local-runtime/llama/supervisor.js.map +1 -1
  53. package/dist/core/observability/rollup.d.ts +12 -0
  54. package/dist/core/observability/rollup.js +37 -2
  55. package/dist/core/observability/rollup.js.map +1 -1
  56. package/dist/core/observability/usage-source.js +49 -1
  57. package/dist/core/observability/usage-source.js.map +1 -1
  58. package/dist/core/resources/connection-monitor.js +47 -4
  59. package/dist/core/resources/connection-monitor.js.map +1 -1
  60. package/dist/core/resources/engineering-mission-store.d.ts +1 -1
  61. package/dist/core/routing/headroom.js +7 -2
  62. package/dist/core/routing/headroom.js.map +1 -1
  63. package/dist/core/routing/router.d.ts +48 -0
  64. package/dist/core/routing/router.js +129 -13
  65. package/dist/core/routing/router.js.map +1 -1
  66. package/dist/core/run/best-of-n.d.ts +7 -0
  67. package/dist/core/run/best-of-n.js +3 -0
  68. package/dist/core/run/best-of-n.js.map +1 -1
  69. package/dist/core/run/harness-dispatch.d.ts +147 -0
  70. package/dist/core/run/harness-dispatch.js +234 -0
  71. package/dist/core/run/harness-dispatch.js.map +1 -0
  72. package/dist/core/run/orchestrator.js +3 -0
  73. package/dist/core/run/orchestrator.js.map +1 -1
  74. package/dist/core/run/provider-client.d.ts +8 -0
  75. package/dist/core/run/provider-client.js +4 -0
  76. package/dist/core/run/provider-client.js.map +1 -1
  77. package/dist/core/run/sandboxed-engine.d.ts +8 -0
  78. package/dist/core/run/sandboxed-engine.js +60 -7
  79. package/dist/core/run/sandboxed-engine.js.map +1 -1
  80. package/dist/core/types.d.ts +14 -0
  81. package/dist/core/types.js.map +1 -1
  82. package/dist/core/universe/builtins/preparation/manifest.json +1 -1
  83. package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +188 -6
  84. package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +187 -5
  85. package/dist/core/universe/firm-demo.d.ts +1 -1
  86. package/dist/core/universe/firm-graph.d.ts +2 -2
  87. package/dist/core/util/scrub.js +16 -3
  88. package/dist/core/util/scrub.js.map +1 -1
  89. package/dist/core/verse/accounts.d.ts +9 -1
  90. package/dist/core/verse/accounts.js +52 -11
  91. package/dist/core/verse/accounts.js.map +1 -1
  92. package/dist/core/verse/apps-api.d.ts +12 -0
  93. package/dist/core/verse/apps-api.js +22 -4
  94. package/dist/core/verse/apps-api.js.map +1 -1
  95. package/dist/core/verse/apps.js +22 -12
  96. package/dist/core/verse/apps.js.map +1 -1
  97. package/dist/core/verse/local-models.js +3 -7
  98. package/dist/core/verse/local-models.js.map +1 -1
  99. package/dist/core/verse/model-display-name.d.ts +34 -0
  100. package/dist/core/verse/model-display-name.js +125 -0
  101. package/dist/core/verse/model-display-name.js.map +1 -0
  102. package/dist/core/verse/seats.d.ts +11 -2
  103. package/dist/core/verse/seats.js +42 -18
  104. package/dist/core/verse/seats.js.map +1 -1
  105. package/dist/core/verse/transient-events.d.ts +21 -0
  106. package/dist/core/verse/transient-events.js +12 -0
  107. package/dist/core/verse/transient-events.js.map +1 -0
  108. package/dist/core/verse/types.d.ts +6 -13
  109. package/dist/core/verse/types.js +5 -36
  110. package/dist/core/verse/types.js.map +1 -1
  111. package/dist/core/web/public/next/assets/ActionMenu-B4-39f2S.js +2 -0
  112. package/dist/core/web/public/next/assets/{ActionMenu-FxXeRbPx.js.map → ActionMenu-B4-39f2S.js.map} +1 -1
  113. package/dist/core/web/public/next/assets/Advanced-B-LqYXvd.js +2 -0
  114. package/dist/core/web/public/next/assets/Advanced-B-LqYXvd.js.map +1 -0
  115. package/dist/core/web/public/next/assets/App-E2zCDRxm.js +7 -0
  116. package/dist/core/web/public/next/assets/App-E2zCDRxm.js.map +1 -0
  117. package/dist/core/web/public/next/assets/AppsSection-8wXPPhZb.js +2 -0
  118. package/dist/core/web/public/next/assets/AppsSection-8wXPPhZb.js.map +1 -0
  119. package/dist/core/web/public/next/assets/AreaTrend-BFimExYn.js +2 -0
  120. package/dist/core/web/public/next/assets/{AreaTrend-CDxrQU4b.js.map → AreaTrend-BFimExYn.js.map} +1 -1
  121. package/dist/core/web/public/next/assets/AutonomyOffState-B5eEkmiz.js +2 -0
  122. package/dist/core/web/public/next/assets/AutonomyOffState-B5eEkmiz.js.map +1 -0
  123. package/dist/core/web/public/next/assets/AutonomyOffState-DmbE71vI.css +1 -0
  124. package/dist/core/web/public/next/assets/AutonomySection-B46igJKR.js +2 -0
  125. package/dist/core/web/public/next/assets/{AutonomySection-DuQkHGD_.js.map → AutonomySection-B46igJKR.js.map} +1 -1
  126. package/dist/core/web/public/next/assets/BranchBar-BRkrEQGs.js +2 -0
  127. package/dist/core/web/public/next/assets/{BranchBar-CLsvOcyK.js.map → BranchBar-BRkrEQGs.js.map} +1 -1
  128. package/dist/core/web/public/next/assets/BudgetControl-T_RjPrw9.js +2 -0
  129. package/dist/core/web/public/next/assets/{BudgetControl-TL3FeZ1D.js.map → BudgetControl-T_RjPrw9.js.map} +1 -1
  130. package/dist/core/web/public/next/assets/{Button-HHXgoXGr.js → Button-BhO-WKPp.js} +2 -2
  131. package/dist/core/web/public/next/assets/{Button-HHXgoXGr.js.map → Button-BhO-WKPp.js.map} +1 -1
  132. package/dist/core/web/public/next/assets/CapacityStrip-CkFz5vq2.js +2 -0
  133. package/dist/core/web/public/next/assets/{CapacityStrip-qReu0RaF.js.map → CapacityStrip-CkFz5vq2.js.map} +1 -1
  134. package/dist/core/web/public/next/assets/{useChartWidth-BW6SwYIK.css → ChartFrame-BVuBe6RP.css} +1 -1
  135. package/dist/core/web/public/next/assets/ChartFrame-SygZ7B3x.js +2 -0
  136. package/dist/core/web/public/next/assets/ChartFrame-SygZ7B3x.js.map +1 -0
  137. package/dist/core/web/public/next/assets/ChatSection-D6WybBpB.js +3 -0
  138. package/dist/core/web/public/next/assets/ChatSection-D6WybBpB.js.map +1 -0
  139. package/dist/core/web/public/next/assets/CloudBudgetForm-Bd91iStN.js +2 -0
  140. package/dist/core/web/public/next/assets/CloudBudgetForm-Bd91iStN.js.map +1 -0
  141. package/dist/core/web/public/next/assets/CommandPalette-B6SgDJH-.js +2 -0
  142. package/dist/core/web/public/next/assets/CommandPalette-B6SgDJH-.js.map +1 -0
  143. package/dist/core/web/public/next/assets/CommandSection-CvAVd1w4.css +1 -0
  144. package/dist/core/web/public/next/assets/CommandSection-DgMGoepd.js +2 -0
  145. package/dist/core/web/public/next/assets/CommandSection-DgMGoepd.js.map +1 -0
  146. package/dist/core/web/public/next/assets/ConfirmDialog-Bv4hdK2T.js +2 -0
  147. package/dist/core/web/public/next/assets/{ConfirmDialog-DLrLKM0c.js.map → ConfirmDialog-Bv4hdK2T.js.map} +1 -1
  148. package/dist/core/web/public/next/assets/DeleteChatDialog-CH1Ix8Eh.js +2 -0
  149. package/dist/core/web/public/next/assets/DeleteChatDialog-CH1Ix8Eh.js.map +1 -0
  150. package/dist/core/web/public/next/assets/Dialog-BSsIFNqD.js +2 -0
  151. package/dist/core/web/public/next/assets/{Dialog-BS9Dxi3G.js.map → Dialog-BSsIFNqD.js.map} +1 -1
  152. package/dist/core/web/public/next/assets/DiffPane-BpNuJmth.js +2 -0
  153. package/dist/core/web/public/next/assets/{DiffPane-TOmUf3b2.js.map → DiffPane-BpNuJmth.js.map} +1 -1
  154. package/dist/core/web/public/next/assets/DiffViewer-CJarUvs0.js +2 -0
  155. package/dist/core/web/public/next/assets/{DiffViewer-BpH56302.js.map → DiffViewer-CJarUvs0.js.map} +1 -1
  156. package/dist/core/web/public/next/assets/DockHost-DW9q0NdR.js +2 -0
  157. package/dist/core/web/public/next/assets/DockHost-DW9q0NdR.js.map +1 -0
  158. package/dist/core/web/public/next/assets/{EmptyState-BqR5YAmf.js → EmptyState-DPrd2aak.js} +2 -2
  159. package/dist/core/web/public/next/assets/{EmptyState-BqR5YAmf.js.map → EmptyState-DPrd2aak.js.map} +1 -1
  160. package/dist/core/web/public/next/assets/{Epistemic-dhvDTwAZ.js → Epistemic-D7MxSmED.js} +2 -2
  161. package/dist/core/web/public/next/assets/{Epistemic-dhvDTwAZ.js.map → Epistemic-D7MxSmED.js.map} +1 -1
  162. package/dist/core/web/public/next/assets/FleetSection-BdZN6rGS.js +3 -0
  163. package/dist/core/web/public/next/assets/FleetSection-BdZN6rGS.js.map +1 -0
  164. package/dist/core/web/public/next/assets/Funnel-BeNQZWv2.js +2 -0
  165. package/dist/core/web/public/next/assets/{Funnel-D2u7Wlzc.js.map → Funnel-BeNQZWv2.js.map} +1 -1
  166. package/dist/core/web/public/next/assets/GearTray-CIPtzeIx.js +2 -0
  167. package/dist/core/web/public/next/assets/{GearTray-Cb2npoxM.js.map → GearTray-CIPtzeIx.js.map} +1 -1
  168. package/dist/core/web/public/next/assets/GrowthSection-iiQg6wvK.js +2 -0
  169. package/dist/core/web/public/next/assets/{GrowthSection-C5aDPs8B.js.map → GrowthSection-iiQg6wvK.js.map} +1 -1
  170. package/dist/core/web/public/next/assets/HandoffDialog-DrQ6ofuy.js +2 -0
  171. package/dist/core/web/public/next/assets/{HandoffDialog-BF3AYg-X.js.map → HandoffDialog-DrQ6ofuy.js.map} +1 -1
  172. package/dist/core/web/public/next/assets/Input-C0MQxEM6.js +2 -0
  173. package/dist/core/web/public/next/assets/{Input-B5dmGLZx.js.map → Input-C0MQxEM6.js.map} +1 -1
  174. package/dist/core/web/public/next/assets/LeaderCard-BRr3_yE-.js +2 -0
  175. package/dist/core/web/public/next/assets/LeaderCard-BRr3_yE-.js.map +1 -0
  176. package/dist/core/web/public/next/assets/MatrixHeatmap-DZvZeWXL.js +2 -0
  177. package/dist/core/web/public/next/assets/{MatrixHeatmap-BgEUs2Eu.js.map → MatrixHeatmap-DZvZeWXL.js.map} +1 -1
  178. package/dist/core/web/public/next/assets/McpSection-BRuCcTjT.js +2 -0
  179. package/dist/core/web/public/next/assets/{McpSection-DZkiOuoq.js.map → McpSection-BRuCcTjT.js.map} +1 -1
  180. package/dist/core/web/public/next/assets/MessageMarkdown-bRvD5nSc.js +3 -0
  181. package/dist/core/web/public/next/assets/{MessageMarkdown-BauY8ZTY.js.map → MessageMarkdown-bRvD5nSc.js.map} +1 -1
  182. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DLBNLfsn.js → MessageMarkdownRenderer-FjjkPKA2.js} +4 -4
  183. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DLBNLfsn.js.map → MessageMarkdownRenderer-FjjkPKA2.js.map} +1 -1
  184. package/dist/core/web/public/next/assets/{Meter-DNeocJnD.js → Meter-CFNLpwA-.js} +2 -2
  185. package/dist/core/web/public/next/assets/{Meter-DNeocJnD.js.map → Meter-CFNLpwA-.js.map} +1 -1
  186. package/dist/core/web/public/next/assets/MindSection-BTIiQS8P.js +2 -0
  187. package/dist/core/web/public/next/assets/MindSection-BTIiQS8P.js.map +1 -0
  188. package/dist/core/web/public/next/assets/MutationTokenDialog-T7gv3a9r.js +2 -0
  189. package/dist/core/web/public/next/assets/{MutationTokenDialog-mxrw0Yvy.js.map → MutationTokenDialog-T7gv3a9r.js.map} +1 -1
  190. package/dist/core/web/public/next/assets/NeedsYouDrawer-lYN4G_aM.js +2 -0
  191. package/dist/core/web/public/next/assets/{NeedsYouDrawer-CO-Balfp.js.map → NeedsYouDrawer-lYN4G_aM.js.map} +1 -1
  192. package/dist/core/web/public/next/assets/NeedsYouList-BgH8ezqf.js +2 -0
  193. package/dist/core/web/public/next/assets/{NeedsYouList-CzDZbzRD.js.map → NeedsYouList-BgH8ezqf.js.map} +1 -1
  194. package/dist/core/web/public/next/assets/NewChatDialog-Db5Xjrk8.js +3 -0
  195. package/dist/core/web/public/next/assets/NewChatDialog-Db5Xjrk8.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/OnboardingFlow-LoY-zuSe.js +2 -0
  198. package/dist/core/web/public/next/assets/OnboardingFlow-LoY-zuSe.js.map +1 -0
  199. package/dist/core/web/public/next/assets/OnboardingGate-C4VXn7BJ.js +3 -0
  200. package/dist/core/web/public/next/assets/OnboardingGate-C4VXn7BJ.js.map +1 -0
  201. package/dist/core/web/public/next/assets/PreviewPane-BPBbcROb.js +2 -0
  202. package/dist/core/web/public/next/assets/{PreviewPane-BS-CleCd.js.map → PreviewPane-BPBbcROb.js.map} +1 -1
  203. package/dist/core/web/public/next/assets/{ProviderLogo-C5mBg8i0.js → ProviderLogo-CT2cSfkg.js} +2 -2
  204. package/dist/core/web/public/next/assets/{ProviderLogo-C5mBg8i0.js.map → ProviderLogo-CT2cSfkg.js.map} +1 -1
  205. package/dist/core/web/public/next/assets/RailStatus-Vgl0GYtd.js +2 -0
  206. package/dist/core/web/public/next/assets/{RailStatus-cPRyOmrk.js.map → RailStatus-Vgl0GYtd.js.map} +1 -1
  207. package/dist/core/web/public/next/assets/{RefreshIndicator-CMwSCiz5.js → RefreshIndicator-CSyqpY_q.js} +2 -2
  208. package/dist/core/web/public/next/assets/{RefreshIndicator-CMwSCiz5.js.map → RefreshIndicator-CSyqpY_q.js.map} +1 -1
  209. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BFi1opsC.js → ResourcePoolConsoleApp-BX2nkdmZ.js} +4 -4
  210. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BFi1opsC.js.map → ResourcePoolConsoleApp-BX2nkdmZ.js.map} +1 -1
  211. package/dist/core/web/public/next/assets/ResourcesChrome-B2U2lO1H.js +3 -0
  212. package/dist/core/web/public/next/assets/ResourcesChrome-B2U2lO1H.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/ResourcesDrawer-DlUKOjl9.js +2 -0
  215. package/dist/core/web/public/next/assets/ResourcesDrawer-DlUKOjl9.js.map +1 -0
  216. package/dist/core/web/public/next/assets/RouteErrorBoundary-BaC7YVzR.js +2 -0
  217. package/dist/core/web/public/next/assets/{RouteErrorBoundary-DYtwc2ja.js.map → RouteErrorBoundary-BaC7YVzR.js.map} +1 -1
  218. package/dist/core/web/public/next/assets/RunInCloudAction-D5PDHJPE.js +2 -0
  219. package/dist/core/web/public/next/assets/{RunInCloudAction-BEGEEM8O.js.map → RunInCloudAction-D5PDHJPE.js.map} +1 -1
  220. package/dist/core/web/public/next/assets/SeatSelector-Cg75LInq.js +3 -0
  221. package/dist/core/web/public/next/assets/{SeatSelector-CYHRR7Wp.js.map → SeatSelector-Cg75LInq.js.map} +1 -1
  222. package/dist/core/web/public/next/assets/Segmented-CametjLt.js +2 -0
  223. package/dist/core/web/public/next/assets/{Segmented-BE53BenI.js.map → Segmented-CametjLt.js.map} +1 -1
  224. package/dist/core/web/public/next/assets/Select-De52fghU.js +2 -0
  225. package/dist/core/web/public/next/assets/{Select-BwSGkHCS.js.map → Select-De52fghU.js.map} +1 -1
  226. package/dist/core/web/public/next/assets/SessionGate-CzlcNq3O.js +2 -0
  227. package/dist/core/web/public/next/assets/{SessionGate-e0dFJm9d.js.map → SessionGate-CzlcNq3O.js.map} +1 -1
  228. package/dist/core/web/public/next/assets/SessionInsightChip-Bk_Owa7u.js +2 -0
  229. package/dist/core/web/public/next/assets/{SessionInsightChip-CxlSyueJ.js.map → SessionInsightChip-Bk_Owa7u.js.map} +1 -1
  230. package/dist/core/web/public/next/assets/SessionSearch-C6C8DHN8.js +2 -0
  231. package/dist/core/web/public/next/assets/{SessionSearch-_yp7S2TP.js.map → SessionSearch-C6C8DHN8.js.map} +1 -1
  232. package/dist/core/web/public/next/assets/SettingsSection-mI9wQYZg.js +2 -0
  233. package/dist/core/web/public/next/assets/SettingsSection-mI9wQYZg.js.map +1 -0
  234. package/dist/core/web/public/next/assets/Sheet-CJhK9Dqv.js +2 -0
  235. package/dist/core/web/public/next/assets/{Sheet-DVP2Mgy6.js.map → Sheet-CJhK9Dqv.js.map} +1 -1
  236. package/dist/core/web/public/next/assets/ShortcutsOverlay-DDW-i9Fc.js +2 -0
  237. package/dist/core/web/public/next/assets/{ShortcutsOverlay-BcIcoClX.js.map → ShortcutsOverlay-DDW-i9Fc.js.map} +1 -1
  238. package/dist/core/web/public/next/assets/Sidebar-DT7ykaqS.js +3 -0
  239. package/dist/core/web/public/next/assets/Sidebar-DT7ykaqS.js.map +1 -0
  240. package/dist/core/web/public/next/assets/Slider-Bwd9HfXl.js +2 -0
  241. package/dist/core/web/public/next/assets/{Slider-BypUWjpH.js.map → Slider-Bwd9HfXl.js.map} +1 -1
  242. package/dist/core/web/public/next/assets/StatTile-DPZ5yyaU.js +2 -0
  243. package/dist/core/web/public/next/assets/StatTile-DPZ5yyaU.js.map +1 -0
  244. package/dist/core/web/public/next/assets/{StatusBadge-HCZp416_.js → StatusBadge-DHKRtttH.js} +2 -2
  245. package/dist/core/web/public/next/assets/{StatusBadge-HCZp416_.js.map → StatusBadge-DHKRtttH.js.map} +1 -1
  246. package/dist/core/web/public/next/assets/StepBand-DQykLkk_.js +2 -0
  247. package/dist/core/web/public/next/assets/{StepBand-Duz1PUes.js.map → StepBand-DQykLkk_.js.map} +1 -1
  248. package/dist/core/web/public/next/assets/Surface-D--LXgQm.js +2 -0
  249. package/dist/core/web/public/next/assets/Surface-D--LXgQm.js.map +1 -0
  250. package/dist/core/web/public/next/assets/Surface-e1z6GdZt.css +1 -0
  251. package/dist/core/web/public/next/assets/Swimlane-BzH6OCee.js +2 -0
  252. package/dist/core/web/public/next/assets/{Swimlane-DGcIcnNA.js.map → Swimlane-BzH6OCee.js.map} +1 -1
  253. package/dist/core/web/public/next/assets/{Switch-iveI-8NY.js → Switch-PMixU6b0.js} +2 -2
  254. package/dist/core/web/public/next/assets/{Switch-iveI-8NY.js.map → Switch-PMixU6b0.js.map} +1 -1
  255. package/dist/core/web/public/next/assets/{Tag-DH15CUJp.js → Tag-fordBsrJ.js} +2 -2
  256. package/dist/core/web/public/next/assets/{Tag-DH15CUJp.js.map → Tag-fordBsrJ.js.map} +1 -1
  257. package/dist/core/web/public/next/assets/TerminalPane-BSnGdUuF.js +7 -0
  258. package/dist/core/web/public/next/assets/TerminalPane-BSnGdUuF.js.map +1 -0
  259. package/dist/core/web/public/next/assets/UniverseConsoleApp-DtXFhAhw.js +2 -0
  260. package/dist/core/web/public/next/assets/{UniverseConsoleApp-C8yQ0AaR.js.map → UniverseConsoleApp-DtXFhAhw.js.map} +1 -1
  261. package/dist/core/web/public/next/assets/{UniverseView-_nPURPqe.js → UniverseView-sWm3pnTW.js} +3 -3
  262. package/dist/core/web/public/next/assets/{UniverseView-_nPURPqe.js.map → UniverseView-sWm3pnTW.js.map} +1 -1
  263. package/dist/core/web/public/next/assets/UsageSection-CiD1DbuF.js +3 -0
  264. package/dist/core/web/public/next/assets/UsageSection-CiD1DbuF.js.map +1 -0
  265. package/dist/core/web/public/next/assets/VerseConsoleApp-BCY5uSok.js +3 -0
  266. package/dist/core/web/public/next/assets/VerseConsoleApp-BCY5uSok.js.map +1 -0
  267. package/dist/core/web/public/next/assets/Workspace-BQSZFSeO.js +10 -0
  268. package/dist/core/web/public/next/assets/Workspace-BQSZFSeO.js.map +1 -0
  269. package/dist/core/web/public/next/assets/actions-BmIf9avl.css +1 -0
  270. package/dist/core/web/public/next/assets/actions-Ci6I4C0l.js +2 -0
  271. package/dist/core/web/public/next/assets/actions-Ci6I4C0l.js.map +1 -0
  272. package/dist/core/web/public/next/assets/apps-model-DlwnfqwJ.js +2 -0
  273. package/dist/core/web/public/next/assets/apps-model-DlwnfqwJ.js.map +1 -0
  274. package/dist/core/web/public/next/assets/authority-model-BFuPezSo.js +2 -0
  275. package/dist/core/web/public/next/assets/authority-model-BFuPezSo.js.map +1 -0
  276. package/dist/core/web/public/next/assets/binding-left-DZpq5sLf.js +2 -0
  277. package/dist/core/web/public/next/assets/binding-left-DZpq5sLf.js.map +1 -0
  278. package/dist/core/web/public/next/assets/{budget-queries-V3wcJVK_.js → budget-queries-DsAjH8ac.js} +2 -2
  279. package/dist/core/web/public/next/assets/{budget-queries-V3wcJVK_.js.map → budget-queries-DsAjH8ac.js.map} +1 -1
  280. package/dist/core/web/public/next/assets/capacity-strip-model-Dn1cNOhz.js +2 -0
  281. package/dist/core/web/public/next/assets/capacity-strip-model-Dn1cNOhz.js.map +1 -0
  282. package/dist/core/web/public/next/assets/charts-C_xJbJiw.js +2 -0
  283. package/dist/core/web/public/next/assets/charts-C_xJbJiw.js.map +1 -0
  284. package/dist/core/web/public/next/assets/charts-DhKTrQLw.css +1 -0
  285. package/dist/core/web/public/next/assets/clipboard-DkZdqlxf.js +2 -0
  286. package/dist/core/web/public/next/assets/clipboard-DkZdqlxf.js.map +1 -0
  287. package/dist/core/web/public/next/assets/cloud-D-HXms6q.css +1 -0
  288. package/dist/core/web/public/next/assets/cloud-model-CX407gPY.js +2 -0
  289. package/dist/core/web/public/next/assets/cloud-model-CX407gPY.js.map +1 -0
  290. package/dist/core/web/public/next/assets/cloud-queries-QAhpExlz.js +2 -0
  291. package/dist/core/web/public/next/assets/cloud-queries-QAhpExlz.js.map +1 -0
  292. package/dist/core/web/public/next/assets/cloud.module-DOP-N4Ch.js +2 -0
  293. package/dist/core/web/public/next/assets/cloud.module-DOP-N4Ch.js.map +1 -0
  294. package/dist/core/web/public/next/assets/command-catalog-CF0cQQac.js +2 -0
  295. package/dist/core/web/public/next/assets/command-catalog-CF0cQQac.js.map +1 -0
  296. package/dist/core/web/public/next/assets/context-model-Co4wh3SM.js +2 -0
  297. package/dist/core/web/public/next/assets/context-model-Co4wh3SM.js.map +1 -0
  298. package/dist/core/web/public/next/assets/context-model-DV1zCfAm.js +3 -0
  299. package/dist/core/web/public/next/assets/context-model-DV1zCfAm.js.map +1 -0
  300. package/dist/core/web/public/next/assets/{context-queries-CrPcHWTz.js → context-queries-CktFQqSS.js} +2 -2
  301. package/dist/core/web/public/next/assets/{context-queries-CrPcHWTz.js.map → context-queries-CktFQqSS.js.map} +1 -1
  302. package/dist/core/web/public/next/assets/{control-queries-CmgBgKV7.js → control-queries-DAvlh_YM.js} +2 -2
  303. package/dist/core/web/public/next/assets/{control-queries-CmgBgKV7.js.map → control-queries-DAvlh_YM.js.map} +1 -1
  304. package/dist/core/web/public/next/assets/copy-setup-CqRSfELB.js +2 -0
  305. package/dist/core/web/public/next/assets/copy-setup-CqRSfELB.js.map +1 -0
  306. package/dist/core/web/public/next/assets/dock-icons-BFuBbqJl.js +2 -0
  307. package/dist/core/web/public/next/assets/{dock-icons-CUh8dOxJ.js.map → dock-icons-BFuBbqJl.js.map} +1 -1
  308. package/dist/core/web/public/next/assets/fleet-model-Dfd5JyLR.js +2 -0
  309. package/dist/core/web/public/next/assets/fleet-model-Dfd5JyLR.js.map +1 -0
  310. package/dist/core/web/public/next/assets/fleet-queries-RtMTd5rR.js +2 -0
  311. package/dist/core/web/public/next/assets/fleet-queries-RtMTd5rR.js.map +1 -0
  312. package/dist/core/web/public/next/assets/{focus-trap-HtcoXeEq.js → focus-trap-BdrbWfC4.js} +2 -2
  313. package/dist/core/web/public/next/assets/{focus-trap-HtcoXeEq.js.map → focus-trap-BdrbWfC4.js.map} +1 -1
  314. package/dist/core/web/public/next/assets/format-Dk4Fmxax.js +2 -0
  315. package/dist/core/web/public/next/assets/format-Dk4Fmxax.js.map +1 -0
  316. package/dist/core/web/public/next/assets/{git-model-bk_RXh3y.js → git-model-_BnI_Ogh.js} +2 -2
  317. package/dist/core/web/public/next/assets/{git-model-bk_RXh3y.js.map → git-model-_BnI_Ogh.js.map} +1 -1
  318. package/dist/core/web/public/next/assets/global-CNNGMril.js +2 -0
  319. package/dist/core/web/public/next/assets/{global-oEl9Qj8u.js.map → global-CNNGMril.js.map} +1 -1
  320. package/dist/core/web/public/next/assets/{guarded-runners-LHLXmXIk.js → guarded-runners-DPh2d32e.js} +2 -2
  321. package/dist/core/web/public/next/assets/{guarded-runners-LHLXmXIk.js.map → guarded-runners-DPh2d32e.js.map} +1 -1
  322. package/dist/core/web/public/next/assets/icons-0haWy6nh.js +2 -0
  323. package/dist/core/web/public/next/assets/icons-0haWy6nh.js.map +1 -0
  324. package/dist/core/web/public/next/assets/{index-BVxOlseC.js → index-QesfXBsb.js} +3 -3
  325. package/dist/core/web/public/next/assets/{index-BVxOlseC.js.map → index-QesfXBsb.js.map} +1 -1
  326. package/dist/core/web/public/next/assets/live-model-De-q0ZFK.js +2 -0
  327. package/dist/core/web/public/next/assets/live-model-De-q0ZFK.js.map +1 -0
  328. package/dist/core/web/public/next/assets/local-model-C9xNi9fN.js +2 -0
  329. package/dist/core/web/public/next/assets/local-model-C9xNi9fN.js.map +1 -0
  330. package/dist/core/web/public/next/assets/mind.module-BrK2nFOL.js +2 -0
  331. package/dist/core/web/public/next/assets/{mind.module-gTGAuJt1.js.map → mind.module-BrK2nFOL.js.map} +1 -1
  332. package/dist/core/web/public/next/assets/mutations-DTCtKCn_.js +2 -0
  333. package/dist/core/web/public/next/assets/{mutations-C5S7okTW.js.map → mutations-DTCtKCn_.js.map} +1 -1
  334. package/dist/core/web/public/next/assets/nav-KmGX0CVz.js +2 -0
  335. package/dist/core/web/public/next/assets/{nav-NVtnuG7A.js.map → nav-KmGX0CVz.js.map} +1 -1
  336. package/dist/core/web/public/next/assets/{overnight-queries-DGm3qL1b.js → overnight-queries-mlO0xzsr.js} +2 -2
  337. package/dist/core/web/public/next/assets/{overnight-queries-DGm3qL1b.js.map → overnight-queries-mlO0xzsr.js.map} +1 -1
  338. package/dist/core/web/public/next/assets/primitives-D0Fb3TtS.js +1 -0
  339. package/dist/core/web/public/next/assets/{queries-CYisSAAB.js → queries-CyBE8nsW.js} +2 -2
  340. package/dist/core/web/public/next/assets/{queries-CYisSAAB.js.map → queries-CyBE8nsW.js.map} +1 -1
  341. package/dist/core/web/public/next/assets/reasoning-pref-CaoA4_Vl.js +2 -0
  342. package/dist/core/web/public/next/assets/{reasoning-pref-BUcFF_5G.js.map → reasoning-pref-CaoA4_Vl.js.map} +1 -1
  343. package/dist/core/web/public/next/assets/{reveal-anchor-D-tV8xau.js → reveal-anchor-BP1VqnPU.js} +2 -2
  344. package/dist/core/web/public/next/assets/{reveal-anchor-D-tV8xau.js.map → reveal-anchor-BP1VqnPU.js.map} +1 -1
  345. package/dist/core/web/public/next/assets/seat-subscription-C5Tvr0WQ.js +2 -0
  346. package/dist/core/web/public/next/assets/{seat-subscription-B-f9ViU2.js.map → seat-subscription-C5Tvr0WQ.js.map} +1 -1
  347. package/dist/core/web/public/next/assets/{sidebar-model-DQ-FyBHW.js → sidebar-model-B5Qk95k_.js} +2 -2
  348. package/dist/core/web/public/next/assets/{sidebar-model-DQ-FyBHW.js.map → sidebar-model-B5Qk95k_.js.map} +1 -1
  349. package/dist/core/web/public/next/assets/slots-DHKQDoE6.js +3 -0
  350. package/dist/core/web/public/next/assets/{slots-BhP8b8tf.js.map → slots-DHKQDoE6.js.map} +1 -1
  351. package/dist/core/web/public/next/assets/surface-data-CchClvHo.js +2 -0
  352. package/dist/core/web/public/next/assets/surface-data-CchClvHo.js.map +1 -0
  353. package/dist/core/web/public/next/assets/surface-prefetch-BWr0LBQn.js +2 -0
  354. package/dist/core/web/public/next/assets/surface-prefetch-BWr0LBQn.js.map +1 -0
  355. package/dist/core/web/public/next/assets/{tasks-model-BKDNqmmt.js → tasks-model-D6WFVULI.js} +2 -2
  356. package/dist/core/web/public/next/assets/{tasks-model-BKDNqmmt.js.map → tasks-model-D6WFVULI.js.map} +1 -1
  357. package/dist/core/web/public/next/assets/{terminal-icons-D2xe-aM1.js → terminal-icons-BvCvuXk2.js} +2 -2
  358. package/dist/core/web/public/next/assets/{terminal-icons-D2xe-aM1.js.map → terminal-icons-BvCvuXk2.js.map} +1 -1
  359. package/dist/core/web/public/next/assets/transient-events-nTLhMBND.js +2 -0
  360. package/dist/core/web/public/next/assets/transient-events-nTLhMBND.js.map +1 -0
  361. package/dist/core/web/public/next/assets/types-D5XOdyw8.js.map +1 -1
  362. package/dist/core/web/public/next/assets/{usage-queries-BZuAANlI.js → usage-queries-D1SU1t7r.js} +2 -2
  363. package/dist/core/web/public/next/assets/{usage-queries-BZuAANlI.js.map → usage-queries-D1SU1t7r.js.map} +1 -1
  364. package/dist/core/web/public/next/assets/{use-guarded-action-Cf4MeNBa.js → use-guarded-action-BZmBv7CJ.js} +2 -2
  365. package/dist/core/web/public/next/assets/{use-guarded-action-Cf4MeNBa.js.map → use-guarded-action-BZmBv7CJ.js.map} +1 -1
  366. package/dist/core/web/public/next/assets/{use-ticker-D9yi49my.js → use-ticker-CkJ4-0wU.js} +2 -2
  367. package/dist/core/web/public/next/assets/{use-ticker-D9yi49my.js.map → use-ticker-CkJ4-0wU.js.map} +1 -1
  368. package/dist/core/web/public/next/assets/{use-token-gate-DqrSXdX6.js → use-token-gate-CYcfk_GS.js} +2 -2
  369. package/dist/core/web/public/next/assets/{use-token-gate-DqrSXdX6.js.map → use-token-gate-CYcfk_GS.js.map} +1 -1
  370. package/dist/core/web/public/next/assets/useOnboarding-CujRS6PK.js +2 -0
  371. package/dist/core/web/public/next/assets/useOnboarding-CujRS6PK.js.map +1 -0
  372. package/dist/core/web/public/next/assets/useSeatsRefresh-BEaQdkZs.js +2 -0
  373. package/dist/core/web/public/next/assets/useSeatsRefresh-BEaQdkZs.js.map +1 -0
  374. package/dist/core/web/public/next/assets/useVerseTranscript-BQ0J6Xhx.js +2 -0
  375. package/dist/core/web/public/next/assets/{useVerseTranscript-CDYrrWOO.js.map → useVerseTranscript-BQ0J6Xhx.js.map} +1 -1
  376. package/dist/core/web/public/next/assets/verse-icons-DndgEgKS.js +2 -0
  377. package/dist/core/web/public/next/assets/verse-icons-DndgEgKS.js.map +1 -0
  378. package/dist/core/web/public/next/assets/verse-model-MMySehjj.js +2 -0
  379. package/dist/core/web/public/next/assets/verse-model-MMySehjj.js.map +1 -0
  380. package/dist/core/web/public/next/assets/verse-store-DNVRuiJL.js +2 -0
  381. package/dist/core/web/public/next/assets/verse-store-DNVRuiJL.js.map +1 -0
  382. package/dist/core/web/public/next/assets/warmup-CNEH_-be.js +3 -0
  383. package/dist/core/web/public/next/assets/{warmup-HG5vYbsN.js.map → warmup-CNEH_-be.js.map} +1 -1
  384. package/dist/core/web/public/next/assets/why-seat-model-jlDTwYSc.js +2 -0
  385. package/dist/core/web/public/next/assets/why-seat-model-jlDTwYSc.js.map +1 -0
  386. package/dist/core/web/public/next/assets/{workspace-model-CbhdPhei.js → workspace-model-Dukb2wwv.js} +2 -2
  387. package/dist/core/web/public/next/assets/{workspace-model-CbhdPhei.js.map → workspace-model-Dukb2wwv.js.map} +1 -1
  388. package/dist/core/web/public/next/index.html +1 -1
  389. package/dist/release-dependency-inventory.json +1 -1
  390. package/docs/README.md +2 -1
  391. package/package.json +1 -1
  392. package/dist/core/web/public/next/assets/ActionMenu-FxXeRbPx.js +0 -2
  393. package/dist/core/web/public/next/assets/Advanced-D_eS4472.js +0 -2
  394. package/dist/core/web/public/next/assets/Advanced-D_eS4472.js.map +0 -1
  395. package/dist/core/web/public/next/assets/App-Cj4zKbG3.js +0 -7
  396. package/dist/core/web/public/next/assets/App-Cj4zKbG3.js.map +0 -1
  397. package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js +0 -2
  398. package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js.map +0 -1
  399. package/dist/core/web/public/next/assets/AreaTrend-CDxrQU4b.js +0 -2
  400. package/dist/core/web/public/next/assets/AutonomySection-DuQkHGD_.js +0 -2
  401. package/dist/core/web/public/next/assets/BranchBar-CLsvOcyK.js +0 -2
  402. package/dist/core/web/public/next/assets/BudgetControl-TL3FeZ1D.js +0 -2
  403. package/dist/core/web/public/next/assets/BurnDown-sFXkUGdB.js +0 -2
  404. package/dist/core/web/public/next/assets/BurnDown-sFXkUGdB.js.map +0 -1
  405. package/dist/core/web/public/next/assets/CapacityStrip-qReu0RaF.js +0 -2
  406. package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js +0 -3
  407. package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js.map +0 -1
  408. package/dist/core/web/public/next/assets/CloudBudgetForm-DJbiT1wi.js +0 -2
  409. package/dist/core/web/public/next/assets/CloudBudgetForm-DJbiT1wi.js.map +0 -1
  410. package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js +0 -2
  411. package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js.map +0 -1
  412. package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js +0 -2
  413. package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js.map +0 -1
  414. package/dist/core/web/public/next/assets/ConfirmDialog-DLrLKM0c.js +0 -2
  415. package/dist/core/web/public/next/assets/Dialog-BS9Dxi3G.js +0 -2
  416. package/dist/core/web/public/next/assets/DiffPane-TOmUf3b2.js +0 -2
  417. package/dist/core/web/public/next/assets/DiffViewer-BpH56302.js +0 -2
  418. package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js +0 -2
  419. package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js.map +0 -1
  420. package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js +0 -3
  421. package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js.map +0 -1
  422. package/dist/core/web/public/next/assets/Funnel-D2u7Wlzc.js +0 -2
  423. package/dist/core/web/public/next/assets/GearTray-Cb2npoxM.js +0 -2
  424. package/dist/core/web/public/next/assets/GrowthSection-C5aDPs8B.js +0 -2
  425. package/dist/core/web/public/next/assets/HandoffDialog-BF3AYg-X.js +0 -2
  426. package/dist/core/web/public/next/assets/Input-B5dmGLZx.js +0 -2
  427. package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js +0 -2
  428. package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js.map +0 -1
  429. package/dist/core/web/public/next/assets/MatrixHeatmap-BgEUs2Eu.js +0 -2
  430. package/dist/core/web/public/next/assets/McpSection-DZkiOuoq.js +0 -2
  431. package/dist/core/web/public/next/assets/MessageMarkdown-BauY8ZTY.js +0 -3
  432. package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js +0 -2
  433. package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js.map +0 -1
  434. package/dist/core/web/public/next/assets/MutationTokenDialog-mxrw0Yvy.js +0 -2
  435. package/dist/core/web/public/next/assets/NeedsYouDrawer-CO-Balfp.js +0 -2
  436. package/dist/core/web/public/next/assets/NeedsYouList-CzDZbzRD.js +0 -2
  437. package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js +0 -3
  438. package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js.map +0 -1
  439. package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js +0 -2
  440. package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js.map +0 -1
  441. package/dist/core/web/public/next/assets/OnboardingFlow-DSpPj8UE.css +0 -1
  442. package/dist/core/web/public/next/assets/PreviewPane-BS-CleCd.js +0 -2
  443. package/dist/core/web/public/next/assets/RailStatus-cPRyOmrk.js +0 -2
  444. package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js +0 -3
  445. package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js.map +0 -1
  446. package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js +0 -2
  447. package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js.map +0 -1
  448. package/dist/core/web/public/next/assets/ResourcesDrawer-CSKIO_wZ.css +0 -1
  449. package/dist/core/web/public/next/assets/RouteErrorBoundary-DYtwc2ja.js +0 -2
  450. package/dist/core/web/public/next/assets/RunInCloudAction-BEGEEM8O.js +0 -2
  451. package/dist/core/web/public/next/assets/SeatSelector-CYHRR7Wp.js +0 -3
  452. package/dist/core/web/public/next/assets/Segmented-BE53BenI.js +0 -2
  453. package/dist/core/web/public/next/assets/Select-BwSGkHCS.js +0 -2
  454. package/dist/core/web/public/next/assets/SessionGate-e0dFJm9d.js +0 -2
  455. package/dist/core/web/public/next/assets/SessionInsightChip-CxlSyueJ.js +0 -2
  456. package/dist/core/web/public/next/assets/SessionSearch-_yp7S2TP.js +0 -2
  457. package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js +0 -2
  458. package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js.map +0 -1
  459. package/dist/core/web/public/next/assets/Sheet-DVP2Mgy6.js +0 -2
  460. package/dist/core/web/public/next/assets/ShortcutsOverlay-BcIcoClX.js +0 -2
  461. package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js +0 -3
  462. package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js.map +0 -1
  463. package/dist/core/web/public/next/assets/Slider-BypUWjpH.js +0 -2
  464. package/dist/core/web/public/next/assets/StepBand-Duz1PUes.js +0 -2
  465. package/dist/core/web/public/next/assets/Surface-B75lVfzm.js +0 -2
  466. package/dist/core/web/public/next/assets/Surface-B75lVfzm.js.map +0 -1
  467. package/dist/core/web/public/next/assets/Surface-DMca0gAe.css +0 -1
  468. package/dist/core/web/public/next/assets/Swimlane-DGcIcnNA.js +0 -2
  469. package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js +0 -7
  470. package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js.map +0 -1
  471. package/dist/core/web/public/next/assets/UniverseConsoleApp-C8yQ0AaR.js +0 -2
  472. package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js +0 -2
  473. package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js.map +0 -1
  474. package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js +0 -3
  475. package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js.map +0 -1
  476. package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js +0 -10
  477. package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js.map +0 -1
  478. package/dist/core/web/public/next/assets/actions-Ddfg2iLl.css +0 -1
  479. package/dist/core/web/public/next/assets/actions-tWevL9HV.js +0 -2
  480. package/dist/core/web/public/next/assets/actions-tWevL9HV.js.map +0 -1
  481. package/dist/core/web/public/next/assets/apps-model-CDFvmsQV.js +0 -2
  482. package/dist/core/web/public/next/assets/apps-model-CDFvmsQV.js.map +0 -1
  483. package/dist/core/web/public/next/assets/capacity-strip-model-BDbmQ3e3.js +0 -2
  484. package/dist/core/web/public/next/assets/capacity-strip-model-BDbmQ3e3.js.map +0 -1
  485. package/dist/core/web/public/next/assets/charts-CfAjuKMv.js +0 -2
  486. package/dist/core/web/public/next/assets/charts-CfAjuKMv.js.map +0 -1
  487. package/dist/core/web/public/next/assets/charts-uSX6xVYN.css +0 -1
  488. package/dist/core/web/public/next/assets/cloud-C1KPNRHC.css +0 -1
  489. package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js +0 -2
  490. package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js.map +0 -1
  491. package/dist/core/web/public/next/assets/cloud.module-ascz58c3.js +0 -2
  492. package/dist/core/web/public/next/assets/cloud.module-ascz58c3.js.map +0 -1
  493. package/dist/core/web/public/next/assets/command-bus-xYZoK9nQ.js +0 -2
  494. package/dist/core/web/public/next/assets/command-bus-xYZoK9nQ.js.map +0 -1
  495. package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js +0 -2
  496. package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js.map +0 -1
  497. package/dist/core/web/public/next/assets/composer-keys-su0g1h9o.js +0 -2
  498. package/dist/core/web/public/next/assets/composer-keys-su0g1h9o.js.map +0 -1
  499. package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js +0 -2
  500. package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js.map +0 -1
  501. package/dist/core/web/public/next/assets/context-model-CIBmSugV.js +0 -2
  502. package/dist/core/web/public/next/assets/context-model-CIBmSugV.js.map +0 -1
  503. package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js +0 -2
  504. package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js.map +0 -1
  505. package/dist/core/web/public/next/assets/dock-icons-CUh8dOxJ.js +0 -2
  506. package/dist/core/web/public/next/assets/dock-store-B2vlxqPu.js +0 -2
  507. package/dist/core/web/public/next/assets/dock-store-B2vlxqPu.js.map +0 -1
  508. package/dist/core/web/public/next/assets/fleet-model-7i-FbzKI.js +0 -2
  509. package/dist/core/web/public/next/assets/fleet-model-7i-FbzKI.js.map +0 -1
  510. package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js +0 -2
  511. package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js.map +0 -1
  512. package/dist/core/web/public/next/assets/format-BkWdOQDL.js +0 -2
  513. package/dist/core/web/public/next/assets/format-BkWdOQDL.js.map +0 -1
  514. package/dist/core/web/public/next/assets/global-oEl9Qj8u.js +0 -2
  515. package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js +0 -3
  516. package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js.map +0 -1
  517. package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js +0 -2
  518. package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js.map +0 -1
  519. package/dist/core/web/public/next/assets/icons-DEQa2rTx.js +0 -2
  520. package/dist/core/web/public/next/assets/icons-DEQa2rTx.js.map +0 -1
  521. package/dist/core/web/public/next/assets/live-model-bmsJgnYD.js +0 -2
  522. package/dist/core/web/public/next/assets/live-model-bmsJgnYD.js.map +0 -1
  523. package/dist/core/web/public/next/assets/local-model-DFyjKX0b.js +0 -2
  524. package/dist/core/web/public/next/assets/local-model-DFyjKX0b.js.map +0 -1
  525. package/dist/core/web/public/next/assets/mind.module-gTGAuJt1.js +0 -2
  526. package/dist/core/web/public/next/assets/mutations-C5S7okTW.js +0 -2
  527. package/dist/core/web/public/next/assets/nav-NVtnuG7A.js +0 -2
  528. package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js +0 -2
  529. package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js.map +0 -1
  530. package/dist/core/web/public/next/assets/primitives-DyCKYSBG.js +0 -1
  531. package/dist/core/web/public/next/assets/reasoning-pref-BUcFF_5G.js +0 -2
  532. package/dist/core/web/public/next/assets/seat-subscription-B-f9ViU2.js +0 -2
  533. package/dist/core/web/public/next/assets/section-visibility-Yctxu-if.js +0 -2
  534. package/dist/core/web/public/next/assets/section-visibility-Yctxu-if.js.map +0 -1
  535. package/dist/core/web/public/next/assets/slots-BhP8b8tf.js +0 -3
  536. package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js +0 -2
  537. package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js.map +0 -1
  538. package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js +0 -2
  539. package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js.map +0 -1
  540. package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js +0 -2
  541. package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js.map +0 -1
  542. package/dist/core/web/public/next/assets/useSeatsRefresh-DgFy-Ph4.js +0 -2
  543. package/dist/core/web/public/next/assets/useSeatsRefresh-DgFy-Ph4.js.map +0 -1
  544. package/dist/core/web/public/next/assets/useVerseTranscript-CDYrrWOO.js +0 -2
  545. package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js +0 -2
  546. package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js.map +0 -1
  547. package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js +0 -2
  548. package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js.map +0 -1
  549. package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js +0 -3
  550. package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js.map +0 -1
  551. package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js +0 -3
  552. package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js.map +0 -1
  553. package/dist/core/web/public/next/assets/viewport-nTubFCwf.js +0 -2
  554. package/dist/core/web/public/next/assets/viewport-nTubFCwf.js.map +0 -1
  555. package/dist/core/web/public/next/assets/warmup-HG5vYbsN.js +0 -3
  556. package/dist/core/web/public/next/assets/workbench-types-DzN-5trg.js +0 -2
  557. package/dist/core/web/public/next/assets/workbench-types-DzN-5trg.js.map +0 -1
  558. /package/dist/core/web/public/next/assets/{BurnDown-BuLMsJMx.css → StatTile-BuLMsJMx.css} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"dock-icons-CUh8dOxJ.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/chat/path-display.ts","../../../../../../src/web-ui/routes/verse/chat/LiveStatus.module.css","../../../../../../src/web-ui/routes/verse/chat/LiveStatus.tsx","../../../../../../src/web-ui/routes/verse/chat/LiveTimer.tsx","../../../../../../src/web-ui/routes/verse/dock/dock-icons.tsx"],"sourcesContent":["/**\n * routes/verse/chat/path-display.ts — how a file path READS in the chat.\n *\n * Tool payloads carry whatever path the CLI used, and that is usually\n * absolute: `/private/tmp/…/scratchpad/e2e-proj-39/math.ts` for a file the\n * operator knows as `math.ts`. Shown raw, the one part that identifies the\n * file is what the row's ellipsis clips. So every path the transcript draws\n * goes through `displayPath`:\n *\n * 1. relative to the chat's roots (the longest root that contains it wins —\n * a worktree nested in its repo is its own root). Paths and roots are\n * compared as `keyOf`s, so `\\` vs `/`, a trailing separator, macOS's\n * `/private/tmp` for `/tmp` and `c:` for `C:` all still match; the rest\n * is sliced out of the ORIGINAL path, in the CLI's own separators;\n * 2. otherwise as the hub sent it when it is relative or `~/…`;\n * 3. otherwise, when it is long, its last three segments behind `…/`.\n *\n * HOME. The hub rewrites the operator's OWN home to `~` on every payload\n * (sanitizePublicJson) and is the only side that knows which home that is —\n * so a `~/…` path or root already says it, and matches as-is. Nothing here\n * guesses a home from `/Users/<x>`, `/home/<x>` or `C:\\Users\\<x>`: one that\n * reaches the browser is another account's or /Users/Shared, and drawing it\n * as `~` (or as in-project, via a `~` root) passes it off as the operator's.\n *\n * Display only. The full path stays in the tooltip and is never rewritten in\n * anything handed back to a tool, a search or a jump anchor. (It is in the\n * chat's first-paint chunk, hence the terse body.)\n */\nimport { createContext, useCallback, useContext } from 'react';\nimport { pathsIn } from './tool-semantics.js';\n\nconst NO_ROOTS: readonly string[] = [];\n\n/** The chat's roots, primary first (Workspace provides them; Transcript can override). */\nexport const PathRootsContext = createContext<readonly string[]>(NO_ROOTS);\n\n/**\n * A path as the operator's home reads: unchanged. The hub already spelled\n * that home `~`; any other `/Users/<x>` is someone else's (see HOME above).\n * Kept as the one seam home display goes through (SessionRoots uses it).\n */\nexport function abbreviateHome(path: string): string {\n return path;\n}\n\n/**\n * One folder's comparable form: `/` separators, no trailing one, the\n * `/private` alias folded (/tmp, /var and /etc are symlinks into it and roots\n * are not realpath'd), a lower-case drive letter. Only the fold changes the\n * length, and only at the head — so a matched tail maps back onto the original.\n */\nfunction keyOf(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/\\/+$/, '')\n .replace(/^\\/private(?=\\/(?:tmp|var|etc)(?:\\/|$))/, '')\n .replace(/^[A-Z](?=:)/, (d) => d.toLowerCase());\n}\n\n/** What the transcript draws for `path`; the full path belongs in the tooltip. */\nexport function displayPath(path: string, roots: readonly string[] = NO_ROOTS): string {\n const key = keyOf(path);\n let root = '';\n for (const raw of roots) {\n const r = keyOf(raw);\n // A bare `/`, `C:` or `\\\\` root would claim every path on the machine.\n if (r.length > root.length && !/^(?:[a-z]:)?$/.test(r) && (key === r || key.startsWith(`${r}/`))) root = r;\n }\n const own = path.replace(/[\\\\/]+$/, '');\n // Inside a root: the rest of the path, or — for the root itself — its name.\n if (root) {\n const rest = key.length - root.length - 1;\n return rest > 0 ? own.slice(own.length - rest) : own.slice(Math.max(own.lastIndexOf('/'), own.lastIndexOf('\\\\')) + 1);\n }\n if (!/^(?:[\\\\/]|[A-Za-z]:[\\\\/])/.test(path)) return path.replace(/^\\.[\\\\/]/, '');\n const sep = path.includes('/') ? '/' : '\\\\';\n const parts = path.replace(/^[A-Za-z]:/, '').split(/[\\\\/]/).filter(Boolean);\n return parts.length > 4 ? `…${sep}${parts.slice(-3).join(sep)}` : path;\n}\n\n/**\n * The file a tool call names, when it runs no command — a shell call keeps\n * its command line verbatim (rewriting a command is not display).\n */\nexport function inputPath(input: unknown): string | null {\n const rec = input !== null && typeof input === 'object' ? input as Record<string, unknown> : null;\n return rec && typeof rec.command !== 'string' && typeof rec.cmd !== 'string' ? pathsIn(rec)[0] ?? null : null;\n}\n\n/** `displayPath` bound to the roots in context. */\nexport function useDisplayPath(): (path: string) => string {\n const roots = useContext(PathRootsContext);\n return useCallback((path: string) => displayPath(path, roots), [roots]);\n}\n","/**\n * The live line sits where the caret used to: under the running turn, on\n * the reading measure, in tertiary text with tabular figures. Colour means\n * state only — the running pulse — and a notice is a 2px rule in the warning\n * colour with its kind in words (DESIGN §6: never colour alone).\n */\n.live {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n min-width: 0;\n}\n\n.line {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n min-height: var(--control-h-sm);\n min-width: 0;\n color: var(--text-tertiary);\n font-size: var(--text-sm-size);\n}\n\n.pulse {\n width: 8px;\n height: 8px;\n flex: none;\n border-radius: var(--radius-full);\n background: var(--status-running-solid);\n animation: live-pulse 1.4s var(--ease-standard) infinite;\n}\n.live[data-phase='waiting'] .pulse { background: var(--border-strong); }\n\n.text {\n display: inline-flex;\n align-items: baseline;\n gap: var(--space-2);\n min-width: 0;\n flex: 1 1 auto;\n overflow: hidden;\n white-space: nowrap;\n}\n.word { color: var(--text-secondary); font-weight: var(--font-weight-medium); }\n.sep { color: var(--text-tertiary); }\n.figure {\n font-family: var(--font-display);\n font-variant-numeric: tabular-nums;\n}\n.detail {\n font-family: var(--font-mono);\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.stop {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n min-height: var(--control-h-xs);\n padding: 0 var(--space-2);\n border: 1px solid transparent;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n cursor: pointer;\n transition: color var(--duration-fast) var(--ease-standard), background var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);\n}\n.stop:hover { color: var(--text-primary); background: var(--bg-hover); border-color: var(--border-default); }\n.stop:active { background: var(--bg-active); }\n.stopIcon {\n width: 8px;\n height: 8px;\n border-radius: 1px;\n background: currentColor;\n}\n\n.notice {\n display: flex;\n gap: var(--space-2);\n margin: 0;\n padding-left: var(--space-3);\n border-left: 2px solid var(--status-warning-solid);\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line-relaxed);\n overflow-wrap: anywhere;\n}\n.notice[data-kind='preflight'] { border-left-color: var(--status-info-solid); }\n.noticeWord { color: var(--status-warning-fg); font-weight: var(--font-weight-medium); white-space: nowrap; }\n.notice[data-kind='preflight'] .noticeWord { color: var(--status-info-fg); }\n.noticeText { min-width: 0; }\n\n@keyframes live-pulse { 50% { opacity: 0.3; } }\n\n@media (prefers-reduced-motion: reduce) {\n :root:not([data-motion=\"full\"]) .pulse { animation: none; }\n}\n:root[data-motion=\"reduce\"] .pulse { animation: none; }\n\n@media (max-width: 480px) {\n /* 3.10: one line above the composer, beside the tasks chip — the text\n ellipsises (its detail first) rather than wrapping Stop onto a row of\n its own. */\n .line { flex-wrap: nowrap; }\n}\n","/**\n * routes/verse/chat/LiveStatus.tsx — the line under a running turn (V3.10):\n *\n * ● Running · 14s · npm test Stop\n * ● Writing · 1m 3s · 38 tok/s Stop\n *\n * It replaces the bare caret that used to be the ONLY live signal: a turn\n * that had been silently retrying an overloaded API for four minutes looked\n * exactly like one that was about to answer.\n *\n * Sources, best first:\n * 1. transient `progress` frames (phase, server-measured elapsed, tok/s);\n * 2. the transcript itself — a pending tool call means \"running that\n * tool\", a streaming bubble means \"writing\" — so a server that sends no\n * progress frames still gets an honest line;\n * 3. the turn's own start stamp for the clock.\n * A figure nobody measured (tok/s, the tool) is left out, never guessed.\n *\n * Under it, when the engine says so, one plumbing notice: an API retry, a\n * failed preflight (e.g. Ollama not answering), or the no-output watchdog.\n * It clears itself once output resumes (verse-store livePersisted).\n *\n * Accessibility: the visible line ticks every second, so it is NOT a live\n * region; a visually hidden status announces only phase/tool changes, and a\n * notice is announced once when it appears.\n */\nimport { memo, useEffect, useState } from 'react';\nimport type { VerseProgressPhase, VerseStatusKind } from '../../../../core/verse/types.js';\nimport { summarizeToolInput } from '../verse-model.js';\nimport type { TranscriptItem, VerseLiveState } from '../verse-store.js';\nimport { inputPath, useDisplayPath } from './path-display.js';\nimport styles from './LiveStatus.module.css';\n\nexport interface LivePhase {\n phase: VerseProgressPhase;\n /** What the phase is about: the running command/path, when known. */\n detail: string | null;\n /** 3.10.1: the file the running call names, drawn relative to the chat's roots. */\n path?: string | null;\n}\n\n/**\n * What the transcript says the running turn is doing right now — the\n * fallback for a server that sends no `progress` frames, and the source of\n * the tool's human-readable argument even when one does.\n */\nexport function derivePhaseFromTranscript(items: readonly TranscriptItem[], live: Pick<VerseLiveState, 'thinking'>): LivePhase {\n for (let i = items.length - 1; i >= 0; i -= 1) {\n const item = items[i]!;\n if (item.kind === 'user') break;\n if (item.kind === 'tool') {\n if (item.result === null) return { phase: 'tool', detail: summarizeToolInput(item.input) || item.name, path: inputPath(item.input) };\n break;\n }\n if (item.kind === 'assistant' && item.streaming) return { phase: 'writing', detail: null };\n if (item.kind === 'assistant' || item.kind === 'thinking') break;\n }\n if (live.thinking) return { phase: 'thinking', detail: null };\n return { phase: 'waiting', detail: null };\n}\n\nconst PHASE_WORD: Record<VerseProgressPhase, string> = {\n thinking: 'Thinking',\n tool: 'Running',\n writing: 'Writing',\n waiting: 'Waiting',\n};\n\nconst NOTICE_WORD: Record<VerseStatusKind, string> = {\n retry: 'Retrying',\n preflight: 'Preflight',\n watchdog: 'Still running',\n};\n\n/** \"14s\" / \"1m 3s\" / \"1h 2m\". */\nexport function formatLiveElapsed(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '0s';\n const s = Math.floor(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${s % 60}s`;\n return `${Math.floor(m / 60)}h ${m % 60}m`;\n}\n\nexport interface LiveStatusLine {\n phase: VerseProgressPhase;\n word: string;\n elapsedMs: number | null;\n detail: string | null;\n rate: string | null;\n}\n\n/** Pure: the parts of the line at clock time `now` (exported for tests). */\nexport function liveStatusLine(live: VerseLiveState, derived: LivePhase, now: number): LiveStatusLine {\n const progress = live.progress;\n // The transcript knows a tool call is pending before (or without) a\n // progress frame saying so, and it knows the call's argument; a progress\n // frame knows about reasoning and waiting, which the transcript cannot see.\n const phase: VerseProgressPhase = derived.phase === 'tool' || derived.phase === 'writing'\n ? derived.phase\n : progress?.phase ?? derived.phase;\n const elapsedMs = progress\n ? progress.elapsedMs + Math.max(0, now - progress.receivedAt)\n : live.startedAt !== null ? Math.max(0, now - live.startedAt) : null;\n const detail = phase === 'tool' ? derived.detail ?? progress?.tool ?? null : null;\n const tps = progress?.tokPerSec ?? null;\n const rate = (phase === 'writing' || phase === 'thinking') && tps !== null && tps > 0 ? `${tps >= 10 ? Math.round(tps) : tps.toFixed(1)} tok/s` : null;\n return { phase, word: PHASE_WORD[phase], elapsedMs, detail, rate };\n}\n\nexport interface LiveStatusProps {\n live: VerseLiveState;\n derived: LivePhase;\n onStop?: () => void;\n /**\n * 3.10: above the composer the engine's notice goes to the notice slot\n * (one notice at a time, in priority order), so the line omits it.\n */\n showNotice?: boolean;\n}\n\nexport const LiveStatus = memo(function LiveStatus({ live, derived, onStop, showNotice = true }: LiveStatusProps) {\n const [now, setNow] = useState(() => Date.now());\n // The clock only; never a request. Re-armed per turn.\n useEffect(() => {\n setNow(Date.now());\n const id = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(id);\n }, [live.turnId]);\n\n const show = useDisplayPath();\n const computed = liveStatusLine(live, derived, now);\n // A running Read names its file as the transcript does — relative, not the\n // head of an absolute path (chat/path-display.ts); the full path is the title.\n const line = computed.phase === 'tool' && derived.path ? { ...computed, detail: show(derived.path) } : computed;\n const spoken = line.detail ? `${line.word}: ${line.detail}` : line.word;\n const notice = showNotice ? live.notice : null;\n\n return (\n <div className={styles.live} data-phase={line.phase}>\n <div className={styles.line}>\n <span className={styles.pulse} aria-hidden=\"true\" />\n <span className={styles.text} aria-hidden=\"true\">\n <span className={styles.word}>{line.word}</span>\n {line.elapsedMs !== null ? <><span className={styles.sep}>·</span><span className={styles.figure}>{formatLiveElapsed(line.elapsedMs)}</span></> : null}\n {line.detail ? <><span className={styles.sep}>·</span><span className={styles.detail} title={derived.path ?? line.detail}>{line.detail}</span></> : null}\n {line.rate ? <><span className={styles.sep}>·</span><span className={styles.figure}>{line.rate}</span></> : null}\n </span>\n <span className=\"visually-hidden\" role=\"status\">{spoken}</span>\n {onStop ? (\n <button type=\"button\" className={styles.stop} onClick={onStop} aria-label=\"Stop this turn\" title=\"Stop this turn (⌘.)\">\n <span className={styles.stopIcon} aria-hidden=\"true\" />Stop\n </button>\n ) : null}\n </div>\n {notice ? (\n <p className={styles.notice} data-kind={notice.kind} role=\"status\">\n <span className={styles.noticeWord}>{NOTICE_WORD[notice.kind]}</span>\n <span className={styles.noticeText}>{notice.message}</span>\n </p>\n ) : null}\n </div>\n );\n});\n","/**\n * routes/verse/chat/LiveTimer.tsx — \"12s\", counting, for anything running\n * (unit C2): a pending tool row, an activity group, a running chat in the\n * sidebar, a task in the Tasks pane.\n *\n * ONE shared one-second clock for every timer on the page. A long session\n * can show dozens of running rows at once (a group of parallel tool calls,\n * the sidebar's running chats, the tasks list); a `setInterval` each would\n * be dozens of timers re-rendering out of phase. Subscribers join a single\n * interval that exists only while at least one of them is mounted, and all\n * of them tick on the same beat.\n *\n * It is a clock, never a request (SPEC-310A §0: no polling faster than 2 s —\n * this polls nothing).\n */\nimport { useSyncExternalStore } from 'react';\nimport { formatLiveElapsed } from './LiveStatus.js';\n\nconst listeners = new Set<() => void>();\nlet timer: ReturnType<typeof setInterval> | null = null;\nlet now = Date.now();\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener);\n if (timer === null) {\n now = Date.now();\n timer = setInterval(() => {\n now = Date.now();\n for (const l of [...listeners]) l();\n }, 1000);\n }\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0 && timer !== null) {\n clearInterval(timer);\n timer = null;\n }\n };\n}\n\nfunction snapshot(): number {\n return now;\n}\n\nconst idle = () => () => {};\n// A constant: useSyncExternalStore requires a stable snapshot between\n// renders, and `Date.now` as a snapshot would loop.\nconst idleSnapshot = () => 0;\n\n/**\n * The shared clock (ms). While `active` is false the component does not\n * subscribe at all — a settled row costs nothing — and reads the wall clock\n * once per render instead.\n */\nexport function useSecondClock(active = true): number {\n const tick = useSyncExternalStore(active ? subscribe : idle, active ? snapshot : idleSnapshot, active ? snapshot : idleSnapshot);\n // A freshly mounted subscriber must not show the clock as it stood when the\n // previous beat fired (up to a second stale): take the later of the two.\n return Math.max(tick, Date.now());\n}\n\n/** Parse an ISO stamp or client-clock ms into ms; null when unusable. */\nexport function startMs(since: string | number | null | undefined): number | null {\n if (typeof since === 'number') return Number.isFinite(since) ? since : null;\n if (typeof since !== 'string') return null;\n const ms = Date.parse(since);\n return Number.isFinite(ms) ? ms : null;\n}\n\nexport interface LiveTimerProps {\n /** ISO start stamp or client-clock ms. Unparseable → renders nothing (an unknown start is not \"0s\"). */\n since: string | number | null | undefined;\n className?: string;\n /** Spoken label prefix, e.g. \"running for\". Omit to hide the timer from assistive tech (it ticks every second). */\n label?: string;\n}\n\nexport function LiveTimer({ since, className, label }: LiveTimerProps) {\n const start = startMs(since);\n const clock = useSecondClock(start !== null);\n if (start === null) return null;\n const text = formatLiveElapsed(Math.max(0, clock - start));\n return (\n <span className={className} data-live-timer=\"\" aria-hidden={label ? undefined : true}\n aria-label={label ? `${label} ${text}` : undefined} role={label ? 'timer' : undefined}>\n {text}\n </span>\n );\n}\n","/**\n * routes/verse/dock/dock-icons.tsx — the chat surface's own 16px glyphs\n * (unit C2): the dock's pane tabs and the header's pane toggles, the ⋯\n * menu, pin and archive. Same drawing grammar as components/primitives/icons\n * (16-unit box, 1.5 stroke, round caps, currentColor) so they sit beside the\n * shared set without looking borrowed; kept here because verse-icons.tsx is\n * the shell's file.\n */\nimport type { ReactNode, SVGProps } from 'react';\nimport type { DockPaneId } from '../shell/dock-catalog.js';\n\nexport interface GlyphProps extends Omit<SVGProps<SVGSVGElement>, 'children' | 'viewBox'> {\n size?: number;\n}\n\nfunction Glyph({ size = 16, children, ...rest }: GlyphProps & { children: ReactNode }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.5}\n strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\" focusable=\"false\" {...rest}>\n {children}\n </svg>\n );\n}\n\nexport function TerminalGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"1.75\" y=\"2.75\" width=\"12.5\" height=\"10.5\" rx=\"1.5\" /><path d=\"m4.5 6.25 2 1.75-2 1.75M8.25 10h3\" /></Glyph>;\n}\n\nexport function PreviewGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"1.75\" y=\"2.75\" width=\"12.5\" height=\"10.5\" rx=\"1.5\" /><path d=\"M1.75 5.75h12.5M4 4.25h.01M5.75 4.25h.01\" /></Glyph>;\n}\n\nexport function ReviewGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M5 2.5v5M2.5 5h5M9 11h4.5\" /><path d=\"M11.5 2.5 4.5 13.5\" /></Glyph>;\n}\n\nexport function TasksGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M6.5 4h7M6.5 8h7M6.5 12h7\" /><path d=\"m2.25 4 1 1 1.5-2M2.5 8h1.75M2.5 12h1.75\" /></Glyph>;\n}\n\nexport function ContextGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"m8 2 6 3-6 3-6-3 6-3Z\" /><path d=\"m2 8 6 3 6-3M2 11l6 3 6-3\" /></Glyph>;\n}\n\nexport function SplitGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"2.25\" y=\"2.25\" width=\"11.5\" height=\"11.5\" rx=\"1.5\" /><path d=\"M2.25 8h11.5\" /></Glyph>;\n}\n\nexport function CloseGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"m4 4 8 8M12 4l-8 8\" /></Glyph>;\n}\n\nexport function MoreGlyph(p: GlyphProps) {\n return (\n <Glyph {...p}>\n <circle cx=\"3.5\" cy=\"8\" r=\"0.9\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"8\" cy=\"8\" r=\"0.9\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"12.5\" cy=\"8\" r=\"0.9\" fill=\"currentColor\" stroke=\"none\" />\n </Glyph>\n );\n}\n\nexport function PinGlyph(p: GlyphProps) {\n return <Glyph {...p}><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\" /><path d=\"m5 11-2.75 2.75\" /></Glyph>;\n}\n\nexport function ArchiveGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"1.75\" y=\"2.75\" width=\"12.5\" height=\"3\" rx=\"1\" /><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\" /></Glyph>;\n}\n\nexport function RenameGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M10.5 2.75 13.25 5.5 6 12.75H3.25V10Z\" /></Glyph>;\n}\n\nexport function HandoffGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M2.5 8h9M8.5 4.5 12 8l-3.5 3.5\" /><path d=\"M13.75 3v10\" /></Glyph>;\n}\n\nexport function CopyGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"5.25\" y=\"5.25\" width=\"8.5\" height=\"8.5\" rx=\"1.5\" /><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\" /></Glyph>;\n}\n\nexport function TrashGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M2.75 4.25h10.5M6.25 4.25V2.75h3.5v1.5M4.25 4.25l.6 9h6.3l.6-9\" /></Glyph>;\n}\n\nexport const DOCK_PANE_GLYPH: Readonly<Record<DockPaneId, (p: GlyphProps) => ReactNode>> = {\n terminal: TerminalGlyph,\n preview: PreviewGlyph,\n diff: ReviewGlyph,\n tasks: TasksGlyph,\n context: ContextGlyph,\n};\n"],"mappings":"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"}
1
+ {"version":3,"file":"dock-icons-BFuBbqJl.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/chat/path-display.ts","../../../../../../src/web-ui/routes/verse/chat/LiveStatus.module.css","../../../../../../src/web-ui/routes/verse/chat/LiveStatus.tsx","../../../../../../src/web-ui/routes/verse/chat/LiveTimer.tsx","../../../../../../src/web-ui/routes/verse/dock/dock-icons.tsx"],"sourcesContent":["/**\n * routes/verse/chat/path-display.ts — how a file path READS in the chat.\n *\n * Tool payloads carry whatever path the CLI used, and that is usually\n * absolute: `/private/tmp/…/scratchpad/e2e-proj-39/math.ts` for a file the\n * operator knows as `math.ts`. Shown raw, the one part that identifies the\n * file is what the row's ellipsis clips. So every path the transcript draws\n * goes through `displayPath`:\n *\n * 1. relative to the chat's roots (the longest root that contains it wins —\n * a worktree nested in its repo is its own root). Paths and roots are\n * compared as `keyOf`s, so `\\` vs `/`, a trailing separator, macOS's\n * `/private/tmp` for `/tmp` and `c:` for `C:` all still match; the rest\n * is sliced out of the ORIGINAL path, in the CLI's own separators;\n * 2. otherwise as the hub sent it when it is relative or `~/…`;\n * 3. otherwise, when it is long, its last three segments behind `…/`.\n *\n * HOME. The hub rewrites the operator's OWN home to `~` on every payload\n * (sanitizePublicJson) and is the only side that knows which home that is —\n * so a `~/…` path or root already says it, and matches as-is. Nothing here\n * guesses a home from `/Users/<x>`, `/home/<x>` or `C:\\Users\\<x>`: one that\n * reaches the browser is another account's or /Users/Shared, and drawing it\n * as `~` (or as in-project, via a `~` root) passes it off as the operator's.\n *\n * Display only. The full path stays in the tooltip and is never rewritten in\n * anything handed back to a tool, a search or a jump anchor. (It is in the\n * chat's first-paint chunk, hence the terse body.)\n */\nimport { createContext, useCallback, useContext } from 'react';\nimport { pathsIn } from './tool-semantics.js';\n\nconst NO_ROOTS: readonly string[] = [];\n\n/** The chat's roots, primary first (Workspace provides them; Transcript can override). */\nexport const PathRootsContext = createContext<readonly string[]>(NO_ROOTS);\n\n/**\n * A path as the operator's home reads: unchanged. The hub already spelled\n * that home `~`; any other `/Users/<x>` is someone else's (see HOME above).\n * Kept as the one seam home display goes through (SessionRoots uses it).\n */\nexport function abbreviateHome(path: string): string {\n return path;\n}\n\n/**\n * One folder's comparable form: `/` separators, no trailing one, the\n * `/private` alias folded (/tmp, /var and /etc are symlinks into it and roots\n * are not realpath'd), a lower-case drive letter. Only the fold changes the\n * length, and only at the head — so a matched tail maps back onto the original.\n */\nfunction keyOf(path: string): string {\n return path.replace(/\\\\/g, '/').replace(/\\/+$/, '')\n .replace(/^\\/private(?=\\/(?:tmp|var|etc)(?:\\/|$))/, '')\n .replace(/^[A-Z](?=:)/, (d) => d.toLowerCase());\n}\n\n/** What the transcript draws for `path`; the full path belongs in the tooltip. */\nexport function displayPath(path: string, roots: readonly string[] = NO_ROOTS): string {\n const key = keyOf(path);\n let root = '';\n for (const raw of roots) {\n const r = keyOf(raw);\n // A bare `/`, `C:` or `\\\\` root would claim every path on the machine.\n if (r.length > root.length && !/^(?:[a-z]:)?$/.test(r) && (key === r || key.startsWith(`${r}/`))) root = r;\n }\n const own = path.replace(/[\\\\/]+$/, '');\n // Inside a root: the rest of the path, or — for the root itself — its name.\n if (root) {\n const rest = key.length - root.length - 1;\n return rest > 0 ? own.slice(own.length - rest) : own.slice(Math.max(own.lastIndexOf('/'), own.lastIndexOf('\\\\')) + 1);\n }\n if (!/^(?:[\\\\/]|[A-Za-z]:[\\\\/])/.test(path)) return path.replace(/^\\.[\\\\/]/, '');\n const sep = path.includes('/') ? '/' : '\\\\';\n const parts = path.replace(/^[A-Za-z]:/, '').split(/[\\\\/]/).filter(Boolean);\n return parts.length > 4 ? `…${sep}${parts.slice(-3).join(sep)}` : path;\n}\n\n/**\n * The file a tool call names, when it runs no command — a shell call keeps\n * its command line verbatim (rewriting a command is not display).\n */\nexport function inputPath(input: unknown): string | null {\n const rec = input !== null && typeof input === 'object' ? input as Record<string, unknown> : null;\n return rec && typeof rec.command !== 'string' && typeof rec.cmd !== 'string' ? pathsIn(rec)[0] ?? null : null;\n}\n\n/** `displayPath` bound to the roots in context. */\nexport function useDisplayPath(): (path: string) => string {\n const roots = useContext(PathRootsContext);\n return useCallback((path: string) => displayPath(path, roots), [roots]);\n}\n","/**\n * The live line sits where the caret used to: under the running turn, on\n * the reading measure, in tertiary text with tabular figures. Colour means\n * state only — the running pulse — and a notice is a 2px rule in the warning\n * colour with its kind in words (DESIGN §6: never colour alone).\n */\n.live {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n min-width: 0;\n}\n\n.line {\n display: flex;\n align-items: center;\n gap: var(--space-2);\n min-height: var(--control-h-sm);\n min-width: 0;\n color: var(--text-tertiary);\n font-size: var(--text-sm-size);\n}\n\n.pulse {\n width: 8px;\n height: 8px;\n flex: none;\n border-radius: var(--radius-full);\n background: var(--status-running-solid);\n animation: live-pulse 1.4s var(--ease-standard) infinite;\n}\n.live[data-phase='waiting'] .pulse { background: var(--border-strong); }\n\n.text {\n display: inline-flex;\n align-items: baseline;\n gap: var(--space-2);\n min-width: 0;\n flex: 1 1 auto;\n overflow: hidden;\n white-space: nowrap;\n}\n.word { color: var(--text-secondary); font-weight: var(--font-weight-medium); }\n.sep { color: var(--text-tertiary); }\n.figure {\n font-family: var(--font-display);\n font-variant-numeric: tabular-nums;\n}\n.detail {\n font-family: var(--font-mono);\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n overflow: hidden;\n text-overflow: ellipsis;\n min-width: 0;\n}\n\n.stop {\n flex: none;\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n min-height: var(--control-h-xs);\n padding: 0 var(--space-2);\n border: 1px solid transparent;\n border-radius: var(--radius-sm);\n background: transparent;\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n cursor: pointer;\n transition: color var(--duration-fast) var(--ease-standard), background var(--duration-fast) var(--ease-standard), border-color var(--duration-fast) var(--ease-standard);\n}\n.stop:hover { color: var(--text-primary); background: var(--bg-hover); border-color: var(--border-default); }\n.stop:active { background: var(--bg-active); }\n.stopIcon {\n width: 8px;\n height: 8px;\n border-radius: 1px;\n background: currentColor;\n}\n\n.notice {\n display: flex;\n gap: var(--space-2);\n margin: 0;\n padding-left: var(--space-3);\n border-left: 2px solid var(--status-warning-solid);\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line-relaxed);\n overflow-wrap: anywhere;\n}\n.notice[data-kind='preflight'] { border-left-color: var(--status-info-solid); }\n.noticeWord { color: var(--status-warning-fg); font-weight: var(--font-weight-medium); white-space: nowrap; }\n.notice[data-kind='preflight'] .noticeWord { color: var(--status-info-fg); }\n.noticeText { min-width: 0; }\n\n@keyframes live-pulse { 50% { opacity: 0.3; } }\n\n@media (prefers-reduced-motion: reduce) {\n :root:not([data-motion=\"full\"]) .pulse { animation: none; }\n}\n:root[data-motion=\"reduce\"] .pulse { animation: none; }\n\n@media (max-width: 480px) {\n /* 3.10: one line above the composer, beside the tasks chip — the text\n ellipsises (its detail first) rather than wrapping Stop onto a row of\n its own. */\n .line { flex-wrap: nowrap; }\n}\n","/**\n * routes/verse/chat/LiveStatus.tsx — the line under a running turn (V3.10):\n *\n * ● Running · 14s · npm test Stop\n * ● Writing · 1m 3s · 38 tok/s Stop\n *\n * It replaces the bare caret that used to be the ONLY live signal: a turn\n * that had been silently retrying an overloaded API for four minutes looked\n * exactly like one that was about to answer.\n *\n * Sources, best first:\n * 1. transient `progress` frames (phase, server-measured elapsed, tok/s);\n * 2. the transcript itself — a pending tool call means \"running that\n * tool\", a streaming bubble means \"writing\" — so a server that sends no\n * progress frames still gets an honest line;\n * 3. the turn's own start stamp for the clock.\n * A figure nobody measured (tok/s, the tool) is left out, never guessed.\n *\n * Under it, when the engine says so, one plumbing notice: an API retry, a\n * failed preflight (e.g. Ollama not answering), or the no-output watchdog.\n * It clears itself once output resumes (verse-store livePersisted).\n *\n * Accessibility: the visible line ticks every second, so it is NOT a live\n * region; a visually hidden status announces only phase/tool changes, and a\n * notice is announced once when it appears.\n */\nimport { memo, useEffect, useState } from 'react';\nimport type { VerseProgressPhase, VerseStatusKind } from '../../../../core/verse/types.js';\nimport { summarizeToolInput } from '../verse-model.js';\nimport type { TranscriptItem, VerseLiveState } from '../verse-store.js';\nimport { inputPath, useDisplayPath } from './path-display.js';\nimport styles from './LiveStatus.module.css';\n\nexport interface LivePhase {\n phase: VerseProgressPhase;\n /** What the phase is about: the running command/path, when known. */\n detail: string | null;\n /** 3.10.1: the file the running call names, drawn relative to the chat's roots. */\n path?: string | null;\n}\n\n/**\n * What the transcript says the running turn is doing right now — the\n * fallback for a server that sends no `progress` frames, and the source of\n * the tool's human-readable argument even when one does.\n */\nexport function derivePhaseFromTranscript(items: readonly TranscriptItem[], live: Pick<VerseLiveState, 'thinking'>): LivePhase {\n for (let i = items.length - 1; i >= 0; i -= 1) {\n const item = items[i]!;\n if (item.kind === 'user') break;\n if (item.kind === 'tool') {\n if (item.result === null) return { phase: 'tool', detail: summarizeToolInput(item.input) || item.name, path: inputPath(item.input) };\n break;\n }\n if (item.kind === 'assistant' && item.streaming) return { phase: 'writing', detail: null };\n if (item.kind === 'assistant' || item.kind === 'thinking') break;\n }\n if (live.thinking) return { phase: 'thinking', detail: null };\n return { phase: 'waiting', detail: null };\n}\n\nconst PHASE_WORD: Record<VerseProgressPhase, string> = {\n thinking: 'Thinking',\n tool: 'Running',\n writing: 'Writing',\n waiting: 'Waiting',\n};\n\nconst NOTICE_WORD: Record<VerseStatusKind, string> = {\n retry: 'Retrying',\n preflight: 'Preflight',\n watchdog: 'Still running',\n};\n\n/** \"14s\" / \"1m 3s\" / \"1h 2m\". */\nexport function formatLiveElapsed(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '0s';\n const s = Math.floor(ms / 1000);\n if (s < 60) return `${s}s`;\n const m = Math.floor(s / 60);\n if (m < 60) return `${m}m ${s % 60}s`;\n return `${Math.floor(m / 60)}h ${m % 60}m`;\n}\n\nexport interface LiveStatusLine {\n phase: VerseProgressPhase;\n word: string;\n elapsedMs: number | null;\n detail: string | null;\n rate: string | null;\n}\n\n/** Pure: the parts of the line at clock time `now` (exported for tests). */\nexport function liveStatusLine(live: VerseLiveState, derived: LivePhase, now: number): LiveStatusLine {\n const progress = live.progress;\n // The transcript knows a tool call is pending before (or without) a\n // progress frame saying so, and it knows the call's argument; a progress\n // frame knows about reasoning and waiting, which the transcript cannot see.\n const phase: VerseProgressPhase = derived.phase === 'tool' || derived.phase === 'writing'\n ? derived.phase\n : progress?.phase ?? derived.phase;\n const elapsedMs = progress\n ? progress.elapsedMs + Math.max(0, now - progress.receivedAt)\n : live.startedAt !== null ? Math.max(0, now - live.startedAt) : null;\n const detail = phase === 'tool' ? derived.detail ?? progress?.tool ?? null : null;\n const tps = progress?.tokPerSec ?? null;\n const rate = (phase === 'writing' || phase === 'thinking') && tps !== null && tps > 0 ? `${tps >= 10 ? Math.round(tps) : tps.toFixed(1)} tok/s` : null;\n return { phase, word: PHASE_WORD[phase], elapsedMs, detail, rate };\n}\n\nexport interface LiveStatusProps {\n live: VerseLiveState;\n derived: LivePhase;\n onStop?: () => void;\n /**\n * 3.10: above the composer the engine's notice goes to the notice slot\n * (one notice at a time, in priority order), so the line omits it.\n */\n showNotice?: boolean;\n}\n\nexport const LiveStatus = memo(function LiveStatus({ live, derived, onStop, showNotice = true }: LiveStatusProps) {\n const [now, setNow] = useState(() => Date.now());\n // The clock only; never a request. Re-armed per turn.\n useEffect(() => {\n setNow(Date.now());\n const id = setInterval(() => setNow(Date.now()), 1000);\n return () => clearInterval(id);\n }, [live.turnId]);\n\n const show = useDisplayPath();\n const computed = liveStatusLine(live, derived, now);\n // A running Read names its file as the transcript does — relative, not the\n // head of an absolute path (chat/path-display.ts); the full path is the title.\n const line = computed.phase === 'tool' && derived.path ? { ...computed, detail: show(derived.path) } : computed;\n const spoken = line.detail ? `${line.word}: ${line.detail}` : line.word;\n const notice = showNotice ? live.notice : null;\n\n return (\n <div className={styles.live} data-phase={line.phase}>\n <div className={styles.line}>\n <span className={styles.pulse} aria-hidden=\"true\" />\n <span className={styles.text} aria-hidden=\"true\">\n <span className={styles.word}>{line.word}</span>\n {line.elapsedMs !== null ? <><span className={styles.sep}>·</span><span className={styles.figure}>{formatLiveElapsed(line.elapsedMs)}</span></> : null}\n {line.detail ? <><span className={styles.sep}>·</span><span className={styles.detail} title={derived.path ?? line.detail}>{line.detail}</span></> : null}\n {line.rate ? <><span className={styles.sep}>·</span><span className={styles.figure}>{line.rate}</span></> : null}\n </span>\n <span className=\"visually-hidden\" role=\"status\">{spoken}</span>\n {onStop ? (\n <button type=\"button\" className={styles.stop} onClick={onStop} aria-label=\"Stop this turn\" title=\"Stop this turn (⌘.)\">\n <span className={styles.stopIcon} aria-hidden=\"true\" />Stop\n </button>\n ) : null}\n </div>\n {notice ? (\n <p className={styles.notice} data-kind={notice.kind} role=\"status\">\n <span className={styles.noticeWord}>{NOTICE_WORD[notice.kind]}</span>\n <span className={styles.noticeText}>{notice.message}</span>\n </p>\n ) : null}\n </div>\n );\n});\n","/**\n * routes/verse/chat/LiveTimer.tsx — \"12s\", counting, for anything running\n * (unit C2): a pending tool row, an activity group, a running chat in the\n * sidebar, a task in the Tasks pane.\n *\n * ONE shared one-second clock for every timer on the page. A long session\n * can show dozens of running rows at once (a group of parallel tool calls,\n * the sidebar's running chats, the tasks list); a `setInterval` each would\n * be dozens of timers re-rendering out of phase. Subscribers join a single\n * interval that exists only while at least one of them is mounted, and all\n * of them tick on the same beat.\n *\n * It is a clock, never a request (SPEC-310A §0: no polling faster than 2 s —\n * this polls nothing).\n */\nimport { useSyncExternalStore } from 'react';\nimport { formatLiveElapsed } from './LiveStatus.js';\n\nconst listeners = new Set<() => void>();\nlet timer: ReturnType<typeof setInterval> | null = null;\nlet now = Date.now();\n\nfunction subscribe(listener: () => void): () => void {\n listeners.add(listener);\n if (timer === null) {\n now = Date.now();\n timer = setInterval(() => {\n now = Date.now();\n for (const l of [...listeners]) l();\n }, 1000);\n }\n return () => {\n listeners.delete(listener);\n if (listeners.size === 0 && timer !== null) {\n clearInterval(timer);\n timer = null;\n }\n };\n}\n\nfunction snapshot(): number {\n return now;\n}\n\nconst idle = () => () => {};\n// A constant: useSyncExternalStore requires a stable snapshot between\n// renders, and `Date.now` as a snapshot would loop.\nconst idleSnapshot = () => 0;\n\n/**\n * The shared clock (ms). While `active` is false the component does not\n * subscribe at all — a settled row costs nothing — and reads the wall clock\n * once per render instead.\n */\nexport function useSecondClock(active = true): number {\n const tick = useSyncExternalStore(active ? subscribe : idle, active ? snapshot : idleSnapshot, active ? snapshot : idleSnapshot);\n // A freshly mounted subscriber must not show the clock as it stood when the\n // previous beat fired (up to a second stale): take the later of the two.\n return Math.max(tick, Date.now());\n}\n\n/** Parse an ISO stamp or client-clock ms into ms; null when unusable. */\nexport function startMs(since: string | number | null | undefined): number | null {\n if (typeof since === 'number') return Number.isFinite(since) ? since : null;\n if (typeof since !== 'string') return null;\n const ms = Date.parse(since);\n return Number.isFinite(ms) ? ms : null;\n}\n\nexport interface LiveTimerProps {\n /** ISO start stamp or client-clock ms. Unparseable → renders nothing (an unknown start is not \"0s\"). */\n since: string | number | null | undefined;\n className?: string;\n /** Spoken label prefix, e.g. \"running for\". Omit to hide the timer from assistive tech (it ticks every second). */\n label?: string;\n}\n\nexport function LiveTimer({ since, className, label }: LiveTimerProps) {\n const start = startMs(since);\n const clock = useSecondClock(start !== null);\n if (start === null) return null;\n const text = formatLiveElapsed(Math.max(0, clock - start));\n return (\n <span className={className} data-live-timer=\"\" aria-hidden={label ? undefined : true}\n aria-label={label ? `${label} ${text}` : undefined} role={label ? 'timer' : undefined}>\n {text}\n </span>\n );\n}\n","/**\n * routes/verse/dock/dock-icons.tsx — the chat surface's own 16px glyphs\n * (unit C2): the dock's pane tabs and the header's pane toggles, the ⋯\n * menu, pin and archive. Same drawing grammar as components/primitives/icons\n * (16-unit box, 1.5 stroke, round caps, currentColor) so they sit beside the\n * shared set without looking borrowed; kept here because verse-icons.tsx is\n * the shell's file.\n */\nimport type { ReactNode, SVGProps } from 'react';\nimport type { DockPaneId } from '../shell/dock-catalog.js';\n\nexport interface GlyphProps extends Omit<SVGProps<SVGSVGElement>, 'children' | 'viewBox'> {\n size?: number;\n}\n\nfunction Glyph({ size = 16, children, ...rest }: GlyphProps & { children: ReactNode }) {\n return (\n <svg width={size} height={size} viewBox=\"0 0 16 16\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.5}\n strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden=\"true\" focusable=\"false\" {...rest}>\n {children}\n </svg>\n );\n}\n\nexport function TerminalGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"1.75\" y=\"2.75\" width=\"12.5\" height=\"10.5\" rx=\"1.5\" /><path d=\"m4.5 6.25 2 1.75-2 1.75M8.25 10h3\" /></Glyph>;\n}\n\nexport function PreviewGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"1.75\" y=\"2.75\" width=\"12.5\" height=\"10.5\" rx=\"1.5\" /><path d=\"M1.75 5.75h12.5M4 4.25h.01M5.75 4.25h.01\" /></Glyph>;\n}\n\nexport function ReviewGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M5 2.5v5M2.5 5h5M9 11h4.5\" /><path d=\"M11.5 2.5 4.5 13.5\" /></Glyph>;\n}\n\nexport function TasksGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M6.5 4h7M6.5 8h7M6.5 12h7\" /><path d=\"m2.25 4 1 1 1.5-2M2.5 8h1.75M2.5 12h1.75\" /></Glyph>;\n}\n\nexport function ContextGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"m8 2 6 3-6 3-6-3 6-3Z\" /><path d=\"m2 8 6 3 6-3M2 11l6 3 6-3\" /></Glyph>;\n}\n\nexport function SplitGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"2.25\" y=\"2.25\" width=\"11.5\" height=\"11.5\" rx=\"1.5\" /><path d=\"M2.25 8h11.5\" /></Glyph>;\n}\n\nexport function CloseGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"m4 4 8 8M12 4l-8 8\" /></Glyph>;\n}\n\nexport function MoreGlyph(p: GlyphProps) {\n return (\n <Glyph {...p}>\n <circle cx=\"3.5\" cy=\"8\" r=\"0.9\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"8\" cy=\"8\" r=\"0.9\" fill=\"currentColor\" stroke=\"none\" />\n <circle cx=\"12.5\" cy=\"8\" r=\"0.9\" fill=\"currentColor\" stroke=\"none\" />\n </Glyph>\n );\n}\n\nexport function PinGlyph(p: GlyphProps) {\n return <Glyph {...p}><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\" /><path d=\"m5 11-2.75 2.75\" /></Glyph>;\n}\n\nexport function ArchiveGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"1.75\" y=\"2.75\" width=\"12.5\" height=\"3\" rx=\"1\" /><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\" /></Glyph>;\n}\n\nexport function RenameGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M10.5 2.75 13.25 5.5 6 12.75H3.25V10Z\" /></Glyph>;\n}\n\nexport function HandoffGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M2.5 8h9M8.5 4.5 12 8l-3.5 3.5\" /><path d=\"M13.75 3v10\" /></Glyph>;\n}\n\nexport function CopyGlyph(p: GlyphProps) {\n return <Glyph {...p}><rect x=\"5.25\" y=\"5.25\" width=\"8.5\" height=\"8.5\" rx=\"1.5\" /><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\" /></Glyph>;\n}\n\nexport function TrashGlyph(p: GlyphProps) {\n return <Glyph {...p}><path d=\"M2.75 4.25h10.5M6.25 4.25V2.75h3.5v1.5M4.25 4.25l.6 9h6.3l.6-9\" /></Glyph>;\n}\n\nexport const DOCK_PANE_GLYPH: Readonly<Record<DockPaneId, (p: GlyphProps) => ReactNode>> = {\n terminal: TerminalGlyph,\n preview: PreviewGlyph,\n diff: ReviewGlyph,\n tasks: TasksGlyph,\n context: ContextGlyph,\n};\n"],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import{_ as e,c as t}from"./format-Dk4Fmxax.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:`Serving runtime unavailable — concurrency unknown.`,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:`Fleet status unavailable.`,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.`,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){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{k as a,y as c,w as d,C as f,M as i,S as l,j as n,A as o,E as p,D as r,N as s,T as t,_ as u};
2
+ //# sourceMappingURL=fleet-model-Dfd5JyLR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet-model-Dfd5JyLR.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 'Serving runtime unavailable — concurrency unknown.',\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 // A missing reading — never shown as an empty fleet.\n detail: 'Fleet status unavailable.',\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.',\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/** 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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"}
@@ -0,0 +1,2 @@
1
+ import{a as e,c as t}from"./index-QesfXBsb.js";import{E as n,H as r,P as i,c as a,l as o,m as s,o as c}from"./global-CNNGMril.js";import{n as l,t as u}from"./control-queries-DAvlh_YM.js";import{c as d,l as f,u as p}from"./fleet-model-Dfd5JyLR.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 doesn't have ${e}.`:`${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:`Unrecognized response — update Ashlr.`}:{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`,p)},x={key:g,fetch:y(`/api/verse/fleet`,d)},S={key:_,fetch:y(`/api/verse/local-only`,f)};async function C(e,t){let r=n();if(!r)throw new l;let a=await o(e,t,r);return i(),a}async function w(e){let t=await C(`/api/verse/runtime`,{action:e});return r(h),r(g),r(u),t}async function T(e){let t=await C(`/api/verse/local-only`,{enabled:e});return r(_),r(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-RtMTd5rR.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fleet-queries-RtMTd5rR.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 // A missing route — never read as an idle machine.\n return `This server doesn't have ${path}.`;\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 // Nothing is shown rather than guessed from an unknown shape.\n reason: 'Unrecognized response — update Ashlr.',\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":"sQA0Ca,EAAoB,gBACpB,EAAkB,cAClB,EAAuB,mBAEpC,SAAS,EAAgB,EAAc,EAAsB,CAQ3D,OAPI,aAAe,EACb,EAAI,SAAW,IAEV,4BAA4B,EAAK,GAEnC,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,EASzB,OARI,IAAU,KACL,CACL,MAAO,KACP,UAAW,GAEX,OAAQ,uCACV,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 +1,2 @@
1
- import{a as e,s as t}from"./index-BVxOlseC.js";var n=t(e(),1),r=[`a[href]`,`button:not([disabled])`,`input:not([disabled])`,`select:not([disabled])`,`textarea:not([disabled])`,`[tabindex]:not([tabindex="-1"])`].join(`,`);function i(e){return Array.from(e.querySelectorAll(r)).filter(e=>e.offsetParent!==null)}function a({open:e,containerRef:t,onClose:r,initialFocusRef:a}){(0,n.useEffect)(()=>{if(!e)return;let n=document.activeElement;return(a?.current??t.current)?.focus({preventScroll:!0}),()=>{n?.focus?.({preventScroll:!0})}},[e]),(0,n.useEffect)(()=>{if(!e)return;function n(e){if(e.key===`Escape`){e.stopPropagation(),r();return}if(e.key!==`Tab`)return;let n=t.current;if(!n)return;let a=i(n);if(a.length===0)return;let o=a[0],s=a[a.length-1];e.shiftKey&&document.activeElement===o?(e.preventDefault(),s.focus()):!e.shiftKey&&document.activeElement===s&&(e.preventDefault(),o.focus())}return document.addEventListener(`keydown`,n,!0),()=>document.removeEventListener(`keydown`,n,!0)},[e,r])}export{a as t};
2
- //# sourceMappingURL=focus-trap-HtcoXeEq.js.map
1
+ import{a as e,c as t}from"./index-QesfXBsb.js";var n=t(e(),1),r=[`a[href]`,`button:not([disabled])`,`input:not([disabled])`,`select:not([disabled])`,`textarea:not([disabled])`,`[tabindex]:not([tabindex="-1"])`].join(`,`);function i(e){return Array.from(e.querySelectorAll(r)).filter(e=>e.offsetParent!==null)}function a({open:e,containerRef:t,onClose:r,initialFocusRef:a}){(0,n.useEffect)(()=>{if(!e)return;let n=document.activeElement;return(a?.current??t.current)?.focus({preventScroll:!0}),()=>{n?.focus?.({preventScroll:!0})}},[e]),(0,n.useEffect)(()=>{if(!e)return;function n(e){if(e.key===`Escape`){e.stopPropagation(),r();return}if(e.key!==`Tab`)return;let n=t.current;if(!n)return;let a=i(n);if(a.length===0)return;let o=a[0],s=a[a.length-1];e.shiftKey&&document.activeElement===o?(e.preventDefault(),s.focus()):!e.shiftKey&&document.activeElement===s&&(e.preventDefault(),o.focus())}return document.addEventListener(`keydown`,n,!0),()=>document.removeEventListener(`keydown`,n,!0)},[e,r])}export{a as t};
2
+ //# sourceMappingURL=focus-trap-BdrbWfC4.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"focus-trap-HtcoXeEq.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/focus-trap.ts"],"sourcesContent":["/**\n * components/primitives/focus-trap.ts — the modal focus contract, extracted\n * from Dialog.tsx so Sheet.tsx (the slide-over overlay) gets exactly the same\n * behavior instead of a second, subtly different implementation:\n *\n * - focus moves into the overlay (or `initialFocusRef`) on open\n * - focus is trapped inside while open (Tab/Shift+Tab wrap)\n * - focus returns to the element that opened it on close\n * - Escape closes\n *\n * Dialog.tsx is unchanged in behavior — it now calls this instead of\n * inlining it. Any future overlay MUST use this rather than hand-rolling a\n * trap (DESIGN.md §3, \"primitives own their accessibility\").\n */\nimport { useEffect, type RefObject } from 'react';\n\nexport const FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\n/** Focusable descendants that are actually rendered (offsetParent is null for hidden nodes). */\nexport function focusableWithin(node: HTMLElement): HTMLElement[] {\n return Array.from(node.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter((el) => el.offsetParent !== null);\n}\n\nexport interface FocusTrapOptions {\n open: boolean;\n containerRef: RefObject<HTMLElement | null>;\n onClose: () => void;\n initialFocusRef?: RefObject<HTMLElement | null>;\n}\n\nexport function useFocusTrap({ open, containerRef, onClose, initialFocusRef }: FocusTrapOptions): void {\n useEffect(() => {\n if (!open) return;\n const previouslyFocused = document.activeElement as HTMLElement | null;\n const target = initialFocusRef?.current ?? containerRef.current;\n target?.focus({ preventScroll: true });\n\n return () => {\n previouslyFocused?.focus?.({ preventScroll: true });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- the refs are refs (stable identity is not the point); only `open` should re-run this.\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n function onKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n e.stopPropagation();\n onClose();\n return;\n }\n if (e.key !== 'Tab') return;\n const node = containerRef.current;\n if (!node) return;\n const focusable = focusableWithin(node);\n if (focusable.length === 0) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n document.addEventListener('keydown', onKeyDown, true);\n return () => document.removeEventListener('keydown', onKeyDown, true);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- containerRef is a ref; re-binding on every render would drop in-flight key handling.\n }, [open, onClose]);\n}\n"],"mappings":"8DAgBa,EAAqB,CAChC,UACA,yBACA,wBACA,yBACA,2BACA,iCACF,CAAC,CAAC,KAAK,GAAG,EAGV,SAAgB,EAAgB,EAAkC,CAChE,OAAO,MAAM,KAAK,EAAK,iBAA8B,CAAkB,CAAC,CAAC,CAAC,OAAQ,GAAO,EAAG,eAAiB,IAAI,CACnH,CASA,SAAgB,EAAa,CAAE,OAAM,eAAc,UAAS,mBAA2C,EACrG,EAAA,EAAA,UAAA,KAAgB,CACd,GAAI,CAAC,EAAM,OACX,IAAM,EAAoB,SAAS,cAInC,OAHe,GAAiB,SAAW,EAAa,QAAA,EAChD,MAAM,CAAE,cAAe,EAAK,CAAC,MAExB,CACX,GAAmB,QAAQ,CAAE,cAAe,EAAK,CAAC,CACpD,CAEF,EAAG,CAAC,CAAI,CAAC,GAET,EAAA,EAAA,UAAA,KAAgB,CACd,GAAI,CAAC,EAAM,OACX,SAAS,EAAU,EAAkB,CACnC,GAAI,EAAE,MAAQ,SAAU,CACtB,EAAE,gBAAgB,EAClB,EAAQ,EACR,MACF,CACA,GAAI,EAAE,MAAQ,MAAO,OACrB,IAAM,EAAO,EAAa,QAC1B,GAAI,CAAC,EAAM,OACX,IAAM,EAAY,EAAgB,CAAI,EACtC,GAAI,EAAU,SAAW,EAAG,OAC5B,IAAM,EAAQ,EAAU,GAClB,EAAO,EAAU,EAAU,OAAS,GACtC,EAAE,UAAY,SAAS,gBAAkB,GAC3C,EAAE,eAAe,EACjB,EAAK,MAAM,GACF,CAAC,EAAE,UAAY,SAAS,gBAAkB,IACnD,EAAE,eAAe,EACjB,EAAM,MAAM,EAEhB,CAEA,OADA,SAAS,iBAAiB,UAAW,EAAW,EAAI,MACvC,SAAS,oBAAoB,UAAW,EAAW,EAAI,CAEtE,EAAG,CAAC,EAAM,CAAO,CAAC,CACpB"}
1
+ {"version":3,"file":"focus-trap-BdrbWfC4.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/focus-trap.ts"],"sourcesContent":["/**\n * components/primitives/focus-trap.ts — the modal focus contract, extracted\n * from Dialog.tsx so Sheet.tsx (the slide-over overlay) gets exactly the same\n * behavior instead of a second, subtly different implementation:\n *\n * - focus moves into the overlay (or `initialFocusRef`) on open\n * - focus is trapped inside while open (Tab/Shift+Tab wrap)\n * - focus returns to the element that opened it on close\n * - Escape closes\n *\n * Dialog.tsx is unchanged in behavior — it now calls this instead of\n * inlining it. Any future overlay MUST use this rather than hand-rolling a\n * trap (DESIGN.md §3, \"primitives own their accessibility\").\n */\nimport { useEffect, type RefObject } from 'react';\n\nexport const FOCUSABLE_SELECTOR = [\n 'a[href]',\n 'button:not([disabled])',\n 'input:not([disabled])',\n 'select:not([disabled])',\n 'textarea:not([disabled])',\n '[tabindex]:not([tabindex=\"-1\"])',\n].join(',');\n\n/** Focusable descendants that are actually rendered (offsetParent is null for hidden nodes). */\nexport function focusableWithin(node: HTMLElement): HTMLElement[] {\n return Array.from(node.querySelectorAll<HTMLElement>(FOCUSABLE_SELECTOR)).filter((el) => el.offsetParent !== null);\n}\n\nexport interface FocusTrapOptions {\n open: boolean;\n containerRef: RefObject<HTMLElement | null>;\n onClose: () => void;\n initialFocusRef?: RefObject<HTMLElement | null>;\n}\n\nexport function useFocusTrap({ open, containerRef, onClose, initialFocusRef }: FocusTrapOptions): void {\n useEffect(() => {\n if (!open) return;\n const previouslyFocused = document.activeElement as HTMLElement | null;\n const target = initialFocusRef?.current ?? containerRef.current;\n target?.focus({ preventScroll: true });\n\n return () => {\n previouslyFocused?.focus?.({ preventScroll: true });\n };\n // eslint-disable-next-line react-hooks/exhaustive-deps -- the refs are refs (stable identity is not the point); only `open` should re-run this.\n }, [open]);\n\n useEffect(() => {\n if (!open) return;\n function onKeyDown(e: KeyboardEvent) {\n if (e.key === 'Escape') {\n e.stopPropagation();\n onClose();\n return;\n }\n if (e.key !== 'Tab') return;\n const node = containerRef.current;\n if (!node) return;\n const focusable = focusableWithin(node);\n if (focusable.length === 0) return;\n const first = focusable[0]!;\n const last = focusable[focusable.length - 1]!;\n if (e.shiftKey && document.activeElement === first) {\n e.preventDefault();\n last.focus();\n } else if (!e.shiftKey && document.activeElement === last) {\n e.preventDefault();\n first.focus();\n }\n }\n document.addEventListener('keydown', onKeyDown, true);\n return () => document.removeEventListener('keydown', onKeyDown, true);\n // eslint-disable-next-line react-hooks/exhaustive-deps -- containerRef is a ref; re-binding on every render would drop in-flight key handling.\n }, [open, onClose]);\n}\n"],"mappings":"8DAgBa,EAAqB,CAChC,UACA,yBACA,wBACA,yBACA,2BACA,iCACF,CAAC,CAAC,KAAK,GAAG,EAGV,SAAgB,EAAgB,EAAkC,CAChE,OAAO,MAAM,KAAK,EAAK,iBAA8B,CAAkB,CAAC,CAAC,CAAC,OAAQ,GAAO,EAAG,eAAiB,IAAI,CACnH,CASA,SAAgB,EAAa,CAAE,OAAM,eAAc,UAAS,mBAA2C,EACrG,EAAA,EAAA,UAAA,KAAgB,CACd,GAAI,CAAC,EAAM,OACX,IAAM,EAAoB,SAAS,cAInC,OAHe,GAAiB,SAAW,EAAa,QAAA,EAChD,MAAM,CAAE,cAAe,EAAK,CAAC,MAExB,CACX,GAAmB,QAAQ,CAAE,cAAe,EAAK,CAAC,CACpD,CAEF,EAAG,CAAC,CAAI,CAAC,GAET,EAAA,EAAA,UAAA,KAAgB,CACd,GAAI,CAAC,EAAM,OACX,SAAS,EAAU,EAAkB,CACnC,GAAI,EAAE,MAAQ,SAAU,CACtB,EAAE,gBAAgB,EAClB,EAAQ,EACR,MACF,CACA,GAAI,EAAE,MAAQ,MAAO,OACrB,IAAM,EAAO,EAAa,QAC1B,GAAI,CAAC,EAAM,OACX,IAAM,EAAY,EAAgB,CAAI,EACtC,GAAI,EAAU,SAAW,EAAG,OAC5B,IAAM,EAAQ,EAAU,GAClB,EAAO,EAAU,EAAU,OAAS,GACtC,EAAE,UAAY,SAAS,gBAAkB,GAC3C,EAAE,eAAe,EACjB,EAAK,MAAM,GACF,CAAC,EAAE,UAAY,SAAS,gBAAkB,IACnD,EAAE,eAAe,EACjB,EAAM,MAAM,EAEhB,CAEA,OADA,SAAS,iBAAiB,UAAW,EAAW,EAAI,MACvC,SAAS,oBAAoB,UAAW,EAAW,EAAI,CAEtE,EAAG,CAAC,EAAM,CAAO,CAAC,CACpB"}
@@ -0,0 +1,2 @@
1
+ import{n as e,r as t}from"./format-DKrNjdwD.js";import{D as n}from"./VerseConsoleApp-BCY5uSok.js";import{_ as r,f as i}from"./verse-model-MMySehjj.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){let t=e.trim().replace(/[\s;,:]+$/,``);return t?/[.!?…]$/.test(t)?t:`${t}.`:``}function C(e){return i(e)?r(e):e}function w(e){return typeof e!=`number`||!Number.isFinite(e)?`—`:`$${e.toFixed(2)}`}function T(e){return typeof e!=`number`||!Number.isFinite(e)?`—`:String(e)}function E(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 D(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 O(e){let t=D(e);return t===`—`?`—`:`${t} ago`}function k(e=new Date){return`${e.getFullYear()}-${String(e.getMonth()+1).padStart(2,`0`)}-${String(e.getDate()).padStart(2,`0`)}`}function A(e,t=new Date){return e===k(t)||e===t.toISOString().slice(0,10)}function j(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 k(r)===k(t)?i:`${r.toLocaleDateString(void 0,{month:`short`,day:`numeric`})} ${i}`}function M(e){return typeof e!=`number`||!Number.isFinite(e)||e<=0?`—`:`every ${E(e).replace(/ 00[ms]$/,``)}`}var N=70;function P(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`&&!A(r,i);if(o===0)return{state:`stopped`,percent:100,label:`${w(a)} spent today · budget $0.00`,note:`Daily budget is $0 — the loop is stopped.`};if(s)return{state:`unknown`,percent:null,label:`— spent today · budget ${w(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?`${w(a)} spent today · budget —`:`— spent today · budget ${w(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>=N?`warn`:`ok`;return{state:u,percent:l,label:`${w(a)} of ${w(o)} today · ${h(a/o*100)}`,note:u===`over`?`Daily budget reached — the loop idles until the date rolls over.`:u===`warn`?`${w(o-a)} left before the loop idles today.`:`${w(o-a)} left today.`}}function F(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 I(e,t){if(e===null)return`—`;let n=e-t;return n>1e3?`in ${E(n)}`:n>-1e3?`due now`:`overdue by ${E(-n)}`}function L(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{c as S,h as _,L as a,o as b,E as c,j as d,w as f,F as g,k as h,I as i,M as l,A as m,S as n,D as o,m as p,P as r,T as s,x as t,O as u,C as v,p as x,b as y};
2
+ //# sourceMappingURL=format-Dk4Fmxax.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"format-Dk4Fmxax.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 * One sentence: trimmed and closed by exactly one full stop — added only when\n * the text does not already end in `.`, `!`, `?` or `…` (a trailing \";\", \",\"\n * or \":\" is dropped first). The fix for \"local Qwen offline..\" when a server\n * reason already carries its own stop. Never re-cased — a sentence may open on\n * a seat id.\n */\nexport function asSentence(text: string): string {\n const t = text.trim().replace(/[\\s;,:]+$/, '');\n if (!t) return '';\n return /[.!?…]$/.test(t) ? t : `${t}.`;\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.',\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":"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"}
@@ -1,5 +1,5 @@
1
- import{D as e,F as t,M as n,O as r,l as i,o as a}from"./global-oEl9Qj8u.js";import{r as o}from"./VerseConsoleApp-DTjDpGCd.js";var s=`/api/verse/git`,c=new Set([`VERSE_GIT_NOT_A_REPO`,`VERSE_GIT_REFUSED`]);async function l(e,t){let i=await fetch(e,{method:`GET`,credentials:`same-origin`,headers:{"x-ashlr-read-client":r()},signal:t});if(i.status===401)throw n(),new a(`Read session expired.`,401,e);if(!i.ok){let t=null,n=null;try{let e=await i.json();t=typeof e.error==`string`&&e.error?e.error:null,n=typeof e.code==`string`&&e.code?e.code:null}catch{}throw new a(`GET ${e} failed (HTTP ${i.status}).`,i.status,e,t,n)}return await i.json()}function u(e,t){return l(`${s}/status?root=${encodeURIComponent(e)}`,t)}function d(e,t,n,r){let i=new URLSearchParams({root:e,scope:t});return n!==null&&i.set(`file`,n),l(`${s}/diff?${i.toString()}`,r)}async function f(n,r){let a=e();if(!a)throw new o;let s=await i(n,r,a);return t(),s}function p(e){return f(`${s}/commit`,e)}function m(e){return f(`${s}/push`,{root:e})}function h(e){return f(`${s}/pr`,e)}function g(e){return f(`${s}/pr/merge`,e)}function _(e,t){return f(`${s}/worktree`,{root:e,name:t})}function v(e){return e instanceof a&&e.code!==null&&c.has(e.code)}var y=new Intl.NumberFormat(`en-US`);function b(e){return y.format(Math.max(0,Math.round(e)))}function x(e,t){return`+${b(e)} −${b(t)}`}function S(e,t,n){return`${b(e)} ${e===1?`file`:`files`} changed, ${b(t)} added, ${b(n)} removed`}function C(e){return!!(e.dirty>0||e.ahead>0||e.diffstat.files>0||e.pr&&(e.pr.state===`open`||e.pr.state===`draft`))}function w(e){let t=new Set,n=[];for(let r of e){let e=r.gitRoot??r.root;t.has(e)||(t.add(e),n.push(r))}return n}function T(e){let t=e.branch??`HEAD`,n=e.base??`the default branch`;switch(e.suggested){case`commit`:return{action:`commit`,label:`Commit`,disclosure:`Commit ${b(e.dirty)} changed ${e.dirty===1?`file`:`files`} on ${t}.`};case`push`:return{action:`push`,label:`Push`,disclosure:e.upstream?`Push ${b(e.ahead)} ${e.ahead===1?`commit`:`commits`} on ${t} to ${e.upstream}.`:`Publish ${t} to origin.`};case`create-pr`:return{action:`create-pr`,label:`Create PR`,disclosure:`Open a pull request from ${t} into ${n}${e.upstream===null||e.ahead>0?`, pushing it first`:``}.`};case`merge`:return e.pr?{action:`merge`,label:`Merge`,disclosure:`Squash-merge #${e.pr.number} into ${e.pr.baseRef||n}. Checks passed.`}:null;case`view-pr`:return e.pr?{action:`view-pr`,label:`View PR`,disclosure:`Open #${e.pr.number} on GitHub.`}:null;default:return null}}function E(e){let t=e.branch===null,n=e.branch!==null&&e.base!==null&&e.branch===e.base,r=(e.conflicts??0)>0,i=e.pr!==null&&(e.pr.state===`open`||e.pr.state===`draft`);return[{id:`draft-pr`,label:`Create draft PR…`,disabledReason:t?`HEAD is detached`:n?`You are on ${e.base}`:i?`#${e.pr.number} is already open`:e.prLookup===`unavailable`?"GitHub is not reachable (is `gh` signed in?)":null},{id:`commit`,label:`Commit…`,disabledReason:t?`HEAD is detached`:r?`Resolve the conflicts first`:e.dirty===0?`Nothing to commit`:null},{id:`push`,label:e.upstream?`Push`:`Publish branch`,disabledReason:t?`HEAD is detached`:e.upstream!==null&&e.ahead===0?`Already pushed`:e.headSha===null?`No commits yet`:null},{id:`open-github`,label:`Open on GitHub`,disabledReason:e.pr?null:`No pull request for this branch`},{id:`copy-branch`,label:`Copy branch name`,disabledReason:t?`HEAD is detached`:null},{id:`review`,label:`Review changes`,disabledReason:e.diffstat.files===0&&e.dirty===0?`No changes`:null}]}function D(e,t){let n=e.state===`open`?`Open`:e.state===`draft`?`Draft`:e.state===`merged`?`Merged`:`Closed`,r=null,i=`neutral`;if(e.state===`merged`)i=`merged`;else if(e.state===`closed`)i=`neutral`;else{switch(e.checks){case`passing`:r=t&&t.total>0?`${t.passed}/${t.total} checks passed`:`checks passed`,i=e.mergeable===!1?`danger`:`success`;break;case`failing`:r=t?`${t.failed} of ${t.total} checks failing`:`checks failing`,i=`danger`;break;case`pending`:r=t?`${t.pending} of ${t.total} checks running`:`checks running`,i=`running`;break;case`none`:r=`no checks`;break;default:r=`checks —`}e.mergeable===!1&&(r=r?`${r}, conflicts`:`conflicts`)}let a=[`Pull request #${e.number}`,e.title,n,r].filter(Boolean).join(`, `);return{number:`#${e.number}`,title:e.title,state:n,checks:r,tone:i,label:a}}function O(e){let t=e.headSubject?.trim();if(t)return t;let n=((e.branch??``).split(`/`).pop()??``).replace(/[-_]+/g,` `).trim();return n?n[0].toUpperCase()+n.slice(1):``}function k(e){let t=e.pr;return t?{number:t.number,title:t.title,headSha:t.headSha,headRef:t.headRef||e.branch||``,baseRef:t.baseRef||e.base||``,checks:t.checks,mergeable:t.mergeable,counts:e.prCheckCounts??null}:null}function A(e){let t=e.headSha?e.headSha.slice(0,7):`—`,n=e.counts,r;switch(e.checks){case`passing`:r=n&&n.total>0?`${n.passed}/${n.total} checks passed`:`checks passed`;break;case`failing`:r=n&&n.total>0?`${n.failed} of ${n.total} checks failing`:`checks failing`;break;case`pending`:r=n&&n.total>0?`${n.pending} of ${n.total} checks still running`:`checks still running`;break;case`none`:r=`no checks reported`;break;default:r=`checks not known`}let i=e.mergeable===!0?`no conflicts`:e.mergeable===!1?`has conflicts`:`GitHub has not finished checking for conflicts`,a=`${r}, ${i}.`;return{sha:t,detail:a,text:`Head ${t}, ${a}`,verified:e.checks===`passing`&&e.mergeable===!0&&e.headSha!==null}}function j(e,t){let n=t?.pr??null;return!n||n.number!==e.number||n.state!==`open`?`#${e.number} is no longer an open, ready pull request — close this and check the branch bar.`:n.headSha===e.headSha?n.checks===`passing`?n.mergeable===!0?null:`GitHub no longer reports this head as mergeable — close and reopen to review.`:`Checks on this head are no longer passing — close and reopen once they are.`:`The PR changed since you opened this — new commits landed. Close and reopen to review the new head.`}function M(e){let t=new Map,n=[...e].sort((e,t)=>e.path<t.path?-1:+(e.path>t.path));for(let e of n){let n=e.path.lastIndexOf(`/`),r=n===-1?``:e.path.slice(0,n),i=n===-1?e.path:e.path.slice(n+1),a=t.get(r);a||(a={dir:r,files:[]},t.set(r,a)),a.files.push({...e,name:i})}return[...t.values()]}var N={M:`modified`,A:`added`,D:`deleted`,R:`renamed`,U:`conflicted`};function P(e){return[...e].sort((e,t)=>e.path===t.path?e.line-t.line:e.path<t.path?-1:1).map(e=>{let[t,...n]=e.note.trim().split(`
1
+ import{D as e,E as t,P as n,j as r,l as i,o as a}from"./global-CNNGMril.js";import{i as o}from"./VerseConsoleApp-BCY5uSok.js";var s=`/api/verse/git`,c=new Set([`VERSE_GIT_NOT_A_REPO`,`VERSE_GIT_REFUSED`]);async function l(t,n){let i=await fetch(t,{method:`GET`,credentials:`same-origin`,headers:{"x-ashlr-read-client":e()},signal:n});if(i.status===401)throw r(),new a(`Read session expired.`,401,t);if(!i.ok){let e=null,n=null;try{let t=await i.json();e=typeof t.error==`string`&&t.error?t.error:null,n=typeof t.code==`string`&&t.code?t.code:null}catch{}throw new a(`GET ${t} failed (HTTP ${i.status}).`,i.status,t,e,n)}return await i.json()}function u(e,t){return l(`${s}/status?root=${encodeURIComponent(e)}`,t)}function d(e,t,n,r){let i=new URLSearchParams({root:e,scope:t});return n!==null&&i.set(`file`,n),l(`${s}/diff?${i.toString()}`,r)}async function f(e,r){let a=t();if(!a)throw new o;let s=await i(e,r,a);return n(),s}function p(e){return f(`${s}/commit`,e)}function m(e){return f(`${s}/push`,{root:e})}function h(e){return f(`${s}/pr`,e)}function g(e){return f(`${s}/pr/merge`,e)}function _(e,t){return f(`${s}/worktree`,{root:e,name:t})}function v(e){return e instanceof a&&e.code!==null&&c.has(e.code)}var y=new Intl.NumberFormat(`en-US`);function b(e){return y.format(Math.max(0,Math.round(e)))}function x(e,t){return`+${b(e)} −${b(t)}`}function S(e,t,n){return`${b(e)} ${e===1?`file`:`files`} changed, ${b(t)} added, ${b(n)} removed`}function C(e){return!!(e.dirty>0||e.ahead>0||e.diffstat.files>0||e.pr&&(e.pr.state===`open`||e.pr.state===`draft`))}function w(e){let t=new Set,n=[];for(let r of e){let e=r.gitRoot??r.root;t.has(e)||(t.add(e),n.push(r))}return n}function T(e){let t=e.branch??`HEAD`,n=e.base??`the default branch`;switch(e.suggested){case`commit`:return{action:`commit`,label:`Commit`,disclosure:`Commit ${b(e.dirty)} changed ${e.dirty===1?`file`:`files`} on ${t}.`};case`push`:return{action:`push`,label:`Push`,disclosure:e.upstream?`Push ${b(e.ahead)} ${e.ahead===1?`commit`:`commits`} on ${t} to ${e.upstream}.`:`Publish ${t} to origin.`};case`create-pr`:return{action:`create-pr`,label:`Create PR`,disclosure:`Open a pull request from ${t} into ${n}${e.upstream===null||e.ahead>0?`, pushing it first`:``}.`};case`merge`:return e.pr?{action:`merge`,label:`Merge`,disclosure:`Squash-merge #${e.pr.number} into ${e.pr.baseRef||n}. Checks passed.`}:null;case`view-pr`:return e.pr?{action:`view-pr`,label:`View PR`,disclosure:`Open #${e.pr.number} on GitHub.`}:null;default:return null}}function E(e){let t=e.branch===null,n=e.branch!==null&&e.base!==null&&e.branch===e.base,r=(e.conflicts??0)>0,i=e.pr!==null&&(e.pr.state===`open`||e.pr.state===`draft`);return[{id:`draft-pr`,label:`Create draft PR…`,disabledReason:t?`HEAD is detached`:n?`You are on ${e.base}`:i?`#${e.pr.number} is already open`:e.prLookup===`unavailable`?"GitHub is not reachable (is `gh` signed in?)":null},{id:`commit`,label:`Commit…`,disabledReason:t?`HEAD is detached`:r?`Resolve the conflicts first`:e.dirty===0?`Nothing to commit`:null},{id:`push`,label:e.upstream?`Push`:`Publish branch`,disabledReason:t?`HEAD is detached`:e.upstream!==null&&e.ahead===0?`Already pushed`:e.headSha===null?`No commits yet`:null},{id:`open-github`,label:`Open on GitHub`,disabledReason:e.pr?null:`No pull request for this branch`},{id:`copy-branch`,label:`Copy branch name`,disabledReason:t?`HEAD is detached`:null},{id:`review`,label:`Review changes`,disabledReason:e.diffstat.files===0&&e.dirty===0?`No changes`:null}]}function D(e,t){let n=e.state===`open`?`Open`:e.state===`draft`?`Draft`:e.state===`merged`?`Merged`:`Closed`,r=null,i=`neutral`;if(e.state===`merged`)i=`merged`;else if(e.state===`closed`)i=`neutral`;else{switch(e.checks){case`passing`:r=t&&t.total>0?`${t.passed}/${t.total} checks passed`:`checks passed`,i=e.mergeable===!1?`danger`:`success`;break;case`failing`:r=t?`${t.failed} of ${t.total} checks failing`:`checks failing`,i=`danger`;break;case`pending`:r=t?`${t.pending} of ${t.total} checks running`:`checks running`,i=`running`;break;case`none`:r=`no checks`;break;default:r=`checks —`}e.mergeable===!1&&(r=r?`${r}, conflicts`:`conflicts`)}let a=[`Pull request #${e.number}`,e.title,n,r].filter(Boolean).join(`, `);return{number:`#${e.number}`,title:e.title,state:n,checks:r,tone:i,label:a}}function O(e){let t=e.headSubject?.trim();if(t)return t;let n=((e.branch??``).split(`/`).pop()??``).replace(/[-_]+/g,` `).trim();return n?n[0].toUpperCase()+n.slice(1):``}function k(e){let t=e.pr;return t?{number:t.number,title:t.title,headSha:t.headSha,headRef:t.headRef||e.branch||``,baseRef:t.baseRef||e.base||``,checks:t.checks,mergeable:t.mergeable,counts:e.prCheckCounts??null}:null}function A(e){let t=e.headSha?e.headSha.slice(0,7):`—`,n=e.counts,r;switch(e.checks){case`passing`:r=n&&n.total>0?`${n.passed}/${n.total} checks passed`:`checks passed`;break;case`failing`:r=n&&n.total>0?`${n.failed} of ${n.total} checks failing`:`checks failing`;break;case`pending`:r=n&&n.total>0?`${n.pending} of ${n.total} checks still running`:`checks still running`;break;case`none`:r=`no checks reported`;break;default:r=`checks not known`}let i=e.mergeable===!0?`no conflicts`:e.mergeable===!1?`has conflicts`:`GitHub has not finished checking for conflicts`,a=`${r}, ${i}.`;return{sha:t,detail:a,text:`Head ${t}, ${a}`,verified:e.checks===`passing`&&e.mergeable===!0&&e.headSha!==null}}function j(e,t){let n=t?.pr??null;return!n||n.number!==e.number||n.state!==`open`?`#${e.number} is no longer an open, ready pull request — close this and check the branch bar.`:n.headSha===e.headSha?n.checks===`passing`?n.mergeable===!0?null:`GitHub no longer reports this head as mergeable — close and reopen to review.`:`Checks on this head are no longer passing — close and reopen once they are.`:`The PR changed since you opened this — new commits landed. Close and reopen to review the new head.`}function M(e){let t=new Map,n=[...e].sort((e,t)=>e.path<t.path?-1:+(e.path>t.path));for(let e of n){let n=e.path.lastIndexOf(`/`),r=n===-1?``:e.path.slice(0,n),i=n===-1?e.path:e.path.slice(n+1),a=t.get(r);a||(a={dir:r,files:[]},t.set(r,a)),a.files.push({...e,name:i})}return[...t.values()]}var N={M:`modified`,A:`added`,D:`deleted`,R:`renamed`,U:`conflicted`};function P(e){return[...e].sort((e,t)=>e.path===t.path?e.line-t.line:e.path<t.path?-1:1).map(e=>{let[t,...n]=e.note.trim().split(`
2
2
  `);return[`${`${e.path}:${e.line}${e.side===`old`?` (removed line)`:``}`}: ${t??``}`,...n.map(e=>` ${e}`)].join(`
3
3
  `)}).join(`
4
4
  `)}function F(e){if(e&&typeof e==`object`){let t=e;if(t.name===`DispatchDisabledError`)return`This server is read-only (started without dispatch), so git actions are off.`;if(t.name===`VerseMutationLockedError`)return`Unlock actions with the mutation token first.`;if(t.status===401)return"The mutation token was rejected. Unlock again with the token `ashlr verse` printed.";if(t.detail)return t.detail;if(t.status===404)return"This server has no git routes yet. Update Ashlr and restart `ashlr verse`.";if(t.status===409)return`Git is busy in this repository. Try again in a moment.`}return`The git action failed. The terminal will show why.`}export{h as C,g as S,p as _,F as a,u as b,b as c,E as d,j as f,T as g,D as h,O as i,M as l,k as m,P as n,S as o,A as p,w as r,x as s,N as t,C as u,_ as v,m as w,v as x,d as y};
5
- //# sourceMappingURL=git-model-bk_RXh3y.js.map
5
+ //# sourceMappingURL=git-model-_BnI_Ogh.js.map