@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 +0,0 @@
1
- {"version":3,"file":"charts-CfAjuKMv.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/ChartContainer.module.css","../../../../../../src/web-ui/components/charts/ChartContainer.tsx","../../../../../../src/web-ui/components/charts/Legend.module.css","../../../../../../src/web-ui/components/charts/Legend.tsx","../../../../../../src/web-ui/components/charts/LineChart.module.css","../../../../../../src/web-ui/components/charts/LineChart.tsx","../../../../../../src/web-ui/components/charts/BarChart.module.css","../../../../../../src/web-ui/components/charts/BarChart.tsx"],"sourcesContent":[".figure {\n margin: 0;\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-lg);\n background: var(--bg-surface);\n padding: var(--space-4);\n /* Fixed heights must include the axis-label band — this container instead\n grows with its content so a chart's x-axis labels never get clipped or\n forced into a nested scroll (dataviz anti-patterns). */\n}\n\n.caption {\n display: flex;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-3);\n margin-bottom: var(--space-3);\n}\n\n.title {\n font-size: var(--text-sm-size);\n font-weight: var(--font-weight-semibold);\n color: var(--text-primary);\n}\n\n.description {\n font-size: var(--text-xs-size);\n color: var(--text-tertiary);\n}\n\n.plot {\n width: 100%;\n overflow-x: auto;\n}\n\n.tableDisclosure {\n margin-top: var(--space-3);\n border-top: 1px solid var(--border-subtle);\n padding-top: var(--space-2);\n}\n\n.tableDisclosure > summary {\n cursor: pointer;\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n list-style: none;\n}\n\n.tableDisclosure > summary::-webkit-details-marker {\n display: none;\n}\n\n.tableDisclosure > summary::before {\n content: '▸ ';\n}\n\n.tableDisclosure[open] > summary::before {\n content: '▾ ';\n}\n\n.tableBody {\n margin-top: var(--space-2);\n}\n\n.caveat {\n margin: 0 0 var(--space-3);\n padding: var(--space-2) var(--space-3);\n border-radius: var(--radius-md);\n background: var(--status-unknown-bg);\n color: var(--status-unknown-fg);\n font-size: var(--text-xs-size);\n line-height: var(--text-sm-line);\n}\n\n.empty {\n color: var(--text-tertiary);\n font-size: var(--text-sm-size);\n padding: var(--space-6) 0;\n text-align: center;\n}\n","/**\n * components/charts/ChartContainer.tsx — the figure every chart mounts\n * inside: title/description, the plot itself, an optional caveat banner\n * (epistemic-honesty-adjacent: for a chart built on data with a known,\n * disclosed limitation — see ProductionView's judge-verdict caveat), an\n * optional table-view twin (the WCAG-clean accessibility equivalent every\n * chart should ship per the dataviz skill), and an empty state that never\n * lies about missing data.\n */\nimport type { ReactNode } from 'react';\nimport './chart-tokens.css';\nimport styles from './ChartContainer.module.css';\n\nexport interface ChartContainerProps {\n title: string;\n description?: string;\n /** A short, honest note about a known limitation of the data behind this\n * chart (e.g. \"counts may include X, not yet separable\"). Never omit a\n * caveat to make a chart look cleaner than the data actually is. */\n caveat?: string;\n /** The chart itself (SVG + legend). */\n children: ReactNode;\n /** The accessibility twin — same data as a real HTML table. Omit only\n * when the chart already IS a table. */\n table?: ReactNode;\n /** When true, renders the empty state instead of `children`. */\n empty?: boolean;\n emptyMessage?: string;\n}\n\nexport function ChartContainer({\n title,\n description,\n caveat,\n children,\n table,\n empty,\n emptyMessage = 'No data for this window.',\n}: ChartContainerProps) {\n return (\n <figure className={styles.figure}>\n <figcaption className={styles.caption}>\n <span className={styles.title}>{title}</span>\n {description ? <span className={styles.description}>{description}</span> : null}\n </figcaption>\n {caveat ? (\n <p className={styles.caveat} role=\"note\">\n {caveat}\n </p>\n ) : null}\n {empty ? (\n <p className={styles.empty}>{emptyMessage}</p>\n ) : (\n <div className={styles.plot}>{children}</div>\n )}\n {table ? (\n <details className={styles.tableDisclosure}>\n <summary>View as table</summary>\n <div className={styles.tableBody}>{table}</div>\n </details>\n ) : null}\n </figure>\n );\n}\n",".legend {\n display: flex;\n flex-wrap: wrap;\n gap: var(--space-1) var(--space-4);\n margin: var(--space-2) 0 0;\n padding: 0;\n list-style: none;\n}\n\n.item {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n font-size: var(--text-xs-size);\n color: var(--text-secondary);\n}\n\n.swatch {\n width: 10px;\n height: 10px;\n border-radius: var(--radius-full);\n flex: none;\n}\n\n.swatchLine {\n width: 14px;\n height: 2px;\n border-radius: var(--radius-full);\n flex: none;\n}\n","/**\n * components/charts/Legend.tsx — the dependable identity channel. A legend\n * is always present for two or more series (never rely on color-matching\n * alone); a single series needs no legend box because the chart's own title\n * already names it (see marks-and-anatomy.md \"Labels & legend\").\n */\nimport styles from './Legend.module.css';\n\nexport interface LegendItem {\n label: string;\n color: string;\n /** 'line' for line charts (a short stroke key), 'swatch' for bar/area. */\n kind?: 'line' | 'swatch';\n}\n\nexport function Legend({ items }: { items: LegendItem[] }) {\n if (items.length < 2) return null;\n return (\n <ul className={styles.legend}>\n {items.map((it) => (\n <li key={it.label} className={styles.item}>\n <span\n className={it.kind === 'line' ? styles.swatchLine : styles.swatch}\n style={{ background: it.color }}\n aria-hidden=\"true\"\n />\n {it.label}\n </li>\n ))}\n </ul>\n );\n}\n",".svg {\n display: block;\n width: 100%;\n height: auto;\n}\n\n.gridline {\n stroke: var(--chart-grid);\n stroke-width: 1;\n}\n\n.axis {\n stroke: var(--chart-axis);\n stroke-width: 1;\n}\n\n.axisLabel {\n font-size: var(--text-xs-size);\n fill: var(--text-tertiary);\n font-family: var(--font-ui);\n}\n\n.line {\n fill: none;\n stroke-width: 2;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.area {\n opacity: 0.1;\n stroke: none;\n}\n\n.marker {\n stroke: var(--chart-surface);\n stroke-width: 2;\n}\n\n.endLabel {\n font-size: var(--text-xs-size);\n font-family: var(--font-ui);\n font-weight: var(--font-weight-medium);\n}\n\n.crosshairLine {\n stroke: var(--chart-axis);\n stroke-width: 1;\n pointer-events: none;\n}\n\n.overlay {\n fill: transparent;\n cursor: crosshair;\n}\n\n.wrap {\n position: relative;\n}\n\n.tooltip {\n position: absolute;\n pointer-events: none;\n background: var(--chart-tooltip-bg);\n border: 1px solid var(--chart-tooltip-border);\n border-radius: var(--radius-sm);\n box-shadow: var(--shadow-md);\n padding: var(--space-2);\n font-size: var(--text-xs-size);\n color: var(--text-primary);\n white-space: nowrap;\n z-index: var(--z-dropdown);\n transform: translate(-50%, -100%);\n margin-top: -10px;\n}\n\n.tooltipDate {\n color: var(--text-tertiary);\n margin-bottom: var(--space-1);\n}\n\n.tooltipRow {\n display: flex;\n align-items: center;\n gap: var(--space-1);\n}\n\n.tooltipKey {\n width: 12px;\n height: 2px;\n flex: none;\n}\n\n.tooltipValue {\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n}\n\n.tooltipGap {\n color: var(--text-tertiary);\n font-style: italic;\n}\n","/**\n * components/charts/LineChart.tsx — trend over time. A gap (`null` y) is\n * split into a separate path segment so it renders as a visible break in\n * the line, never as a straight line through a missing value and never as\n * a silent zero. Single series gets an optional soft area fill; two-plus\n * series always render a legend (never color-matching alone).\n */\nimport { useRef, useState } from 'react';\nimport type { Series } from './types.js';\nimport { seriesColor, CHART_GRID, CHART_AXIS } from './colors.js';\nimport { Legend } from './Legend.js';\nimport {\n MIN_TIME_SPAN_MS,\n allIntegers,\n axisTicks,\n dodgeLabels,\n ensureSpan,\n isTimeAxis,\n labelCharPx,\n layoutAxisLabels,\n xKeeper,\n} from './chart-math.js';\nimport { timeLabelLadder } from './format.js';\nimport { useTextScale } from './useTextScale.js';\nimport './chart-tokens.css';\nimport styles from './LineChart.module.css';\n\nconst VBOX_W = 640;\n/** Minimum left gutter; it widens when the y tick labels need more (see padL). */\nconst PAD_L = 44;\nconst PAD_R = 12;\nconst PAD_T = 12;\nconst PAD_B = 24;\nconst TICKS_Y = 4;\n/* Direct end-of-line labels need a gutter of their own. They are drawn in USER\n units — the viewBox scales the font along with the geometry, so a reserve\n measured in user units holds at every rendered width — and `--text-xs-size`\n resolves to 12 user units here, where the UI sans averages a shade over 6\n units per character at medium weight. 6.4 rounds that up so the reserve errs\n wide rather than clipping. Without the reserve the label was drawn at\n `VBOX_W - PAD_R + 4` with only PAD_R (12u) of room and the svg's own\n `overflow: hidden` cropped it to its first glyph — \"Estimated spend\"\n rendered as a lone \"E\".\n Every text measure here (END_LABEL_CH, END_LABEL_GAP_Y, the axis label\n advance) is for 12 px text and is multiplied by the operator's Display\n size (useTextScale): --text-xs-size is 12px × --ui-text-scale, so at\n XLarge the same label is 15 units tall and 25% wider. END_LABEL_MAX is a\n budget of plot width, not a text measure, and stays as it is. */\nconst END_LABEL_CH = 6.4;\nconst END_LABEL_GAP = 4;\n/* Past this the gutter would cost more plot than the label is worth, so the\n label is dropped rather than shrinking the chart around it. Nothing is lost:\n Legend.tsx deliberately renders nothing below two series because the panel\n heading already names a lone series, and two-plus series always have the\n legend regardless. */\nconst END_LABEL_MAX = 150;\n/** Line height of a direct end label at 12 px (user units): two closer than this overlap. */\nconst END_LABEL_GAP_Y = 14;\n\ninterface Run {\n x: number;\n y: number;\n}\n\nfunction splitRuns(points: Series['points']): Run[][] {\n const runs: Run[][] = [];\n let current: Run[] = [];\n for (const p of points) {\n if (p.y === null) {\n if (current.length) runs.push(current);\n current = [];\n continue;\n }\n current.push({ x: p.x, y: p.y });\n }\n if (current.length) runs.push(current);\n return runs;\n}\n\nexport function LineChart({\n series: seriesProp,\n height = 200,\n area = false,\n formatX: formatXProp,\n formatY: formatYProp,\n ariaLabel,\n}: {\n series: Series[];\n height?: number;\n area?: boolean;\n formatX?: (x: number) => string;\n formatY?: (y: number) => string;\n ariaLabel: string;\n}) {\n const svgRef = useRef<SVGSVGElement>(null);\n const textScale = useTextScale();\n /* Axis labels' estimated advance per character, at the size they render. */\n const axisLabelCh = labelCharPx(textScale);\n const [hoverX, setHoverX] = useState<number | null>(null);\n const [tooltipPos, setTooltipPos] = useState<{ left: number; top: number } | null>(null);\n\n const formatX = formatXProp ?? ((x: number) => String(x));\n const formatY = formatYProp ?? ((y: number) => String(y));\n /* On a time axis a 0 / NaN / pre-2000 x is a null timestamp that leaked\n through, not a moment: it would start the axis at \"Dec 31\" 1969. Such\n points are left out of the domain AND the drawing. */\n const keepX = xKeeper(seriesProp.flatMap((s) => s.points.map((p) => p.x)));\n const series = seriesProp.map((s) => ({ ...s, points: s.points.filter((p) => keepX(p.x)) }));\n const allX = series.flatMap((s) => s.points.map((p) => p.x));\n const knownY = series.flatMap((s) => s.points.map((p) => p.y)).filter((y): y is number => y !== null && Number.isFinite(y));\n if (allX.length === 0) {\n return <p>No data.</p>;\n }\n const rawXMin = Math.min(...allX);\n const rawXMax = Math.max(...allX);\n const timeAxis = isTimeAxis(allX);\n // A burst of points seconds apart is widened to MIN_TIME_SPAN_MS around\n // itself instead of stretched edge to edge under identical labels.\n const [xMin, xMax] = timeAxis && rawXMax > rawXMin ? ensureSpan(rawXMin, rawXMax, MIN_TIME_SPAN_MS) : [rawXMin, rawXMax];\n const xRange = xMax - xMin || 1;\n\n // Nice ticks whose labels are exact: integer data get integer ticks, and a\n // caller's formatter never prints a rounded label on a precise tick.\n const yAxis = axisTicks(Math.min(0, ...knownY), Math.max(0, ...knownY), {\n count: TICKS_Y,\n integer: knownY.length > 0 && allIntegers(knownY),\n format: formatYProp,\n });\n const yTicks = yAxis.ticks;\n const yMin = yTicks[0]!;\n const yMax = yTicks[yTicks.length - 1]!;\n const yRange = yMax - yMin || 1;\n const plotH = height - PAD_T - PAD_B;\n const yScale = (y: number) => PAD_T + plotH - ((y - yMin) / yRange) * plotH;\n /* The y labels hang right-aligned 6 units left of the plot, and the svg\n clips at its edge: the gutter grows to fit the widest one (+2 of air) —\n 44 still fits five 12 px characters, a larger Display size fewer. */\n const padL = Math.max(PAD_L, Math.ceil(Math.max(0, ...yAxis.labels.map((l) => l.length)) * axisLabelCh) + 8);\n\n /* Decided before the x scale, because the reserved gutter is what plotW is\n measured against — and the gridlines and x-axis stop at the same edge.\n End labels are dodged vertically so two lines ending on one value never\n print their names over each other; if they cannot all fit, the legend\n (always present for 2+ series) names them instead. */\n const wantEndLabels = series.length >= 1 && series.length <= 4;\n const endLabelW = wantEndLabels\n ? Math.max(...series.map((s) => s.label.length)) * END_LABEL_CH * textScale\n : 0;\n const endPoints = series.flatMap((s) => {\n for (let i = s.points.length - 1; i >= 0; i--) {\n const y = s.points[i]!.y;\n if (y !== null && Number.isFinite(y)) return [{ key: s.id, y: yScale(y) }];\n }\n return [];\n });\n const dodged = wantEndLabels && endLabelW <= END_LABEL_MAX ? dodgeLabels(endPoints, END_LABEL_GAP_Y * textScale, PAD_T, PAD_T + plotH) : null;\n const showEndLabels = dodged !== null && endPoints.length > 0;\n const padR = PAD_R + (showEndLabels ? END_LABEL_GAP + endLabelW : 0);\n const showLegend = series.length >= 2;\n\n const plotW = VBOX_W - padL - padR;\n const xScale = (x: number) => padL + ((x - xMin) / xRange) * plotW;\n\n // Nearest-x lookup across a reference axis (the union of all distinct x\n // values, since series may not share every point).\n const xAxis = Array.from(new Set(allX)).sort((a, b) => a - b);\n\n /* First and last x labels, collision-free: the end outranks the start;\n on a time axis both walk one detail ladder (the caller's format → a\n shorter date/time; clock time only inside one day) until they fit. */\n const xEnds = xAxis.length > 1 ? [xAxis[0]!, xAxis[xAxis.length - 1]!] : [];\n const ladder = timeAxis ? timeLabelLadder(rawXMin, rawXMax, formatXProp, xEnds) : [formatX];\n const xLabels = layoutAxisLabels(\n xEnds.map((x, i) => {\n const px = xScale(x);\n const edge = i === 0 ? px <= padL + 0.5 : px >= VBOX_W - padR - 0.5;\n return {\n key: i === 0 ? 'start' : 'end',\n x: px,\n anchor: edge ? (i === 0 ? 'start' as const : 'end' as const) : 'middle' as const,\n priority: i === 0 ? 2 : 3,\n variants: ladder.map((f) => f(x)),\n };\n }),\n { min: padL, max: VBOX_W - padR, charPx: axisLabelCh },\n );\n\n function nearestX(clientX: number): number | null {\n const svg = svgRef.current;\n if (!svg) return null;\n const rect = svg.getBoundingClientRect();\n const svgX = ((clientX - rect.left) / rect.width) * VBOX_W;\n const dataX = xMin + ((svgX - padL) / plotW) * xRange;\n let nearest = xAxis[0];\n let best = Infinity;\n for (const x of xAxis) {\n const d = Math.abs(x - dataX);\n if (d < best) {\n best = d;\n nearest = x;\n }\n }\n return nearest;\n }\n\n function handleMove(e: React.PointerEvent<SVGSVGElement>) {\n const x = nearestX(e.clientX);\n if (x === null) return;\n setHoverX(x);\n const svg = svgRef.current;\n if (svg) {\n const rect = svg.getBoundingClientRect();\n const px = (xScale(x) / VBOX_W) * rect.width;\n setTooltipPos({ left: px, top: 0 });\n }\n }\n\n const hoverPoints =\n hoverX !== null\n ? series.map((s) => ({\n series: s,\n point: s.points.find((p) => p.x === hoverX) ?? null,\n }))\n : null;\n\n return (\n <div className={styles.wrap}>\n <svg\n ref={svgRef}\n className={styles.svg}\n viewBox={`0 0 ${VBOX_W} ${height}`}\n role=\"img\"\n aria-label={ariaLabel}\n onPointerMove={handleMove}\n onPointerLeave={() => setHoverX(null)}\n >\n {yTicks.map((t, i) => (\n <g key={i}>\n <line\n x1={padL}\n x2={VBOX_W - padR}\n y1={yScale(t)}\n y2={yScale(t)}\n className={styles.gridline}\n stroke={CHART_GRID}\n />\n <text x={padL - 6} y={yScale(t)} dy=\"0.32em\" textAnchor=\"end\" className={styles.axisLabel}>\n {yAxis.labels[i]}\n </text>\n </g>\n ))}\n <line\n x1={padL}\n x2={VBOX_W - padR}\n y1={height - PAD_B}\n y2={height - PAD_B}\n className={styles.axis}\n stroke={CHART_AXIS}\n />\n {xLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} x={l.x} y={height - 6} textAnchor={l.anchor} className={styles.axisLabel}>\n {l.text}\n </text>\n ))}\n\n {series.map((s, si) => {\n const color = seriesColor(si);\n const runs = splitRuns(s.points);\n return (\n <g key={s.id}>\n {area && series.length === 1\n ? runs.map((run, ri) => {\n const d =\n run.map((p, j) => `${j === 0 ? 'M' : 'L'}${xScale(p.x)},${yScale(p.y)}`).join(' ') +\n ` L${xScale(run[run.length - 1].x)},${yScale(yMin)} L${xScale(run[0].x)},${yScale(yMin)} Z`;\n return <path key={ri} d={d} fill={color} className={styles.area} />;\n })\n : null}\n {runs.map((run, ri) => (\n <path\n key={ri}\n d={run.map((p, j) => `${j === 0 ? 'M' : 'L'}${xScale(p.x)},${yScale(p.y)}`).join(' ')}\n stroke={color}\n className={styles.line}\n />\n ))}\n {showEndLabels && runs.length ? (\n (() => {\n const lastRun = runs[runs.length - 1];\n const last = lastRun[lastRun.length - 1];\n return (\n <text\n data-end-label={s.id}\n x={xScale(last.x) + END_LABEL_GAP}\n y={dodged?.get(s.id) ?? yScale(last.y)}\n dy=\"0.32em\"\n className={styles.endLabel}\n fill={color}\n >\n {s.label}\n </text>\n );\n })()\n ) : null}\n </g>\n );\n })}\n\n {hoverX !== null ? (\n <line\n x1={xScale(hoverX)}\n x2={xScale(hoverX)}\n y1={PAD_T}\n y2={height - PAD_B}\n className={styles.crosshairLine}\n />\n ) : null}\n {hoverX !== null\n ? series.map((s, si) => {\n const p = s.points.find((pt) => pt.x === hoverX);\n if (!p || p.y === null) return null;\n return (\n <circle\n key={s.id}\n cx={xScale(p.x)}\n cy={yScale(p.y)}\n r={4}\n fill={seriesColor(si)}\n className={styles.marker}\n />\n );\n })\n : null}\n\n <rect\n x={padL}\n y={PAD_T}\n width={plotW}\n height={plotH}\n className={styles.overlay}\n onFocus={() => setHoverX(xAxis[xAxis.length - 1] ?? null)}\n />\n </svg>\n {hoverPoints && tooltipPos ? (\n <div className={styles.tooltip} style={{ left: tooltipPos.left, top: tooltipPos.top }}>\n <div className={styles.tooltipDate}>{formatX(hoverX as number)}</div>\n {hoverPoints.map(({ series: s, point }, i) => (\n <div className={styles.tooltipRow} key={s.id}>\n <span className={styles.tooltipKey} style={{ background: seriesColor(i) }} aria-hidden=\"true\" />\n {point && point.y !== null ? (\n <>\n <span className={styles.tooltipValue}>{formatY(point.y)}</span>\n {showLegend ? <span>{s.label}</span> : null}\n </>\n ) : (\n <span className={styles.tooltipGap}>no data{showLegend ? ` — ${s.label}` : ''}</span>\n )}\n </div>\n ))}\n </div>\n ) : null}\n {showLegend ? (\n <Legend items={series.map((s, i) => ({ label: s.label, color: seriesColor(i), kind: 'line' }))} />\n ) : null}\n </div>\n );\n}\n",".svg {\n display: block;\n overflow: visible;\n}\n\n.bar {\n transition: opacity var(--duration-fast) var(--ease-standard);\n}\n\n.bar:hover,\n.bar:focus-visible {\n opacity: 0.82;\n}\n\n.baseline {\n stroke: var(--chart-axis);\n stroke-width: 1;\n}\n\n.gridline {\n stroke: var(--chart-grid);\n stroke-width: 1;\n}\n\n.axisLabel {\n font-size: 10px;\n fill: var(--text-tertiary);\n font-family: var(--font-ui);\n}\n\n.valueLabel {\n font-size: 10px;\n fill: var(--text-secondary);\n font-family: var(--font-ui);\n font-variant-numeric: tabular-nums;\n}\n\n.categoryLabel {\n font-size: 10px;\n fill: var(--text-secondary);\n font-family: var(--font-ui);\n}\n\n.hitArea {\n fill: transparent;\n cursor: pointer;\n}\n\n.tooltip {\n position: absolute;\n pointer-events: none;\n background: var(--chart-tooltip-bg);\n border: 1px solid var(--chart-tooltip-border);\n border-radius: var(--radius-sm);\n box-shadow: var(--shadow-md);\n padding: var(--space-1) var(--space-2);\n font-size: var(--text-xs-size);\n color: var(--text-primary);\n white-space: nowrap;\n z-index: var(--z-dropdown);\n}\n\n.tooltipValue {\n font-weight: var(--font-weight-semibold);\n font-variant-numeric: tabular-nums;\n}\n\n.tooltipLabel {\n color: var(--text-tertiary);\n margin-left: var(--space-1);\n}\n\n.wrap {\n position: relative;\n}\n","/**\n * components/charts/BarChart.tsx — categorical magnitude comparison.\n * Single hue by default (nominal categories never get a value-ramp — see\n * dataviz anti-patterns \"a value-ramp on nominal categories\"). Vertical for\n * a handful of short-named categories, horizontal for many or long-named\n * ones (dataviz choosing-a-form.md). Null values render as an explicit\n * \"no data\" dash, never a silent zero-height bar indistinguishable from a\n * real zero.\n */\nimport { useId, useState } from 'react';\nimport type { CategoricalDatum } from './types.js';\nimport { CHART_SEQUENTIAL, CHART_AXIS, CHART_GRID } from './colors.js';\nimport './chart-tokens.css';\nimport styles from './BarChart.module.css';\n\nconst BAR_MAX = 24;\nconst GAP = 10;\n\nexport function BarChart({\n data,\n height = 160,\n orientation = 'vertical',\n color = CHART_SEQUENTIAL,\n formatValue = (v: number) => String(v),\n ariaLabel,\n}: {\n data: CategoricalDatum[];\n height?: number;\n orientation?: 'vertical' | 'horizontal';\n color?: string;\n formatValue?: (v: number) => string;\n ariaLabel: string;\n}) {\n const uid = useId();\n const [hover, setHover] = useState<number | null>(null);\n\n const known = data.map((d) => d.value).filter((v): v is number => v !== null);\n const maxVal = Math.max(0, ...known, 0.0001);\n const minVal = Math.min(0, ...known);\n const range = maxVal - minVal || 1;\n\n if (orientation === 'horizontal') {\n const LABEL_W = 120;\n const PAD_R = 48;\n const rowH = Math.min(BAR_MAX, Math.max(14, Math.floor((height - GAP) / data.length) - GAP));\n const plotW = 420;\n const svgH = data.length * (rowH + GAP) + GAP;\n const svgW = LABEL_W + plotW + PAD_R;\n\n return (\n <div className={styles.wrap}>\n <svg\n className={styles.svg}\n width={svgW}\n height={svgH}\n viewBox={`0 0 ${svgW} ${svgH}`}\n role=\"img\"\n aria-label={ariaLabel}\n >\n <line x1={LABEL_W} y1={0} x2={LABEL_W} y2={svgH} className={styles.baseline} stroke={CHART_AXIS} />\n {data.map((d, i) => {\n const y = GAP + i * (rowH + GAP);\n const barW = d.value !== null ? ((d.value - minVal) / range) * plotW : 0;\n return (\n <g key={d.label + i}>\n <text\n x={LABEL_W - 8}\n y={y + rowH / 2}\n dy=\"0.32em\"\n textAnchor=\"end\"\n className={styles.categoryLabel}\n >\n {d.label.length > 22 ? `${d.label.slice(0, 21)}…` : d.label}\n </text>\n {d.value === null ? (\n <line\n x1={LABEL_W + 4}\n y1={y + rowH / 2}\n x2={LABEL_W + 14}\n y2={y + rowH / 2}\n stroke={CHART_GRID}\n strokeWidth={2}\n strokeDasharray=\"2 2\"\n />\n ) : (\n <>\n <rect\n x={LABEL_W}\n y={y}\n width={Math.max(2, barW)}\n height={rowH}\n rx={4}\n fill={color}\n className={styles.bar}\n />\n <text\n x={LABEL_W + Math.max(2, barW) + 6}\n y={y + rowH / 2}\n dy=\"0.32em\"\n className={styles.valueLabel}\n >\n {formatValue(d.value)}\n </text>\n </>\n )}\n <rect\n className={styles.hitArea}\n x={0}\n y={y - GAP / 2}\n width={svgW}\n height={rowH + GAP}\n tabIndex={0}\n role=\"img\"\n aria-label={`${d.label}: ${d.value === null ? 'no data' : formatValue(d.value)}`}\n onPointerEnter={() => setHover(i)}\n onPointerLeave={() => setHover((h) => (h === i ? null : h))}\n onFocus={() => setHover(i)}\n onBlur={() => setHover((h) => (h === i ? null : h))}\n />\n </g>\n );\n })}\n </svg>\n {hover !== null ? (\n <div\n className={styles.tooltip}\n style={{ left: LABEL_W + 8, top: GAP + hover * (rowH + GAP) - 4 }}\n >\n <span className={styles.tooltipValue}>\n {data[hover].value === null ? 'no data' : formatValue(data[hover].value as number)}\n </span>\n <span className={styles.tooltipLabel}>{data[hover].label}</span>\n </div>\n ) : null}\n </div>\n );\n }\n\n // Vertical orientation.\n const barSlot = data.length ? Math.max(BAR_MAX, 0) : BAR_MAX;\n const barW = Math.min(BAR_MAX, barSlot);\n const PAD_T = 20;\n const PAD_B = 30;\n const plotH = height;\n const svgH = plotH + PAD_T + PAD_B;\n const svgW = data.length * (barW + GAP) + GAP;\n const zeroY = PAD_T + plotH - ((0 - minVal) / range) * plotH;\n\n return (\n <div className={styles.wrap}>\n <svg\n className={styles.svg}\n width={svgW}\n height={svgH}\n viewBox={`0 0 ${svgW} ${svgH}`}\n role=\"img\"\n aria-label={ariaLabel}\n >\n <line x1={0} y1={zeroY} x2={svgW} y2={zeroY} className={styles.baseline} stroke={CHART_AXIS} />\n {data.map((d, i) => {\n const x = GAP + i * (barW + GAP);\n const barH = d.value !== null ? (Math.abs(d.value - minVal) / range) * plotH : 0;\n const top = d.value !== null && d.value >= 0 ? zeroY - barH : zeroY;\n return (\n <g key={d.label + i}>\n {d.value === null ? (\n <line\n x1={x + barW / 2 - 5}\n y1={zeroY}\n x2={x + barW / 2 + 5}\n y2={zeroY}\n stroke={CHART_GRID}\n strokeWidth={2}\n strokeDasharray=\"2 2\"\n />\n ) : (\n <>\n <rect\n x={x}\n y={top}\n width={barW}\n height={Math.max(2, barH)}\n rx={4}\n fill={color}\n className={styles.bar}\n />\n <text x={x + barW / 2} y={top - 4} textAnchor=\"middle\" className={styles.valueLabel}>\n {formatValue(d.value)}\n </text>\n </>\n )}\n <text\n x={x + barW / 2}\n y={svgH - 8}\n textAnchor=\"middle\"\n className={styles.axisLabel}\n >\n {d.label.length > 10 ? `${d.label.slice(0, 9)}…` : d.label}\n </text>\n <rect\n className={styles.hitArea}\n x={x - GAP / 2}\n y={0}\n width={barW + GAP}\n height={svgH}\n tabIndex={0}\n role=\"img\"\n aria-label={`${d.label}: ${d.value === null ? 'no data' : formatValue(d.value)}`}\n onPointerEnter={() => setHover(i)}\n onPointerLeave={() => setHover((h) => (h === i ? null : h))}\n onFocus={() => setHover(i)}\n onBlur={() => setHover((h) => (h === i ? null : h))}\n />\n </g>\n );\n })}\n </svg>\n {hover !== null ? (\n <div\n className={styles.tooltip}\n style={{ left: GAP + hover * (barW + GAP), top: 0 }}\n id={`${uid}-tooltip`}\n >\n <span className={styles.tooltipValue}>\n {data[hover].value === null ? 'no data' : formatValue(data[hover].value as number)}\n </span>\n <span className={styles.tooltipLabel}>{data[hover].label}</span>\n </div>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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"}
@@ -1 +0,0 @@
1
- ._figure_1si9v_1{border:1px solid var(--border-subtle);border-radius:var(--radius-lg);background:var(--bg-surface);padding:var(--space-4);margin:0}._caption_1si9v_12{justify-content:space-between;align-items:baseline;gap:var(--space-3);margin-bottom:var(--space-3);display:flex}._title_1si9v_20{font-size:var(--text-sm-size);font-weight:var(--font-weight-semibold);color:var(--text-primary)}._description_1si9v_26{font-size:var(--text-xs-size);color:var(--text-tertiary)}._plot_1si9v_31{width:100%;overflow-x:auto}._tableDisclosure_1si9v_36{margin-top:var(--space-3);border-top:1px solid var(--border-subtle);padding-top:var(--space-2)}._tableDisclosure_1si9v_36>summary{cursor:pointer;font-size:var(--text-xs-size);color:var(--text-secondary);list-style:none}._tableDisclosure_1si9v_36>summary::-webkit-details-marker{display:none}._tableDisclosure_1si9v_36>summary:before{content:"▸ "}._tableDisclosure_1si9v_36[open]>summary:before{content:"▾ "}._tableBody_1si9v_61{margin-top:var(--space-2)}._caveat_1si9v_65{margin:0 0 var(--space-3);padding:var(--space-2) var(--space-3);border-radius:var(--radius-md);background:var(--status-unknown-bg);color:var(--status-unknown-fg);font-size:var(--text-xs-size);line-height:var(--text-sm-line)}._empty_1si9v_75{color:var(--text-tertiary);font-size:var(--text-sm-size);padding:var(--space-6) 0;text-align:center}._legend_4pgvn_1{gap:var(--space-1) var(--space-4);margin:var(--space-2) 0 0;flex-wrap:wrap;padding:0;list-style:none;display:flex}._item_4pgvn_10{align-items:center;gap:var(--space-2);font-size:var(--text-xs-size);color:var(--text-secondary);display:inline-flex}._swatch_4pgvn_18{border-radius:var(--radius-full);flex:none;width:10px;height:10px}._swatchLine_4pgvn_25{border-radius:var(--radius-full);flex:none;width:14px;height:2px}._svg_djmd1_1{width:100%;height:auto;display:block}._gridline_djmd1_7{stroke:var(--chart-grid);stroke-width:1px}._axis_djmd1_12{stroke:var(--chart-axis);stroke-width:1px}._axisLabel_djmd1_17{font-size:var(--text-xs-size);fill:var(--text-tertiary);font-family:var(--font-ui)}._line_djmd1_23{fill:none;stroke-width:2px;stroke-linecap:round;stroke-linejoin:round}._area_djmd1_30{opacity:.1;stroke:none}._marker_djmd1_35{stroke:var(--chart-surface);stroke-width:2px}._endLabel_djmd1_40{font-size:var(--text-xs-size);font-family:var(--font-ui);font-weight:var(--font-weight-medium)}._crosshairLine_djmd1_46{stroke:var(--chart-axis);stroke-width:1px;pointer-events:none}._overlay_djmd1_52{fill:#0000;cursor:crosshair}._wrap_djmd1_57{position:relative}._tooltip_djmd1_61{pointer-events:none;background:var(--chart-tooltip-bg);border:1px solid var(--chart-tooltip-border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);padding:var(--space-2);font-size:var(--text-xs-size);color:var(--text-primary);white-space:nowrap;z-index:var(--z-dropdown);margin-top:-10px;position:absolute;transform:translate(-50%,-100%)}._tooltipDate_djmd1_77{color:var(--text-tertiary);margin-bottom:var(--space-1)}._tooltipRow_djmd1_82{align-items:center;gap:var(--space-1);display:flex}._tooltipKey_djmd1_88{flex:none;width:12px;height:2px}._tooltipValue_djmd1_94{font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums}._tooltipGap_djmd1_99{color:var(--text-tertiary);font-style:italic}._svg_o4jfa_1{display:block;overflow:visible}._bar_o4jfa_6{transition:opacity var(--duration-fast) var(--ease-standard)}._bar_o4jfa_6:hover,._bar_o4jfa_6:focus-visible{opacity:.82}._baseline_o4jfa_15{stroke:var(--chart-axis);stroke-width:1px}._gridline_o4jfa_20{stroke:var(--chart-grid);stroke-width:1px}._axisLabel_o4jfa_25{fill:var(--text-tertiary);font-size:10px;font-family:var(--font-ui)}._valueLabel_o4jfa_31{fill:var(--text-secondary);font-size:10px;font-family:var(--font-ui);font-variant-numeric:tabular-nums}._categoryLabel_o4jfa_38{fill:var(--text-secondary);font-size:10px;font-family:var(--font-ui)}._hitArea_o4jfa_44{fill:#0000;cursor:pointer}._tooltip_o4jfa_49{pointer-events:none;background:var(--chart-tooltip-bg);border:1px solid var(--chart-tooltip-border);border-radius:var(--radius-sm);box-shadow:var(--shadow-md);padding:var(--space-1) var(--space-2);font-size:var(--text-xs-size);color:var(--text-primary);white-space:nowrap;z-index:var(--z-dropdown);position:absolute}._tooltipValue_o4jfa_63{font-weight:var(--font-weight-semibold);font-variant-numeric:tabular-nums}._tooltipLabel_o4jfa_68{color:var(--text-tertiary);margin-left:var(--space-1)}._wrap_o4jfa_73{position:relative}
@@ -1 +0,0 @@
1
- ._body_1uchw_10{gap:var(--space-3);flex-direction:column;min-width:0;display:flex}._actionsRow_1uchw_17{align-items:center;gap:var(--space-2);flex-wrap:wrap;display:flex}._headActions_1uchw_24{align-items:center;gap:var(--space-2);display:inline-flex;position:relative}._meterBlock_1uchw_31{gap:var(--space-1);flex-direction:column;display:flex}._estimateNote_1uchw_37,._muted_1uchw_38{color:var(--text-tertiary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);overflow-wrap:break-word;margin:0}._facts_1uchw_46{color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);overflow-wrap:break-word;margin:0}._link_1uchw_54{color:var(--text-link);font-size:var(--text-xs-size);line-height:var(--text-xs-line);white-space:nowrap;text-decoration:none}._link_1uchw_54:hover{text-decoration:underline}._link_1uchw_54:focus-visible,._linkButton_1uchw_67:focus-visible{outline:2px solid var(--border-focus);outline-offset:2px}._linkButton_1uchw_67{color:var(--text-link);font:inherit;font-size:var(--text-xs-size);line-height:var(--text-xs-line);cursor:pointer;white-space:nowrap;background:0 0;border:0;padding:0}._linkButton_1uchw_67:hover{text-decoration:underline}._linkButton_1uchw_67:disabled{color:var(--text-disabled);cursor:default;text-decoration:none}._toggleRow_1uchw_94{align-items:center;gap:var(--space-2) var(--space-3);flex-wrap:wrap;display:flex}._toggleText_1uchw_101{flex:16rem;min-width:0}._tasks_1uchw_108{flex-direction:column;margin:0;padding:0;list-style:none;display:flex}._task_1uchw_108{gap:var(--space-1) var(--space-3);padding:var(--space-2) 0;border-top:1px solid var(--border-subtle);grid-template-columns:auto minmax(0,1fr);display:grid}._task_1uchw_108:first-child{border-top:0}._taskChip_1uchw_128{padding-top:1px}._taskMain_1uchw_132{gap:var(--space-1);flex-direction:column;min-width:0;display:flex}._taskTitle_1uchw_139{color:var(--text-primary);font-size:var(--text-sm-size);line-height:var(--text-sm-line);font-weight:var(--font-weight-medium);overflow-wrap:break-word;margin:0}._taskLinks_1uchw_148{align-items:center;gap:var(--space-1) var(--space-3);flex-wrap:wrap;display:flex}._notice_1uchw_157{padding:var(--space-2) var(--space-3);border:1px solid var(--border-subtle);border-radius:var(--radius-md);background:var(--bg-surface-raised);color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);overflow-wrap:break-word;margin:0}._notice_1uchw_157[data-tone=warning]{border-color:var(--status-warning-solid);background:var(--status-warning-bg);color:var(--status-warning-fg)}._notice_1uchw_157[data-tone=danger]{border-color:var(--status-danger-solid);background:var(--status-danger-bg);color:var(--status-danger-fg)}._notice_1uchw_157[data-tone=success]{border-color:var(--status-success-solid);background:var(--status-success-bg);color:var(--status-success-fg)}._noticeRow_1uchw_187{justify-content:space-between;align-items:baseline;gap:var(--space-1) var(--space-3);flex-wrap:wrap;display:flex}._popover_1uchw_197{top:calc(100% + var(--space-2));z-index:var(--z-dropdown);width:min(26rem, calc(100vw - var(--space-8)));max-height:min(34rem,70vh);padding:var(--space-4);border:1px solid var(--border-default);border-radius:var(--radius-lg);background:var(--bg-surface-raised);box-shadow:var(--shadow-menu);position:absolute;right:0;overflow-y:auto}._popoverTitle_1uchw_212{margin:0 0 var(--space-3);color:var(--text-primary);font-size:var(--text-sm-size);line-height:var(--text-sm-line);font-weight:var(--font-weight-semibold)}._form_1uchw_222{gap:var(--space-3);flex-direction:column;display:flex}._fieldGrid_1uchw_228{gap:var(--space-3);grid-template-columns:repeat(auto-fill,minmax(11rem,1fr));display:grid}._textareaField_1uchw_234{gap:var(--space-1);flex-direction:column;display:flex}._label_1uchw_240{color:var(--text-secondary);font-size:var(--text-xs-size);line-height:var(--text-xs-line);font-weight:var(--font-weight-medium)}._textarea_1uchw_234{min-height:8rem;padding:var(--space-2) var(--space-3);border:1px solid var(--border-default);border-radius:var(--radius-md);background:var(--bg-input);color:var(--text-primary);font:inherit;font-size:var(--text-sm-size);line-height:var(--text-sm-line);resize:vertical}._textarea_1uchw_234:focus-visible{outline:2px solid var(--border-focus);outline-offset:0}._textarea_1uchw_234[aria-invalid=true]{border-color:var(--status-danger-solid)}._fieldError_1uchw_269{color:var(--status-danger-fg);font-size:var(--text-xs-size);line-height:var(--text-xs-line);margin:0}._formActions_1uchw_276{justify-content:flex-end;gap:var(--space-2);flex-wrap:wrap;display:flex}._dialogWidth_1uchw_283{width:min(34rem, calc(100vw - var(--space-8)))}._laneChip_1uchw_289[data-active=true]{border-color:var(--status-running-solid)}._sheetAction_1uchw_295{gap:var(--space-2);padding-top:var(--space-3);border-top:1px solid var(--border-subtle);flex-direction:column;display:flex}
@@ -1,2 +0,0 @@
1
- import{D as e,F as t,U as n,c as r,l as i,o as a}from"./global-oEl9Qj8u.js";import{F as o}from"./VerseConsoleApp-DTjDpGCd.js";import{c as s,d as c,l,o as u,r as d,s as f,u as p}from"./types-D5XOdyw8.js";var m=`verse-cloud`,h=3e4,g=class extends Error{constructor(){super(`Unlock actions with the mutation token first.`),this.name=`CloudLockedError`}},_=class extends Error{failure;constructor(e,t){super(e),this.failure=t,this.name=`CloudLaunchRefusedError`}};function v(e){return typeof e==`object`&&!!e&&!Array.isArray(e)}function y(e){if(!v(e))return null;let{seat:t,budget:n,tasks:r,backlog:i}=e;if(!v(t)||typeof t.ready!=`boolean`||!v(n)||!v(n.budget)||!v(n.canLaunch)||!v(n.canSelfImprove))return null;for(let e of[`creditsTotalUsd`,`estimatedSpentUsd`,`estimatedRemainingUsd`,`sessionsToday`,`selfImproveToday`,`running`])if(typeof n[e]!=`number`||!Number.isFinite(n[e]))return null;return!Array.isArray(r)||!r.every(e=>v(e)&&typeof e.id==`string`&&typeof e.state==`string`)||!v(i)||!Array.isArray(i.items)?null:e}function b(e){return e instanceof a?e.status===404?`The cloud lane is not in this build yet.`:e.status===503?`The cloud lane failed to load on the server.`:`The cloud lane answered HTTP ${e.status}.`:`The cloud lane could not be reached.`}var x={key:m,fetch:async e=>{try{let t=y(await r(l,e));return t===null?{value:null,available:!0,reason:`The cloud lane answered in a shape this version does not recognise, so nothing is shown rather than guessed.`}:{value:t,available:!0,reason:null}}catch(e){if(e instanceof a&&e.status===401||e instanceof DOMException&&e.name===`AbortError`)throw e;return{value:null,available:!1,reason:b(e)}}}};async function S(n,r){let a=e();if(!a)throw new g;let o=await i(n,r,a);return t(),o}function C(){n(m),o()}async function w(e){try{let t=await S(s,e);if(!v(t)||t.ok!==!0||!v(t.task))throw new _(v(t)&&typeof t.error==`string`&&t.error?t.error:`The cloud session was not started, and the server sent no reason.`,v(t)&&typeof t.failure==`string`?t.failure:null);return t}finally{C()}}async function T(e){let t=await S(u,e);return n(m),t}async function E(e={count:1}){try{let t=await S(f,e);return{launched:v(t)&&Array.isArray(t.launched)?t.launched:[],skipped:v(t)&&Array.isArray(t.skipped)?t.skipped:[]}}finally{C()}}async function D(){try{return await S(p,{})}finally{C()}}async function O(e){if(!d.test(e))throw Error(`That task id is not one Verse issued, so nothing was sent.`);try{return await S(`${c}/${e}/dismiss`,{})}finally{C()}}export{D as a,w as i,x as n,E as o,O as r,T as s,h as t};
2
- //# sourceMappingURL=cloud-queries-Br_r0UAz.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cloud-queries-Br_r0UAz.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/cloud/cloud-queries.ts"],"sourcesContent":["/**\n * routes/verse/cloud/cloud-queries.ts — the one read and the writes behind\n * the cloud lane's UI (3.11 unit C3; server: core/cloud/cloud-api.ts, C2).\n *\n * GET /api/verse/cloud CloudOverviewResponse\n * POST /api/verse/cloud/launch CloudLaunchRequest → CloudLaunchResponse\n * POST /api/verse/cloud/budget CloudBudgetUpdate\n * POST /api/verse/cloud/refresh (re-read tasks from GitHub)\n * POST /api/verse/cloud/improve CloudImproveRequest → CloudImproveResponse\n * POST /api/verse/cloud/tasks/<id>/dismiss (mark closed; never touches GitHub)\n *\n * WHY the read is OPTIONAL (the surface-data.ts rule): the routes land in a\n * parallel unit, and a server without them answers 404. That is \"this build\n * has no cloud lane yet\" — one card's designed state — never a broken\n * Command. 401 and aborts still propagate: an expired read session is the\n * whole app's state.\n *\n * LAZY ONLY. Everything that imports this file (Command's card, the Usage\n * panel, the Fleet chip, the composer's \"Run in cloud\") is itself behind an\n * import(); nothing cloud-related may cost chat first-paint bytes.\n *\n * Writes pull the held mutation token (CloudLockedError without one — the\n * callers route every write through a token gate that opens the unlock\n * dialog first), then invalidate the overview so every cloud view moves\n * together, and nudge the shell's activity poll (Needs-you carries cloud\n * items).\n */\nimport {\n CLOUD_TASK_ID_PATTERN,\n VERSE_CLOUD_BUDGET_PATH,\n VERSE_CLOUD_IMPROVE_PATH,\n VERSE_CLOUD_LAUNCH_PATH,\n VERSE_CLOUD_PATH,\n VERSE_CLOUD_REFRESH_PATH,\n VERSE_CLOUD_TASKS_PATH,\n type CloudBudgetUpdate,\n type CloudImproveRequest,\n type CloudImproveResponse,\n type CloudLaunchFailureCode,\n type CloudLaunchRequest,\n type CloudLaunchResponse,\n type CloudOverviewResponse,\n} from '../../../../core/cloud/types.js';\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 { refreshActivity } from '../shell/useActivity.js';\nimport type { OptionalRead } from '../command/surface-data.js';\n\nexport const CLOUD_KEY = 'verse-cloud';\n\n/** The card, the chip and the panel all poll at this pace while visible (SPEC 3.11 C3). */\nexport const CLOUD_POLL_MS = 30_000;\n\nexport class CloudLockedError extends Error {\n constructor() {\n super('Unlock actions with the mutation token first.');\n this.name = 'CloudLockedError';\n }\n}\n\n/**\n * The server answered a launch with `ok: false` — a budget gate, a missing\n * seat, a CLI that printed no session. `message` is the server's own\n * sentence; `failure` the machine code for tests and chips.\n */\nexport class CloudLaunchRefusedError extends Error {\n constructor(message: string, public readonly failure: CloudLaunchFailureCode | null) {\n super(message);\n this.name = 'CloudLaunchRefusedError';\n }\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return value !== null && typeof value === 'object' && !Array.isArray(value);\n}\n\n/**\n * Just enough structure that no render can crash on `undefined.map` or read\n * a budget field that is not there. Field-level honesty (null = unknown) is\n * the model's job.\n */\nexport function narrowCloudOverview(raw: unknown): CloudOverviewResponse | null {\n if (!isRecord(raw)) return null;\n const { seat, budget, tasks, backlog } = raw;\n if (!isRecord(seat) || typeof seat['ready'] !== 'boolean') return null;\n if (!isRecord(budget) || !isRecord(budget['budget']) || !isRecord(budget['canLaunch']) || !isRecord(budget['canSelfImprove'])) return null;\n for (const key of ['creditsTotalUsd', 'estimatedSpentUsd', 'estimatedRemainingUsd', 'sessionsToday', 'selfImproveToday', 'running']) {\n if (typeof budget[key] !== 'number' || !Number.isFinite(budget[key])) return null;\n }\n if (!Array.isArray(tasks) || !tasks.every((t) => isRecord(t) && typeof t['id'] === 'string' && typeof t['state'] === 'string')) return null;\n if (!isRecord(backlog) || !Array.isArray(backlog['items'])) return null;\n return raw as unknown as CloudOverviewResponse;\n}\n\n/** Operator words for a cloud read that did not answer — never a path, never a trace. */\nfunction absence(err: unknown): string {\n if (err instanceof ApiError) {\n if (err.status === 404) return 'The cloud lane is not in this build yet.';\n if (err.status === 503) return 'The cloud lane failed to load on the server.';\n return `The cloud lane answered HTTP ${err.status}.`;\n }\n return 'The cloud lane could not be reached.';\n}\n\nexport const cloudQuery: QueryDef<OptionalRead<CloudOverviewResponse>> = {\n key: CLOUD_KEY,\n fetch: async (signal) => {\n try {\n const value = narrowCloudOverview(await apiGet<unknown>(VERSE_CLOUD_PATH, signal));\n if (value === null) {\n return { value: null, available: true, reason: 'The cloud lane answered in a shape this version does not recognise, so nothing is shown rather than guessed.' };\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: absence(err) };\n }\n },\n};\n\nasync function post<T>(path: string, body: unknown): Promise<T> {\n const token = getMutationToken();\n if (!token) throw new CloudLockedError();\n const result = await apiPost<T>(path, body, token);\n touchMutationHold();\n return result;\n}\n\nfunction settled(): void {\n invalidate(CLOUD_KEY);\n void refreshActivity();\n}\n\n/**\n * Launch one cloud session. Resolves only on `ok: true` with a task; a\n * refusal the server words in a 200 body is thrown as CloudLaunchRefusedError\n * so every caller shows it the same way as a 4xx refusal (whose sentence is\n * `ApiError.detail`). Invalidates either way — a failed launch is still a\n * recorded task.\n */\nexport async function launchCloudTask(request: CloudLaunchRequest): Promise<CloudLaunchResponse & { task: NonNullable<CloudLaunchResponse['task']> }> {\n try {\n const response = await post<CloudLaunchResponse>(VERSE_CLOUD_LAUNCH_PATH, request);\n if (!isRecord(response) || response.ok !== true || !isRecord(response.task)) {\n const error = isRecord(response) && typeof response.error === 'string' && response.error ? response.error : 'The cloud session was not started, and the server sent no reason.';\n const failure = isRecord(response) && typeof response.failure === 'string' ? response.failure : null;\n throw new CloudLaunchRefusedError(error, failure);\n }\n return response as CloudLaunchResponse & { task: NonNullable<CloudLaunchResponse['task']> };\n } finally {\n settled();\n }\n}\n\n/** One budget change (any subset; the server validates and clamps). */\nexport async function updateCloudBudget(update: CloudBudgetUpdate): Promise<unknown> {\n const result = await post<unknown>(VERSE_CLOUD_BUDGET_PATH, update);\n invalidate(CLOUD_KEY);\n return result;\n}\n\n/** Launch up to `count` backlog items now (the \"Improve Verse\" button). */\nexport async function runCloudImprove(request: CloudImproveRequest = { count: 1 }): Promise<CloudImproveResponse> {\n try {\n const result = await post<unknown>(VERSE_CLOUD_IMPROVE_PATH, request);\n const launched = isRecord(result) && Array.isArray(result['launched']) ? (result['launched'] as CloudImproveResponse['launched']) : [];\n const skipped = isRecord(result) && Array.isArray(result['skipped']) ? (result['skipped'] as CloudImproveResponse['skipped']) : [];\n return { launched, skipped };\n } finally {\n settled();\n }\n}\n\n/** Ask the server to re-read every open task from GitHub now. */\nexport async function refreshCloudTasks(): Promise<unknown> {\n try {\n return await post<unknown>(VERSE_CLOUD_REFRESH_PATH, {});\n } finally {\n settled();\n }\n}\n\n/**\n * Stop tracking one task (it becomes `closed`, \"Dismissed in Verse.\"). The id\n * is re-checked against the contract's pattern: it came from the server, but\n * it is spliced into a path the mutation token is sent to.\n */\nexport async function dismissCloudTask(taskId: string): Promise<unknown> {\n if (!CLOUD_TASK_ID_PATTERN.test(taskId)) throw new Error('That task id is not one Verse issued, so nothing was sent.');\n try {\n return await post<unknown>(`${VERSE_CLOUD_TASKS_PATH}/${taskId}/dismiss`, {});\n } finally {\n settled();\n }\n}\n"],"mappings":"2MAkDA,IAAa,EAAY,cAGZ,EAAgB,IAEhB,EAAb,cAAsC,KAAM,CAC1C,aAAc,CACZ,MAAM,+CAA+C,EACrD,KAAK,KAAO,kBACd,CACF,EAOa,EAAb,cAA6C,KAAM,CACJ,QAA7C,YAAY,EAAiB,EAAwD,CACnF,MAAM,CAAO,EAD8B,KAAA,QAAA,EAE3C,KAAK,KAAO,yBACd,CACF,EAEA,SAAS,EAAS,EAAkD,CAClE,OAAyB,OAAO,GAAU,YAAnC,GAA+C,CAAC,MAAM,QAAQ,CAAK,CAC5E,CAOA,SAAgB,EAAoB,EAA4C,CAC9E,GAAI,CAAC,EAAS,CAAG,EAAG,OAAO,KAC3B,GAAM,CAAE,OAAM,SAAQ,QAAO,WAAY,EAEzC,GADI,CAAC,EAAS,CAAI,GAAK,OAAO,EAAK,OAAa,WAC5C,CAAC,EAAS,CAAM,GAAK,CAAC,EAAS,EAAO,MAAS,GAAK,CAAC,EAAS,EAAO,SAAY,GAAK,CAAC,EAAS,EAAO,cAAiB,EAAG,OAAO,KACtI,IAAK,IAAM,IAAO,CAAC,kBAAmB,oBAAqB,wBAAyB,gBAAiB,mBAAoB,SAAS,EAChI,GAAI,OAAO,EAAO,IAAS,UAAY,CAAC,OAAO,SAAS,EAAO,EAAI,EAAG,OAAO,KAI/E,MAFI,CAAC,MAAM,QAAQ,CAAK,GAAK,CAAC,EAAM,MAAO,GAAM,EAAS,CAAC,GAAK,OAAO,EAAE,IAAU,UAAY,OAAO,EAAE,OAAa,QAAQ,GACzH,CAAC,EAAS,CAAO,GAAK,CAAC,MAAM,QAAQ,EAAQ,KAAQ,EAAU,KAC5D,CACT,CAGA,SAAS,EAAQ,EAAsB,CAMrC,OALI,aAAe,EACb,EAAI,SAAW,IAAY,2CAC3B,EAAI,SAAW,IAAY,+CACxB,gCAAgC,EAAI,OAAO,GAE7C,sCACT,CAEA,IAAa,EAA4D,CACvE,IAAK,EACL,MAAO,KAAO,IAAW,CACvB,GAAI,CACF,IAAM,EAAQ,EAAoB,MAAM,EAAgB,EAAkB,CAAM,CAAC,EAIjF,OAHI,IAAU,KACL,CAAE,MAAO,KAAM,UAAW,GAAM,OAAQ,8GAA+G,EAEzJ,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,EAAQ,CAAG,CAAE,CAC/D,CACF,CACF,EAEA,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,CAEA,SAAS,GAAgB,CACvB,EAAW,CAAS,EACpB,EAAqB,CACvB,CASA,eAAsB,EAAgB,EAAgH,CACpJ,GAAI,CACF,IAAM,EAAW,MAAM,EAA0B,EAAyB,CAAO,EACjF,GAAI,CAAC,EAAS,CAAQ,GAAK,EAAS,KAAO,IAAQ,CAAC,EAAS,EAAS,IAAI,EAGxE,MAAM,IAAI,EAFI,EAAS,CAAQ,GAAK,OAAO,EAAS,OAAU,UAAY,EAAS,MAAQ,EAAS,MAAQ,oEAC5F,EAAS,CAAQ,GAAK,OAAO,EAAS,SAAY,SAAW,EAAS,QAAU,IAChD,EAElD,OAAO,CACT,QAAU,CACR,EAAQ,CACV,CACF,CAGA,eAAsB,EAAkB,EAA6C,CACnF,IAAM,EAAS,MAAM,EAAc,EAAyB,CAAM,EAElE,OADA,EAAW,CAAS,EACb,CACT,CAGA,eAAsB,EAAgB,EAA+B,CAAE,MAAO,CAAE,EAAkC,CAChH,GAAI,CACF,IAAM,EAAS,MAAM,EAAc,EAA0B,CAAO,EAGpE,MAAO,CAAE,SAFQ,EAAS,CAAM,GAAK,MAAM,QAAQ,EAAO,QAAW,EAAK,EAAO,SAAmD,CAAC,EAElH,QADH,EAAS,CAAM,GAAK,MAAM,QAAQ,EAAO,OAAU,EAAK,EAAO,QAAiD,CAAC,CACtG,CAC7B,QAAU,CACR,EAAQ,CACV,CACF,CAGA,eAAsB,GAAsC,CAC1D,GAAI,CACF,OAAO,MAAM,EAAc,EAA0B,CAAC,CAAC,CACzD,QAAU,CACR,EAAQ,CACV,CACF,CAOA,eAAsB,EAAiB,EAAkC,CACvE,GAAI,CAAC,EAAsB,KAAK,CAAM,EAAG,MAAU,MAAM,4DAA4D,EACrH,GAAI,CACF,OAAO,MAAM,EAAc,GAAG,EAAuB,GAAG,EAAO,UAAW,CAAC,CAAC,CAC9E,QAAU,CACR,EAAQ,CACV,CACF"}
@@ -1,2 +0,0 @@
1
- import{E as e}from"./VerseConsoleApp-DTjDpGCd.js";import{v as t,y as n}from"./format-BkWdOQDL.js";import{v as r}from"./context-model-BC-HOmPo.js";import{a as i,i as a,n as o}from"./types-D5XOdyw8.js";var s=i.selfImprove.repo,c=/^[A-Za-z0-9-]+\/[A-Za-z0-9._-]+$/,l=/^[A-Za-z0-9._/+-]{1,200}$/;function u(e){return!l.test(e)||e.startsWith(`-`)||e.startsWith(`/`)||e.endsWith(`/`)||e.endsWith(`.`)||e.endsWith(`.lock`)?!1:!e.includes(`..`)&&!e.includes(`//`)}function d(e,t){if(typeof e!=`string`||e.length>2048)return null;try{let n=new URL(e);return n.protocol===`https:`&&n.hostname===t?n.toString():null}catch{return null}}function f(e){if(!Number.isFinite(e))return`—`;let t=Math.abs(e)<.005?0:e,n=Number.isInteger(t)?String(Math.abs(t)):Math.abs(t).toFixed(2);return`${t<0?`−`:``}$${n}`}function p(t){let n=t.creditsTotalUsd,r=t.estimatedRemainingUsd,i=t.budget.selfImprove.reserveUsd,a=n>0?n:null,o=a===null?null:(n-Math.max(0,r))/n*100,s=r<=0?`danger`:r<i?`warning`:`accent`,c=r<=0?`The estimate says the credits are spent. Check the real balance on claude.ai and adjust the budget.`:r<i?`Under the ${f(i)} reserve, so Verse stops launching self-improvement tasks.`:null;return{value:Math.max(0,r),max:a,text:`${f(Math.max(0,r))} of ${f(n)} · estimate`,usedText:o===null?`no credit total set`:`${e(o)} used`,tone:s,warning:c}}function m(e){let t=new Date(e);return t.setHours(24,0,0,0),t.getTime()}function h(e,t=Date.now()){let r=n(new Date(m(t)).toISOString(),t),i=e.running===1?`1 running`:`${e.running} running`;return`${e.sessionsToday} of ${e.budget.maxSessionsPerDay} sessions today · ${i}${r?` · resets ${r}`:``}`}function g(e){let t=e.budget.selfImprove;return t.enabled?`${e.selfImproveToday} of ${t.maxPerDay} self-improvement launches today, on ${t.repo}. Stops under a ${f(t.reserveUsd)} estimated balance.`:`Self-improvement is off. Verse launches cloud tasks only when you ask.`}function _(e,n){return e.ok?null:e.reason?t(e.reason):n}var v=`The Claude seat isn't set up on this Mac.`;function y(e){return e.ready?null:e.reason?t(e.reason):v}function b(e,t){return y(e)??_(t.canLaunch,`The cloud budget does not allow another launch right now.`)}var x={queued:`Queued`,launching:`Launching`,running:`Running`,"pr-open":`PR open`,merged:`Merged`,closed:`Closed`,failed:`Failed`,expired:`Expired`},S={queued:`info`,launching:`info`,running:`running`,"pr-open":`warning`,merged:`success`,closed:`neutral`,failed:`danger`,expired:`unknown`};function C(e){return e.state===`pr-open`&&e.pr?.draft?`Draft PR`:x[e.state]??e.state}function w(e){return a.includes(e)}function T(e){return e===`queued`||e===`launching`||e===`running`}var E=864e5;function D(e,t=Date.now()){let n=e=>{let n=Date.parse(e.updatedAt);return Number.isFinite(n)&&t-n<E},r=e.filter(e=>!w(e.state)||n(e)).sort((e,t)=>(Date.parse(t.createdAt)||0)-(Date.parse(e.createdAt)||0));return{shown:r.slice(0,6),hidden:Math.max(0,r.length-6)}}function O(e){return e.filter(e=>T(e.state)).length}function k(e,t=Date.now()){let n=e.state===`queued`||e.state===`launching`?e.createdAt:e.launchedAt??e.createdAt,i=r(n,t),a=e.state===`queued`?`queued`:e.state===`failed`?`tried`:`started`;return`${e.repo} from ${e.baseBranch}${i?` · ${a} ${i}`:``}`}function A(e,n=Date.now()){return e.report?.summary&&(e.state===`pr-open`||e.state===`merged`)?t(e.report.summary,n):e.stateReason?t(e.stateReason,n):null}function j(e){return e.state!==`merged`&&e.state!==`closed`}var M=new Intl.NumberFormat(`en-US`);function N(e){let t={},n=e.repo.trim(),r=e.baseBranch.trim(),i=e.prompt.trim();return n?c.test(n)||(t.repo=`Use the GitHub owner/name form, like ashlrai/ashlr-hub.`):t.repo=`Enter the GitHub repository as owner/name.`,r&&!u(r)&&(t.baseBranch=`That isn't a branch name git accepts.`),i?i.length>2e4&&(t.prompt=`The task is ${M.format(i.length)} characters; the limit is ${M.format(o)}.`):t.prompt=`Describe the task for the cloud session.`,Object.keys(t).length>0?{ok:!1,errors:t}:{ok:!0,request:{repo:n,...r?{baseBranch:r}:{},prompt:i}}}var P=[{field:`total`,label:`Credits on the account`,hint:`What claude.ai says you have.`,money:!0,integer:!1,min:0,max:1e5},{field:`spent`,label:`Already spent`,hint:`Spent before Verse tracked it, or a correction after checking.`,money:!0,integer:!1,min:-1e5,max:1e5},{field:`perSession`,label:`Estimate per session`,hint:`Flat cost Verse counts for each launch.`,money:!0,integer:!1,min:.01,max:1e3},{field:`maxPerDay`,label:`Sessions per day`,hint:`From every origin, counted per local day.`,money:!1,integer:!0,min:0,max:500},{field:`maxConcurrent`,label:`Running at once`,hint:`Launching or running together.`,money:!1,integer:!0,min:1,max:50},{field:`selfImproveMax`,label:`Self-improvement per day`,hint:`Launches Verse may make on its own.`,money:!1,integer:!0,min:0,max:100},{field:`reserve`,label:`Reserve`,hint:`Self-improvement stops under this estimated balance.`,money:!0,integer:!1,min:0,max:1e5}];function F(e){return String(Number.isInteger(e)?e:Math.round(e*100)/100)}function I(e){return{total:F(e.creditsTotalUsd),spent:F(e.creditsSpentAdjustmentUsd),perSession:F(e.estimatedCostPerSessionUsd),maxPerDay:F(e.maxSessionsPerDay),maxConcurrent:F(e.maxConcurrent),selfImprove:e.selfImprove.enabled,selfImproveMax:F(e.selfImprove.maxPerDay),reserve:F(e.selfImprove.reserveUsd)}}function L(e,t){let n={},r={};for(let t of P){let i=e[t.field].trim().replace(/^\$/,``),a=i===``?NaN:Number(i);Number.isFinite(a)?t.integer&&!Number.isInteger(a)?n[t.field]=`Enter a whole number.`:a<t.min||a>t.max?n[t.field]=t.money?`Between ${f(t.min)} and ${f(t.max)}.`:`Between ${M.format(t.min)} and ${M.format(t.max)}.`:r[t.field]=a:n[t.field]=`Enter a number.`}if(Object.keys(n).length>0)return{ok:!1,errors:n};let i={},a=(e,t)=>Math.abs(e-t)<.005;a(r.total,t.creditsTotalUsd)||(i.creditsTotalUsd=r.total),a(r.spent,t.creditsSpentAdjustmentUsd)||(i.creditsSpentAdjustmentUsd=r.spent),a(r.perSession,t.estimatedCostPerSessionUsd)||(i.estimatedCostPerSessionUsd=r.perSession),a(r.maxPerDay,t.maxSessionsPerDay)||(i.maxSessionsPerDay=r.maxPerDay),a(r.maxConcurrent,t.maxConcurrent)||(i.maxConcurrent=r.maxConcurrent);let o={};return e.selfImprove!==t.selfImprove.enabled&&(o.enabled=e.selfImprove),a(r.selfImproveMax,t.selfImprove.maxPerDay)||(o.maxPerDay=r.selfImproveMax),a(r.reserve,t.selfImprove.reserveUsd)||(o.reserveUsd=r.reserve),Object.keys(o).length>0&&(i.selfImprove=o),{ok:!0,update:i,changed:Object.keys(i).length>0}}function R(e){return e.overview?y(e.overview.seat)||(e.repo?_(e.overview.budget.canLaunch,`The cloud budget does not allow another launch right now.`)||(e.prompt.trim()?e.prompt.trim().length>2e4?`The message is over ${M.format(o)} characters — trim it to run it in the cloud.`:null:`Type the task in the message box first.`):e.rootsLoading?`Reading this chat's project…`:`This chat's project has no GitHub origin, so a cloud session has nothing to clone.`):e.overviewReason??`The cloud lane did not answer.`}var z={body:`_body_1uchw_10`,actionsRow:`_actionsRow_1uchw_17`,headActions:`_headActions_1uchw_24`,meterBlock:`_meterBlock_1uchw_31`,estimateNote:`_estimateNote_1uchw_37`,muted:`_muted_1uchw_38`,facts:`_facts_1uchw_46`,link:`_link_1uchw_54`,linkButton:`_linkButton_1uchw_67`,toggleRow:`_toggleRow_1uchw_94`,toggleText:`_toggleText_1uchw_101`,tasks:`_tasks_1uchw_108`,task:`_task_1uchw_108`,taskChip:`_taskChip_1uchw_128`,taskMain:`_taskMain_1uchw_132`,taskTitle:`_taskTitle_1uchw_139`,taskLinks:`_taskLinks_1uchw_148`,notice:`_notice_1uchw_157`,noticeRow:`_noticeRow_1uchw_187`,popover:`_popover_1uchw_197`,popoverTitle:`_popoverTitle_1uchw_212`,form:`_form_1uchw_222`,fieldGrid:`_fieldGrid_1uchw_228`,textareaField:`_textareaField_1uchw_234`,label:`_label_1uchw_240`,textarea:`_textarea_1uchw_234`,fieldError:`_fieldError_1uchw_269`,formActions:`_formActions_1uchw_276`,dialogWidth:`_dialogWidth_1uchw_283`,laneChip:`_laneChip_1uchw_289`,sheetAction:`_sheetAction_1uchw_295`};export{N as S,g as _,I as a,A as b,D as c,_ as d,O as f,y as g,d as h,S as i,p as l,R as m,P as n,L as o,b as p,s as r,j as s,z as t,f as u,h as v,k as x,C as y};
2
- //# sourceMappingURL=cloud.module-ascz58c3.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"cloud.module-ascz58c3.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/cloud/cloud-model.ts","../../../../../../src/web-ui/routes/verse/cloud/cloud.module.css"],"sourcesContent":["/**\n * routes/verse/cloud/cloud-model.ts — the cloud lane's words and decisions as\n * pure functions (3.11 unit C3), so the card, the Usage panel, the Fleet chip\n * and the composer action say the same thing and the copy is tested as a\n * table. No React here.\n *\n * Copy rules (DESIGN §13.8, and the cloud contract's own):\n * - spend is ALWAYS an estimate and says so — Claude does not expose the\n * credit balance, so every dollar figure carries \"estimate\" beside it;\n * - server prose (gate reasons, state reasons, report summaries) goes\n * through `tidyProse`, so an ISO instant reads as local time;\n * - times are local and relative (\"started 5m ago\"), never ISO;\n * - a state is always a WORD beside any colour.\n */\nimport {\n CLOUD_PROMPT_MAX_CHARS,\n CLOUD_TERMINAL_STATES,\n DEFAULT_CLOUD_BUDGET,\n type CloudBudgetUpdate,\n type CloudBudgetV1,\n type CloudBudgetView,\n type CloudSeatStatus,\n type CloudTaskState,\n type CloudTaskV1,\n} from '../../../../core/cloud/types.js';\nimport { describeResetAt } from '../../../../core/verse/seat-readiness.js';\nimport type { Tone } from '../../../components/primitives/StatusBadge.js';\nimport type { MeterTone } from '../../../components/primitives/Meter.js';\nimport { tidyProse } from '../autonomy/format.js';\nimport { relativePhrase } from '../context/context-model.js';\nimport { usedPercentText } from '../percent-text.js';\n\n/** The repo a new task targets unless the operator names another (the self-improvement default). */\nexport const CLOUD_DEFAULT_REPO = DEFAULT_CLOUD_BUDGET.selfImprove.repo;\n\n/** Same rule the service enforces (core/cloud/service.ts), checked here so the dialog can say so first. */\nexport const CLOUD_REPO_PATTERN = /^[A-Za-z0-9-]+\\/[A-Za-z0-9._-]+$/;\n\n/**\n * A branch name git would accept, conservatively: no spaces or control\n * characters, no `..`, no leading `-` or `/`, no trailing `/` or `.lock`.\n * The server re-checks it against origin; this only catches typing slips.\n */\nconst BRANCH_CHARS = /^[A-Za-z0-9._/+-]{1,200}$/;\nexport function isBranchName(value: string): boolean {\n if (!BRANCH_CHARS.test(value)) return false;\n if (value.startsWith('-') || value.startsWith('/') || value.endsWith('/') || value.endsWith('.') || value.endsWith('.lock')) return false;\n return !value.includes('..') && !value.includes('//');\n}\n\n/** Only these hosts become links: the ids came from a CLI's stdout and gh's JSON. */\nexport function safeHref(url: string | null | undefined, host: 'claude.ai' | 'github.com'): string | null {\n if (typeof url !== 'string' || url.length > 2_048) return null;\n try {\n const parsed = new URL(url);\n return parsed.protocol === 'https:' && parsed.hostname === host ? parsed.toString() : null;\n } catch {\n return null;\n }\n}\n\n// ---------------------------------------------------------------------------\n// Money and the credits meter\n// ---------------------------------------------------------------------------\n\n/** \"$250\", \"$12.50\" — whole dollars stay whole; never \"-$0\". */\nexport function formatDollars(value: number): string {\n if (!Number.isFinite(value)) return '—';\n const v = Math.abs(value) < 0.005 ? 0 : value;\n const text = Number.isInteger(v) ? String(Math.abs(v)) : Math.abs(v).toFixed(2);\n return `${v < 0 ? '−' : ''}$${text}`;\n}\n\nexport interface CreditsMeterView {\n /** Remaining, clamped at 0 for the bar (the text says when it went below). */\n value: number;\n max: number | null;\n /** \"$212 of $250 · estimate\" */\n text: string;\n /** \"15% used\" — the one percent rule. */\n usedText: string;\n tone: MeterTone;\n /** A plain sentence when the estimate is at or under the self-improvement reserve. */\n warning: string | null;\n}\n\nexport function creditsMeter(view: CloudBudgetView): CreditsMeterView {\n const total = view.creditsTotalUsd;\n const remaining = view.estimatedRemainingUsd;\n const reserve = view.budget.selfImprove.reserveUsd;\n const max = total > 0 ? total : null;\n const used = max === null ? null : ((total - Math.max(0, remaining)) / total) * 100;\n const tone: MeterTone = remaining <= 0 ? 'danger' : remaining < reserve ? 'warning' : 'accent';\n const warning = remaining <= 0\n ? 'The estimate says the credits are spent. Check the real balance on claude.ai and adjust the budget.'\n : remaining < reserve\n ? `Under the ${formatDollars(reserve)} reserve, so Verse stops launching self-improvement tasks.`\n : null;\n return {\n value: Math.max(0, remaining),\n max,\n text: `${formatDollars(Math.max(0, remaining))} of ${formatDollars(total)} · estimate`,\n usedText: used === null ? 'no credit total set' : `${usedPercentText(used)} used`,\n tone,\n warning,\n };\n}\n\n/** The next local midnight — when the per-day caps start counting again. */\nexport function nextLocalMidnight(now: number): number {\n const d = new Date(now);\n d.setHours(24, 0, 0, 0);\n return d.getTime();\n}\n\n/** \"3 of 20 sessions today · 1 running\" plus when the daily count resets. */\nexport function sessionsLine(view: CloudBudgetView, now: number = Date.now()): string {\n const reset = describeResetAt(new Date(nextLocalMidnight(now)).toISOString(), now);\n const running = view.running === 1 ? '1 running' : `${view.running} running`;\n return `${view.sessionsToday} of ${view.budget.maxSessionsPerDay} sessions today · ${running}${reset ? ` · resets ${reset}` : ''}`;\n}\n\nexport function selfImproveLine(view: CloudBudgetView): string {\n const si = view.budget.selfImprove;\n if (!si.enabled) return 'Self-improvement is off. Verse launches cloud tasks only when you ask.';\n return `${view.selfImproveToday} of ${si.maxPerDay} self-improvement launches today, on ${si.repo}. Stops under a ${formatDollars(si.reserveUsd)} estimated balance.`;\n}\n\n/** A gate's reason, fit to print (null when the gate is open). */\nexport function gateText(gate: { ok: boolean; reason: string | null }, fallback: string): string | null {\n if (gate.ok) return null;\n return gate.reason ? tidyProse(gate.reason) : fallback;\n}\n\nexport const SEAT_NOT_READY = \"The Claude seat isn't set up on this Mac.\";\n\nexport function seatText(seat: CloudSeatStatus): string | null {\n if (seat.ready) return null;\n return seat.reason ? tidyProse(seat.reason) : SEAT_NOT_READY;\n}\n\n/**\n * Why a launch button is disabled right now, or null when it may be pressed.\n * Seat first (nothing launches without it), then the budget gate.\n */\nexport function launchBlock(seat: CloudSeatStatus, budget: CloudBudgetView): string | null {\n return seatText(seat) ?? gateText(budget.canLaunch, 'The cloud budget does not allow another launch right now.');\n}\n\n// ---------------------------------------------------------------------------\n// Tasks\n// ---------------------------------------------------------------------------\n\nexport const STATE_WORD: Record<CloudTaskState, string> = {\n queued: 'Queued',\n launching: 'Launching',\n running: 'Running',\n 'pr-open': 'PR open',\n merged: 'Merged',\n closed: 'Closed',\n failed: 'Failed',\n expired: 'Expired',\n};\n\nexport const STATE_TONE: Record<CloudTaskState, Tone> = {\n queued: 'info',\n launching: 'info',\n running: 'running',\n 'pr-open': 'warning',\n merged: 'success',\n closed: 'neutral',\n failed: 'danger',\n expired: 'unknown',\n};\n\n/** A draft PR reads \"Draft PR\", not \"PR open\": the session may still be pushing. */\nexport function stateWord(task: Pick<CloudTaskV1, 'state' | 'pr'>): string {\n if (task.state === 'pr-open' && task.pr?.draft) return 'Draft PR';\n return STATE_WORD[task.state] ?? task.state;\n}\n\nexport function isTerminal(state: CloudTaskState): boolean {\n return CLOUD_TERMINAL_STATES.includes(state);\n}\n\n/** In flight: counted by the Fleet chip and the \"running\" line. */\nexport function isInFlight(state: CloudTaskState): boolean {\n return state === 'queued' || state === 'launching' || state === 'running';\n}\n\nconst DAY_MS = 24 * 60 * 60 * 1000;\n/** How many tasks the card lists before \"N more on GitHub\". */\nexport const CARD_TASK_LIMIT = 6;\n\n/**\n * What the card lists: everything still moving or waiting on review, then\n * anything that ended in the last 24 h (a failure you have not seen yet),\n * newest first. Older finished tasks live in `ashlr cloud list --all`.\n */\nexport function cardTasks(tasks: readonly CloudTaskV1[], now: number = Date.now()): { shown: CloudTaskV1[]; hidden: number } {\n const recent = (t: CloudTaskV1) => {\n const at = Date.parse(t.updatedAt);\n return Number.isFinite(at) && now - at < DAY_MS;\n };\n const listed = tasks\n .filter((t) => !isTerminal(t.state) || recent(t))\n .sort((a, b) => (Date.parse(b.createdAt) || 0) - (Date.parse(a.createdAt) || 0));\n return { shown: listed.slice(0, CARD_TASK_LIMIT), hidden: Math.max(0, listed.length - CARD_TASK_LIMIT) };\n}\n\nexport function inFlightCount(tasks: readonly CloudTaskV1[]): number {\n return tasks.filter((t) => isInFlight(t.state)).length;\n}\n\n/** \"ashlrai/ashlr-hub from master · started 5m ago\" */\nexport function taskMeta(task: CloudTaskV1, now: number = Date.now()): string {\n const when = task.state === 'queued' || task.state === 'launching' ? task.createdAt : task.launchedAt ?? task.createdAt;\n const phrase = relativePhrase(when, now);\n const verb = task.state === 'queued' ? 'queued' : task.state === 'failed' ? 'tried' : 'started';\n return `${task.repo} from ${task.baseBranch}${phrase ? ` · ${verb} ${phrase}` : ''}`;\n}\n\n/** The one line under a task's title: the report for a PR, else the state's reason. */\nexport function taskDetail(task: CloudTaskV1, now: number = Date.now()): string | null {\n if (task.report?.summary && (task.state === 'pr-open' || task.state === 'merged')) return tidyProse(task.report.summary, now);\n return task.stateReason ? tidyProse(task.stateReason, now) : null;\n}\n\n/** Dismiss is offered for anything Verse is still tracking; merged and closed tasks are already done. */\nexport function canDismiss(task: Pick<CloudTaskV1, 'state'>): boolean {\n return task.state !== 'merged' && task.state !== 'closed';\n}\n\n// ---------------------------------------------------------------------------\n// The launch form\n// ---------------------------------------------------------------------------\n\nexport interface LaunchDraft {\n repo: string;\n baseBranch: string;\n prompt: string;\n}\n\nexport type LaunchErrors = Partial<Record<keyof LaunchDraft, string>>;\n\nexport type LaunchValidation =\n | { ok: true; request: { repo: string; baseBranch?: string; prompt: string } }\n | { ok: false; errors: LaunchErrors };\n\nconst COUNT = new Intl.NumberFormat('en-US');\n\nexport function validateLaunch(draft: LaunchDraft): LaunchValidation {\n const errors: LaunchErrors = {};\n const repo = draft.repo.trim();\n const base = draft.baseBranch.trim();\n const prompt = draft.prompt.trim();\n if (!repo) errors.repo = 'Enter the GitHub repository as owner/name.';\n else if (!CLOUD_REPO_PATTERN.test(repo)) errors.repo = 'Use the GitHub owner/name form, like ashlrai/ashlr-hub.';\n if (base && !isBranchName(base)) errors.baseBranch = \"That isn't a branch name git accepts.\";\n if (!prompt) errors.prompt = 'Describe the task for the cloud session.';\n else if (prompt.length > CLOUD_PROMPT_MAX_CHARS) {\n errors.prompt = `The task is ${COUNT.format(prompt.length)} characters; the limit is ${COUNT.format(CLOUD_PROMPT_MAX_CHARS)}.`;\n }\n if (Object.keys(errors).length > 0) return { ok: false, errors };\n return { ok: true, request: { repo, ...(base ? { baseBranch: base } : {}), prompt } };\n}\n\n// ---------------------------------------------------------------------------\n// The budget form (Edit budget popover and the Usage panel share it)\n// ---------------------------------------------------------------------------\n\nexport interface BudgetForm {\n total: string;\n spent: string;\n perSession: string;\n maxPerDay: string;\n maxConcurrent: string;\n selfImprove: boolean;\n selfImproveMax: string;\n reserve: string;\n}\n\nexport type BudgetFormField = Exclude<keyof BudgetForm, 'selfImprove'>;\nexport type BudgetErrors = Partial<Record<BudgetFormField, string>>;\n\n/** Field → label and bounds. Bounds are the form's sanity check; the server clamps as well. */\nexport const BUDGET_FIELDS: ReadonlyArray<{\n field: BudgetFormField;\n label: string;\n hint: string;\n money: boolean;\n integer: boolean;\n min: number;\n max: number;\n}> = [\n { field: 'total', label: 'Credits on the account', hint: 'What claude.ai says you have.', money: true, integer: false, min: 0, max: 100_000 },\n { field: 'spent', label: 'Already spent', hint: 'Spent before Verse tracked it, or a correction after checking.', money: true, integer: false, min: -100_000, max: 100_000 },\n { field: 'perSession', label: 'Estimate per session', hint: 'Flat cost Verse counts for each launch.', money: true, integer: false, min: 0.01, max: 1_000 },\n { field: 'maxPerDay', label: 'Sessions per day', hint: 'From every origin, counted per local day.', money: false, integer: true, min: 0, max: 500 },\n { field: 'maxConcurrent', label: 'Running at once', hint: 'Launching or running together.', money: false, integer: true, min: 1, max: 50 },\n { field: 'selfImproveMax', label: 'Self-improvement per day', hint: 'Launches Verse may make on its own.', money: false, integer: true, min: 0, max: 100 },\n { field: 'reserve', label: 'Reserve', hint: 'Self-improvement stops under this estimated balance.', money: true, integer: false, min: 0, max: 100_000 },\n];\n\nfunction numText(n: number): string {\n return Number.isInteger(n) ? String(n) : String(Math.round(n * 100) / 100);\n}\n\nexport function budgetFormFrom(b: CloudBudgetV1): BudgetForm {\n return {\n total: numText(b.creditsTotalUsd),\n spent: numText(b.creditsSpentAdjustmentUsd),\n perSession: numText(b.estimatedCostPerSessionUsd),\n maxPerDay: numText(b.maxSessionsPerDay),\n maxConcurrent: numText(b.maxConcurrent),\n selfImprove: b.selfImprove.enabled,\n selfImproveMax: numText(b.selfImprove.maxPerDay),\n reserve: numText(b.selfImprove.reserveUsd),\n };\n}\n\nexport type BudgetPatch = { ok: true; update: CloudBudgetUpdate; changed: boolean } | { ok: false; errors: BudgetErrors };\n\n/**\n * The form as ONE update carrying only what changed — so two people editing\n * different fields never overwrite each other's numbers with stale ones.\n */\nexport function budgetPatch(form: BudgetForm, current: CloudBudgetV1): BudgetPatch {\n const errors: BudgetErrors = {};\n const values: Partial<Record<BudgetFormField, number>> = {};\n for (const spec of BUDGET_FIELDS) {\n const raw = form[spec.field].trim().replace(/^\\$/, '');\n const n = raw === '' ? Number.NaN : Number(raw);\n if (!Number.isFinite(n)) errors[spec.field] = 'Enter a number.';\n else if (spec.integer && !Number.isInteger(n)) errors[spec.field] = 'Enter a whole number.';\n else if (n < spec.min || n > spec.max) {\n errors[spec.field] = spec.money\n ? `Between ${formatDollars(spec.min)} and ${formatDollars(spec.max)}.`\n : `Between ${COUNT.format(spec.min)} and ${COUNT.format(spec.max)}.`;\n } else values[spec.field] = n;\n }\n if (Object.keys(errors).length > 0) return { ok: false, errors };\n const update: CloudBudgetUpdate = {};\n const same = (a: number, b: number) => Math.abs(a - b) < 0.005;\n if (!same(values.total!, current.creditsTotalUsd)) update.creditsTotalUsd = values.total!;\n if (!same(values.spent!, current.creditsSpentAdjustmentUsd)) update.creditsSpentAdjustmentUsd = values.spent!;\n if (!same(values.perSession!, current.estimatedCostPerSessionUsd)) update.estimatedCostPerSessionUsd = values.perSession!;\n if (!same(values.maxPerDay!, current.maxSessionsPerDay)) update.maxSessionsPerDay = values.maxPerDay!;\n if (!same(values.maxConcurrent!, current.maxConcurrent)) update.maxConcurrent = values.maxConcurrent!;\n const selfImprove: NonNullable<CloudBudgetUpdate['selfImprove']> = {};\n if (form.selfImprove !== current.selfImprove.enabled) selfImprove.enabled = form.selfImprove;\n if (!same(values.selfImproveMax!, current.selfImprove.maxPerDay)) selfImprove.maxPerDay = values.selfImproveMax!;\n if (!same(values.reserve!, current.selfImprove.reserveUsd)) selfImprove.reserveUsd = values.reserve!;\n if (Object.keys(selfImprove).length > 0) update.selfImprove = selfImprove;\n return { ok: true, update, changed: Object.keys(update).length > 0 };\n}\n\n// ---------------------------------------------------------------------------\n// The composer's \"Run in cloud\"\n// ---------------------------------------------------------------------------\n\nexport interface RunInCloudInputs {\n /** The cloud overview, or null when the route did not answer. */\n overview: { seat: CloudSeatStatus; budget: CloudBudgetView } | null;\n /** Why the overview is missing, when it is. */\n overviewReason: string | null;\n /** The chat project's GitHub `owner/name`, or null when it has none. */\n repo: string | null;\n /** True while the chat's roots have not been read yet. */\n rootsLoading: boolean;\n prompt: string;\n}\n\n/** Null when \"Run in cloud\" may be pressed; otherwise the tooltip saying why not. */\nexport function runInCloudBlock(inputs: RunInCloudInputs): string | null {\n if (!inputs.overview) return inputs.overviewReason ?? 'The cloud lane did not answer.';\n const seat = seatText(inputs.overview.seat);\n if (seat) return seat;\n if (!inputs.repo) {\n return inputs.rootsLoading\n ? \"Reading this chat's project…\"\n : \"This chat's project has no GitHub origin, so a cloud session has nothing to clone.\";\n }\n const gate = gateText(inputs.overview.budget.canLaunch, 'The cloud budget does not allow another launch right now.');\n if (gate) return gate;\n if (!inputs.prompt.trim()) return 'Type the task in the message box first.';\n if (inputs.prompt.trim().length > CLOUD_PROMPT_MAX_CHARS) {\n return `The message is over ${COUNT.format(CLOUD_PROMPT_MAX_CHARS)} characters — trim it to run it in the cloud.`;\n }\n return null;\n}\n","/*\n * routes/verse/cloud/cloud.module.css — the cloud lane's card, dialog,\n * popover, Usage panel, Fleet chip and composer action (3.11 unit C3).\n * Tokens only (style-scan-310): no raw hex colour, no px font size, and\n * every colour follows the theme. Nothing is ellipsized: long titles and\n * reasons wrap at word boundaries (only an unbreakable run, like a URL, may\n * break inside itself).\n */\n\n.body {\n display: flex;\n flex-direction: column;\n gap: var(--space-3);\n min-width: 0;\n}\n\n.actionsRow {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2);\n}\n\n.headActions {\n position: relative;\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n}\n\n.meterBlock {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n}\n\n.estimateNote,\n.muted {\n margin: 0;\n color: var(--text-tertiary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n overflow-wrap: break-word;\n}\n\n.facts {\n margin: 0;\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n overflow-wrap: break-word;\n}\n\n.link {\n color: var(--text-link);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n text-decoration: none;\n white-space: nowrap;\n}\n\n.link:hover {\n text-decoration: underline;\n}\n\n.link:focus-visible,\n.linkButton:focus-visible {\n outline: 2px solid var(--border-focus);\n outline-offset: 2px;\n}\n\n.linkButton {\n padding: 0;\n border: 0;\n background: none;\n color: var(--text-link);\n font: inherit;\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n cursor: pointer;\n white-space: nowrap;\n}\n\n.linkButton:hover {\n text-decoration: underline;\n}\n\n.linkButton:disabled {\n color: var(--text-disabled);\n cursor: default;\n text-decoration: none;\n}\n\n.toggleRow {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-2) var(--space-3);\n}\n\n.toggleText {\n flex: 1 1 16rem;\n min-width: 0;\n}\n\n/* ---- tasks ------------------------------------------------------------ */\n\n.tasks {\n display: flex;\n flex-direction: column;\n margin: 0;\n padding: 0;\n list-style: none;\n}\n\n.task {\n display: grid;\n grid-template-columns: auto minmax(0, 1fr);\n gap: var(--space-1) var(--space-3);\n padding: var(--space-2) 0;\n border-top: 1px solid var(--border-subtle);\n}\n\n.task:first-child {\n border-top: 0;\n}\n\n.taskChip {\n padding-top: 1px;\n}\n\n.taskMain {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n min-width: 0;\n}\n\n.taskTitle {\n margin: 0;\n color: var(--text-primary);\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n font-weight: var(--font-weight-medium);\n overflow-wrap: break-word;\n}\n\n.taskLinks {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: var(--space-1) var(--space-3);\n}\n\n/* ---- notices (the NoticeSlot tones, inside a card) --------------------- */\n\n.notice {\n margin: 0;\n padding: var(--space-2) var(--space-3);\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-md);\n background: var(--bg-surface-raised);\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n overflow-wrap: break-word;\n}\n\n.notice[data-tone='warning'] {\n border-color: var(--status-warning-solid);\n background: var(--status-warning-bg);\n color: var(--status-warning-fg);\n}\n\n.notice[data-tone='danger'] {\n border-color: var(--status-danger-solid);\n background: var(--status-danger-bg);\n color: var(--status-danger-fg);\n}\n\n.notice[data-tone='success'] {\n border-color: var(--status-success-solid);\n background: var(--status-success-bg);\n color: var(--status-success-fg);\n}\n\n.noticeRow {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n justify-content: space-between;\n gap: var(--space-1) var(--space-3);\n}\n\n/* ---- the Edit budget popover ------------------------------------------ */\n\n.popover {\n position: absolute;\n top: calc(100% + var(--space-2));\n right: 0;\n z-index: var(--z-dropdown);\n width: min(26rem, calc(100vw - var(--space-8)));\n max-height: min(34rem, 70vh);\n overflow-y: auto;\n padding: var(--space-4);\n border: 1px solid var(--border-default);\n border-radius: var(--radius-lg);\n background: var(--bg-surface-raised);\n box-shadow: var(--shadow-menu);\n}\n\n.popoverTitle {\n margin: 0 0 var(--space-3);\n color: var(--text-primary);\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n font-weight: var(--font-weight-semibold);\n}\n\n/* ---- forms (launch dialog, budget) ------------------------------------ */\n\n.form {\n display: flex;\n flex-direction: column;\n gap: var(--space-3);\n}\n\n.fieldGrid {\n display: grid;\n grid-template-columns: repeat(auto-fill, minmax(11rem, 1fr));\n gap: var(--space-3);\n}\n\n.textareaField {\n display: flex;\n flex-direction: column;\n gap: var(--space-1);\n}\n\n.label {\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n font-weight: var(--font-weight-medium);\n}\n\n.textarea {\n min-height: 8rem;\n padding: var(--space-2) var(--space-3);\n border: 1px solid var(--border-default);\n border-radius: var(--radius-md);\n background: var(--bg-input);\n color: var(--text-primary);\n font: inherit;\n font-size: var(--text-sm-size);\n line-height: var(--text-sm-line);\n resize: vertical;\n}\n\n.textarea:focus-visible {\n outline: 2px solid var(--border-focus);\n outline-offset: 0;\n}\n\n.textarea[aria-invalid='true'] {\n border-color: var(--status-danger-solid);\n}\n\n.fieldError {\n margin: 0;\n color: var(--status-danger-fg);\n font-size: var(--text-xs-size);\n line-height: var(--text-xs-line);\n}\n\n.formActions {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: var(--space-2);\n}\n\n.dialogWidth {\n width: min(34rem, calc(100vw - var(--space-8)));\n}\n\n/* ---- the Fleet chip ---------------------------------------------------- */\n\n.laneChip[data-active='true'] {\n border-color: var(--status-running-solid);\n}\n\n/* ---- the composer's \"Run in cloud\" ------------------------------------- */\n\n.sheetAction {\n display: flex;\n flex-direction: column;\n gap: var(--space-2);\n padding-top: var(--space-3);\n border-top: 1px solid var(--border-subtle);\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{a as e,s as t}from"./index-BVxOlseC.js";var n=t(e(),1),r=new Map,i=null,a=4e3;function o(e){if(!i||i.id!==e)return;if(Date.now()>i.until){i=null;return}let{invocation:t}=i;i=null,queueMicrotask(()=>{c(e,t)})}function s(e,t){let n=r.get(e)??[];return n.push(t),r.set(e,n),o(e),()=>{let n=r.get(e);if(!n)return;let i=n.lastIndexOf(t);i>=0&&n.splice(i,1),n.length===0&&r.delete(e)}}function c(e,t={}){let n=r.get(e);if(!n)return!1;for(let r of[...n].reverse())try{if(r(t)!==!1)return!0}catch(t){return console.error(`[verse] command ${e} failed`,t),!0}return!1}function l(e,t={},n=a){return c(e,t)?!0:(i={id:e,invocation:t,until:Date.now()+n},!1)}function u(e,t,r=!0){let i=(0,n.useRef)(t);i.current=t,(0,n.useEffect)(()=>{if(r)return s(e,e=>i.current(e))},[e,r])}export{u as a,l as i,s as n,c as r,a as t};
2
- //# sourceMappingURL=command-bus-xYZoK9nQ.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"command-bus-xYZoK9nQ.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/command-bus.ts"],"sourcesContent":["/**\n * routes/verse/shell/command-bus.ts — how a catalog command reaches the unit\n * that owns its behaviour (unit C1; the keys and titles are C0's\n * command-catalog.ts).\n *\n * The catalog is one table; the behaviour behind it is spread over units:\n * the shell runs the global commands, the chat (C2) runs `dock.*` and\n * `chat.*`, the composer (C3) runs `composer.*`. The palette, the desktop\n * menu bridge and the shell's key handler all call `runCommand(id)`; the\n * owning unit registers a handler for the ids it serves:\n *\n * useCommandHandler('dock.terminal', () => openDockPane('terminal'));\n *\n * A handler may return `false` to decline (e.g. a composer command with no\n * chat open), and the most recently registered handler for an id is asked\n * first — a mounted chat outranks nothing, a focused one outranks a hidden\n * one because it registers last.\n *\n * DELIVERY LATER. A chat command run from another surface (⌘K \"Terminal\"\n * while on Fleet) has no handler until Chat mounts. The shell switches to\n * Chat and parks the command with `runCommandWhenReady`; the first handler to\n * register for that id within the window receives it. Parked commands expire\n * — a command that runs 20 s after the operator asked for it is a surprise,\n * not a feature.\n *\n * Framework-free except the one hook at the bottom.\n */\nimport { useEffect, useRef } from 'react';\n\n/** What a palette argument (Tab) filled in, or what a caller passes along. */\nexport interface CommandArgument {\n kind: 'seat' | 'project' | 'section' | 'session';\n id: string;\n label: string;\n}\n\nexport interface CommandInvocation {\n argument?: CommandArgument;\n /** Where it came from — handlers may word a toast differently for a key press. */\n via?: 'palette' | 'key' | 'menu' | 'button';\n}\n\n/** Return false to decline (the next handler is asked); anything else = handled. */\nexport type CommandHandler = (invocation: CommandInvocation) => void | boolean;\n\nconst handlers = new Map<string, CommandHandler[]>();\n\ninterface Parked {\n id: string;\n invocation: CommandInvocation;\n until: number;\n}\n\nlet parked: Parked | null = null;\n\nexport const PARKED_COMMAND_TTL_MS = 4_000;\n\nfunction deliverParked(id: string): void {\n if (!parked || parked.id !== id) return;\n if (Date.now() > parked.until) {\n parked = null;\n return;\n }\n const { invocation } = parked;\n parked = null;\n // After the registering effect has finished: the handler's own component\n // is mounted, but its sibling effects may not have run yet.\n queueMicrotask(() => {\n runCommand(id, invocation);\n });\n}\n\n/** Register `handler` for command `id`. Returns the unregister function. */\nexport function registerCommandHandler(id: string, handler: CommandHandler): () => void {\n const list = handlers.get(id) ?? [];\n list.push(handler);\n handlers.set(id, list);\n deliverParked(id);\n return () => {\n const current = handlers.get(id);\n if (!current) return;\n const index = current.lastIndexOf(handler);\n if (index >= 0) current.splice(index, 1);\n if (current.length === 0) handlers.delete(id);\n };\n}\n\nexport function hasCommandHandler(id: string): boolean {\n return (handlers.get(id)?.length ?? 0) > 0;\n}\n\n/** Run `id` now. True when a handler took it. */\nexport function runCommand(id: string, invocation: CommandInvocation = {}): boolean {\n const list = handlers.get(id);\n if (!list) return false;\n for (const handler of [...list].reverse()) {\n try {\n if (handler(invocation) !== false) return true;\n } catch (err) {\n // A broken handler must not take the palette or the key handler down.\n console.error(`[verse] command ${id} failed`, err);\n return true;\n }\n }\n return false;\n}\n\n/** Run `id` now if someone serves it, else hold it for the next handler to register (within the TTL). */\nexport function runCommandWhenReady(id: string, invocation: CommandInvocation = {}, ttlMs: number = PARKED_COMMAND_TTL_MS): boolean {\n if (runCommand(id, invocation)) return true;\n parked = { id, invocation, until: Date.now() + ttlMs };\n return false;\n}\n\n/** Test hygiene. */\nexport function resetCommandBus(): void {\n handlers.clear();\n parked = null;\n}\n\n/**\n * Serve command `id` while mounted (and `enabled`). The latest `handler` is\n * always the one called, so an inline closure does not re-register each render.\n */\nexport function useCommandHandler(id: string, handler: CommandHandler, enabled = true): void {\n const ref = useRef(handler);\n ref.current = handler;\n useEffect(() => {\n if (!enabled) return;\n return registerCommandHandler(id, (invocation) => ref.current(invocation));\n }, [id, enabled]);\n}\n"],"mappings":"8DA6CM,EAAW,IAAI,IAQjB,EAAwB,KAEf,EAAwB,IAErC,SAAS,EAAc,EAAkB,CACvC,GAAI,CAAC,GAAU,EAAO,KAAO,EAAI,OACjC,GAAI,KAAK,IAAI,EAAI,EAAO,MAAO,CAC7B,EAAS,KACT,MACF,CACA,GAAM,CAAE,cAAe,EACvB,EAAS,KAGT,mBAAqB,CACnB,EAAW,EAAI,CAAU,CAC3B,CAAC,CACH,CAGA,SAAgB,EAAuB,EAAY,EAAqC,CACtF,IAAM,EAAO,EAAS,IAAI,CAAE,GAAK,CAAC,EAIlC,OAHA,EAAK,KAAK,CAAO,EACjB,EAAS,IAAI,EAAI,CAAI,EACrB,EAAc,CAAE,MACH,CACX,IAAM,EAAU,EAAS,IAAI,CAAE,EAC/B,GAAI,CAAC,EAAS,OACd,IAAM,EAAQ,EAAQ,YAAY,CAAO,EACrC,GAAS,GAAG,EAAQ,OAAO,EAAO,CAAC,EACnC,EAAQ,SAAW,GAAG,EAAS,OAAO,CAAE,CAC9C,CACF,CAOA,SAAgB,EAAW,EAAY,EAAgC,CAAC,EAAY,CAClF,IAAM,EAAO,EAAS,IAAI,CAAE,EAC5B,GAAI,CAAC,EAAM,MAAO,GAClB,IAAK,IAAM,IAAW,CAAC,GAAG,CAAI,CAAC,CAAC,QAAQ,EACtC,GAAI,CACF,GAAI,EAAQ,CAAU,IAAM,GAAO,MAAO,EAC5C,OAAS,EAAK,CAGZ,OADA,QAAQ,MAAM,mBAAmB,EAAG,SAAU,CAAG,EAC1C,EACT,CAEF,MAAO,EACT,CAGA,SAAgB,EAAoB,EAAY,EAAgC,CAAC,EAAG,EAAgB,EAAgC,CAGlI,OAFI,EAAW,EAAI,CAAU,EAAU,IACvC,EAAS,CAAE,KAAI,aAAY,MAAO,KAAK,IAAI,EAAI,CAAM,EAC9C,GACT,CAYA,SAAgB,EAAkB,EAAY,EAAyB,EAAU,GAAY,CAC3F,IAAM,GAAA,EAAM,EAAA,OAAA,CAAO,CAAO,EAC1B,EAAI,QAAU,GACd,EAAA,EAAA,UAAA,KAAgB,CACT,KACL,OAAO,EAAuB,EAAK,GAAe,EAAI,QAAQ,CAAU,CAAC,CAC3E,EAAG,CAAC,EAAI,CAAO,CAAC,CAClB"}
@@ -1,2 +0,0 @@
1
- var e=`ashlr:command`,t={"open-settings":`section.settings`,"toggle-theme":`appearance.toggle-theme`,"open-needs-you":`needs-you.open`,"new-chat":`chat.new`,"focus-composer":`app.summon`},n=/^open-session:([A-Za-z0-9._-]{1,128})$/;function r(e){if(typeof e!=`string`)return null;if(Object.prototype.hasOwnProperty.call(t,e)){let n=e;return{kind:`command`,name:n,commandId:t[n]}}let r=n.exec(e);return r?{kind:`open-session`,sessionId:r[1]}:null}var i=[{id:`needs-you`,label:`Needs you`},{id:`chats`,label:`Chats`},{id:`actions`,label:`Actions`},{id:`go-to`,label:`Go to`},{id:`seats-apps`,label:`Seats & Apps`},{id:`projects`,label:`Projects`}],a={">":`actions`,"#":`chats`},o=[`Surfaces`,`Navigation`,`Chat`,`Dock`,`Composer`,`Needs you`,`Charts`,`App`],s={confirm:{title:`Stop every running chat?`,body:`Each running turn is cancelled. Queued follow-ups are held, not sent.`,confirmLabel:`Stop chats`,destructive:!0},token:!0},c={confirm:{title:`Stop the fleet?`,body:`Autonomous work halts within one tick and stays stopped until you resume it. Chats keep running.`,confirmLabel:`Stop fleet`,destructive:!0},token:!0},l=(e,t,n)=>({id:`surface.${t}`,title:`Go to ${n}`,scope:`global`,keys:[{key:String(e),mod:!0}],group:`go-to`,section:`Surfaces`,keywords:[n.toLowerCase()]}),u=[l(1,`command`,`Command`),l(2,`fleet`,`Fleet`),l(3,`growth`,`Growth`),l(4,`mind`,`Mind`),l(5,`chat`,`Chat`),{id:`section.settings`,title:`Open Settings`,scope:`global`,keys:[{key:`,`,mod:!0}],group:`go-to`,section:`Surfaces`,keywords:[`preferences`,`appearance`],native:{kind:`menu`,desktopCommand:`open-settings`,accelerator:`CmdOrCtrl+,`}},{id:`section.apps`,title:`Open Apps & Accounts`,scope:`global`,keys:[],group:`go-to`,section:`Surfaces`,keywords:[`mcp`,`accounts`,`seats`,`integrations`,`ollama`]},{id:`section.usage`,title:`Open Usage`,scope:`global`,keys:[],group:`go-to`,section:`Surfaces`,keywords:[`capacity`,`spend`,`limits`]},{id:`palette.open`,title:`Command palette`,scope:`global`,keys:[{key:`k`,mod:!0}],group:null,section:`Navigation`},{id:`needs-you.open`,title:`Open Needs you`,scope:`global`,keys:[{key:`j`,mod:!0}],group:`actions`,section:`Navigation`,keywords:[`approvals`,`inbox`,`triage`]},{id:`shortcuts.open`,title:`Keyboard shortcuts`,scope:`global`,keys:[{key:`/`,mod:!0}],group:`actions`,section:`Navigation`,keywords:[`keys`,`help`]},{id:`resources.toggle`,title:`Show resources`,scope:`global`,keys:[{key:`.`,mod:!0}],group:`actions`,section:`Navigation`,keywords:[`accounts`,`seats`,`capacity`,`credits`,`cloud`,`local models`]},{id:`resources.bar.toggle`,title:`Show or hide the resource bar`,scope:`global`,keys:[],group:`actions`,section:`Navigation`,keywords:[`battery`,`usage bars`,`accounts`,`capacity`,`rail`,`resources`]},{id:`history.back`,title:`Back`,scope:`global`,keys:[{key:`[`,mod:!0}],group:null,section:`Navigation`,note:`through surfaces and chats`},{id:`history.forward`,title:`Forward`,scope:`global`,keys:[{key:`]`,mod:!0}],group:null,section:`Navigation`,note:`through surfaces and chats`},{id:`chat.recent-next`,title:`Next recent chat`,scope:`global`,keys:[{key:`tab`,ctrl:!0}],group:null,section:`Navigation`},{id:`chat.recent-prev`,title:`Previous recent chat`,scope:`global`,keys:[{key:`tab`,ctrl:!0,shift:!0}],group:null,section:`Navigation`},{id:`rail.toggle-labels`,title:`Show or hide rail labels`,scope:`global`,keys:[{key:`\\`,mod:!0,shift:!0}],group:`actions`,section:`Navigation`},{id:`chat.new`,title:`New chat`,scope:`global`,keys:[{key:`n`,mod:!0}],group:`actions`,section:`Chat`},{id:`chat.new-on`,title:`New chat on…`,scope:`global`,keys:[],group:`actions`,section:`Chat`,argument:{kind:`seat`,prompt:`Seat`},keywords:[`seat`,`account`,`engine`]},{id:`chat.sidebar`,title:`Show or hide the chat list`,scope:`chat`,keys:[{key:`b`,mod:!0}],group:`actions`,section:`Chat`},{id:`chat.find`,title:`Find in chat`,scope:`chat`,keys:[{key:`f`,mod:!0}],group:`actions`,section:`Chat`,keywords:[`search`]},{id:`chat.turn-prev`,title:`Previous turn`,scope:`chat`,keys:[{key:`arrowup`,alt:!0}],group:null,section:`Chat`},{id:`chat.turn-next`,title:`Next turn`,scope:`chat`,keys:[{key:`arrowdown`,alt:!0}],group:null,section:`Chat`},{id:`chats.stop-all`,title:`Stop running chats…`,scope:`global`,keys:[],group:`actions`,section:`Chat`,guard:s,keywords:[`cancel`,`halt`]},{id:`git.create-pr`,title:`Create pull request…`,scope:`chat`,keys:[],group:`actions`,section:`Chat`,keywords:[`pr`,`github`,`git`,`open pull request`]},{id:`git.merge-pr`,title:`Merge pull request…`,scope:`chat`,keys:[],group:`actions`,section:`Chat`,keywords:[`pr`,`github`,`git`,`land`,`ship`]},{id:`dock.toggle`,title:`Show or hide the dock`,scope:`chat`,keys:[{key:`\\`,mod:!0}],group:`actions`,section:`Dock`},{id:`dock.terminal`,title:`Terminal`,scope:`chat`,keys:[{key:"`",ctrl:!0}],group:`actions`,section:`Dock`,keywords:[`shell`,`console`]},{id:`dock.terminal-new`,title:`New terminal tab`,scope:`chat`,keys:[{key:"`",ctrl:!0,shift:!0}],group:`actions`,section:`Dock`},{id:`dock.preview`,title:`Preview`,scope:`chat`,keys:[{key:`b`,mod:!0,shift:!0}],group:`actions`,section:`Dock`,keywords:[`browser`,`dev server`]},{id:`dock.diff`,title:`Review changes`,scope:`chat`,keys:[{key:`d`,mod:!0,shift:!0}],group:`actions`,section:`Dock`,keywords:[`diff`,`git`]},{id:`composer.permission`,title:`Permission mode…`,scope:`chat`,keys:[{key:`m`,mod:!0,shift:!0}],group:`actions`,section:`Composer`,keywords:[`plan`,`bypass`,`auto`]},{id:`composer.model`,title:`Model…`,scope:`chat`,keys:[{key:`i`,mod:!0,shift:!0}],group:`actions`,section:`Composer`},{id:`composer.effort`,title:`Effort…`,scope:`chat`,keys:[{key:`e`,mod:!0,shift:!0}],group:`actions`,section:`Composer`,keywords:[`reasoning`,`thinking`]},{id:`composer.attach`,title:`Attach files…`,scope:`chat`,keys:[{key:`u`,mod:!0}],group:`actions`,section:`Composer`,keywords:[`upload`,`image`]},{id:`composer.send`,title:`Send`,scope:`composer`,keys:[{key:`enter`}],group:null,section:`Composer`,note:`queues while a turn runs (up to 3)`},{id:`composer.stop-and-send`,title:`Stop and send`,scope:`composer`,keys:[{key:`enter`,mod:!0,shift:!0}],group:null,section:`Composer`},{id:`composer.stop`,title:`Stop the running turn`,scope:`composer`,keys:[{key:`escape`}],group:null,section:`Composer`,note:`only from an empty composer with no overlay open`},{id:`drawer.next`,title:`Next item`,scope:`drawer`,keys:[{key:`j`}],group:null,section:`Needs you`},{id:`drawer.prev`,title:`Previous item`,scope:`drawer`,keys:[{key:`k`}],group:null,section:`Needs you`},{id:`drawer.open`,title:`Open item`,scope:`drawer`,keys:[{key:`enter`}],group:null,section:`Needs you`},{id:`drawer.approve`,title:`Approve`,scope:`drawer`,keys:[{key:`a`}],group:null,section:`Needs you`,note:`confirms, then asks for the token`},{id:`drawer.reject`,title:`Reject`,scope:`drawer`,keys:[{key:`r`}],group:null,section:`Needs you`,note:`confirms, then asks for the token`},{id:`drawer.veto`,title:`Veto`,scope:`drawer`,keys:[{key:`v`}],group:null,section:`Needs you`,note:`confirms, then asks for the token`},{id:`drawer.done`,title:`Mark done`,scope:`drawer`,keys:[{key:`e`}],group:null,section:`Needs you`},{id:`drawer.split-prev`,title:`Previous split`,scope:`drawer`,keys:[{key:`h`}],group:null,section:`Needs you`},{id:`drawer.split-next`,title:`Next split`,scope:`drawer`,keys:[{key:`l`}],group:null,section:`Needs you`},{id:`chart.table`,title:`Show as a table`,scope:`chart`,keys:[{key:`t`}],group:null,section:`Charts`,note:`when a chart card has focus`},{id:`appearance.toggle-theme`,title:`Toggle light / dark`,scope:`global`,keys:[{key:`l`,mod:!0,shift:!0}],group:`actions`,section:`App`,keywords:[`theme`,`dark mode`],native:{kind:`menu`,desktopCommand:`toggle-theme`,accelerator:`Shift+CmdOrCtrl+L`}},{id:`app.summon`,title:`Show Verse and focus the composer`,scope:`global`,keys:[{key:`space`,ctrl:!0,alt:!0}],group:null,section:`App`,note:`system-wide; turn on in Settings ▸ Desktop`,native:{kind:`global-hotkey`,accelerator:`Control+Alt+Space`}},{id:`fleet.stop`,title:`Stop the fleet…`,scope:`global`,keys:[],group:`actions`,section:`App`,guard:c,keywords:[`kill`,`halt`,`autonomy`]}],d=new Map(u.map(e=>[e.id,e]));function f(e){return d.get(e)??null}function p(e){return u.filter(t=>t.group===e)}function m(){let e=u.filter(e=>e.keys.length>0);return o.map(t=>({section:t,commands:e.filter(e=>e.section===t)})).filter(e=>e.commands.length>0)}function h(){if(typeof navigator>`u`)return`mac`;let e=navigator,t=e.userAgentData?.platform??e.platform??``;return/mac|iphone|ipad|ipod/i.test(t)?`mac`:`other`}var g={Backslash:`\\`,Backquote:"`",BracketLeft:`[`,BracketRight:`]`,Slash:`/`,Comma:`,`,Period:`.`,Semicolon:`;`,Quote:`'`,Minus:`-`,Equal:`=`,Space:`space`},_={" ":`space`,spacebar:`space`,esc:`escape`,return:`enter`,up:`arrowup`,down:`arrowdown`,left:`arrowleft`,right:`arrowright`};function v(e){let t=e.key??``;if(/^[a-z]$/i.test(t))return t.toLowerCase();let n=e.code??``;if(/^Digit[0-9]$/.test(n))return n.slice(5);if(g[n])return g[n];if(/^Key[A-Z]$/.test(n))return n.slice(3).toLowerCase();let r=t.toLowerCase();return _[r]??r}function y(e,t,n=h()){if(n===`mac`){if(!!t.mod!==e.metaKey||!!t.ctrl!==e.ctrlKey)return!1}else if(e.metaKey||!!(t.mod||t.ctrl)!==e.ctrlKey)return!1;return!!t.shift!==e.shiftKey||!!t.alt!==e.altKey?!1:v(e)===t.key}function b(e,t,n=h()){for(let r of t)for(let t of u)if(t.scope===r&&t.native?.kind!==`global-hotkey`&&t.keys.some(t=>y(e,t,n)))return t;return null}var x={enter:`↩`,escape:`Esc`,tab:`⇥`,space:`Space`,arrowup:`↑`,arrowdown:`↓`,arrowleft:`←`,arrowright:`→`,backspace:`⌫`},S={enter:`Enter`,escape:`Esc`,tab:`Tab`,space:`Space`,arrowup:`↑`,arrowdown:`↓`,arrowleft:`←`,arrowright:`→`,backspace:`Backspace`};function C(e,t=h()){let n=e.key.length===1?e.key.toUpperCase():(t===`mac`?x:S)[e.key]??e.key;return t===`mac`?`${e.ctrl?`⌃`:``}${e.alt?`⌥`:``}${e.shift?`⇧`:``}${e.mod?`⌘`:``}${n}`:[e.mod||e.ctrl?`Ctrl`:``,e.alt?`Alt`:``,e.shift?`Shift`:``,n].filter(Boolean).join(`+`)}export{h as a,C as c,r as d,m as f,y as i,b as l,a as n,v as o,e as r,f as s,i as t,p as u};
2
- //# sourceMappingURL=command-catalog-Bb_PxC5w.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"command-catalog-Bb_PxC5w.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/shell/command-catalog.ts"],"sourcesContent":["/**\n * routes/verse/shell/command-catalog.ts — every workbench command and its\n * keys, in ONE table (unit C0; SPEC-310C §1).\n *\n * The ⌘K palette (C1), the shortcuts overlay (⌘/), the native menu bridge\n * (C8), the drawer and every surface's key handler read this table; the key\n * test reads it too, which is how \"no two commands share a key\" and \"no key\n * the native menu already owns\" stay true as units add commands. A key that\n * is not here does not exist.\n *\n * Pure data plus pure helpers — no React, no DOM beyond reading a\n * KeyboardEvent-shaped object — so the palette can import it without pulling\n * a surface into its chunk.\n *\n * Adding a command: one entry below (a change request to C0 when another\n * unit needs it). The handler lives with the unit that owns the behaviour and\n * dispatches on the command `id`.\n */\n\n// ===========================================================================\n// Scopes — where a key is live\n// ===========================================================================\n\n/**\n * global anywhere in the workbench (except inside the palette, which\n * owns every key while open, and native text editing keys)\n * chat the Chat surface has focus (transcript, sidebar, dock)\n * composer the composer's text box has focus\n * drawer the Needs-you drawer list has focus (bare letters are safe\n * there: nothing in it takes text)\n * chart a chart card has focus\n */\nexport const COMMAND_SCOPES = ['global', 'chat', 'composer', 'drawer', 'chart'] as const;\nexport type CommandScope = (typeof COMMAND_SCOPES)[number];\n\n/**\n * The scopes live AT THE SAME TIME as each scope (itself included). A key\n * must be unique across every such set — the key test checks exactly this —\n * while two scopes that are never live together (the drawer's bare `Enter`\n * and the composer's) may reuse a key.\n */\nexport const SCOPE_LAYERS: Readonly<Record<CommandScope, readonly CommandScope[]>> = {\n global: ['global'],\n chat: ['chat', 'global'],\n composer: ['composer', 'chat', 'global'],\n drawer: ['drawer', 'global'],\n chart: ['chart', 'global'],\n};\n\n// ===========================================================================\n// Keys\n// ===========================================================================\n\n/**\n * One key chord. `key` is the UNSHIFTED US-layout name: a lowercase letter or\n * digit, a punctuation character, or one of the named keys below. `mod` is ⌘\n * on macOS and Ctrl elsewhere (\"CmdOrCtrl\"); `ctrl` is the literal ⌃ key.\n */\nexport interface KeyChord {\n key: string;\n mod?: true;\n ctrl?: true;\n shift?: true;\n alt?: true;\n}\n\nexport const NAMED_KEYS = ['enter', 'escape', 'tab', 'space', 'arrowup', 'arrowdown', 'arrowleft', 'arrowright', 'backspace'] as const;\n\n/**\n * Keys the page never binds, because macOS or the desktop shell answers them\n * first: the native menu's own accelerators live in app_menu.rs (the key test\n * parses that file), these are the system's.\n */\nexport const SYSTEM_RESERVED_CHORDS: readonly KeyChord[] = [\n { key: 'space', mod: true }, // Spotlight\n { key: 'space', ctrl: true }, // input sources\n { key: 'tab', mod: true }, // app switcher\n { key: 'tab', mod: true, shift: true },\n { key: '`', mod: true }, // cycle this app's windows\n { key: '3', mod: true, shift: true }, // screenshots\n { key: '4', mod: true, shift: true },\n { key: '5', mod: true, shift: true },\n];\n\n/**\n * How a key reaches the page when a native layer is involved.\n * menu the desktop menu owns the accelerator and forwards the\n * command (via `ashlr:desktop-command`); the page's own\n * handler only fires in a plain browser.\n * global-hotkey registered system-wide by the desktop app (C8); the page\n * never binds it — it is listed for the shortcuts overlay.\n */\nexport type NativeBinding =\n | { kind: 'menu'; desktopCommand: DesktopCommandName; accelerator: string }\n | { kind: 'global-hotkey'; accelerator: string };\n\n// ===========================================================================\n// The window event (units that are not on the command bus)\n// ===========================================================================\n\n/**\n * The window event the palette (C1) and the native menu bridge dispatch to\n * run a catalog command on a surface that listens for it instead of\n * registering on the command bus:\n * window.dispatchEvent(new CustomEvent(WORKBENCH_COMMAND_EVENT, { detail: { id } }))\n * The composer (C3) answers the `composer.*` ids it implements.\n *\n * It lives HERE, beside the ids it carries, so the shell (run-command.ts)\n * does not have to import a composer module to name its own event —\n * composer/composer-keys.ts re-exports it for its existing importers.\n */\nexport const WORKBENCH_COMMAND_EVENT = 'ashlr:command';\n\n// ===========================================================================\n// Desktop commands (C8 → page)\n// ===========================================================================\n\n/**\n * What the desktop shell may send the page (`ashlr:desktop-command`), and the\n * catalog command each one runs. C8 dispatches these from the menu bar, the\n * tray, a clicked notification (focus regained within 60 s) and the global\n * hotkey; C1 runs them. `open-session:<id>` carries a session id.\n */\nexport const DESKTOP_COMMAND_NAMES = ['open-settings', 'toggle-theme', 'open-needs-you', 'new-chat', 'focus-composer'] as const;\n// Its own literal list (not `keyof typeof DESKTOP_COMMANDS`): NativeBinding\n// names it, WORKBENCH_COMMANDS uses NativeBinding, and DESKTOP_COMMANDS is\n// typed by CommandId — deriving it from the map would make the types circular.\nexport type DesktopCommandName = (typeof DESKTOP_COMMAND_NAMES)[number];\n\nexport const DESKTOP_COMMANDS: Readonly<Record<DesktopCommandName, CommandId>> = {\n 'open-settings': 'section.settings',\n 'toggle-theme': 'appearance.toggle-theme',\n 'open-needs-you': 'needs-you.open',\n 'new-chat': 'chat.new',\n 'focus-composer': 'app.summon',\n};\n\n/** `open-session:<id>` — the notification for a finished or failed chat. */\nexport const OPEN_SESSION_COMMAND_RE = /^open-session:([A-Za-z0-9._-]{1,128})$/;\n\nexport type ParsedDesktopCommand =\n | { kind: 'command'; name: DesktopCommandName; commandId: CommandId }\n | { kind: 'open-session'; sessionId: string };\n\n/** Parse a raw desktop command string; null for anything unknown (never guessed). */\nexport function parseDesktopCommand(raw: unknown): ParsedDesktopCommand | null {\n if (typeof raw !== 'string') return null;\n if (Object.prototype.hasOwnProperty.call(DESKTOP_COMMANDS, raw)) {\n const name = raw as DesktopCommandName;\n return { kind: 'command', name, commandId: DESKTOP_COMMANDS[name] };\n }\n const session = OPEN_SESSION_COMMAND_RE.exec(raw);\n return session ? { kind: 'open-session', sessionId: session[1]! } : null;\n}\n\n// ===========================================================================\n// The palette\n// ===========================================================================\n\n/** Result groups, in the order the palette shows them (SPEC-310C §1). */\nexport const PALETTE_GROUPS = [\n { id: 'needs-you', label: 'Needs you' },\n { id: 'chats', label: 'Chats' },\n { id: 'actions', label: 'Actions' },\n { id: 'go-to', label: 'Go to' },\n { id: 'seats-apps', label: 'Seats & Apps' },\n { id: 'projects', label: 'Projects' },\n] as const;\nexport type PaletteGroupId = (typeof PALETTE_GROUPS)[number]['id'];\n\n/** A leading `>` limits results to actions; `#` to chats. */\nexport const PALETTE_PREFIXES: Readonly<Record<'>' | '#', PaletteGroupId>> = { '>': 'actions', '#': 'chats' };\n\n/** An empty query shows the last this-many actions run. */\nexport const PALETTE_RECENT_LIMIT = 5;\n\n/** The palette opens in under this (it lives in the shell chunk). */\nexport const PALETTE_OPEN_BUDGET_MS = 50;\n\n// ===========================================================================\n// Commands\n// ===========================================================================\n\nexport type CommandArgumentKind = 'seat' | 'project' | 'section' | 'session';\n\n/**\n * A guarded command asks for confirmation FIRST, then the mutation token\n * (the palette must never be a shortcut around the confirm step its regular\n * UI requires).\n */\nexport interface CommandGuard {\n confirm: { title: string; body: string; confirmLabel: string; destructive: boolean };\n token: boolean;\n}\n\n/** Sections of the shortcuts overlay (⌘/), in display order. */\nexport const SHORTCUT_SECTIONS = ['Surfaces', 'Navigation', 'Chat', 'Dock', 'Composer', 'Needs you', 'Charts', 'App'] as const;\nexport type ShortcutSection = (typeof SHORTCUT_SECTIONS)[number];\n\nexport interface WorkbenchCommand {\n id: string;\n /** Palette / overlay text: a verb phrase, operator language. */\n title: string;\n scope: CommandScope;\n /** Empty = reachable from the palette (or a button) only. */\n keys: readonly KeyChord[];\n /** Where the palette lists it; null = not a palette entry (drawer and chart keys). */\n group: 'actions' | 'go-to' | null;\n section: ShortcutSection;\n keywords?: readonly string[];\n /** Tab fills this argument (\"New chat on…\" → a seat). */\n argument?: { kind: CommandArgumentKind; prompt: string };\n guard?: CommandGuard;\n native?: NativeBinding;\n /** A qualifier the overlay prints under the title. */\n note?: string;\n}\n\nconst STOP_CHATS_GUARD: CommandGuard = {\n confirm: {\n title: 'Stop every running chat?',\n body: 'Each running turn is cancelled. Queued follow-ups are held, not sent.',\n confirmLabel: 'Stop chats',\n destructive: true,\n },\n token: true,\n};\n\nconst STOP_FLEET_GUARD: CommandGuard = {\n confirm: {\n title: 'Stop the fleet?',\n body: 'Autonomous work halts within one tick and stays stopped until you resume it. Chats keep running.',\n confirmLabel: 'Stop fleet',\n destructive: true,\n },\n token: true,\n};\n\nconst surface = (n: 1 | 2 | 3 | 4 | 5, id: string, name: string): WorkbenchCommand => ({\n id: `surface.${id}`,\n title: `Go to ${name}`,\n scope: 'global',\n keys: [{ key: String(n), mod: true }],\n group: 'go-to',\n section: 'Surfaces',\n keywords: [name.toLowerCase()],\n});\n\nexport const WORKBENCH_COMMANDS = [\n // ── Surfaces (⌘1 Command … ⌘5 Chat) and the gear tray ────────────────────\n surface(1, 'command', 'Command'),\n surface(2, 'fleet', 'Fleet'),\n surface(3, 'growth', 'Growth'),\n surface(4, 'mind', 'Mind'),\n surface(5, 'chat', 'Chat'),\n {\n id: 'section.settings',\n title: 'Open Settings',\n scope: 'global',\n keys: [{ key: ',', mod: true }],\n group: 'go-to',\n section: 'Surfaces',\n keywords: ['preferences', 'appearance'],\n native: { kind: 'menu', desktopCommand: 'open-settings', accelerator: 'CmdOrCtrl+,' },\n },\n { id: 'section.apps', title: 'Open Apps & Accounts', scope: 'global', keys: [], group: 'go-to', section: 'Surfaces', keywords: ['mcp', 'accounts', 'seats', 'integrations', 'ollama'] },\n { id: 'section.usage', title: 'Open Usage', scope: 'global', keys: [], group: 'go-to', section: 'Surfaces', keywords: ['capacity', 'spend', 'limits'] },\n\n // ── Navigation ───────────────────────────────────────────────────────────\n { id: 'palette.open', title: 'Command palette', scope: 'global', keys: [{ key: 'k', mod: true }], group: null, section: 'Navigation' },\n { id: 'needs-you.open', title: 'Open Needs you', scope: 'global', keys: [{ key: 'j', mod: true }], group: 'actions', section: 'Navigation', keywords: ['approvals', 'inbox', 'triage'] },\n { id: 'shortcuts.open', title: 'Keyboard shortcuts', scope: 'global', keys: [{ key: '/', mod: true }], group: 'actions', section: 'Navigation', keywords: ['keys', 'help'] },\n // The Resources drawer (3.11 C6): the key toggles it, the palette opens it.\n // ⌘. — not ⇧⌘R, which browsers keep for a hard reload.\n {\n id: 'resources.toggle',\n title: 'Show resources',\n scope: 'global',\n keys: [{ key: '.', mod: true }],\n group: 'actions',\n section: 'Navigation',\n keywords: ['accounts', 'seats', 'capacity', 'credits', 'cloud', 'local models'],\n },\n {\n id: 'resources.bar.toggle',\n title: 'Show or hide the resource bar',\n scope: 'global',\n keys: [],\n group: 'actions',\n section: 'Navigation',\n keywords: ['battery', 'usage bars', 'accounts', 'capacity', 'rail', 'resources'],\n },\n { id: 'history.back', title: 'Back', scope: 'global', keys: [{ key: '[', mod: true }], group: null, section: 'Navigation', note: 'through surfaces and chats' },\n { id: 'history.forward', title: 'Forward', scope: 'global', keys: [{ key: ']', mod: true }], group: null, section: 'Navigation', note: 'through surfaces and chats' },\n { id: 'chat.recent-next', title: 'Next recent chat', scope: 'global', keys: [{ key: 'tab', ctrl: true }], group: null, section: 'Navigation' },\n { id: 'chat.recent-prev', title: 'Previous recent chat', scope: 'global', keys: [{ key: 'tab', ctrl: true, shift: true }], group: null, section: 'Navigation' },\n { id: 'rail.toggle-labels', title: 'Show or hide rail labels', scope: 'global', keys: [{ key: '\\\\', mod: true, shift: true }], group: 'actions', section: 'Navigation' },\n\n // ── Chats ────────────────────────────────────────────────────────────────\n { id: 'chat.new', title: 'New chat', scope: 'global', keys: [{ key: 'n', mod: true }], group: 'actions', section: 'Chat' },\n {\n id: 'chat.new-on',\n title: 'New chat on…',\n scope: 'global',\n keys: [],\n group: 'actions',\n section: 'Chat',\n argument: { kind: 'seat', prompt: 'Seat' },\n keywords: ['seat', 'account', 'engine'],\n },\n { id: 'chat.sidebar', title: 'Show or hide the chat list', scope: 'chat', keys: [{ key: 'b', mod: true }], group: 'actions', section: 'Chat' },\n { id: 'chat.find', title: 'Find in chat', scope: 'chat', keys: [{ key: 'f', mod: true }], group: 'actions', section: 'Chat', keywords: ['search'] },\n { id: 'chat.turn-prev', title: 'Previous turn', scope: 'chat', keys: [{ key: 'arrowup', alt: true }], group: null, section: 'Chat' },\n { id: 'chat.turn-next', title: 'Next turn', scope: 'chat', keys: [{ key: 'arrowdown', alt: true }], group: null, section: 'Chat' },\n { id: 'chats.stop-all', title: 'Stop running chats…', scope: 'global', keys: [], group: 'actions', section: 'Chat', guard: STOP_CHATS_GUARD, keywords: ['cancel', 'halt'] },\n // ── Git (C5's BranchBar serves these) ─────────────────────────────────────\n // Palette-only and unguarded ON PURPOSE: each OPENS BranchBar's own dialog\n // (CreatePrDialog / MergeDialog), which carries the before-click disclosure,\n // and every write inside it still goes through the mutation-token gate —\n // so the palette is never a shortcut around a confirm step. No key: a\n // merge is never one keystroke away. Chat-scoped because the bar lives\n // above the composer; from another surface the shell switches to Chat and\n // parks the command until BranchBar registers (command-bus).\n { id: 'git.create-pr', title: 'Create pull request…', scope: 'chat', keys: [], group: 'actions', section: 'Chat', keywords: ['pr', 'github', 'git', 'open pull request'] },\n { id: 'git.merge-pr', title: 'Merge pull request…', scope: 'chat', keys: [], group: 'actions', section: 'Chat', keywords: ['pr', 'github', 'git', 'land', 'ship'] },\n\n // ── Dock (C2 container; panes from dock-catalog.ts) ───────────────────────\n { id: 'dock.toggle', title: 'Show or hide the dock', scope: 'chat', keys: [{ key: '\\\\', mod: true }], group: 'actions', section: 'Dock' },\n { id: 'dock.terminal', title: 'Terminal', scope: 'chat', keys: [{ key: '`', ctrl: true }], group: 'actions', section: 'Dock', keywords: ['shell', 'console'] },\n { id: 'dock.terminal-new', title: 'New terminal tab', scope: 'chat', keys: [{ key: '`', ctrl: true, shift: true }], group: 'actions', section: 'Dock' },\n { id: 'dock.preview', title: 'Preview', scope: 'chat', keys: [{ key: 'b', mod: true, shift: true }], group: 'actions', section: 'Dock', keywords: ['browser', 'dev server'] },\n { id: 'dock.diff', title: 'Review changes', scope: 'chat', keys: [{ key: 'd', mod: true, shift: true }], group: 'actions', section: 'Dock', keywords: ['diff', 'git'] },\n\n // ── Composer ─────────────────────────────────────────────────────────────\n { id: 'composer.permission', title: 'Permission mode…', scope: 'chat', keys: [{ key: 'm', mod: true, shift: true }], group: 'actions', section: 'Composer', keywords: ['plan', 'bypass', 'auto'] },\n { id: 'composer.model', title: 'Model…', scope: 'chat', keys: [{ key: 'i', mod: true, shift: true }], group: 'actions', section: 'Composer' },\n { id: 'composer.effort', title: 'Effort…', scope: 'chat', keys: [{ key: 'e', mod: true, shift: true }], group: 'actions', section: 'Composer', keywords: ['reasoning', 'thinking'] },\n { id: 'composer.attach', title: 'Attach files…', scope: 'chat', keys: [{ key: 'u', mod: true }], group: 'actions', section: 'Composer', keywords: ['upload', 'image'] },\n { id: 'composer.send', title: 'Send', scope: 'composer', keys: [{ key: 'enter' }], group: null, section: 'Composer', note: 'queues while a turn runs (up to 3)' },\n { id: 'composer.stop-and-send', title: 'Stop and send', scope: 'composer', keys: [{ key: 'enter', mod: true, shift: true }], group: null, section: 'Composer' },\n { id: 'composer.stop', title: 'Stop the running turn', scope: 'composer', keys: [{ key: 'escape' }], group: null, section: 'Composer', note: 'only from an empty composer with no overlay open' },\n\n // ── Needs-you drawer ─────────────────────────────────────────────────────\n { id: 'drawer.next', title: 'Next item', scope: 'drawer', keys: [{ key: 'j' }], group: null, section: 'Needs you' },\n { id: 'drawer.prev', title: 'Previous item', scope: 'drawer', keys: [{ key: 'k' }], group: null, section: 'Needs you' },\n { id: 'drawer.open', title: 'Open item', scope: 'drawer', keys: [{ key: 'enter' }], group: null, section: 'Needs you' },\n { id: 'drawer.approve', title: 'Approve', scope: 'drawer', keys: [{ key: 'a' }], group: null, section: 'Needs you', note: 'confirms, then asks for the token' },\n { id: 'drawer.reject', title: 'Reject', scope: 'drawer', keys: [{ key: 'r' }], group: null, section: 'Needs you', note: 'confirms, then asks for the token' },\n { id: 'drawer.veto', title: 'Veto', scope: 'drawer', keys: [{ key: 'v' }], group: null, section: 'Needs you', note: 'confirms, then asks for the token' },\n { id: 'drawer.done', title: 'Mark done', scope: 'drawer', keys: [{ key: 'e' }], group: null, section: 'Needs you' },\n { id: 'drawer.split-prev', title: 'Previous split', scope: 'drawer', keys: [{ key: 'h' }], group: null, section: 'Needs you' },\n { id: 'drawer.split-next', title: 'Next split', scope: 'drawer', keys: [{ key: 'l' }], group: null, section: 'Needs you' },\n\n // ── Charts ───────────────────────────────────────────────────────────────\n { id: 'chart.table', title: 'Show as a table', scope: 'chart', keys: [{ key: 't' }], group: null, section: 'Charts', note: 'when a chart card has focus' },\n\n // ── App ──────────────────────────────────────────────────────────────────\n {\n id: 'appearance.toggle-theme',\n title: 'Toggle light / dark',\n scope: 'global',\n keys: [{ key: 'l', mod: true, shift: true }],\n group: 'actions',\n section: 'App',\n keywords: ['theme', 'dark mode'],\n native: { kind: 'menu', desktopCommand: 'toggle-theme', accelerator: 'Shift+CmdOrCtrl+L' },\n },\n {\n id: 'app.summon',\n title: 'Show Verse and focus the composer',\n scope: 'global',\n keys: [{ key: 'space', ctrl: true, alt: true }],\n group: null,\n section: 'App',\n note: 'system-wide; turn on in Settings ▸ Desktop',\n native: { kind: 'global-hotkey', accelerator: 'Control+Alt+Space' },\n },\n { id: 'fleet.stop', title: 'Stop the fleet…', scope: 'global', keys: [], group: 'actions', section: 'App', guard: STOP_FLEET_GUARD, keywords: ['kill', 'halt', 'autonomy'] },\n] as const satisfies readonly WorkbenchCommand[];\n\nexport type CommandId = (typeof WORKBENCH_COMMANDS)[number]['id'];\n\nconst BY_ID: ReadonlyMap<string, WorkbenchCommand> = new Map(WORKBENCH_COMMANDS.map((c) => [c.id, c as WorkbenchCommand]));\n\nexport function findCommand(id: string): WorkbenchCommand | null {\n return BY_ID.get(id) ?? null;\n}\n\n/** Palette entries of one group, in catalog order. */\nexport function paletteCommands(group: 'actions' | 'go-to'): WorkbenchCommand[] {\n return (WORKBENCH_COMMANDS as readonly WorkbenchCommand[]).filter((c) => c.group === group);\n}\n\n/** The shortcuts overlay: every command with keys, grouped by section, in display order. */\nexport function shortcutSections(): Array<{ section: ShortcutSection; commands: WorkbenchCommand[] }> {\n const withKeys = (WORKBENCH_COMMANDS as readonly WorkbenchCommand[]).filter((c) => c.keys.length > 0);\n return SHORTCUT_SECTIONS.map((section) => ({ section, commands: withKeys.filter((c) => c.section === section) })).filter(\n (s) => s.commands.length > 0,\n );\n}\n\n// ===========================================================================\n// Matching and display\n// ===========================================================================\n\nexport type KeyPlatform = 'mac' | 'other';\n\n/** The platform the page runs on, for ⌘ vs Ctrl. */\nexport function detectKeyPlatform(): KeyPlatform {\n if (typeof navigator === 'undefined') return 'mac';\n const nav = navigator as Navigator & { userAgentData?: { platform?: string } };\n const platform = nav.userAgentData?.platform ?? nav.platform ?? '';\n return /mac|iphone|ipad|ipod/i.test(platform) ? 'mac' : 'other';\n}\n\n/** The part of a KeyboardEvent matching needs (so tests can pass plain objects). */\nexport interface KeyEventLike {\n key: string;\n code?: string;\n metaKey: boolean;\n ctrlKey: boolean;\n shiftKey: boolean;\n altKey: boolean;\n}\n\nconst CODE_CHARS: Readonly<Record<string, string>> = {\n Backslash: '\\\\',\n Backquote: '`',\n BracketLeft: '[',\n BracketRight: ']',\n Slash: '/',\n Comma: ',',\n Period: '.',\n Semicolon: ';',\n Quote: \"'\",\n Minus: '-',\n Equal: '=',\n Space: 'space',\n};\n\nconst KEY_ALIASES: Readonly<Record<string, string>> = {\n ' ': 'space',\n spacebar: 'space',\n esc: 'escape',\n return: 'enter',\n up: 'arrowup',\n down: 'arrowdown',\n left: 'arrowleft',\n right: 'arrowright',\n};\n\n/**\n * The event's key as a chord `key`. Letters come from `event.key` (so ⌘K is\n * ⌘K on any keyboard layout); digits and punctuation come from `event.code`\n * when it is known, because Shift and ⌥ change `event.key` (⇧\\ reads \"|\",\n * ⌥J reads \"∆\") while the chord names the unshifted key.\n */\nexport function eventKeyName(event: Pick<KeyEventLike, 'key' | 'code'>): string {\n const key = event.key ?? '';\n if (/^[a-z]$/i.test(key)) return key.toLowerCase();\n const code = event.code ?? '';\n if (/^Digit[0-9]$/.test(code)) return code.slice(5);\n if (CODE_CHARS[code]) return CODE_CHARS[code]!;\n if (/^Key[A-Z]$/.test(code)) return code.slice(3).toLowerCase();\n const lower = key.toLowerCase();\n return KEY_ALIASES[lower] ?? lower;\n}\n\n/**\n * Does `event` press `chord`? Modifiers must match EXACTLY (⌘K is not ⇧⌘K).\n * Off macOS, `mod` and `ctrl` are both the Ctrl key and ⌘/Win never matches.\n */\nexport function chordMatches(event: KeyEventLike, chord: KeyChord, platform: KeyPlatform = detectKeyPlatform()): boolean {\n if (platform === 'mac') {\n if (Boolean(chord.mod) !== event.metaKey) return false;\n if (Boolean(chord.ctrl) !== event.ctrlKey) return false;\n } else {\n if (event.metaKey) return false;\n if (Boolean(chord.mod || chord.ctrl) !== event.ctrlKey) return false;\n }\n if (Boolean(chord.shift) !== event.shiftKey) return false;\n if (Boolean(chord.alt) !== event.altKey) return false;\n return eventKeyName(event) === chord.key;\n}\n\n/**\n * The command a key press runs, given the scopes live right now (innermost\n * first, e.g. ['composer', 'chat', 'global']). Null when nothing is bound —\n * the caller must then leave the event alone.\n */\nexport function matchCommand(event: KeyEventLike, liveScopes: readonly CommandScope[], platform: KeyPlatform = detectKeyPlatform()): WorkbenchCommand | null {\n for (const scope of liveScopes) {\n for (const command of WORKBENCH_COMMANDS as readonly WorkbenchCommand[]) {\n if (command.scope !== scope) continue;\n // The page never handles a system-wide hotkey itself.\n if (command.native?.kind === 'global-hotkey') continue;\n if (command.keys.some((chord) => chordMatches(event, chord, platform))) return command;\n }\n }\n return null;\n}\n\n/** Stable identity for a chord (\"mod+shift+b\"), for de-duplication and tests. */\nexport function chordId(chord: KeyChord): string {\n return [chord.ctrl ? 'ctrl' : '', chord.alt ? 'alt' : '', chord.shift ? 'shift' : '', chord.mod ? 'mod' : '', chord.key].filter(Boolean).join('+');\n}\n\nconst MAC_KEY_GLYPHS: Readonly<Record<string, string>> = {\n enter: '↩',\n escape: 'Esc',\n tab: '⇥',\n space: 'Space',\n arrowup: '↑',\n arrowdown: '↓',\n arrowleft: '←',\n arrowright: '→',\n backspace: '⌫',\n};\n\nconst OTHER_KEY_NAMES: Readonly<Record<string, string>> = {\n enter: 'Enter',\n escape: 'Esc',\n tab: 'Tab',\n space: 'Space',\n arrowup: '↑',\n arrowdown: '↓',\n arrowleft: '←',\n arrowright: '→',\n backspace: 'Backspace',\n};\n\n/**\n * How a chord is printed. macOS uses Apple's modifier order (⌃ ⌥ ⇧ ⌘) with\n * no separators (\"⇧⌘B\", \"⌃`\", \"⌥↑\"); elsewhere \"Ctrl+Shift+B\".\n */\nexport function formatChord(chord: KeyChord, platform: KeyPlatform = detectKeyPlatform()): string {\n const key = chord.key.length === 1 ? chord.key.toUpperCase() : (platform === 'mac' ? MAC_KEY_GLYPHS : OTHER_KEY_NAMES)[chord.key] ?? chord.key;\n if (platform === 'mac') {\n return `${chord.ctrl ? '⌃' : ''}${chord.alt ? '⌥' : ''}${chord.shift ? '⇧' : ''}${chord.mod ? '⌘' : ''}${key}`;\n }\n const parts = [chord.mod || chord.ctrl ? 'Ctrl' : '', chord.alt ? 'Alt' : '', chord.shift ? 'Shift' : '', key].filter(Boolean);\n return parts.join('+');\n}\n\n/**\n * Tauri's accelerator string for a chord (\"Shift+CmdOrCtrl+L\") — what C8\n * writes in app_menu.rs, and what the key test compares against.\n */\nexport function chordAccelerator(chord: KeyChord): string {\n const TAURI_KEYS: Readonly<Record<string, string>> = {\n enter: 'Enter',\n escape: 'Escape',\n tab: 'Tab',\n space: 'Space',\n arrowup: 'Up',\n arrowdown: 'Down',\n arrowleft: 'Left',\n arrowright: 'Right',\n backspace: 'Backspace',\n };\n const key = TAURI_KEYS[chord.key] ?? (chord.key.length === 1 ? chord.key.toUpperCase() : chord.key);\n return [chord.shift ? 'Shift' : '', chord.ctrl ? 'Control' : '', chord.alt ? 'Alt' : '', chord.mod ? 'CmdOrCtrl' : '', key].filter(Boolean).join('+');\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{c as e,i as t,s as n}from"./command-catalog-Bb_PxC5w.js";var r=[`composer.permission`,`composer.model`,`composer.effort`,`composer.attach`,`composer.send`,`composer.stop-and-send`,`composer.stop`];function i(e,r){let i=n(r);return i!==null&&i.keys.some(n=>t(e,n))}function a(t){let r=n(t)?.keys[0];return r?e(r):``}export{i as n,a as r,r as t};
2
- //# sourceMappingURL=composer-keys-su0g1h9o.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"composer-keys-su0g1h9o.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/composer/composer-keys.ts"],"sourcesContent":["/**\n * routes/verse/composer/composer-keys.ts — the composer's keys, read from\n * C0's command catalog (the one table the palette, the shortcuts overlay and\n * the native menu also read), never re-declared here (unit C3).\n */\nimport {\n chordMatches,\n findCommand,\n formatChord,\n type KeyEventLike,\n} from '../shell/command-catalog.js';\n\n/** The composer commands this unit implements (command-catalog ids). */\nexport const COMPOSER_COMMAND_IDS = [\n 'composer.permission',\n 'composer.model',\n 'composer.effort',\n 'composer.attach',\n 'composer.send',\n 'composer.stop-and-send',\n 'composer.stop',\n] as const;\nexport type ComposerCommandId = (typeof COMPOSER_COMMAND_IDS)[number];\n\n/**\n * The window event the palette (C1) and the native menu bridge dispatch to\n * run a catalog command on the surface that owns it. Defined in C0's\n * command-catalog.ts (beside the ids it carries); re-exported here so the\n * composer's importers keep one import site.\n */\nexport { WORKBENCH_COMMAND_EVENT } from '../shell/command-catalog.js';\n\n/** Does this key event press the catalog chord for `id`? */\nexport function pressesCommand(event: KeyEventLike, id: ComposerCommandId): boolean {\n const command = findCommand(id);\n return command !== null && command.keys.some((chord) => chordMatches(event, chord));\n}\n\n/** The chord for `id` as the platform prints it (\"⇧⌘M\" / \"Ctrl+Shift+M\"); '' when unbound. */\nexport function shortcutLabel(id: ComposerCommandId): string {\n const chord = findCommand(id)?.keys[0];\n return chord ? formatChord(chord) : '';\n}\n"],"mappings":"gEAaA,IAAa,EAAuB,CAClC,sBACA,iBACA,kBACA,kBACA,gBACA,yBACA,eACF,EAYA,SAAgB,EAAe,EAAqB,EAAgC,CAClF,IAAM,EAAU,EAAY,CAAE,EAC9B,OAAO,IAAY,MAAQ,EAAQ,KAAK,KAAM,GAAU,EAAa,EAAO,CAAK,CAAC,CACpF,CAGA,SAAgB,EAAc,EAA+B,CAC3D,IAAM,EAAQ,EAAY,CAAE,CAAC,EAAE,KAAK,GACpC,OAAO,EAAQ,EAAY,CAAK,EAAI,EACtC"}
@@ -1,2 +0,0 @@
1
- import{F as e,L as t,N as n,c as r,j as i,k as a,z as o}from"./verse-model-DyCwZF-M.js";import{S as s,r as c,x as l}from"./verse-store-b_Lek_c5.js";import{g as u,t as d,v as f}from"./format-BkWdOQDL.js";var p=/\s·\spart\s(\d+)$/;function m(e){let t=e.replace(/\s+/g,` `).trim(),n=p.exec(t),r=(n?t.slice(0,n.index):t)||`Untitled chat`,i=` · part ${n?Number.parseInt(n[1],10)+1:2}`,a=120-i.length;return`${r.length>a?`${r.slice(0,a-1).trimEnd()}…`:r}${i}`}function h(e,t){if(!e)return null;let n=e.models.find(e=>e.id===t);if(n)return n;let r=i(t);return e.models.find(e=>i(e.id)===r)??null}function g(e,t,n=Date.now()){return e?e.health.state===`unavailable`?`${e.label} is unavailable: ${d(f(e.health.summary??`no reason given`,n))}.`:t?t.unavailableReason?`${t.label} cannot run on ${e.label}: ${d(f(t.unavailableReason,n))}.`:null:`Pick a model on this seat.`:`Pick a seat to continue on.`}function _(e,t){let n=e.find(e=>e.id===t.seatId);if(n&&n.health.state!==`unavailable`){let e=h(n,t.model);if(e&&!e.unavailableReason)return{seatId:n.id,model:e.id};let r=n.models.find(e=>!e.unavailableReason);if(r)return{seatId:n.id,model:r.id}}for(let t of e){if(t.health.state===`unavailable`)continue;let e=t.models.find(e=>!e.unavailableReason);if(e)return{seatId:t.id,model:e.id}}return null}function v(e){let{option:t,target:n,source:r,preferences:o}=e,s=e=>e!==void 0&&a(t,e)!==null;if(n!==null&&n.seatId===r.seatId&&i(n.model)===i(r.model)&&s(r.contextMode??`standard`))return r.contextMode??`standard`;let c=n?o?.seats[n.seatId]?.contextMode:void 0;return s(c)?c:`standard`}function y(e,t){return a(e,t)===null?void 0:t}function b(e,t){let n=a(e,t);if(!n)return null;let r=`${c(n.contextWindow)} window`;return n.autoCompactAt===null?r:`${r} · compacts ≈${c(n.autoCompactAt)}`}function x(t,r,i,s){let l=n(t),d=o(s),f=l+d,p=e(l,r,d),m=`~${c(l)} tokens of handoff + an estimated ~${c(d)} of fixed prompt`,h=a(r,`standard`),g=h?h.autoCompactAt??h.contextWindow:null,_={verdict:p,handoffTokens:l,overheadTokens:d,needTokens:f};switch(p){case`fits`:return{..._,tone:`ok`,text:`Fits: ${m} leaves most of the budget before the first compaction.`};case`tight`:return{..._,tone:`warn`,text:`Tight: ${m} is ${u(f/(g??f)*100)} of where this model compacts — the new chat will compact early.`};case`expansive`:return i===`expansive`?{..._,tone:`warn`,text:`Fits only the expansive budget: ${m}.`}:{..._,tone:`danger`,text:`Too big for the standard budget (${m}). Switch to Expansive, or trim the handoff.`};case`split`:return{..._,tone:`danger`,text:`Too big for one context on this model (${m}). Trim the handoff or pick a seat with a larger window.`};default:return{..._,verdict:null,tone:`unknown`,text:`This model’s window is not known, so there is no fit estimate.`}}}function S(e){return t(e)}function C(e,t){return e===`local`?`Runs on this machine with ${t}; it spends no subscription usage.`:`Sends one turn to ${t} and spends from its usage. The automatic preview costs nothing.`}var w=typeof TextEncoder==`function`?new TextEncoder:null;function T(e){if(w)return w.encode(e).length;let t=0;for(let n of e){let e=n.codePointAt(0)??0;t+=e<128?1:e<2048?2:e<65536?3:4}return t}var E=65536,D=s;function O(e){return T(JSON.stringify(e)??``)}function k(e){if(!Number.isFinite(e)||e<0)return`—`;if(e<1024)return`${e} B`;let t=e/1024;return`${t<10?t.toFixed(1).replace(/\.0$/,``):Math.round(t)} KB`}function A(e,t=Date.now()){if(!e)return null;let n=r(e,t);return n?n===`now`?`just now`:/^\d+[mhd]$/.test(n)?`${n} ago`:`on ${n}`:null}var j=[{label:`a private key`,re:/-----BEGIN [A-Z ]*PRIVATE KEY-----/},{label:`an Anthropic API key`,re:/\bsk-ant-[A-Za-z0-9_-]{20,}/},{label:`an OpenAI-style API key`,re:/\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/},{label:`an xAI API key`,re:/\bxai-[A-Za-z0-9]{32,}/},{label:`a GitHub token`,re:/\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{30,}|\bgithub_pat_[A-Za-z0-9_]{40,}/},{label:`an AWS access key`,re:/\b(?:AKIA|ASIA)[0-9A-Z]{16}\b/},{label:`a Slack token`,re:/\bxox[abprs]-[A-Za-z0-9-]{10,}/},{label:`a Google API key`,re:/\bAIza[0-9A-Za-z_-]{35}\b/},{label:`a Stripe secret key`,re:/\b(?:sk|rk)_live_[0-9A-Za-z]{20,}/}],M=l,N=`Reading and editing memory here spends nothing. On a paid seat it is not free to use: each new chat’s system prompt carries a memory block of up to ${M/1024} KB, re-sent every turn (cached after the first), and the agent reads and updates MEMORY.md as it works. Local seats spend nothing.`;function P(e){for(let{label:t,re:n}of j)if(n.test(e))return t;return null}var F=`[REDACTED]`;function I(e){return e.split(F).length-1}function L(e){let t=[];for(let n of e.toLowerCase().split(/\s+/))n&&!t.includes(n)&&t.push(n);return t}function R(e){return e.replace(/[.*+?^${}()|[\]\\]/g,`\\$&`)}function z(e,t){let n=[...t].filter(e=>e.length>0).sort((e,t)=>t.length-e.length);if(n.length===0||e.length===0)return e?[{text:e,match:!1}]:[];let r=new RegExp(n.map(R).join(`|`),`gi`),i=[],a=0;for(let t of e.matchAll(r)){let n=t.index??0;t[0].length!==0&&(n>a&&i.push({text:e.slice(a,n),match:!1}),i.push({text:t[0],match:!0}),a=n+t[0].length)}return a<e.length&&i.push({text:e.slice(a),match:!1}),i}function B(e){let t=new Map;for(let n of e){let e=t.get(n.sessionId);if(!e){t.set(n.sessionId,{sessionId:n.sessionId,title:n.title,projectPath:n.projectPath,engine:n.engine,top:n,count:1,latestAt:n.at});continue}e.count+=1,n.at>e.latestAt&&(e.latestAt=n.at)}return[...t.values()]}export{C,g as S,I as _,F as a,L as b,_ as c,x as d,m as f,S as g,h,N as i,k as l,O as m,M as n,b as o,z as p,D as r,v as s,E as t,B as u,A as v,T as w,P as x,y};
2
- //# sourceMappingURL=context-model-BC-HOmPo.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"context-model-BC-HOmPo.js","names":[],"sources":["../../../../../../src/web-ui/routes/verse/context/context-model.ts"],"sourcesContent":["/**\n * routes/verse/context/context-model.ts — the pure half of the context\n * components (handoff dialog, memory panel, session search). No React, no\n * I/O, so every rule the components render is pinned by a plain unit test.\n *\n * Every number shown here comes from context-math.ts (the one module the\n * server and the browser share), so \"compacts ≈367k\" in the handoff dialog is\n * the same figure the meter and the seat picker show.\n */\nimport type { VerseEngine, VerseModelOption, VerseSeat, VerseSession } from '../../../data/api-types.js';\nimport type {\n VerseContextMode,\n VerseFitVerdict,\n VersePreferences,\n VerseSearchHit,\n} from '../../../../core/verse/types.js';\nimport { VERSE_MEMORY_BLOCK_MAX_BYTES, VERSE_MEMORY_BODY_MAX_BYTES } from '../../../../core/verse/types.js';\nimport {\n budgetFor,\n canonicalModelId,\n estimateTokensFromChars,\n fitVerdict,\n hasExpansiveMode,\n sessionOverheadTokens,\n} from '../../../../core/verse/context-math.js';\nimport { formatRelative } from '../verse-model.js';\nimport { asClause, percentText, tidyProse } from '../autonomy/format.js';\nimport { formatTokens } from '../verse-store.js';\n\n// ---------------------------------------------------------------------------\n// Handoff\n// ---------------------------------------------------------------------------\n\n// The canned \"Ask this seat to summarize first\" turn is\n// VERSE_HANDOFF_SUMMARY_REQUEST in core/verse/types.ts, not a copy here: the\n// handoff builder on the server matches that exact text to keep it OUT of the\n// new session's \"latest requests\" (otherwise the new chat is told to write\n// another handoff note). A local copy that drifted by one character would\n// silently defeat that filter.\n\n/** Mirrors session-engine's TITLE_MAX so a title we send is never cut by the server instead. */\nexport const TITLE_MAX_CHARS = 120;\n\nconst PART_SUFFIX = /\\s·\\spart\\s(\\d+)$/;\n\n/**\n * Title for the session a handoff continues in: \"Fix the login bug · part 2\".\n * A continuation of a continuation counts up rather than stacking suffixes, so\n * the sidebar reads \"part 3\", never \"part 2 · part 2\".\n */\nexport function handoffTitle(sourceTitle: string): string {\n const collapsed = sourceTitle.replace(/\\s+/g, ' ').trim();\n const match = PART_SUFFIX.exec(collapsed);\n const base = (match ? collapsed.slice(0, match.index) : collapsed) || 'Untitled chat';\n const next = match ? Number.parseInt(match[1]!, 10) + 1 : 2;\n const suffix = ` · part ${next}`;\n const room = TITLE_MAX_CHARS - suffix.length;\n const clipped = base.length > room ? `${base.slice(0, room - 1).trimEnd()}…` : base;\n return `${clipped}${suffix}`;\n}\n\n/**\n * A seat's catalog entry for a model id. Exact id first, then canonical — a\n * session created before the alias fix stores `claude-opus-5.5` while the\n * catalog now lists `claude-opus-5-5` (context-math VERSE_MODEL_ID_ALIASES).\n */\nexport function modelOption(seat: VerseSeat | null | undefined, modelId: string): VerseModelOption | null {\n if (!seat) return null;\n const exact = seat.models.find((m) => m.id === modelId);\n if (exact) return exact;\n const canonical = canonicalModelId(modelId);\n return seat.models.find((m) => canonicalModelId(m.id) === canonical) ?? null;\n}\n\n/**\n * Why a seat+model cannot take a new session right now; null when it can.\n *\n * The seat's own reason is embedded as a clause: its closing period is\n * dropped (no \"exhausted..\") and any ISO instant in it — a health summary\n * saying when usage resets — is read as the viewer's local time.\n */\nexport function targetUnavailableReason(\n seat: VerseSeat | null | undefined,\n option: VerseModelOption | null,\n now: number = Date.now(),\n): string | null {\n if (!seat) return 'Pick a seat to continue on.';\n if (seat.health.state === 'unavailable') {\n return `${seat.label} is unavailable: ${asClause(tidyProse(seat.health.summary ?? 'no reason given', now))}.`;\n }\n if (!option) return 'Pick a model on this seat.';\n if (option.unavailableReason) {\n return `${option.label} cannot run on ${seat.label}: ${asClause(tidyProse(option.unavailableReason, now))}.`;\n }\n return null;\n}\n\nexport interface HandoffTarget {\n seatId: string;\n model: string;\n}\n\n/**\n * Where a handoff lands by default: the SAME seat and model (the common case\n * is \"same agent, fresh context\"). When that model can no longer run there,\n * the seat's first runnable model; when the seat itself is gone or\n * unavailable, the first runnable model on any available seat, in the seat\n * list's own order.\n */\nexport function defaultHandoffTarget(seats: readonly VerseSeat[], source: Pick<VerseSession, 'seatId' | 'model'>): HandoffTarget | null {\n const own = seats.find((s) => s.id === source.seatId);\n if (own && own.health.state !== 'unavailable') {\n const same = modelOption(own, source.model);\n if (same && !same.unavailableReason) return { seatId: own.id, model: same.id };\n const runnable = own.models.find((m) => !m.unavailableReason);\n if (runnable) return { seatId: own.id, model: runnable.id };\n }\n for (const seat of seats) {\n if (seat.health.state === 'unavailable') continue;\n const runnable = seat.models.find((m) => !m.unavailableReason);\n if (runnable) return { seatId: seat.id, model: runnable.id };\n }\n return null;\n}\n\n/**\n * The mode a handoff starts in. Only a mode that EXISTS for the target model\n * is ever returned (a mode with no budget would be refused by the server).\n *\n * 1. Same seat and model as the source → keep the source's mode. \"Continue in\n * a fresh chat\" means the same settings with a clean context; an operator\n * who chose expansive for this work chose it for the work.\n * 2. Otherwise the target seat's standing preference (preferences.json).\n * 3. Otherwise standard.\n */\nexport function defaultHandoffMode(input: {\n option: VerseModelOption | null;\n target: HandoffTarget | null;\n source: Pick<VerseSession, 'seatId' | 'model' | 'contextMode'>;\n preferences: VersePreferences | null | undefined;\n}): VerseContextMode {\n const { option, target, source, preferences } = input;\n const valid = (mode: VerseContextMode | undefined): mode is VerseContextMode =>\n mode !== undefined && budgetFor(option, mode) !== null;\n const sameModel = target !== null && target.seatId === source.seatId\n && canonicalModelId(target.model) === canonicalModelId(source.model);\n if (sameModel && valid(source.contextMode ?? 'standard')) return source.contextMode ?? 'standard';\n const preferred = target ? preferences?.seats[target.seatId]?.contextMode : undefined;\n if (valid(preferred)) return preferred;\n return 'standard';\n}\n\n/**\n * The mode to put on the create request, or undefined to leave it to the\n * server. A mode is sent only when the model has a budget for it — which is\n * exactly the server's acceptance rule — so what the dialog shows is what is\n * created, and an unknown-window model is never refused over a mode it could\n * not have.\n */\nexport function requestMode(option: VerseModelOption | null, mode: VerseContextMode): VerseContextMode | undefined {\n return budgetFor(option, mode) !== null ? mode : undefined;\n}\n\n/** \"1M window · compacts ≈367k\" for a model in a mode; null when the budget is unknown. */\nexport function budgetLine(option: VerseModelOption | null, mode: VerseContextMode): string | null {\n const budget = budgetFor(option, mode);\n if (!budget) return null;\n const window = `${formatTokens(budget.contextWindow)} window`;\n return budget.autoCompactAt === null ? window : `${window} · compacts ≈${formatTokens(budget.autoCompactAt)}`;\n}\n\nexport interface HandoffFit {\n verdict: VerseFitVerdict | null;\n /** The handoff text's own estimate (chars / 4). */\n handoffTokens: number;\n /** The target engine's estimated fixed prompt (context-math `sessionOverheadTokens`). */\n overheadTokens: number;\n /** Handoff + that fixed prompt: what the new session holds before its first reply. */\n needTokens: number;\n /** One sentence for the dialog. */\n text: string;\n tone: 'ok' | 'warn' | 'danger' | 'unknown';\n}\n\n/**\n * Will the new session START comfortably? The handoff is small by design\n * (≤ 12k chars ≈ 3k tokens), but every fresh session also carries the CLI's\n * fixed prompt — a large share of a 64k local slot — so this is a real\n * question on small windows, and the sentence shows both halves of the sum\n * rather than a bare verdict.\n *\n * The fixed prompt is the TARGET seat's engine estimate (local ≈15k measured,\n * claude ≈25k, …), not one flat figure: a flat 30k called every handoff to a\n * 64k local seat \"too big for one context\" when the real sum was ~20k. It is\n * still an estimate — no CLI reports its base prompt before the first turn —\n * so the sentence says \"estimated\" rather than presenting it as a reading.\n * `engine` null (target seat not known yet) falls back to the largest estimate.\n */\nexport function handoffFit(\n textChars: number,\n option: VerseModelOption | null,\n mode: VerseContextMode,\n engine: VerseEngine | null,\n): HandoffFit {\n const handoffTokens = estimateTokensFromChars(textChars);\n const overheadTokens = sessionOverheadTokens(engine);\n const needTokens = handoffTokens + overheadTokens;\n const verdict = fitVerdict(handoffTokens, option, overheadTokens);\n const sum = `~${formatTokens(handoffTokens)} tokens of handoff + an estimated ~${formatTokens(overheadTokens)} of fixed prompt`;\n const standard = budgetFor(option, 'standard');\n const standardCap = standard ? standard.autoCompactAt ?? standard.contextWindow : null;\n const base = { verdict, handoffTokens, overheadTokens, needTokens };\n switch (verdict) {\n case 'fits':\n return { ...base, tone: 'ok', text: `Fits: ${sum} leaves most of the budget before the first compaction.` };\n case 'tight':\n return {\n ...base,\n tone: 'warn',\n text: `Tight: ${sum} is ${percentText((needTokens / (standardCap ?? needTokens)) * 100)} of where this model compacts — the new chat will compact early.`,\n };\n case 'expansive':\n return mode === 'expansive'\n ? { ...base, tone: 'warn', text: `Fits only the expansive budget: ${sum}.` }\n : { ...base, tone: 'danger', text: `Too big for the standard budget (${sum}). Switch to Expansive, or trim the handoff.` };\n case 'split':\n return { ...base, tone: 'danger', text: `Too big for one context on this model (${sum}). Trim the handoff or pick a seat with a larger window.` };\n default:\n return { ...base, verdict: null, tone: 'unknown', text: 'This model’s window is not known, so there is no fit estimate.' };\n }\n}\n\n/** True when the target model has a real expansive budget (context-math, re-exported for the dialog). */\nexport function offersExpansive(option: VerseModelOption | null): boolean {\n return hasExpansiveMode(option);\n}\n\n/** A local turn runs on this machine; every other engine spends subscription usage. */\nexport function turnCostSentence(engine: VerseEngine, seatLabel: string): string {\n return engine === 'local'\n ? `Runs on this machine with ${seatLabel}; it spends no subscription usage.`\n : `Sends one turn to ${seatLabel} and spends from its usage. The automatic preview costs nothing.`;\n}\n\n// ---------------------------------------------------------------------------\n// Bytes\n// ---------------------------------------------------------------------------\n\nconst encoder = typeof TextEncoder === 'function' ? new TextEncoder() : null;\n\n/** UTF-8 byte length — the unit the server's caps (64 KB memory content, 64 KB turn) are written in. */\nexport function utf8Bytes(text: string): number {\n if (encoder) return encoder.encode(text).length;\n // Fallback for an environment with no TextEncoder: count code points by width.\n let bytes = 0;\n for (const ch of text) {\n const cp = ch.codePointAt(0) ?? 0;\n bytes += cp < 0x80 ? 1 : cp < 0x800 ? 2 : cp < 0x10000 ? 3 : 4;\n }\n return bytes;\n}\n\n/**\n * The API's default request-body cap: `readBody` in src/core/web/api.ts, which\n * every /api/verse POST uses unless its route passes a larger one (only\n * POST /memory does — see MEMORY_BODY_MAX_BYTES). A write travels as JSON, so what must fit is\n * the ENCODED body — every `\\n` and `\"` escaped to two bytes — not the text\n * alone; the editors measure it so a refusal happens on screen instead of as\n * \"request body too large\".\n */\nexport const API_BODY_MAX_BYTES = 65_536;\n\n/**\n * POST /api/verse/memory's own body cap — mirrors `VERSE_MEMORY_BODY_MAX_BYTES`\n * in src/core/verse/verse-api.ts (a server module the browser cannot import):\n * room for 64 KiB of content in which EVERY byte escapes to two, plus the\n * project path and the JSON around it. The server still holds the CONTENT to\n * VERSE_MEMORY_MAX_BYTES after parsing. Guarding the memory editor with the\n * 64 KiB default instead blocked saves the server accepts — a 60–64 KB\n * MEMORY.md with ordinary line breaks could not be edited from the panel,\n * which is the exact case the server's larger cap exists for.\n */\nexport const MEMORY_BODY_MAX_BYTES = VERSE_MEMORY_BODY_MAX_BYTES;\n\n/** UTF-8 size of `body` exactly as the client will send it. */\nexport function jsonBodyBytes(body: unknown): number {\n return utf8Bytes(JSON.stringify(body) ?? '');\n}\n\nexport function formatBytes(bytes: number): string {\n if (!Number.isFinite(bytes) || bytes < 0) return '—';\n if (bytes < 1024) return `${bytes} B`;\n const kb = bytes / 1024;\n return `${kb < 10 ? kb.toFixed(1).replace(/\\.0$/, '') : Math.round(kb)} KB`;\n}\n\n/**\n * A relative time that reads as a phrase: \"just now\", \"5m ago\", \"on Sep 19\".\n * `formatRelative` (verse-model) is sized for a 5ch sidebar column and reads\n * as a bare token; prose needs the preposition.\n */\nexport function relativePhrase(iso: string | null | undefined, now: number = Date.now()): string | null {\n if (!iso) return null;\n const short = formatRelative(iso, now);\n if (!short) return null;\n if (short === 'now') return 'just now';\n // Only the relative tokens (\"5m\", \"3h\", \"2d\") take \"ago\". Anything else is a\n // DATE, whatever the locale prints: \"Sep 1\" (en-US) but \"1 Sept\" (en-GB)\n // and \"1. Sept.\" (de) start with a digit — testing for a leading digit\n // printed \"Last completed 1 Sept ago.\" outside the US.\n return /^\\d+[mhd]$/.test(short) ? `${short} ago` : `on ${short}`;\n}\n\n// ---------------------------------------------------------------------------\n// Memory\n// ---------------------------------------------------------------------------\n\n/**\n * Shapes that are almost certainly credentials. MEMORY.md is sent to every\n * seat's model on every turn, so a pasted key would travel to every provider\n * — the panel warns BEFORE the save rather than trusting the server's scrub\n * to catch it on the way out. Conservative on purpose: a false alarm on prose\n * would teach the operator to ignore the warning.\n */\nconst SECRET_PATTERNS: ReadonlyArray<{ label: string; re: RegExp }> = [\n { label: 'a private key', re: /-----BEGIN [A-Z ]*PRIVATE KEY-----/ },\n { label: 'an Anthropic API key', re: /\\bsk-ant-[A-Za-z0-9_-]{20,}/ },\n { label: 'an OpenAI-style API key', re: /\\bsk-(?:proj-)?[A-Za-z0-9_-]{32,}/ },\n { label: 'an xAI API key', re: /\\bxai-[A-Za-z0-9]{32,}/ },\n { label: 'a GitHub token', re: /\\b(?:ghp|gho|ghu|ghs|ghr)_[A-Za-z0-9]{30,}|\\bgithub_pat_[A-Za-z0-9_]{40,}/ },\n { label: 'an AWS access key', re: /\\b(?:AKIA|ASIA)[0-9A-Z]{16}\\b/ },\n { label: 'a Slack token', re: /\\bxox[abprs]-[A-Za-z0-9-]{10,}/ },\n { label: 'a Google API key', re: /\\bAIza[0-9A-Za-z_-]{35}\\b/ },\n { label: 'a Stripe secret key', re: /\\b(?:sk|rk)_live_[0-9A-Za-z]{20,}/ },\n];\n\n/**\n * Mirrors `VERSE_MEMORY_BLOCK_MAX_BYTES` in src/core/verse/project-memory.ts\n * (a node module the browser cannot import): the most memory text a chat's\n * instructions carry, however large MEMORY.md itself is.\n */\nexport const MEMORY_BLOCK_MAX_BYTES = VERSE_MEMORY_BLOCK_MAX_BYTES;\n\n/**\n * What memory costs, in the one wording the memory panel and the resources\n * panel share. Memory is ON by default and snapshotted into every new chat's\n * system prompt (claude `--append-system-prompt`, codex `developer_instructions`,\n * grok `--rules`), which re-rides every turn, and it asks writable seats to\n * read and update MEMORY.md — tool calls and output. On a paid seat that is\n * real (if small, mostly cached) usage, so \"nothing here spends\" would be\n * false for exactly the operator deciding whether to leave it on near a limit.\n * Reading and editing the file from the panel is still free.\n */\nexport const MEMORY_SPEND_NOTE =\n `Reading and editing memory here spends nothing. On a paid seat it is not free to use: each new chat’s system prompt carries a memory block of up to ${MEMORY_BLOCK_MAX_BYTES / 1024} KB, re-sent every turn (cached after the first), and the agent reads and updates MEMORY.md as it works. Local seats spend nothing.`;\n\n/** The first credential shape found, as a phrase (\"a GitHub token\"), or null. */\nexport function secretLike(text: string): string | null {\n for (const { label, re } of SECRET_PATTERNS) if (re.test(text)) return label;\n return null;\n}\n\n/**\n * The placeholder the server's scrubber (src/core/util/scrub.ts) writes over\n * secret-shaped text in every rule. In a memory view flagged\n * `contentSanitized`, each one stands for a REAL value still in MEMORY.md.\n */\nexport const REDACTION_MARKER = '[REDACTED]';\n\n/** How many redaction placeholders a text carries. */\nexport function redactionMarkers(text: string): number {\n return text.split(REDACTION_MARKER).length - 1;\n}\n\n// ---------------------------------------------------------------------------\n// Search\n// ---------------------------------------------------------------------------\n\n/** Below this many characters a keyword search over every message is noise, not recall. */\nexport const SEARCH_MIN_CHARS = 2;\n/** Keystrokes inside this window collapse into one request. */\nexport const SEARCH_DEBOUNCE_MS = 250;\n/** Hits asked for per search — enough to fill the sidebar twice over. */\nexport const SEARCH_LIMIT = 30;\n\n/** Whitespace-separated terms, lowercased and de-duplicated (the server ANDs them). */\nexport function searchTerms(query: string): string[] {\n const out: string[] = [];\n for (const raw of query.toLowerCase().split(/\\s+/)) {\n if (raw && !out.includes(raw)) out.push(raw);\n }\n return out;\n}\n\nexport interface HighlightSegment {\n text: string;\n match: boolean;\n}\n\nfunction escapeRegExp(value: string): string {\n return value.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&');\n}\n\n/**\n * Split `text` into plain and matched runs for every term, case-insensitive.\n * Longest terms first so \"migrate\" wins over \"migrat\" at the same position.\n */\nexport function highlightSegments(text: string, terms: readonly string[]): HighlightSegment[] {\n const usable = [...terms].filter((t) => t.length > 0).sort((a, b) => b.length - a.length);\n if (usable.length === 0 || text.length === 0) return text ? [{ text, match: false }] : [];\n const re = new RegExp(usable.map(escapeRegExp).join('|'), 'gi');\n const out: HighlightSegment[] = [];\n let last = 0;\n for (const m of text.matchAll(re)) {\n const start = m.index ?? 0;\n if (m[0].length === 0) continue;\n if (start > last) out.push({ text: text.slice(last, start), match: false });\n out.push({ text: m[0], match: true });\n last = start + m[0].length;\n }\n if (last < text.length) out.push({ text: text.slice(last), match: false });\n return out;\n}\n\nexport interface SessionSearchGroup {\n sessionId: string;\n title: string;\n projectPath: string;\n engine: VerseEngine;\n /** The best-scoring hit in this session (the server returns hits best-first). */\n top: VerseSearchHit;\n /** Every hit this session contributed to the response. */\n count: number;\n /** Newest hit time, for the row's relative time. */\n latestAt: string;\n}\n\n/**\n * One row per session. The server ranks MESSAGES; the sidebar lists CHATS,\n * and five rows for one chat would push every other match off screen. Order\n * is the order each session first appears, i.e. by its best hit.\n */\nexport function groupSearchHits(hits: readonly VerseSearchHit[]): SessionSearchGroup[] {\n const groups = new Map<string, SessionSearchGroup>();\n for (const hit of hits) {\n const existing = groups.get(hit.sessionId);\n if (!existing) {\n groups.set(hit.sessionId, {\n sessionId: hit.sessionId,\n title: hit.title,\n projectPath: hit.projectPath,\n engine: hit.engine,\n top: hit,\n count: 1,\n latestAt: hit.at,\n });\n continue;\n }\n existing.count += 1;\n if (hit.at > existing.latestAt) existing.latestAt = hit.at;\n }\n return [...groups.values()];\n}\n"],"mappings":"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"}
@@ -1,2 +0,0 @@
1
- import{A as e,F as t,L as n,S as r,b as i,i as a,k as o,m as s,t as c,z as l}from"./verse-model-DyCwZF-M.js";import{r as u}from"./verse-store-b_Lek_c5.js";import{f as d}from"./format-BkWdOQDL.js";function f(e,t){return e?s([e],{seatId:e.id,model:t}):null}function p(e,t){return t!==`standard`&&o(e,t)!==null?t:`standard`}function m(e,t){return o(e,p(e,t))}function h(e,t){let n=i(e);if(n!==null)return n;let r=t.unavailableReason;return typeof r==`string`&&r.trim().length>0?r.trim():null}var g={standard:`Standard`,expansive:`Expansive`},_={claude:`Claude Code`,codex:`Codex CLI`,grok:`Grok CLI`,local:`Claude Code`};function v(e){let t=typeof e.cliVersion==`string`?e.cliVersion.trim():``;return t.length>0?`${_[e.engine]} ${t}`:null}function y(e){return(e.notes??[]).filter(e=>typeof e==`string`&&e.trim().length>0)}function b(e){return e===`fallback`}function x(e,t=`standard`){let n=p(e,t),r=o(e,n);return r?`${`${u(r.contextWindow)} ctx${b(e.windowSource)?` (est.)`:``}`}${r.autoCompactAt===null?``:` · compacts ≈${u(r.autoCompactAt)}`}${n===`expansive`?` (expansive)`:``}`:`window unknown`}function S(e){let t=o(e,`standard`),r=n(e)?o(e,`expansive`):null,i=[];if(!t)i.push(`Context window unknown for this model.`);else{let e=t.autoCompactAt===null?``:`; compacts at about ${u(t.autoCompactAt)}${r?` in Standard`:``}`;i.push(`${u(t.contextWindow)}-token window${e}.`)}return r&&i.push(`Expansive runs to about ${u(r.autoCompactAt??r.contextWindow)} before compacting.`),e.windowSource&&i.push(`Window ${a[e.windowSource]}.`),i.join(` `)}function C(e){return e===`codex`?c:null}function w(e){let t=o(e,`standard`),n=o(e,`expansive`),r=t?t.autoCompactAt??t.contextWindow:null,i=n?n.autoCompactAt??n.contextWindow:null;return r===null||i===null||r<=0?null:`A turn at ${u(i)} re-sends ${(i/r).toFixed(1)}× the tokens of one at ${u(r)}.`}function T(e,t,n){let r=o(t,`standard`),i=o(t,`expansive`),a=r?r.autoCompactAt??r.contextWindow:null,s=i?i.autoCompactAt??i.contextWindow:null;if(n===`standard`||s===null)return a===null?`The CLI compacts at its own default point for this model.`:e===`claude`?`Compacts at about ${u(a)}. Every turn re-sends the whole context, so holding it under this point keeps each turn cheaper and recall sharper.`:`Compacts at about ${u(a)} — the CLI's own default budget for this model.`;let c=w(t),l=C(e);return`Runs to about ${u(s)} before compacting — for tightly coupled, cross-cutting work that needs everything in view at once. Each turn re-sends everything held, so a long expansive chat uses noticeably more of your plan per turn.${c?` ${c}`:``}${l?` ${l}`:``}`}function E(e,t){return o(t,`standard`)?e===`grok`||e===`local`?`One budget: this CLI compacts at its own fixed point, and Verse cannot raise it per chat.`:`One budget: this model has no larger window to expand into.`:`This model’s window is unknown, so Verse cannot offer a larger budget for it.`}var D={fits:`code fits`,tight:`code fits, tight`,expansive:`code needs expansive`,split:`code too big — split`},O={fits:`Fits`,tight:`Tight fit`,expansive:`Needs expansive`,split:`Split the work`};function k(e){return e.roots.some(e=>e.truncated)}function A(e,n,r,i){if(typeof e!=`number`||!Number.isFinite(e)||e<0)return null;let a=l(i);if(p(n,r)===`expansive`&&n){let r=o(n,`expansive`);return t(e,{...n,contextWindow:r.contextWindow,autoCompactAt:r.autoCompactAt,expansive:null},a)}return t(e,n,a)}function j(e){let t=`${e.floor?`at least `:``}~${u(e.tokens)} tokens of tracked code`,r=p(e.option,e.mode)===`expansive`,i=o(e.option,`standard`),a=o(e.option,`expansive`),s=i?u(i.autoCompactAt??i.contextWindow):null,c=a?u(a.autoCompactAt??a.contextWindow):null,l=r?c:s,d=r?`Expansive budget`:`budget`;switch(e.verdict){case`fits`:return`All ${t} fits well inside this model's ${d}${l?` (compacts ≈${l})`:``}, with room left for the conversation.`;case`tight`:{let i=!r&&c!==null&&n(e.option)?` Expansive (≈${c}) would hold it with room to spare.`:``;return`${N(t)} fits under the ≈${l??`?`} compaction point${r?` of the Expansive budget`:``}, with little room for the conversation — expect it to compact if the agent reads widely.${i}`}case`expansive`:return`${N(t)} is more than the Standard budget (≈${s??`?`}) holds; only Expansive (≈${c??`?`}) takes it all. Switch to Expansive, or narrow the folders to the part you are changing.`;case`split`:return`${N(t)} is more than any single context on this model holds${c?`, even Expansive (≈${c})`:``}. Split the work: fan it out across several chats, each scoped to one folder or subsystem, or narrow this chat to the part you are changing.`}}function M(e){let t=e?` for ${_[e]}`:``;return`Estimated from the size of tracked text files (bytes ÷ 4), plus an estimated ~${u(l(e))} of fixed prompt${t} that every chat starts with. An agent rarely reads everything, so this is a ceiling, not a forecast.`}function N(e){return e.length===0?e:e.charAt(0).toUpperCase()+e.slice(1)}function P(e,t){let i=r(t,e);return{tokens:Math.floor(i.contextTokens),exact:i.exact,window:i.contextWindow,autoCompactAt:i.autoCompactAt,source:i.source,mode:i.mode,hasModes:n(i.option)}}function F(t){return t.cacheReadTokens<=0&&t.cacheCreationTokens<=0?null:e(t)}function I(e){return e===null||!Number.isFinite(e)?`—`:d(e)}function L(e){let t=new Map,n=0,r=null,i=(e,n,r)=>{if(!Number.isFinite(n)||n<0)return;let i=t.get(e)??{exact:null,bound:null};r?i.exact=Math.max(i.exact??0,n):i.bound=Math.max(i.bound??0,n),t.set(e,i)};for(let t of e)switch(t.type){case`usage`:r=t.usage,i(t.turnId,t.usage.contextTokens,t.usage.contextTokensExact!==!1);break;case`context`:t.turnId!==null&&i(t.turnId,t.contextTokens,t.exact);break;case`compaction`:n+=1}let a=0,o=null,s=!0,c=0;for(let e of t.values()){let t=e.exact??e.bound;t!==null&&(e.exact===null&&(s=!1),c+=1,a+=t,o=o===null?t:Math.max(o,t))}return{turns:c,average:c===0?null:Math.round(a/c),peak:o,exact:s,compactions:n,lastTurnCacheHit:r===null?null:F(r)}}function R(e,t,n,r){if(e.status===`running`||r===null)return null;let i=Date.parse(r);if(!Number.isFinite(i))return null;let a=n-i;return a<36e5||t<l(e.engine)?null:{idleMs:a,tokens:t,local:e.engine===`local`}}function z(e,t){return e.window!==null&&t.window!==null?e.tokens/e.window>t.tokens/t.window:e.window!==null||t.window===null&&e.tokens>t.tokens}function B(e,t){let n=new Map;for(let t of e){let e=n.get(t.seatId)??[];e.push(t),n.set(t.seatId,e)}let r=[];for(let[e,i]of n){let n=t.find(t=>t.id===e)??null,a=0,o=0,s=0,c=0,l=0,u=0,d=0,f=null;for(let e of i){a+=e.usage.inputTokens,o+=e.usage.cacheReadTokens,s+=e.usage.cacheCreationTokens,c+=e.usage.outputTokens,l+=e.turnCount,u+=e.compactionCount??0;let n=P(e,t);if(n.mode===`expansive`&&(d+=1),n.tokens<=0)continue;let r={sessionId:e.id,title:e.title,tokens:n.tokens,window:n.window,exact:n.exact};(f===null||z(r,f))&&(f=r)}r.push({seatId:e,label:n?.label??e,engine:n?.engine??i[0].engine,retired:n===null,sessions:i.length,turns:l,promptTokens:a+o+s,outputTokens:c,cacheHitRatio:F({inputTokens:a,cacheReadTokens:o,cacheCreationTokens:s}),compactions:u,expansiveSessions:d,fullest:f})}return r.sort((e,t)=>t.promptTokens-e.promptTokens||e.label.localeCompare(t.label))}export{f as C,B as S,L as T,E as _,m as a,v as b,j as c,I as d,R as f,h as g,A as h,T as i,k as l,S as m,O as n,C as o,x as p,D as r,w as s,g as t,M as u,F as v,P as w,y as x,p as y};
2
- //# sourceMappingURL=context-model-CIBmSugV.js.map