@ashlr/hub 3.11.3 → 3.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (558) hide show
  1. package/CHANGELOG.md +104 -0
  2. package/README.md +44 -18
  3. package/dist/authority-surface.json +74 -59
  4. package/dist/build-identity.json +2 -2
  5. package/dist/cli/authority.d.ts +39 -0
  6. package/dist/cli/authority.js +222 -55
  7. package/dist/cli/authority.js.map +1 -1
  8. package/dist/cli/help.js +1 -1
  9. package/dist/cli/help.js.map +1 -1
  10. package/dist/cli/verse.d.ts +3 -0
  11. package/dist/cli/verse.js +10 -0
  12. package/dist/cli/verse.js.map +1 -1
  13. package/dist/core/authority/trust-roots.js +7 -1
  14. package/dist/core/authority/trust-roots.js.map +1 -1
  15. package/dist/core/authority/types.d.ts +2 -2
  16. package/dist/core/cloud/cloud-api.js +1 -1
  17. package/dist/core/cloud/cloud-api.js.map +1 -1
  18. package/dist/core/cloud/delivery-contract.d.ts +1 -1
  19. package/dist/core/cloud/delivery-contract.js +25 -15
  20. package/dist/core/cloud/delivery-contract.js.map +1 -1
  21. package/dist/core/cloud/store.js +6 -0
  22. package/dist/core/cloud/store.js.map +1 -1
  23. package/dist/core/cloud/tracker.d.ts +2 -0
  24. package/dist/core/cloud/tracker.js +140 -37
  25. package/dist/core/cloud/tracker.js.map +1 -1
  26. package/dist/core/cloud/types.d.ts +9 -1
  27. package/dist/core/cloud/types.js.map +1 -1
  28. package/dist/core/comms/dispatch.d.ts +5 -0
  29. package/dist/core/comms/dispatch.js +12 -1
  30. package/dist/core/comms/dispatch.js.map +1 -1
  31. package/dist/core/comms/requests.d.ts +27 -1
  32. package/dist/core/comms/requests.js +50 -1
  33. package/dist/core/comms/requests.js.map +1 -1
  34. package/dist/core/daemon/loop.d.ts +14 -0
  35. package/dist/core/daemon/loop.js +35 -0
  36. package/dist/core/daemon/loop.js.map +1 -1
  37. package/dist/core/fabric/claude-usage.js +23 -1
  38. package/dist/core/fabric/claude-usage.js.map +1 -1
  39. package/dist/core/fleet/dispatch-router.d.ts +7 -0
  40. package/dist/core/fleet/dispatch-router.js +4 -1
  41. package/dist/core/fleet/dispatch-router.js.map +1 -1
  42. package/dist/core/fleet/tick-hooks-live.d.ts +5 -1
  43. package/dist/core/fleet/tick-hooks-live.js +10 -1
  44. package/dist/core/fleet/tick-hooks-live.js.map +1 -1
  45. package/dist/core/local-runtime/llama/config.d.ts +14 -0
  46. package/dist/core/local-runtime/llama/config.js +20 -2
  47. package/dist/core/local-runtime/llama/config.js.map +1 -1
  48. package/dist/core/local-runtime/llama/process.d.ts +19 -0
  49. package/dist/core/local-runtime/llama/process.js +67 -17
  50. package/dist/core/local-runtime/llama/process.js.map +1 -1
  51. package/dist/core/local-runtime/llama/supervisor.js +14 -3
  52. package/dist/core/local-runtime/llama/supervisor.js.map +1 -1
  53. package/dist/core/observability/rollup.d.ts +12 -0
  54. package/dist/core/observability/rollup.js +37 -2
  55. package/dist/core/observability/rollup.js.map +1 -1
  56. package/dist/core/observability/usage-source.js +49 -1
  57. package/dist/core/observability/usage-source.js.map +1 -1
  58. package/dist/core/resources/connection-monitor.js +47 -4
  59. package/dist/core/resources/connection-monitor.js.map +1 -1
  60. package/dist/core/resources/engineering-mission-store.d.ts +1 -1
  61. package/dist/core/routing/headroom.js +7 -2
  62. package/dist/core/routing/headroom.js.map +1 -1
  63. package/dist/core/routing/router.d.ts +48 -0
  64. package/dist/core/routing/router.js +129 -13
  65. package/dist/core/routing/router.js.map +1 -1
  66. package/dist/core/run/best-of-n.d.ts +7 -0
  67. package/dist/core/run/best-of-n.js +3 -0
  68. package/dist/core/run/best-of-n.js.map +1 -1
  69. package/dist/core/run/harness-dispatch.d.ts +147 -0
  70. package/dist/core/run/harness-dispatch.js +234 -0
  71. package/dist/core/run/harness-dispatch.js.map +1 -0
  72. package/dist/core/run/orchestrator.js +3 -0
  73. package/dist/core/run/orchestrator.js.map +1 -1
  74. package/dist/core/run/provider-client.d.ts +8 -0
  75. package/dist/core/run/provider-client.js +4 -0
  76. package/dist/core/run/provider-client.js.map +1 -1
  77. package/dist/core/run/sandboxed-engine.d.ts +8 -0
  78. package/dist/core/run/sandboxed-engine.js +60 -7
  79. package/dist/core/run/sandboxed-engine.js.map +1 -1
  80. package/dist/core/types.d.ts +14 -0
  81. package/dist/core/types.js.map +1 -1
  82. package/dist/core/universe/builtins/preparation/manifest.json +1 -1
  83. package/dist/core/universe/builtins/preparation/preparation-bridge.mjs +188 -6
  84. package/dist/core/universe/builtins/preparation/preparation-verification-fixtures.mjs +187 -5
  85. package/dist/core/universe/firm-demo.d.ts +1 -1
  86. package/dist/core/universe/firm-graph.d.ts +2 -2
  87. package/dist/core/util/scrub.js +16 -3
  88. package/dist/core/util/scrub.js.map +1 -1
  89. package/dist/core/verse/accounts.d.ts +9 -1
  90. package/dist/core/verse/accounts.js +52 -11
  91. package/dist/core/verse/accounts.js.map +1 -1
  92. package/dist/core/verse/apps-api.d.ts +12 -0
  93. package/dist/core/verse/apps-api.js +22 -4
  94. package/dist/core/verse/apps-api.js.map +1 -1
  95. package/dist/core/verse/apps.js +22 -12
  96. package/dist/core/verse/apps.js.map +1 -1
  97. package/dist/core/verse/local-models.js +3 -7
  98. package/dist/core/verse/local-models.js.map +1 -1
  99. package/dist/core/verse/model-display-name.d.ts +34 -0
  100. package/dist/core/verse/model-display-name.js +125 -0
  101. package/dist/core/verse/model-display-name.js.map +1 -0
  102. package/dist/core/verse/seats.d.ts +11 -2
  103. package/dist/core/verse/seats.js +42 -18
  104. package/dist/core/verse/seats.js.map +1 -1
  105. package/dist/core/verse/transient-events.d.ts +21 -0
  106. package/dist/core/verse/transient-events.js +12 -0
  107. package/dist/core/verse/transient-events.js.map +1 -0
  108. package/dist/core/verse/types.d.ts +6 -13
  109. package/dist/core/verse/types.js +5 -36
  110. package/dist/core/verse/types.js.map +1 -1
  111. package/dist/core/web/public/next/assets/ActionMenu-B4-39f2S.js +2 -0
  112. package/dist/core/web/public/next/assets/{ActionMenu-FxXeRbPx.js.map → ActionMenu-B4-39f2S.js.map} +1 -1
  113. package/dist/core/web/public/next/assets/Advanced-B-LqYXvd.js +2 -0
  114. package/dist/core/web/public/next/assets/Advanced-B-LqYXvd.js.map +1 -0
  115. package/dist/core/web/public/next/assets/App-E2zCDRxm.js +7 -0
  116. package/dist/core/web/public/next/assets/App-E2zCDRxm.js.map +1 -0
  117. package/dist/core/web/public/next/assets/AppsSection-8wXPPhZb.js +2 -0
  118. package/dist/core/web/public/next/assets/AppsSection-8wXPPhZb.js.map +1 -0
  119. package/dist/core/web/public/next/assets/AreaTrend-BFimExYn.js +2 -0
  120. package/dist/core/web/public/next/assets/{AreaTrend-CDxrQU4b.js.map → AreaTrend-BFimExYn.js.map} +1 -1
  121. package/dist/core/web/public/next/assets/AutonomyOffState-B5eEkmiz.js +2 -0
  122. package/dist/core/web/public/next/assets/AutonomyOffState-B5eEkmiz.js.map +1 -0
  123. package/dist/core/web/public/next/assets/AutonomyOffState-DmbE71vI.css +1 -0
  124. package/dist/core/web/public/next/assets/AutonomySection-B46igJKR.js +2 -0
  125. package/dist/core/web/public/next/assets/{AutonomySection-DuQkHGD_.js.map → AutonomySection-B46igJKR.js.map} +1 -1
  126. package/dist/core/web/public/next/assets/BranchBar-BRkrEQGs.js +2 -0
  127. package/dist/core/web/public/next/assets/{BranchBar-CLsvOcyK.js.map → BranchBar-BRkrEQGs.js.map} +1 -1
  128. package/dist/core/web/public/next/assets/BudgetControl-T_RjPrw9.js +2 -0
  129. package/dist/core/web/public/next/assets/{BudgetControl-TL3FeZ1D.js.map → BudgetControl-T_RjPrw9.js.map} +1 -1
  130. package/dist/core/web/public/next/assets/{Button-HHXgoXGr.js → Button-BhO-WKPp.js} +2 -2
  131. package/dist/core/web/public/next/assets/{Button-HHXgoXGr.js.map → Button-BhO-WKPp.js.map} +1 -1
  132. package/dist/core/web/public/next/assets/CapacityStrip-CkFz5vq2.js +2 -0
  133. package/dist/core/web/public/next/assets/{CapacityStrip-qReu0RaF.js.map → CapacityStrip-CkFz5vq2.js.map} +1 -1
  134. package/dist/core/web/public/next/assets/{useChartWidth-BW6SwYIK.css → ChartFrame-BVuBe6RP.css} +1 -1
  135. package/dist/core/web/public/next/assets/ChartFrame-SygZ7B3x.js +2 -0
  136. package/dist/core/web/public/next/assets/ChartFrame-SygZ7B3x.js.map +1 -0
  137. package/dist/core/web/public/next/assets/ChatSection-D6WybBpB.js +3 -0
  138. package/dist/core/web/public/next/assets/ChatSection-D6WybBpB.js.map +1 -0
  139. package/dist/core/web/public/next/assets/CloudBudgetForm-Bd91iStN.js +2 -0
  140. package/dist/core/web/public/next/assets/CloudBudgetForm-Bd91iStN.js.map +1 -0
  141. package/dist/core/web/public/next/assets/CommandPalette-B6SgDJH-.js +2 -0
  142. package/dist/core/web/public/next/assets/CommandPalette-B6SgDJH-.js.map +1 -0
  143. package/dist/core/web/public/next/assets/CommandSection-CvAVd1w4.css +1 -0
  144. package/dist/core/web/public/next/assets/CommandSection-DgMGoepd.js +2 -0
  145. package/dist/core/web/public/next/assets/CommandSection-DgMGoepd.js.map +1 -0
  146. package/dist/core/web/public/next/assets/ConfirmDialog-Bv4hdK2T.js +2 -0
  147. package/dist/core/web/public/next/assets/{ConfirmDialog-DLrLKM0c.js.map → ConfirmDialog-Bv4hdK2T.js.map} +1 -1
  148. package/dist/core/web/public/next/assets/DeleteChatDialog-CH1Ix8Eh.js +2 -0
  149. package/dist/core/web/public/next/assets/DeleteChatDialog-CH1Ix8Eh.js.map +1 -0
  150. package/dist/core/web/public/next/assets/Dialog-BSsIFNqD.js +2 -0
  151. package/dist/core/web/public/next/assets/{Dialog-BS9Dxi3G.js.map → Dialog-BSsIFNqD.js.map} +1 -1
  152. package/dist/core/web/public/next/assets/DiffPane-BpNuJmth.js +2 -0
  153. package/dist/core/web/public/next/assets/{DiffPane-TOmUf3b2.js.map → DiffPane-BpNuJmth.js.map} +1 -1
  154. package/dist/core/web/public/next/assets/DiffViewer-CJarUvs0.js +2 -0
  155. package/dist/core/web/public/next/assets/{DiffViewer-BpH56302.js.map → DiffViewer-CJarUvs0.js.map} +1 -1
  156. package/dist/core/web/public/next/assets/DockHost-DW9q0NdR.js +2 -0
  157. package/dist/core/web/public/next/assets/DockHost-DW9q0NdR.js.map +1 -0
  158. package/dist/core/web/public/next/assets/{EmptyState-BqR5YAmf.js → EmptyState-DPrd2aak.js} +2 -2
  159. package/dist/core/web/public/next/assets/{EmptyState-BqR5YAmf.js.map → EmptyState-DPrd2aak.js.map} +1 -1
  160. package/dist/core/web/public/next/assets/{Epistemic-dhvDTwAZ.js → Epistemic-D7MxSmED.js} +2 -2
  161. package/dist/core/web/public/next/assets/{Epistemic-dhvDTwAZ.js.map → Epistemic-D7MxSmED.js.map} +1 -1
  162. package/dist/core/web/public/next/assets/FleetSection-BdZN6rGS.js +3 -0
  163. package/dist/core/web/public/next/assets/FleetSection-BdZN6rGS.js.map +1 -0
  164. package/dist/core/web/public/next/assets/Funnel-BeNQZWv2.js +2 -0
  165. package/dist/core/web/public/next/assets/{Funnel-D2u7Wlzc.js.map → Funnel-BeNQZWv2.js.map} +1 -1
  166. package/dist/core/web/public/next/assets/GearTray-CIPtzeIx.js +2 -0
  167. package/dist/core/web/public/next/assets/{GearTray-Cb2npoxM.js.map → GearTray-CIPtzeIx.js.map} +1 -1
  168. package/dist/core/web/public/next/assets/GrowthSection-iiQg6wvK.js +2 -0
  169. package/dist/core/web/public/next/assets/{GrowthSection-C5aDPs8B.js.map → GrowthSection-iiQg6wvK.js.map} +1 -1
  170. package/dist/core/web/public/next/assets/HandoffDialog-DrQ6ofuy.js +2 -0
  171. package/dist/core/web/public/next/assets/{HandoffDialog-BF3AYg-X.js.map → HandoffDialog-DrQ6ofuy.js.map} +1 -1
  172. package/dist/core/web/public/next/assets/Input-C0MQxEM6.js +2 -0
  173. package/dist/core/web/public/next/assets/{Input-B5dmGLZx.js.map → Input-C0MQxEM6.js.map} +1 -1
  174. package/dist/core/web/public/next/assets/LeaderCard-BRr3_yE-.js +2 -0
  175. package/dist/core/web/public/next/assets/LeaderCard-BRr3_yE-.js.map +1 -0
  176. package/dist/core/web/public/next/assets/MatrixHeatmap-DZvZeWXL.js +2 -0
  177. package/dist/core/web/public/next/assets/{MatrixHeatmap-BgEUs2Eu.js.map → MatrixHeatmap-DZvZeWXL.js.map} +1 -1
  178. package/dist/core/web/public/next/assets/McpSection-BRuCcTjT.js +2 -0
  179. package/dist/core/web/public/next/assets/{McpSection-DZkiOuoq.js.map → McpSection-BRuCcTjT.js.map} +1 -1
  180. package/dist/core/web/public/next/assets/MessageMarkdown-bRvD5nSc.js +3 -0
  181. package/dist/core/web/public/next/assets/{MessageMarkdown-BauY8ZTY.js.map → MessageMarkdown-bRvD5nSc.js.map} +1 -1
  182. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DLBNLfsn.js → MessageMarkdownRenderer-FjjkPKA2.js} +4 -4
  183. package/dist/core/web/public/next/assets/{MessageMarkdownRenderer-DLBNLfsn.js.map → MessageMarkdownRenderer-FjjkPKA2.js.map} +1 -1
  184. package/dist/core/web/public/next/assets/{Meter-DNeocJnD.js → Meter-CFNLpwA-.js} +2 -2
  185. package/dist/core/web/public/next/assets/{Meter-DNeocJnD.js.map → Meter-CFNLpwA-.js.map} +1 -1
  186. package/dist/core/web/public/next/assets/MindSection-BTIiQS8P.js +2 -0
  187. package/dist/core/web/public/next/assets/MindSection-BTIiQS8P.js.map +1 -0
  188. package/dist/core/web/public/next/assets/MutationTokenDialog-T7gv3a9r.js +2 -0
  189. package/dist/core/web/public/next/assets/{MutationTokenDialog-mxrw0Yvy.js.map → MutationTokenDialog-T7gv3a9r.js.map} +1 -1
  190. package/dist/core/web/public/next/assets/NeedsYouDrawer-lYN4G_aM.js +2 -0
  191. package/dist/core/web/public/next/assets/{NeedsYouDrawer-CO-Balfp.js.map → NeedsYouDrawer-lYN4G_aM.js.map} +1 -1
  192. package/dist/core/web/public/next/assets/NeedsYouList-BgH8ezqf.js +2 -0
  193. package/dist/core/web/public/next/assets/{NeedsYouList-CzDZbzRD.js.map → NeedsYouList-BgH8ezqf.js.map} +1 -1
  194. package/dist/core/web/public/next/assets/NewChatDialog-Db5Xjrk8.js +3 -0
  195. package/dist/core/web/public/next/assets/NewChatDialog-Db5Xjrk8.js.map +1 -0
  196. package/dist/core/web/public/next/assets/OnboardingFlow-HUNQGQuU.css +1 -0
  197. package/dist/core/web/public/next/assets/OnboardingFlow-LoY-zuSe.js +2 -0
  198. package/dist/core/web/public/next/assets/OnboardingFlow-LoY-zuSe.js.map +1 -0
  199. package/dist/core/web/public/next/assets/OnboardingGate-C4VXn7BJ.js +3 -0
  200. package/dist/core/web/public/next/assets/OnboardingGate-C4VXn7BJ.js.map +1 -0
  201. package/dist/core/web/public/next/assets/PreviewPane-BPBbcROb.js +2 -0
  202. package/dist/core/web/public/next/assets/{PreviewPane-BS-CleCd.js.map → PreviewPane-BPBbcROb.js.map} +1 -1
  203. package/dist/core/web/public/next/assets/{ProviderLogo-C5mBg8i0.js → ProviderLogo-CT2cSfkg.js} +2 -2
  204. package/dist/core/web/public/next/assets/{ProviderLogo-C5mBg8i0.js.map → ProviderLogo-CT2cSfkg.js.map} +1 -1
  205. package/dist/core/web/public/next/assets/RailStatus-Vgl0GYtd.js +2 -0
  206. package/dist/core/web/public/next/assets/{RailStatus-cPRyOmrk.js.map → RailStatus-Vgl0GYtd.js.map} +1 -1
  207. package/dist/core/web/public/next/assets/{RefreshIndicator-CMwSCiz5.js → RefreshIndicator-CSyqpY_q.js} +2 -2
  208. package/dist/core/web/public/next/assets/{RefreshIndicator-CMwSCiz5.js.map → RefreshIndicator-CSyqpY_q.js.map} +1 -1
  209. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BFi1opsC.js → ResourcePoolConsoleApp-BX2nkdmZ.js} +4 -4
  210. package/dist/core/web/public/next/assets/{ResourcePoolConsoleApp-BFi1opsC.js.map → ResourcePoolConsoleApp-BX2nkdmZ.js.map} +1 -1
  211. package/dist/core/web/public/next/assets/ResourcesChrome-B2U2lO1H.js +3 -0
  212. package/dist/core/web/public/next/assets/ResourcesChrome-B2U2lO1H.js.map +1 -0
  213. package/dist/core/web/public/next/assets/ResourcesDrawer-BCFJ2Uq8.css +1 -0
  214. package/dist/core/web/public/next/assets/ResourcesDrawer-DlUKOjl9.js +2 -0
  215. package/dist/core/web/public/next/assets/ResourcesDrawer-DlUKOjl9.js.map +1 -0
  216. package/dist/core/web/public/next/assets/RouteErrorBoundary-BaC7YVzR.js +2 -0
  217. package/dist/core/web/public/next/assets/{RouteErrorBoundary-DYtwc2ja.js.map → RouteErrorBoundary-BaC7YVzR.js.map} +1 -1
  218. package/dist/core/web/public/next/assets/RunInCloudAction-D5PDHJPE.js +2 -0
  219. package/dist/core/web/public/next/assets/{RunInCloudAction-BEGEEM8O.js.map → RunInCloudAction-D5PDHJPE.js.map} +1 -1
  220. package/dist/core/web/public/next/assets/SeatSelector-Cg75LInq.js +3 -0
  221. package/dist/core/web/public/next/assets/{SeatSelector-CYHRR7Wp.js.map → SeatSelector-Cg75LInq.js.map} +1 -1
  222. package/dist/core/web/public/next/assets/Segmented-CametjLt.js +2 -0
  223. package/dist/core/web/public/next/assets/{Segmented-BE53BenI.js.map → Segmented-CametjLt.js.map} +1 -1
  224. package/dist/core/web/public/next/assets/Select-De52fghU.js +2 -0
  225. package/dist/core/web/public/next/assets/{Select-BwSGkHCS.js.map → Select-De52fghU.js.map} +1 -1
  226. package/dist/core/web/public/next/assets/SessionGate-CzlcNq3O.js +2 -0
  227. package/dist/core/web/public/next/assets/{SessionGate-e0dFJm9d.js.map → SessionGate-CzlcNq3O.js.map} +1 -1
  228. package/dist/core/web/public/next/assets/SessionInsightChip-Bk_Owa7u.js +2 -0
  229. package/dist/core/web/public/next/assets/{SessionInsightChip-CxlSyueJ.js.map → SessionInsightChip-Bk_Owa7u.js.map} +1 -1
  230. package/dist/core/web/public/next/assets/SessionSearch-C6C8DHN8.js +2 -0
  231. package/dist/core/web/public/next/assets/{SessionSearch-_yp7S2TP.js.map → SessionSearch-C6C8DHN8.js.map} +1 -1
  232. package/dist/core/web/public/next/assets/SettingsSection-mI9wQYZg.js +2 -0
  233. package/dist/core/web/public/next/assets/SettingsSection-mI9wQYZg.js.map +1 -0
  234. package/dist/core/web/public/next/assets/Sheet-CJhK9Dqv.js +2 -0
  235. package/dist/core/web/public/next/assets/{Sheet-DVP2Mgy6.js.map → Sheet-CJhK9Dqv.js.map} +1 -1
  236. package/dist/core/web/public/next/assets/ShortcutsOverlay-DDW-i9Fc.js +2 -0
  237. package/dist/core/web/public/next/assets/{ShortcutsOverlay-BcIcoClX.js.map → ShortcutsOverlay-DDW-i9Fc.js.map} +1 -1
  238. package/dist/core/web/public/next/assets/Sidebar-DT7ykaqS.js +3 -0
  239. package/dist/core/web/public/next/assets/Sidebar-DT7ykaqS.js.map +1 -0
  240. package/dist/core/web/public/next/assets/Slider-Bwd9HfXl.js +2 -0
  241. package/dist/core/web/public/next/assets/{Slider-BypUWjpH.js.map → Slider-Bwd9HfXl.js.map} +1 -1
  242. package/dist/core/web/public/next/assets/StatTile-DPZ5yyaU.js +2 -0
  243. package/dist/core/web/public/next/assets/StatTile-DPZ5yyaU.js.map +1 -0
  244. package/dist/core/web/public/next/assets/{StatusBadge-HCZp416_.js → StatusBadge-DHKRtttH.js} +2 -2
  245. package/dist/core/web/public/next/assets/{StatusBadge-HCZp416_.js.map → StatusBadge-DHKRtttH.js.map} +1 -1
  246. package/dist/core/web/public/next/assets/StepBand-DQykLkk_.js +2 -0
  247. package/dist/core/web/public/next/assets/{StepBand-Duz1PUes.js.map → StepBand-DQykLkk_.js.map} +1 -1
  248. package/dist/core/web/public/next/assets/Surface-D--LXgQm.js +2 -0
  249. package/dist/core/web/public/next/assets/Surface-D--LXgQm.js.map +1 -0
  250. package/dist/core/web/public/next/assets/Surface-e1z6GdZt.css +1 -0
  251. package/dist/core/web/public/next/assets/Swimlane-BzH6OCee.js +2 -0
  252. package/dist/core/web/public/next/assets/{Swimlane-DGcIcnNA.js.map → Swimlane-BzH6OCee.js.map} +1 -1
  253. package/dist/core/web/public/next/assets/{Switch-iveI-8NY.js → Switch-PMixU6b0.js} +2 -2
  254. package/dist/core/web/public/next/assets/{Switch-iveI-8NY.js.map → Switch-PMixU6b0.js.map} +1 -1
  255. package/dist/core/web/public/next/assets/{Tag-DH15CUJp.js → Tag-fordBsrJ.js} +2 -2
  256. package/dist/core/web/public/next/assets/{Tag-DH15CUJp.js.map → Tag-fordBsrJ.js.map} +1 -1
  257. package/dist/core/web/public/next/assets/TerminalPane-BSnGdUuF.js +7 -0
  258. package/dist/core/web/public/next/assets/TerminalPane-BSnGdUuF.js.map +1 -0
  259. package/dist/core/web/public/next/assets/UniverseConsoleApp-DtXFhAhw.js +2 -0
  260. package/dist/core/web/public/next/assets/{UniverseConsoleApp-C8yQ0AaR.js.map → UniverseConsoleApp-DtXFhAhw.js.map} +1 -1
  261. package/dist/core/web/public/next/assets/{UniverseView-_nPURPqe.js → UniverseView-sWm3pnTW.js} +3 -3
  262. package/dist/core/web/public/next/assets/{UniverseView-_nPURPqe.js.map → UniverseView-sWm3pnTW.js.map} +1 -1
  263. package/dist/core/web/public/next/assets/UsageSection-CiD1DbuF.js +3 -0
  264. package/dist/core/web/public/next/assets/UsageSection-CiD1DbuF.js.map +1 -0
  265. package/dist/core/web/public/next/assets/VerseConsoleApp-BCY5uSok.js +3 -0
  266. package/dist/core/web/public/next/assets/VerseConsoleApp-BCY5uSok.js.map +1 -0
  267. package/dist/core/web/public/next/assets/Workspace-BQSZFSeO.js +10 -0
  268. package/dist/core/web/public/next/assets/Workspace-BQSZFSeO.js.map +1 -0
  269. package/dist/core/web/public/next/assets/actions-BmIf9avl.css +1 -0
  270. package/dist/core/web/public/next/assets/actions-Ci6I4C0l.js +2 -0
  271. package/dist/core/web/public/next/assets/actions-Ci6I4C0l.js.map +1 -0
  272. package/dist/core/web/public/next/assets/apps-model-DlwnfqwJ.js +2 -0
  273. package/dist/core/web/public/next/assets/apps-model-DlwnfqwJ.js.map +1 -0
  274. package/dist/core/web/public/next/assets/authority-model-BFuPezSo.js +2 -0
  275. package/dist/core/web/public/next/assets/authority-model-BFuPezSo.js.map +1 -0
  276. package/dist/core/web/public/next/assets/binding-left-DZpq5sLf.js +2 -0
  277. package/dist/core/web/public/next/assets/binding-left-DZpq5sLf.js.map +1 -0
  278. package/dist/core/web/public/next/assets/{budget-queries-V3wcJVK_.js → budget-queries-DsAjH8ac.js} +2 -2
  279. package/dist/core/web/public/next/assets/{budget-queries-V3wcJVK_.js.map → budget-queries-DsAjH8ac.js.map} +1 -1
  280. package/dist/core/web/public/next/assets/capacity-strip-model-Dn1cNOhz.js +2 -0
  281. package/dist/core/web/public/next/assets/capacity-strip-model-Dn1cNOhz.js.map +1 -0
  282. package/dist/core/web/public/next/assets/charts-C_xJbJiw.js +2 -0
  283. package/dist/core/web/public/next/assets/charts-C_xJbJiw.js.map +1 -0
  284. package/dist/core/web/public/next/assets/charts-DhKTrQLw.css +1 -0
  285. package/dist/core/web/public/next/assets/clipboard-DkZdqlxf.js +2 -0
  286. package/dist/core/web/public/next/assets/clipboard-DkZdqlxf.js.map +1 -0
  287. package/dist/core/web/public/next/assets/cloud-D-HXms6q.css +1 -0
  288. package/dist/core/web/public/next/assets/cloud-model-CX407gPY.js +2 -0
  289. package/dist/core/web/public/next/assets/cloud-model-CX407gPY.js.map +1 -0
  290. package/dist/core/web/public/next/assets/cloud-queries-QAhpExlz.js +2 -0
  291. package/dist/core/web/public/next/assets/cloud-queries-QAhpExlz.js.map +1 -0
  292. package/dist/core/web/public/next/assets/cloud.module-DOP-N4Ch.js +2 -0
  293. package/dist/core/web/public/next/assets/cloud.module-DOP-N4Ch.js.map +1 -0
  294. package/dist/core/web/public/next/assets/command-catalog-CF0cQQac.js +2 -0
  295. package/dist/core/web/public/next/assets/command-catalog-CF0cQQac.js.map +1 -0
  296. package/dist/core/web/public/next/assets/context-model-Co4wh3SM.js +2 -0
  297. package/dist/core/web/public/next/assets/context-model-Co4wh3SM.js.map +1 -0
  298. package/dist/core/web/public/next/assets/context-model-DV1zCfAm.js +3 -0
  299. package/dist/core/web/public/next/assets/context-model-DV1zCfAm.js.map +1 -0
  300. package/dist/core/web/public/next/assets/{context-queries-CrPcHWTz.js → context-queries-CktFQqSS.js} +2 -2
  301. package/dist/core/web/public/next/assets/{context-queries-CrPcHWTz.js.map → context-queries-CktFQqSS.js.map} +1 -1
  302. package/dist/core/web/public/next/assets/{control-queries-CmgBgKV7.js → control-queries-DAvlh_YM.js} +2 -2
  303. package/dist/core/web/public/next/assets/{control-queries-CmgBgKV7.js.map → control-queries-DAvlh_YM.js.map} +1 -1
  304. package/dist/core/web/public/next/assets/copy-setup-CqRSfELB.js +2 -0
  305. package/dist/core/web/public/next/assets/copy-setup-CqRSfELB.js.map +1 -0
  306. package/dist/core/web/public/next/assets/dock-icons-BFuBbqJl.js +2 -0
  307. package/dist/core/web/public/next/assets/{dock-icons-CUh8dOxJ.js.map → dock-icons-BFuBbqJl.js.map} +1 -1
  308. package/dist/core/web/public/next/assets/fleet-model-Dfd5JyLR.js +2 -0
  309. package/dist/core/web/public/next/assets/fleet-model-Dfd5JyLR.js.map +1 -0
  310. package/dist/core/web/public/next/assets/fleet-queries-RtMTd5rR.js +2 -0
  311. package/dist/core/web/public/next/assets/fleet-queries-RtMTd5rR.js.map +1 -0
  312. package/dist/core/web/public/next/assets/{focus-trap-HtcoXeEq.js → focus-trap-BdrbWfC4.js} +2 -2
  313. package/dist/core/web/public/next/assets/{focus-trap-HtcoXeEq.js.map → focus-trap-BdrbWfC4.js.map} +1 -1
  314. package/dist/core/web/public/next/assets/format-Dk4Fmxax.js +2 -0
  315. package/dist/core/web/public/next/assets/format-Dk4Fmxax.js.map +1 -0
  316. package/dist/core/web/public/next/assets/{git-model-bk_RXh3y.js → git-model-_BnI_Ogh.js} +2 -2
  317. package/dist/core/web/public/next/assets/{git-model-bk_RXh3y.js.map → git-model-_BnI_Ogh.js.map} +1 -1
  318. package/dist/core/web/public/next/assets/global-CNNGMril.js +2 -0
  319. package/dist/core/web/public/next/assets/{global-oEl9Qj8u.js.map → global-CNNGMril.js.map} +1 -1
  320. package/dist/core/web/public/next/assets/{guarded-runners-LHLXmXIk.js → guarded-runners-DPh2d32e.js} +2 -2
  321. package/dist/core/web/public/next/assets/{guarded-runners-LHLXmXIk.js.map → guarded-runners-DPh2d32e.js.map} +1 -1
  322. package/dist/core/web/public/next/assets/icons-0haWy6nh.js +2 -0
  323. package/dist/core/web/public/next/assets/icons-0haWy6nh.js.map +1 -0
  324. package/dist/core/web/public/next/assets/{index-BVxOlseC.js → index-QesfXBsb.js} +3 -3
  325. package/dist/core/web/public/next/assets/{index-BVxOlseC.js.map → index-QesfXBsb.js.map} +1 -1
  326. package/dist/core/web/public/next/assets/live-model-De-q0ZFK.js +2 -0
  327. package/dist/core/web/public/next/assets/live-model-De-q0ZFK.js.map +1 -0
  328. package/dist/core/web/public/next/assets/local-model-C9xNi9fN.js +2 -0
  329. package/dist/core/web/public/next/assets/local-model-C9xNi9fN.js.map +1 -0
  330. package/dist/core/web/public/next/assets/mind.module-BrK2nFOL.js +2 -0
  331. package/dist/core/web/public/next/assets/{mind.module-gTGAuJt1.js.map → mind.module-BrK2nFOL.js.map} +1 -1
  332. package/dist/core/web/public/next/assets/mutations-DTCtKCn_.js +2 -0
  333. package/dist/core/web/public/next/assets/{mutations-C5S7okTW.js.map → mutations-DTCtKCn_.js.map} +1 -1
  334. package/dist/core/web/public/next/assets/nav-KmGX0CVz.js +2 -0
  335. package/dist/core/web/public/next/assets/{nav-NVtnuG7A.js.map → nav-KmGX0CVz.js.map} +1 -1
  336. package/dist/core/web/public/next/assets/{overnight-queries-DGm3qL1b.js → overnight-queries-mlO0xzsr.js} +2 -2
  337. package/dist/core/web/public/next/assets/{overnight-queries-DGm3qL1b.js.map → overnight-queries-mlO0xzsr.js.map} +1 -1
  338. package/dist/core/web/public/next/assets/primitives-D0Fb3TtS.js +1 -0
  339. package/dist/core/web/public/next/assets/{queries-CYisSAAB.js → queries-CyBE8nsW.js} +2 -2
  340. package/dist/core/web/public/next/assets/{queries-CYisSAAB.js.map → queries-CyBE8nsW.js.map} +1 -1
  341. package/dist/core/web/public/next/assets/reasoning-pref-CaoA4_Vl.js +2 -0
  342. package/dist/core/web/public/next/assets/{reasoning-pref-BUcFF_5G.js.map → reasoning-pref-CaoA4_Vl.js.map} +1 -1
  343. package/dist/core/web/public/next/assets/{reveal-anchor-D-tV8xau.js → reveal-anchor-BP1VqnPU.js} +2 -2
  344. package/dist/core/web/public/next/assets/{reveal-anchor-D-tV8xau.js.map → reveal-anchor-BP1VqnPU.js.map} +1 -1
  345. package/dist/core/web/public/next/assets/seat-subscription-C5Tvr0WQ.js +2 -0
  346. package/dist/core/web/public/next/assets/{seat-subscription-B-f9ViU2.js.map → seat-subscription-C5Tvr0WQ.js.map} +1 -1
  347. package/dist/core/web/public/next/assets/{sidebar-model-DQ-FyBHW.js → sidebar-model-B5Qk95k_.js} +2 -2
  348. package/dist/core/web/public/next/assets/{sidebar-model-DQ-FyBHW.js.map → sidebar-model-B5Qk95k_.js.map} +1 -1
  349. package/dist/core/web/public/next/assets/slots-DHKQDoE6.js +3 -0
  350. package/dist/core/web/public/next/assets/{slots-BhP8b8tf.js.map → slots-DHKQDoE6.js.map} +1 -1
  351. package/dist/core/web/public/next/assets/surface-data-CchClvHo.js +2 -0
  352. package/dist/core/web/public/next/assets/surface-data-CchClvHo.js.map +1 -0
  353. package/dist/core/web/public/next/assets/surface-prefetch-BWr0LBQn.js +2 -0
  354. package/dist/core/web/public/next/assets/surface-prefetch-BWr0LBQn.js.map +1 -0
  355. package/dist/core/web/public/next/assets/{tasks-model-BKDNqmmt.js → tasks-model-D6WFVULI.js} +2 -2
  356. package/dist/core/web/public/next/assets/{tasks-model-BKDNqmmt.js.map → tasks-model-D6WFVULI.js.map} +1 -1
  357. package/dist/core/web/public/next/assets/{terminal-icons-D2xe-aM1.js → terminal-icons-BvCvuXk2.js} +2 -2
  358. package/dist/core/web/public/next/assets/{terminal-icons-D2xe-aM1.js.map → terminal-icons-BvCvuXk2.js.map} +1 -1
  359. package/dist/core/web/public/next/assets/transient-events-nTLhMBND.js +2 -0
  360. package/dist/core/web/public/next/assets/transient-events-nTLhMBND.js.map +1 -0
  361. package/dist/core/web/public/next/assets/types-D5XOdyw8.js.map +1 -1
  362. package/dist/core/web/public/next/assets/{usage-queries-BZuAANlI.js → usage-queries-D1SU1t7r.js} +2 -2
  363. package/dist/core/web/public/next/assets/{usage-queries-BZuAANlI.js.map → usage-queries-D1SU1t7r.js.map} +1 -1
  364. package/dist/core/web/public/next/assets/{use-guarded-action-Cf4MeNBa.js → use-guarded-action-BZmBv7CJ.js} +2 -2
  365. package/dist/core/web/public/next/assets/{use-guarded-action-Cf4MeNBa.js.map → use-guarded-action-BZmBv7CJ.js.map} +1 -1
  366. package/dist/core/web/public/next/assets/{use-ticker-D9yi49my.js → use-ticker-CkJ4-0wU.js} +2 -2
  367. package/dist/core/web/public/next/assets/{use-ticker-D9yi49my.js.map → use-ticker-CkJ4-0wU.js.map} +1 -1
  368. package/dist/core/web/public/next/assets/{use-token-gate-DqrSXdX6.js → use-token-gate-CYcfk_GS.js} +2 -2
  369. package/dist/core/web/public/next/assets/{use-token-gate-DqrSXdX6.js.map → use-token-gate-CYcfk_GS.js.map} +1 -1
  370. package/dist/core/web/public/next/assets/useOnboarding-CujRS6PK.js +2 -0
  371. package/dist/core/web/public/next/assets/useOnboarding-CujRS6PK.js.map +1 -0
  372. package/dist/core/web/public/next/assets/useSeatsRefresh-BEaQdkZs.js +2 -0
  373. package/dist/core/web/public/next/assets/useSeatsRefresh-BEaQdkZs.js.map +1 -0
  374. package/dist/core/web/public/next/assets/useVerseTranscript-BQ0J6Xhx.js +2 -0
  375. package/dist/core/web/public/next/assets/{useVerseTranscript-CDYrrWOO.js.map → useVerseTranscript-BQ0J6Xhx.js.map} +1 -1
  376. package/dist/core/web/public/next/assets/verse-icons-DndgEgKS.js +2 -0
  377. package/dist/core/web/public/next/assets/verse-icons-DndgEgKS.js.map +1 -0
  378. package/dist/core/web/public/next/assets/verse-model-MMySehjj.js +2 -0
  379. package/dist/core/web/public/next/assets/verse-model-MMySehjj.js.map +1 -0
  380. package/dist/core/web/public/next/assets/verse-store-DNVRuiJL.js +2 -0
  381. package/dist/core/web/public/next/assets/verse-store-DNVRuiJL.js.map +1 -0
  382. package/dist/core/web/public/next/assets/warmup-CNEH_-be.js +3 -0
  383. package/dist/core/web/public/next/assets/{warmup-HG5vYbsN.js.map → warmup-CNEH_-be.js.map} +1 -1
  384. package/dist/core/web/public/next/assets/why-seat-model-jlDTwYSc.js +2 -0
  385. package/dist/core/web/public/next/assets/why-seat-model-jlDTwYSc.js.map +1 -0
  386. package/dist/core/web/public/next/assets/{workspace-model-CbhdPhei.js → workspace-model-Dukb2wwv.js} +2 -2
  387. package/dist/core/web/public/next/assets/{workspace-model-CbhdPhei.js.map → workspace-model-Dukb2wwv.js.map} +1 -1
  388. package/dist/core/web/public/next/index.html +1 -1
  389. package/dist/release-dependency-inventory.json +1 -1
  390. package/docs/README.md +2 -1
  391. package/package.json +1 -1
  392. package/dist/core/web/public/next/assets/ActionMenu-FxXeRbPx.js +0 -2
  393. package/dist/core/web/public/next/assets/Advanced-D_eS4472.js +0 -2
  394. package/dist/core/web/public/next/assets/Advanced-D_eS4472.js.map +0 -1
  395. package/dist/core/web/public/next/assets/App-Cj4zKbG3.js +0 -7
  396. package/dist/core/web/public/next/assets/App-Cj4zKbG3.js.map +0 -1
  397. package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js +0 -2
  398. package/dist/core/web/public/next/assets/AppsSection-Ddu_RCQE.js.map +0 -1
  399. package/dist/core/web/public/next/assets/AreaTrend-CDxrQU4b.js +0 -2
  400. package/dist/core/web/public/next/assets/AutonomySection-DuQkHGD_.js +0 -2
  401. package/dist/core/web/public/next/assets/BranchBar-CLsvOcyK.js +0 -2
  402. package/dist/core/web/public/next/assets/BudgetControl-TL3FeZ1D.js +0 -2
  403. package/dist/core/web/public/next/assets/BurnDown-sFXkUGdB.js +0 -2
  404. package/dist/core/web/public/next/assets/BurnDown-sFXkUGdB.js.map +0 -1
  405. package/dist/core/web/public/next/assets/CapacityStrip-qReu0RaF.js +0 -2
  406. package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js +0 -3
  407. package/dist/core/web/public/next/assets/ChatSection-DZuZfTaC.js.map +0 -1
  408. package/dist/core/web/public/next/assets/CloudBudgetForm-DJbiT1wi.js +0 -2
  409. package/dist/core/web/public/next/assets/CloudBudgetForm-DJbiT1wi.js.map +0 -1
  410. package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js +0 -2
  411. package/dist/core/web/public/next/assets/CommandPalette-zYLFZRnj.js.map +0 -1
  412. package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js +0 -2
  413. package/dist/core/web/public/next/assets/CommandSection-rIeMK5Ch.js.map +0 -1
  414. package/dist/core/web/public/next/assets/ConfirmDialog-DLrLKM0c.js +0 -2
  415. package/dist/core/web/public/next/assets/Dialog-BS9Dxi3G.js +0 -2
  416. package/dist/core/web/public/next/assets/DiffPane-TOmUf3b2.js +0 -2
  417. package/dist/core/web/public/next/assets/DiffViewer-BpH56302.js +0 -2
  418. package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js +0 -2
  419. package/dist/core/web/public/next/assets/DockHost-DzkzR-HD.js.map +0 -1
  420. package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js +0 -3
  421. package/dist/core/web/public/next/assets/FleetSection-ViAb549H.js.map +0 -1
  422. package/dist/core/web/public/next/assets/Funnel-D2u7Wlzc.js +0 -2
  423. package/dist/core/web/public/next/assets/GearTray-Cb2npoxM.js +0 -2
  424. package/dist/core/web/public/next/assets/GrowthSection-C5aDPs8B.js +0 -2
  425. package/dist/core/web/public/next/assets/HandoffDialog-BF3AYg-X.js +0 -2
  426. package/dist/core/web/public/next/assets/Input-B5dmGLZx.js +0 -2
  427. package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js +0 -2
  428. package/dist/core/web/public/next/assets/LeaderCard-DZrmjDbI.js.map +0 -1
  429. package/dist/core/web/public/next/assets/MatrixHeatmap-BgEUs2Eu.js +0 -2
  430. package/dist/core/web/public/next/assets/McpSection-DZkiOuoq.js +0 -2
  431. package/dist/core/web/public/next/assets/MessageMarkdown-BauY8ZTY.js +0 -3
  432. package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js +0 -2
  433. package/dist/core/web/public/next/assets/MindSection-BvJXFjyX.js.map +0 -1
  434. package/dist/core/web/public/next/assets/MutationTokenDialog-mxrw0Yvy.js +0 -2
  435. package/dist/core/web/public/next/assets/NeedsYouDrawer-CO-Balfp.js +0 -2
  436. package/dist/core/web/public/next/assets/NeedsYouList-CzDZbzRD.js +0 -2
  437. package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js +0 -3
  438. package/dist/core/web/public/next/assets/NewChatDialog-B8eJjlFf.js.map +0 -1
  439. package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js +0 -2
  440. package/dist/core/web/public/next/assets/OnboardingFlow-Cij6KWat.js.map +0 -1
  441. package/dist/core/web/public/next/assets/OnboardingFlow-DSpPj8UE.css +0 -1
  442. package/dist/core/web/public/next/assets/PreviewPane-BS-CleCd.js +0 -2
  443. package/dist/core/web/public/next/assets/RailStatus-cPRyOmrk.js +0 -2
  444. package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js +0 -3
  445. package/dist/core/web/public/next/assets/ResourcesChrome-BJCauW_t.js.map +0 -1
  446. package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js +0 -2
  447. package/dist/core/web/public/next/assets/ResourcesDrawer-BDecg6nO.js.map +0 -1
  448. package/dist/core/web/public/next/assets/ResourcesDrawer-CSKIO_wZ.css +0 -1
  449. package/dist/core/web/public/next/assets/RouteErrorBoundary-DYtwc2ja.js +0 -2
  450. package/dist/core/web/public/next/assets/RunInCloudAction-BEGEEM8O.js +0 -2
  451. package/dist/core/web/public/next/assets/SeatSelector-CYHRR7Wp.js +0 -3
  452. package/dist/core/web/public/next/assets/Segmented-BE53BenI.js +0 -2
  453. package/dist/core/web/public/next/assets/Select-BwSGkHCS.js +0 -2
  454. package/dist/core/web/public/next/assets/SessionGate-e0dFJm9d.js +0 -2
  455. package/dist/core/web/public/next/assets/SessionInsightChip-CxlSyueJ.js +0 -2
  456. package/dist/core/web/public/next/assets/SessionSearch-_yp7S2TP.js +0 -2
  457. package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js +0 -2
  458. package/dist/core/web/public/next/assets/SettingsSection-wGnpWeGW.js.map +0 -1
  459. package/dist/core/web/public/next/assets/Sheet-DVP2Mgy6.js +0 -2
  460. package/dist/core/web/public/next/assets/ShortcutsOverlay-BcIcoClX.js +0 -2
  461. package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js +0 -3
  462. package/dist/core/web/public/next/assets/Sidebar-DjQOqPbm.js.map +0 -1
  463. package/dist/core/web/public/next/assets/Slider-BypUWjpH.js +0 -2
  464. package/dist/core/web/public/next/assets/StepBand-Duz1PUes.js +0 -2
  465. package/dist/core/web/public/next/assets/Surface-B75lVfzm.js +0 -2
  466. package/dist/core/web/public/next/assets/Surface-B75lVfzm.js.map +0 -1
  467. package/dist/core/web/public/next/assets/Surface-DMca0gAe.css +0 -1
  468. package/dist/core/web/public/next/assets/Swimlane-DGcIcnNA.js +0 -2
  469. package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js +0 -7
  470. package/dist/core/web/public/next/assets/TerminalPane-MQT-veKZ.js.map +0 -1
  471. package/dist/core/web/public/next/assets/UniverseConsoleApp-C8yQ0AaR.js +0 -2
  472. package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js +0 -2
  473. package/dist/core/web/public/next/assets/UsageSection-CqxRGJ40.js.map +0 -1
  474. package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js +0 -3
  475. package/dist/core/web/public/next/assets/VerseConsoleApp-DTjDpGCd.js.map +0 -1
  476. package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js +0 -10
  477. package/dist/core/web/public/next/assets/Workspace-DfcFGzME.js.map +0 -1
  478. package/dist/core/web/public/next/assets/actions-Ddfg2iLl.css +0 -1
  479. package/dist/core/web/public/next/assets/actions-tWevL9HV.js +0 -2
  480. package/dist/core/web/public/next/assets/actions-tWevL9HV.js.map +0 -1
  481. package/dist/core/web/public/next/assets/apps-model-CDFvmsQV.js +0 -2
  482. package/dist/core/web/public/next/assets/apps-model-CDFvmsQV.js.map +0 -1
  483. package/dist/core/web/public/next/assets/capacity-strip-model-BDbmQ3e3.js +0 -2
  484. package/dist/core/web/public/next/assets/capacity-strip-model-BDbmQ3e3.js.map +0 -1
  485. package/dist/core/web/public/next/assets/charts-CfAjuKMv.js +0 -2
  486. package/dist/core/web/public/next/assets/charts-CfAjuKMv.js.map +0 -1
  487. package/dist/core/web/public/next/assets/charts-uSX6xVYN.css +0 -1
  488. package/dist/core/web/public/next/assets/cloud-C1KPNRHC.css +0 -1
  489. package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js +0 -2
  490. package/dist/core/web/public/next/assets/cloud-queries-Br_r0UAz.js.map +0 -1
  491. package/dist/core/web/public/next/assets/cloud.module-ascz58c3.js +0 -2
  492. package/dist/core/web/public/next/assets/cloud.module-ascz58c3.js.map +0 -1
  493. package/dist/core/web/public/next/assets/command-bus-xYZoK9nQ.js +0 -2
  494. package/dist/core/web/public/next/assets/command-bus-xYZoK9nQ.js.map +0 -1
  495. package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js +0 -2
  496. package/dist/core/web/public/next/assets/command-catalog-Bb_PxC5w.js.map +0 -1
  497. package/dist/core/web/public/next/assets/composer-keys-su0g1h9o.js +0 -2
  498. package/dist/core/web/public/next/assets/composer-keys-su0g1h9o.js.map +0 -1
  499. package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js +0 -2
  500. package/dist/core/web/public/next/assets/context-model-BC-HOmPo.js.map +0 -1
  501. package/dist/core/web/public/next/assets/context-model-CIBmSugV.js +0 -2
  502. package/dist/core/web/public/next/assets/context-model-CIBmSugV.js.map +0 -1
  503. package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js +0 -2
  504. package/dist/core/web/public/next/assets/dark-since-DOMvtB_G.js.map +0 -1
  505. package/dist/core/web/public/next/assets/dock-icons-CUh8dOxJ.js +0 -2
  506. package/dist/core/web/public/next/assets/dock-store-B2vlxqPu.js +0 -2
  507. package/dist/core/web/public/next/assets/dock-store-B2vlxqPu.js.map +0 -1
  508. package/dist/core/web/public/next/assets/fleet-model-7i-FbzKI.js +0 -2
  509. package/dist/core/web/public/next/assets/fleet-model-7i-FbzKI.js.map +0 -1
  510. package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js +0 -2
  511. package/dist/core/web/public/next/assets/fleet-queries-DzGoqq8X.js.map +0 -1
  512. package/dist/core/web/public/next/assets/format-BkWdOQDL.js +0 -2
  513. package/dist/core/web/public/next/assets/format-BkWdOQDL.js.map +0 -1
  514. package/dist/core/web/public/next/assets/global-oEl9Qj8u.js +0 -2
  515. package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js +0 -3
  516. package/dist/core/web/public/next/assets/guarded-action-OzqcPjmh.js.map +0 -1
  517. package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js +0 -2
  518. package/dist/core/web/public/next/assets/icon-base-DvM1eI5V.js.map +0 -1
  519. package/dist/core/web/public/next/assets/icons-DEQa2rTx.js +0 -2
  520. package/dist/core/web/public/next/assets/icons-DEQa2rTx.js.map +0 -1
  521. package/dist/core/web/public/next/assets/live-model-bmsJgnYD.js +0 -2
  522. package/dist/core/web/public/next/assets/live-model-bmsJgnYD.js.map +0 -1
  523. package/dist/core/web/public/next/assets/local-model-DFyjKX0b.js +0 -2
  524. package/dist/core/web/public/next/assets/local-model-DFyjKX0b.js.map +0 -1
  525. package/dist/core/web/public/next/assets/mind.module-gTGAuJt1.js +0 -2
  526. package/dist/core/web/public/next/assets/mutations-C5S7okTW.js +0 -2
  527. package/dist/core/web/public/next/assets/nav-NVtnuG7A.js +0 -2
  528. package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js +0 -2
  529. package/dist/core/web/public/next/assets/preloaded-Cwf9rsnZ.js.map +0 -1
  530. package/dist/core/web/public/next/assets/primitives-DyCKYSBG.js +0 -1
  531. package/dist/core/web/public/next/assets/reasoning-pref-BUcFF_5G.js +0 -2
  532. package/dist/core/web/public/next/assets/seat-subscription-B-f9ViU2.js +0 -2
  533. package/dist/core/web/public/next/assets/section-visibility-Yctxu-if.js +0 -2
  534. package/dist/core/web/public/next/assets/section-visibility-Yctxu-if.js.map +0 -1
  535. package/dist/core/web/public/next/assets/slots-BhP8b8tf.js +0 -3
  536. package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js +0 -2
  537. package/dist/core/web/public/next/assets/surface-data-DTI7LjvH.js.map +0 -1
  538. package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js +0 -2
  539. package/dist/core/web/public/next/assets/surface-prefetch-CdUEBFrl.js.map +0 -1
  540. package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js +0 -2
  541. package/dist/core/web/public/next/assets/useChartWidth-owwodNVz.js.map +0 -1
  542. package/dist/core/web/public/next/assets/useSeatsRefresh-DgFy-Ph4.js +0 -2
  543. package/dist/core/web/public/next/assets/useSeatsRefresh-DgFy-Ph4.js.map +0 -1
  544. package/dist/core/web/public/next/assets/useVerseTranscript-CDYrrWOO.js +0 -2
  545. package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js +0 -2
  546. package/dist/core/web/public/next/assets/verse-icons-F9VwX07_.js.map +0 -1
  547. package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js +0 -2
  548. package/dist/core/web/public/next/assets/verse-model-DyCwZF-M.js.map +0 -1
  549. package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js +0 -3
  550. package/dist/core/web/public/next/assets/verse-store-b_Lek_c5.js.map +0 -1
  551. package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js +0 -3
  552. package/dist/core/web/public/next/assets/verse-ui-store-62DxpVHS.js.map +0 -1
  553. package/dist/core/web/public/next/assets/viewport-nTubFCwf.js +0 -2
  554. package/dist/core/web/public/next/assets/viewport-nTubFCwf.js.map +0 -1
  555. package/dist/core/web/public/next/assets/warmup-HG5vYbsN.js +0 -3
  556. package/dist/core/web/public/next/assets/workbench-types-DzN-5trg.js +0 -2
  557. package/dist/core/web/public/next/assets/workbench-types-DzN-5trg.js.map +0 -1
  558. /package/dist/core/web/public/next/assets/{BurnDown-BuLMsJMx.css → StatTile-BuLMsJMx.css} +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"Swimlane-DGcIcnNA.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/Sparkline.module.css","../../../../../../src/web-ui/components/charts/Sparkline.tsx","../../../../../../src/web-ui/components/charts/Swimlane.module.css","../../../../../../src/web-ui/components/charts/Swimlane.tsx"],"sourcesContent":[".sparkline {\n display: block;\n overflow: visible;\n}\n\n.line {\n fill: none;\n stroke: var(--text-tertiary);\n stroke-width: 1.5;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.dot {\n fill: var(--chart-sequential);\n}\n\n.area {\n fill: var(--chart-sequential);\n opacity: 0.1;\n stroke: none;\n}\n\n/* Fewer than two known points: a quiet dashed baseline, not an empty box. */\n.flat {\n stroke: var(--chart-grid);\n stroke-width: 1;\n stroke-dasharray: 2 2;\n}\n","/**\n * components/charts/Sparkline.tsx — the 12-ish-point inline trend for a\n * stat tile (marks-and-anatomy.md \"Figures\" stat-tile contract). No axes,\n * no legend, no tooltip — it is a glance, not a chart; the real numbers\n * live in the stat tile's value and in the full chart elsewhere on the\n * view. Gaps (`null`) break the line rather than reading as a dip to zero.\n *\n * V3.10: optional `area` wash, an optional `describe` formatter that appends a\n * spoken summary (first → latest, min–max) to the aria-label so the glance is\n * not image-only for a screen reader, and a designed flat/unknown state (a\n * dashed baseline) instead of an empty box when fewer than two points are known.\n */\nimport './chart-tokens.css';\nimport styles from './Sparkline.module.css';\n\nexport function sparklineSummary(points: (number | null)[], format: (v: number) => string): string {\n const known = points.filter((p): p is number => p !== null && Number.isFinite(p));\n if (known.length === 0) return 'no data';\n const first = known[0]!;\n const latest = known[known.length - 1]!;\n const gaps = points.length - known.length;\n return `from ${format(first)} to ${format(latest)}, range ${format(Math.min(...known))} to ${format(Math.max(...known))}` +\n (gaps > 0 ? `, ${gaps} point${gaps === 1 ? '' : 's'} without data` : '');\n}\n\nexport function Sparkline({\n points,\n width = 72,\n height = 24,\n ariaLabel,\n area = false,\n describe,\n}: {\n points: (number | null)[];\n width?: number;\n height?: number;\n ariaLabel: string;\n /** Soft 10% wash under the line. */\n area?: boolean;\n /** When given, a spoken summary is appended to `ariaLabel`. */\n describe?: (v: number) => string;\n}) {\n const label = describe ? `${ariaLabel}: ${sparklineSummary(points, describe)}` : ariaLabel;\n const known = points.filter((p): p is number => p !== null);\n if (known.length < 2) {\n return (\n <svg className={styles.sparkline} width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={label}>\n <line className={styles.flat} x1={1} x2={width - 1} y1={height - 1.5} y2={height - 1.5} />\n </svg>\n );\n }\n const min = Math.min(...known, 0);\n const max = Math.max(...known, 0);\n const range = max - min || 1;\n const stepX = width / Math.max(1, points.length - 1);\n const yOf = (v: number) => height - ((v - min) / range) * (height - 2) - 1;\n\n // Split into contiguous runs so a null renders as a real gap, not a dip.\n const runs: { x: number; y: number }[][] = [];\n let current: { x: number; y: number }[] = [];\n points.forEach((v, i) => {\n if (v === null) {\n if (current.length) runs.push(current);\n current = [];\n return;\n }\n current.push({ x: i * stepX, y: yOf(v) });\n });\n if (current.length) runs.push(current);\n\n const lastKnownIndex = points.map((v) => v !== null).lastIndexOf(true);\n const lastPoint =\n lastKnownIndex >= 0 ? { x: lastKnownIndex * stepX, y: yOf(points[lastKnownIndex] as number) } : null;\n const baseY = yOf(Math.max(min, 0));\n\n return (\n <svg className={styles.sparkline} width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={label}>\n {area\n ? runs.map((run, i) =>\n run.length > 1 ? (\n <path\n key={`a${i}`}\n className={styles.area}\n d={`${run.map((p, j) => `${j === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ')} L${run[run.length - 1]!.x.toFixed(1)},${baseY.toFixed(1)} L${run[0]!.x.toFixed(1)},${baseY.toFixed(1)} Z`}\n />\n ) : null,\n )\n : null}\n {runs.map((run, i) => (\n <path\n key={i}\n className={styles.line}\n d={run.map((p, j) => `${j === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ')}\n />\n ))}\n {lastPoint ? <circle className={styles.dot} cx={lastPoint.x} cy={lastPoint.y} r={2} /> : null}\n </svg>\n );\n}\n",".scroller {\n position: relative;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.band {\n fill: var(--chart-grid);\n opacity: 0.35;\n}\n\n.bar {\n cursor: default;\n}\n\n/* Running on disk but silent for a long time: faded, and said in words in\n the tooltip and table — the fade is never the only signal. */\n.stale {\n opacity: 0.4;\n}\n\n.open {\n /* Square corners on open-ended work: a rounded end reads as \"finished\". */\n rx: 0;\n}\n\n.now {\n stroke: var(--text-tertiary);\n stroke-width: 1;\n stroke-dasharray: 2 3;\n}\n\n.laneStops {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n pointer-events: none;\n}\n\n.laneStop {\n position: absolute;\n left: 0;\n right: 0;\n}\n\n/* Queued / parked: a neutral outline, no fill — holding a place, not running. */\n.outline {\n stroke-width: 1.5;\n}\n","/**\n * components/charts/Swimlane.tsx — who ran what, when: one row (lane) per repo\n * or agent, one bar per run from its start to its end, coloured by STATUS\n * (the StatusBadge tones — state, not identity — always with a text legend).\n *\n * Open-ended work: a bar with `end: null` extends to `now` and gets an open\n * right edge; a `stale` one (running on disk, silent for a long time) is drawn\n * faded and says so in its tooltip and the table.\n *\n * V3.10: a lane may carry its ENGINE — drawn as the 2px identity tick and\n * the C/X/G/L monogram beside the label (never a vendor logo, and never the\n * bar fill: bars keep STATUS colour). Queued and parked work draws as a\n * neutral OUTLINE with no fill (\"not running yet\" must not look like a\n * status), and an unknown status draws as the 45° unknown hatch.\n *\n * Scale: past VIRTUALIZE_AFTER lanes the body becomes a fixed-height scroller\n * that renders only the rows in view (plus overscan), so a 500-lane history\n * costs the same DOM as a 20-lane one. Each lane is a keyboard stop with a\n * spoken summary; every run is in the Table view.\n */\nimport { useId, useMemo, useRef, useState, type UIEvent } from 'react';\nimport { CHART_QUEUED_OUTLINE, hatchPatternId, toneColor, type ChartEngine, type ChartTone } from './colors.js';\nimport { ChartFrame, type ChartStatus } from './ChartFrame.js';\nimport { ChartLegend, ChartTooltip, EngineTick, HatchPattern, clampTooltipLeft, type ChartLegendItem } from './ChartParts.js';\nimport { TableView, type TableColumn } from './TableView.js';\nimport { MIN_TIME_SPAN_MS, ensureSpan, isPlausibleTime, labelCharPx, layoutAxisLabels, linearScale } from './chart-math.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport { useTextScale } from './useTextScale.js';\nimport plot from './plot.module.css';\nimport styles from './Swimlane.module.css';\n\nexport interface SwimlaneItem {\n id: string;\n /** Epoch ms. */\n start: number;\n /** Epoch ms; null while still running. */\n end: number | null;\n /** Free-form status string (done / failed / aborted / running …). */\n status: string;\n /** Optional short text for tooltip and table (e.g. the engine). */\n detail?: string;\n stale?: boolean;\n /**\n * Draw as an outline with no fill — queued / parked work that holds a place\n * in line but is not running. Defaults to true for the statuses in\n * OUTLINE_STATUSES.\n */\n outline?: boolean;\n}\n\nexport interface SwimlaneLane {\n id: string;\n label: string;\n items: SwimlaneItem[];\n /** The lane's engine: a 2px identity tick + monogram beside the label. */\n engine?: ChartEngine;\n}\n\n/** Statuses that draw as an outline by default (they hold a place; nothing runs). */\nexport const OUTLINE_STATUSES: ReadonlySet<string> = new Set(['queued', 'parked', 'waiting']);\n\nfunction isOutline(item: SwimlaneItem): boolean {\n return item.outline ?? OUTLINE_STATUSES.has(item.status.toLowerCase());\n}\n\nexport interface SwimlaneProps {\n title: string;\n description?: string;\n caveat?: string;\n status?: ChartStatus;\n lanes: SwimlaneLane[];\n /** Visible time window, epoch ms. */\n from: number;\n to: number;\n /** \"Now\" for open-ended bars (defaults to `to`). */\n now?: number;\n width?: number;\n /** Map a status string to a tone. Defaults to the StatusBadge vocabulary subset below. */\n toneOf?: (status: string) => ChartTone;\n /** Full timestamp for tooltip and table. */\n formatTime?: (ms: number) => string;\n /** Axis tick label. Defaults to a span-aware short form (dates past 36 h, clock times below). */\n formatTick?: (ms: number) => string;\n ariaLabel?: string;\n}\n\nexport const ROW_H = 24;\nexport const VIRTUALIZE_AFTER = 50;\nconst VIEWPORT_ROWS = 14;\nconst OVERSCAN = 6;\nconst AXIS_H = 22;\nconst MIN_BAR_W = 3;\n\nconst DEFAULT_TONES: Record<string, ChartTone> = {\n done: 'success',\n success: 'success',\n merged: 'success',\n failed: 'danger',\n error: 'danger',\n aborted: 'neutral',\n cancelled: 'neutral',\n running: 'running',\n queued: 'neutral',\n parked: 'neutral',\n};\n\nfunction defaultToneOf(status: string): ChartTone {\n return DEFAULT_TONES[status.toLowerCase()] ?? 'unknown';\n}\n\nfunction defaultFormatTime(ms: number): string {\n const d = new Date(ms);\n return Number.isNaN(d.getTime())\n ? ''\n : d.toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });\n}\n\n/** Short axis labels: long windows get dates, short ones get clock times — full timestamps collide. */\nexport function spanTickFormatter(from: number, to: number): (ms: number) => string {\n const long = to - from > 36 * 3_600_000;\n return (ms) => {\n const d = new Date(ms);\n if (Number.isNaN(d.getTime())) return '';\n return long\n ? d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })\n : d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });\n };\n}\n\nfunction truncateLabel(label: string, chars: number): string {\n return label.length > chars ? `${label.slice(0, Math.max(1, chars - 1))}…` : label;\n}\n\nfunction formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '—';\n const m = Math.round(ms / 60_000);\n if (m < 1) return '<1m';\n if (m < 60) return `${m}m`;\n const h = Math.floor(m / 60);\n return h < 48 ? `${h}h ${m % 60}m` : `${Math.round(h / 24)}d`;\n}\n\ninterface FlatItem extends SwimlaneItem {\n lane: string;\n engine: ChartEngine | undefined;\n}\n\nexport function Swimlane({\n title,\n description,\n caveat,\n status,\n lanes,\n from: fromProp,\n to: toProp,\n now,\n width: fixedWidth,\n toneOf = defaultToneOf,\n formatTime = defaultFormatTime,\n formatTick,\n ariaLabel,\n}: SwimlaneProps) {\n // A window bound of 0 / NaN / pre-2000 is a null timestamp that leaked\n // through; fall back to the runs themselves (then to a day ending now), and\n // widen a degenerate window so its ticks are distinct times.\n const itemTimes = lanes.flatMap((l) => l.items.flatMap((i) => [i.start, i.end ?? Number.NaN])).filter(isPlausibleTime);\n const toBound = isPlausibleTime(toProp)\n ? toProp\n : now !== undefined && isPlausibleTime(now) ? now : itemTimes.length ? Math.max(...itemTimes) : Date.now();\n const fromBound = isPlausibleTime(fromProp) ? fromProp : itemTimes.length ? Math.min(...itemTimes) : toBound - 86_400_000;\n const [from, to] = ensureSpan(fromBound, toBound, MIN_TIME_SPAN_MS, 'end');\n const tickLabel = formatTick ?? spanTickFormatter(from, to);\n const wrapRef = useRef<HTMLDivElement>(null);\n const width = useChartWidth(wrapRef, fixedWidth);\n const textScale = useTextScale();\n const [scrollTop, setScrollTop] = useState(0);\n const [hover, setHover] = useState<{ lane: number; item: number } | null>(null);\n const liveId = useId();\n const hatchId = hatchPatternId(useId());\n const nowMs = now ?? to;\n\n const itemCount = lanes.reduce((n, l) => n + l.items.length, 0);\n const resolvedStatus: ChartStatus = status ?? (itemCount === 0 ? { kind: 'empty', message: 'No runs in this window.' } : { kind: 'ready' });\n\n // Narrow screens give the labels less room, never less than a readable 72 px\n // (plus room for the engine tick and monogram when lanes carry one).\n const tickW = lanes.some((l) => l.engine !== undefined) ? 18 : 0;\n const labelW = Math.max(72, Math.min(160, Math.round(width * 0.24))) + tickW;\n // 7 px a character at 12 px text, scaled to the Display size.\n const labelChars = Math.floor((labelW - tickW) / (7 * textScale));\n const plotW = Math.max(40, width - labelW - 8);\n const xs = linearScale(from, Math.max(to, from + 1), labelW, labelW + plotW);\n const virtual = lanes.length > VIRTUALIZE_AFTER;\n const first = virtual ? Math.max(0, Math.floor(scrollTop / ROW_H) - OVERSCAN) : 0;\n const last = virtual ? Math.min(lanes.length, Math.ceil(scrollTop / ROW_H) + VIEWPORT_ROWS + OVERSCAN) : lanes.length;\n const bodyH = lanes.length * ROW_H;\n\n // Legend: one entry per drawn style — a status tone, the outline (queued /\n // parked) or the unknown hatch — each named by the statuses it stands for.\n const legendItems = useMemo((): ChartLegendItem[] => {\n const seen = new Map<string, { item: Omit<ChartLegendItem, 'label'>; names: Set<string> }>();\n for (const lane of lanes) for (const item of lane.items) {\n const tone = toneOf(item.status);\n const key = isOutline(item) ? 'outline' : tone === 'unknown' ? 'hatch' : tone;\n const style: Omit<ChartLegendItem, 'label'> = key === 'outline' ? { kind: 'empty' } : key === 'hatch' ? { kind: 'hatch' } : { color: toneColor(tone) };\n if (!seen.has(key)) seen.set(key, { item: style, names: new Set() });\n seen.get(key)!.names.add(item.status.toLowerCase());\n }\n return [...seen.values()].map(({ item, names }) => ({ ...item, label: [...names].sort().join(' / ') }));\n }, [lanes, toneOf]);\n const anyEngine = lanes.some((l) => l.engine !== undefined);\n\n const ticks = useMemo(() => {\n const count = Math.max(2, Math.floor(plotW / 90));\n const step = (to - from) / Math.max(1, count);\n return Array.from({ length: count + 1 }, (_, i) => from + step * i);\n }, [from, to, plotW]);\n\n const flat: FlatItem[] = useMemo(\n () => lanes.flatMap((lane) => lane.items.map((item) => ({ ...item, lane: lane.label, engine: lane.engine }))),\n [lanes],\n );\n\n function laneSummary(lane: SwimlaneLane): string {\n const counts = new Map<string, number>();\n for (const item of lane.items) counts.set(item.status, (counts.get(item.status) ?? 0) + 1);\n const parts = [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([s, n]) => `${n} ${s}`);\n const engine = lane.engine ? ` (${lane.engine})` : '';\n return `${lane.label}${engine}: ${lane.items.length} run${lane.items.length === 1 ? '' : 's'}${parts.length ? ` (${parts.join(', ')})` : ''}`;\n }\n\n const summary = ariaLabel ?? `${title}: ${itemCount} runs across ${lanes.length} lanes from ${formatTime(from)} to ${formatTime(to)}.`;\n\n const columns: TableColumn<FlatItem>[] = [\n { key: 'lane', label: 'Lane', render: (r) => r.lane },\n ...(anyEngine ? [{ key: 'engine', label: 'Engine', render: (r: FlatItem) => r.engine ?? '—' }] : []),\n { key: 'status', label: 'Status', render: (r) => `${r.status}${r.stale ? ' (stale)' : ''}` },\n { key: 'start', label: 'Started', render: (r) => formatTime(r.start) },\n { key: 'dur', label: 'Duration', numeric: true, render: (r) => (r.end === null ? `${formatDuration(nowMs - r.start)}+` : formatDuration(r.end - r.start)) },\n { key: 'detail', label: 'Detail', render: (r) => r.detail ?? '' },\n ];\n\n const hovered = hover ? lanes[hover.lane]?.items[hover.item] : undefined;\n\n function renderLane(lane: SwimlaneLane, index: number) {\n const y = index * ROW_H;\n return (\n <g key={lane.id} data-lane={lane.id}>\n {index % 2 === 1 ? <rect className={styles.band} x={0} y={y} width={width} height={ROW_H} /> : null}\n {lane.engine ? <EngineTick engine={lane.engine} x={2} y={y + 5} height={ROW_H - 10} /> : null}\n <text className={plot.label} x={labelW - 8} y={y + ROW_H / 2} dy=\"0.32em\" textAnchor=\"end\">\n {truncateLabel(lane.label, labelChars)}\n </text>\n {lane.items.map((item, itemIndex) => {\n const start = Math.max(from, item.start);\n const endMs = Math.min(to, item.end ?? nowMs);\n if (endMs < from || start > to) return null;\n const x0 = xs(start);\n const w = Math.max(MIN_BAR_W, xs(Math.max(endMs, start)) - x0);\n const tone = toneOf(item.status);\n const outline = isOutline(item);\n const unknown = !outline && tone === 'unknown';\n return (\n <rect\n key={item.id}\n data-item={item.id}\n data-status={item.status}\n data-open={item.end === null ? 'true' : undefined}\n data-style={outline ? 'outline' : unknown ? 'hatch' : 'fill'}\n className={`${styles.bar} ${item.stale ? styles.stale : ''} ${item.end === null ? styles.open : ''} ${outline ? styles.outline : ''} ${unknown ? plot.unknownMark : ''}`}\n x={outline ? x0 + 0.5 : x0}\n y={outline ? y + 5.5 : y + 5}\n width={outline ? Math.max(MIN_BAR_W, w - 1) : w}\n height={outline ? ROW_H - 11 : ROW_H - 10}\n rx={3}\n fill={outline ? 'none' : unknown ? `url(#${hatchId})` : toneColor(tone)}\n stroke={outline ? CHART_QUEUED_OUTLINE : undefined}\n onPointerEnter={() => setHover({ lane: index, item: itemIndex })}\n onPointerLeave={() => setHover((h) => (h && h.lane === index && h.item === itemIndex ? null : h))}\n />\n );\n })}\n </g>\n );\n }\n\n // Tick labels never overprint: the window's end outranks its start, and an\n // interior tick whose label would touch a neighbour is dropped (its\n // gridline stays).\n const tickLabels = layoutAxisLabels(\n ticks.map((t, i) => ({\n key: String(i),\n x: xs(t),\n anchor: i === 0 ? 'start' as const : i === ticks.length - 1 ? 'end' as const : 'middle' as const,\n priority: i === ticks.length - 1 ? 3 : i === 0 ? 2 : 1,\n required: i === 0 || i === ticks.length - 1,\n variants: [tickLabel(t)],\n })),\n { min: labelW, max: labelW + plotW, charPx: labelCharPx(textScale) },\n );\n\n const axis = (\n <svg className={plot.svg} width={width} height={AXIS_H} viewBox={`0 0 ${width} ${AXIS_H}`} aria-hidden=\"true\">\n <line className={plot.axis} x1={labelW} x2={labelW + plotW} y1={AXIS_H - 1} y2={AXIS_H - 1} />\n {tickLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} className={plot.tick} x={l.x} y={AXIS_H - 7} textAnchor={l.anchor}>\n {l.text}\n </text>\n ))}\n </svg>\n );\n\n return (\n <ChartFrame\n title={title}\n description={description}\n caveat={caveat}\n status={resolvedStatus}\n table={<TableView caption={title} columns={columns} rows={flat} rowKey={(r) => r.id} />}\n footer={<ChartLegend min={1} items={legendItems} />}\n >\n <div ref={wrapRef} className={plot.plotWrap}>\n {axis}\n <div\n className={virtual ? styles.scroller : undefined}\n style={virtual ? { height: VIEWPORT_ROWS * ROW_H } : undefined}\n onScroll={virtual ? (e: UIEvent<HTMLDivElement>) => setScrollTop(e.currentTarget.scrollTop) : undefined}\n data-virtualized={virtual ? 'true' : undefined}\n >\n <svg className={plot.svg} width={width} height={bodyH} viewBox={`0 0 ${width} ${bodyH}`} role=\"img\" aria-label={summary}>\n <defs>\n <HatchPattern id={hatchId} />\n </defs>\n {ticks.map((t) => (\n <line key={t} className={plot.grid} x1={xs(t)} x2={xs(t)} y1={0} y2={bodyH} />\n ))}\n {nowMs >= from && nowMs <= to ? (\n <line className={styles.now} x1={xs(nowMs)} x2={xs(nowMs)} y1={0} y2={bodyH} />\n ) : null}\n {lanes.slice(first, last).map((lane, i) => renderLane(lane, first + i))}\n </svg>\n {/* Keyboard + screen-reader lane list, overlaid on the rows it describes. */}\n <ul className={styles.laneStops} style={{ height: bodyH }} aria-label={`${title} lanes`} aria-describedby={liveId}>\n {lanes.slice(first, last).map((lane, i) => (\n <li\n key={lane.id}\n tabIndex={0}\n className={`${styles.laneStop} ${plot.focusable}`}\n style={{ top: (first + i) * ROW_H, height: ROW_H }}\n aria-label={laneSummary(lane)}\n onFocus={() => setHover(lane.items.length ? { lane: first + i, item: lane.items.length - 1 } : null)}\n onBlur={() => setHover(null)}\n />\n ))}\n </ul>\n </div>\n <span id={liveId} className={plot.srOnly}>Each lane lists its runs by status; open the Table view for every run.</span>\n {hover && hovered ? (\n <ChartTooltip\n left={clampTooltipLeft(xs(Math.max(from, hovered.start)), width)}\n top={AXIS_H + hover.lane * ROW_H - (virtual ? scrollTop : 0)}\n title={lanes[hover.lane]!.label}\n rows={[\n {\n key: 's',\n label: 'Status',\n value: `${hovered.status}${hovered.stale ? ' (stale)' : ''}`,\n ...(isOutline(hovered) || toneOf(hovered.status) === 'unknown' ? {} : { color: toneColor(toneOf(hovered.status)) }),\n },\n { key: 't', label: 'Started', value: formatTime(hovered.start) },\n {\n key: 'd',\n label: 'Duration',\n value: hovered.end === null ? `${formatDuration(nowMs - hovered.start)} so far` : formatDuration(hovered.end - hovered.start),\n },\n ...(hovered.detail ? [{ key: 'x', label: 'Detail', value: hovered.detail }] : []),\n ]}\n />\n ) : null}\n </div>\n </ChartFrame>\n );\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"Swimlane-BzH6OCee.js","names":[],"sources":["../../../../../../src/web-ui/components/charts/Sparkline.module.css","../../../../../../src/web-ui/components/charts/Sparkline.tsx","../../../../../../src/web-ui/components/charts/Swimlane.module.css","../../../../../../src/web-ui/components/charts/Swimlane.tsx"],"sourcesContent":[".sparkline {\n display: block;\n overflow: visible;\n}\n\n.line {\n fill: none;\n stroke: var(--text-tertiary);\n stroke-width: 1.5;\n stroke-linecap: round;\n stroke-linejoin: round;\n}\n\n.dot {\n fill: var(--chart-sequential);\n}\n\n.area {\n fill: var(--chart-sequential);\n opacity: 0.1;\n stroke: none;\n}\n\n/* Fewer than two known points: a quiet dashed baseline, not an empty box. */\n.flat {\n stroke: var(--chart-grid);\n stroke-width: 1;\n stroke-dasharray: 2 2;\n}\n","/**\n * components/charts/Sparkline.tsx — the 12-ish-point inline trend for a\n * stat tile (marks-and-anatomy.md \"Figures\" stat-tile contract). No axes,\n * no legend, no tooltip — it is a glance, not a chart; the real numbers\n * live in the stat tile's value and in the full chart elsewhere on the\n * view. Gaps (`null`) break the line rather than reading as a dip to zero.\n *\n * V3.10: optional `area` wash, an optional `describe` formatter that appends a\n * spoken summary (first → latest, min–max) to the aria-label so the glance is\n * not image-only for a screen reader, and a designed flat/unknown state (a\n * dashed baseline) instead of an empty box when fewer than two points are known.\n */\nimport './chart-tokens.css';\nimport styles from './Sparkline.module.css';\n\nexport function sparklineSummary(points: (number | null)[], format: (v: number) => string): string {\n const known = points.filter((p): p is number => p !== null && Number.isFinite(p));\n if (known.length === 0) return 'no data';\n const first = known[0]!;\n const latest = known[known.length - 1]!;\n const gaps = points.length - known.length;\n return `from ${format(first)} to ${format(latest)}, range ${format(Math.min(...known))} to ${format(Math.max(...known))}` +\n (gaps > 0 ? `, ${gaps} point${gaps === 1 ? '' : 's'} without data` : '');\n}\n\nexport function Sparkline({\n points,\n width = 72,\n height = 24,\n ariaLabel,\n area = false,\n describe,\n}: {\n points: (number | null)[];\n width?: number;\n height?: number;\n ariaLabel: string;\n /** Soft 10% wash under the line. */\n area?: boolean;\n /** When given, a spoken summary is appended to `ariaLabel`. */\n describe?: (v: number) => string;\n}) {\n const label = describe ? `${ariaLabel}: ${sparklineSummary(points, describe)}` : ariaLabel;\n const known = points.filter((p): p is number => p !== null);\n if (known.length < 2) {\n return (\n <svg className={styles.sparkline} width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={label}>\n <line className={styles.flat} x1={1} x2={width - 1} y1={height - 1.5} y2={height - 1.5} />\n </svg>\n );\n }\n const min = Math.min(...known, 0);\n const max = Math.max(...known, 0);\n const range = max - min || 1;\n const stepX = width / Math.max(1, points.length - 1);\n const yOf = (v: number) => height - ((v - min) / range) * (height - 2) - 1;\n\n // Split into contiguous runs so a null renders as a real gap, not a dip.\n const runs: { x: number; y: number }[][] = [];\n let current: { x: number; y: number }[] = [];\n points.forEach((v, i) => {\n if (v === null) {\n if (current.length) runs.push(current);\n current = [];\n return;\n }\n current.push({ x: i * stepX, y: yOf(v) });\n });\n if (current.length) runs.push(current);\n\n const lastKnownIndex = points.map((v) => v !== null).lastIndexOf(true);\n const lastPoint =\n lastKnownIndex >= 0 ? { x: lastKnownIndex * stepX, y: yOf(points[lastKnownIndex] as number) } : null;\n const baseY = yOf(Math.max(min, 0));\n\n return (\n <svg className={styles.sparkline} width={width} height={height} viewBox={`0 0 ${width} ${height}`} role=\"img\" aria-label={label}>\n {area\n ? runs.map((run, i) =>\n run.length > 1 ? (\n <path\n key={`a${i}`}\n className={styles.area}\n d={`${run.map((p, j) => `${j === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ')} L${run[run.length - 1]!.x.toFixed(1)},${baseY.toFixed(1)} L${run[0]!.x.toFixed(1)},${baseY.toFixed(1)} Z`}\n />\n ) : null,\n )\n : null}\n {runs.map((run, i) => (\n <path\n key={i}\n className={styles.line}\n d={run.map((p, j) => `${j === 0 ? 'M' : 'L'}${p.x.toFixed(1)},${p.y.toFixed(1)}`).join(' ')}\n />\n ))}\n {lastPoint ? <circle className={styles.dot} cx={lastPoint.x} cy={lastPoint.y} r={2} /> : null}\n </svg>\n );\n}\n",".scroller {\n position: relative;\n overflow-y: auto;\n overscroll-behavior: contain;\n}\n\n.band {\n fill: var(--chart-grid);\n opacity: 0.35;\n}\n\n.bar {\n cursor: default;\n}\n\n/* Running on disk but silent for a long time: faded, and said in words in\n the tooltip and table — the fade is never the only signal. */\n.stale {\n opacity: 0.4;\n}\n\n.open {\n /* Square corners on open-ended work: a rounded end reads as \"finished\". */\n rx: 0;\n}\n\n.now {\n stroke: var(--text-tertiary);\n stroke-width: 1;\n stroke-dasharray: 2 3;\n}\n\n.laneStops {\n position: absolute;\n left: 0;\n right: 0;\n top: 0;\n margin: 0;\n padding: 0;\n list-style: none;\n pointer-events: none;\n}\n\n.laneStop {\n position: absolute;\n left: 0;\n right: 0;\n}\n\n/* Queued / parked: a neutral outline, no fill — holding a place, not running. */\n.outline {\n stroke-width: 1.5;\n}\n","/**\n * components/charts/Swimlane.tsx — who ran what, when: one row (lane) per repo\n * or agent, one bar per run from its start to its end, coloured by STATUS\n * (the StatusBadge tones — state, not identity — always with a text legend).\n *\n * Open-ended work: a bar with `end: null` extends to `now` and gets an open\n * right edge; a `stale` one (running on disk, silent for a long time) is drawn\n * faded and says so in its tooltip and the table.\n *\n * V3.10: a lane may carry its ENGINE — drawn as the 2px identity tick and\n * the C/X/G/L monogram beside the label (never a vendor logo, and never the\n * bar fill: bars keep STATUS colour). Queued and parked work draws as a\n * neutral OUTLINE with no fill (\"not running yet\" must not look like a\n * status), and an unknown status draws as the 45° unknown hatch.\n *\n * Scale: past VIRTUALIZE_AFTER lanes the body becomes a fixed-height scroller\n * that renders only the rows in view (plus overscan), so a 500-lane history\n * costs the same DOM as a 20-lane one. Each lane is a keyboard stop with a\n * spoken summary; every run is in the Table view.\n */\nimport { useId, useMemo, useRef, useState, type UIEvent } from 'react';\nimport { CHART_QUEUED_OUTLINE, hatchPatternId, toneColor, type ChartEngine, type ChartTone } from './colors.js';\nimport { ChartFrame, type ChartStatus } from './ChartFrame.js';\nimport { ChartLegend, ChartTooltip, EngineTick, HatchPattern, clampTooltipLeft, type ChartLegendItem } from './ChartParts.js';\nimport { TableView, type TableColumn } from './TableView.js';\nimport { MIN_TIME_SPAN_MS, ensureSpan, isPlausibleTime, labelCharPx, layoutAxisLabels, linearScale } from './chart-math.js';\nimport { useChartWidth } from './useChartWidth.js';\nimport { useTextScale } from './useTextScale.js';\nimport plot from './plot.module.css';\nimport styles from './Swimlane.module.css';\n\nexport interface SwimlaneItem {\n id: string;\n /** Epoch ms. */\n start: number;\n /** Epoch ms; null while still running. */\n end: number | null;\n /** Free-form status string (done / failed / aborted / running …). */\n status: string;\n /** Optional short text for tooltip and table (e.g. the engine). */\n detail?: string;\n stale?: boolean;\n /**\n * Draw as an outline with no fill — queued / parked work that holds a place\n * in line but is not running. Defaults to true for the statuses in\n * OUTLINE_STATUSES.\n */\n outline?: boolean;\n}\n\nexport interface SwimlaneLane {\n id: string;\n label: string;\n items: SwimlaneItem[];\n /** The lane's engine: a 2px identity tick + monogram beside the label. */\n engine?: ChartEngine;\n}\n\n/** Statuses that draw as an outline by default (they hold a place; nothing runs). */\nexport const OUTLINE_STATUSES: ReadonlySet<string> = new Set(['queued', 'parked', 'waiting']);\n\nfunction isOutline(item: SwimlaneItem): boolean {\n return item.outline ?? OUTLINE_STATUSES.has(item.status.toLowerCase());\n}\n\nexport interface SwimlaneProps {\n title: string;\n description?: string;\n caveat?: string;\n status?: ChartStatus;\n lanes: SwimlaneLane[];\n /** Visible time window, epoch ms. */\n from: number;\n to: number;\n /** \"Now\" for open-ended bars (defaults to `to`). */\n now?: number;\n width?: number;\n /** Map a status string to a tone. Defaults to the StatusBadge vocabulary subset below. */\n toneOf?: (status: string) => ChartTone;\n /** Full timestamp for tooltip and table. */\n formatTime?: (ms: number) => string;\n /** Axis tick label. Defaults to a span-aware short form (dates past 36 h, clock times below). */\n formatTick?: (ms: number) => string;\n ariaLabel?: string;\n}\n\nexport const ROW_H = 24;\nexport const VIRTUALIZE_AFTER = 50;\nconst VIEWPORT_ROWS = 14;\nconst OVERSCAN = 6;\nconst AXIS_H = 22;\nconst MIN_BAR_W = 3;\n\nconst DEFAULT_TONES: Record<string, ChartTone> = {\n done: 'success',\n success: 'success',\n merged: 'success',\n failed: 'danger',\n error: 'danger',\n aborted: 'neutral',\n cancelled: 'neutral',\n running: 'running',\n queued: 'neutral',\n parked: 'neutral',\n};\n\nfunction defaultToneOf(status: string): ChartTone {\n return DEFAULT_TONES[status.toLowerCase()] ?? 'unknown';\n}\n\nfunction defaultFormatTime(ms: number): string {\n const d = new Date(ms);\n return Number.isNaN(d.getTime())\n ? ''\n : d.toLocaleString('en-US', { month: 'short', day: 'numeric', hour: 'numeric', minute: '2-digit' });\n}\n\n/** Short axis labels: long windows get dates, short ones get clock times — full timestamps collide. */\nexport function spanTickFormatter(from: number, to: number): (ms: number) => string {\n const long = to - from > 36 * 3_600_000;\n return (ms) => {\n const d = new Date(ms);\n if (Number.isNaN(d.getTime())) return '';\n return long\n ? d.toLocaleDateString('en-US', { month: 'short', day: 'numeric' })\n : d.toLocaleTimeString('en-US', { hour: 'numeric', minute: '2-digit' });\n };\n}\n\nfunction truncateLabel(label: string, chars: number): string {\n return label.length > chars ? `${label.slice(0, Math.max(1, chars - 1))}…` : label;\n}\n\nfunction formatDuration(ms: number): string {\n if (!Number.isFinite(ms) || ms < 0) return '—';\n const m = Math.round(ms / 60_000);\n if (m < 1) return '<1m';\n if (m < 60) return `${m}m`;\n const h = Math.floor(m / 60);\n return h < 48 ? `${h}h ${m % 60}m` : `${Math.round(h / 24)}d`;\n}\n\ninterface FlatItem extends SwimlaneItem {\n lane: string;\n engine: ChartEngine | undefined;\n}\n\nexport function Swimlane({\n title,\n description,\n caveat,\n status,\n lanes,\n from: fromProp,\n to: toProp,\n now,\n width: fixedWidth,\n toneOf = defaultToneOf,\n formatTime = defaultFormatTime,\n formatTick,\n ariaLabel,\n}: SwimlaneProps) {\n // A window bound of 0 / NaN / pre-2000 is a null timestamp that leaked\n // through; fall back to the runs themselves (then to a day ending now), and\n // widen a degenerate window so its ticks are distinct times.\n const itemTimes = lanes.flatMap((l) => l.items.flatMap((i) => [i.start, i.end ?? Number.NaN])).filter(isPlausibleTime);\n const toBound = isPlausibleTime(toProp)\n ? toProp\n : now !== undefined && isPlausibleTime(now) ? now : itemTimes.length ? Math.max(...itemTimes) : Date.now();\n const fromBound = isPlausibleTime(fromProp) ? fromProp : itemTimes.length ? Math.min(...itemTimes) : toBound - 86_400_000;\n const [from, to] = ensureSpan(fromBound, toBound, MIN_TIME_SPAN_MS, 'end');\n const tickLabel = formatTick ?? spanTickFormatter(from, to);\n const wrapRef = useRef<HTMLDivElement>(null);\n const width = useChartWidth(wrapRef, fixedWidth);\n const textScale = useTextScale();\n const [scrollTop, setScrollTop] = useState(0);\n const [hover, setHover] = useState<{ lane: number; item: number } | null>(null);\n const liveId = useId();\n const hatchId = hatchPatternId(useId());\n const nowMs = now ?? to;\n\n const itemCount = lanes.reduce((n, l) => n + l.items.length, 0);\n const resolvedStatus: ChartStatus = status ?? (itemCount === 0 ? { kind: 'empty', message: 'No runs in this window.' } : { kind: 'ready' });\n\n // Narrow screens give the labels less room, never less than a readable 72 px\n // (plus room for the engine tick and monogram when lanes carry one).\n const tickW = lanes.some((l) => l.engine !== undefined) ? 18 : 0;\n const labelW = Math.max(72, Math.min(160, Math.round(width * 0.24))) + tickW;\n // 7 px a character at 12 px text, scaled to the Display size.\n const labelChars = Math.floor((labelW - tickW) / (7 * textScale));\n const plotW = Math.max(40, width - labelW - 8);\n const xs = linearScale(from, Math.max(to, from + 1), labelW, labelW + plotW);\n const virtual = lanes.length > VIRTUALIZE_AFTER;\n const first = virtual ? Math.max(0, Math.floor(scrollTop / ROW_H) - OVERSCAN) : 0;\n const last = virtual ? Math.min(lanes.length, Math.ceil(scrollTop / ROW_H) + VIEWPORT_ROWS + OVERSCAN) : lanes.length;\n const bodyH = lanes.length * ROW_H;\n\n // Legend: one entry per drawn style — a status tone, the outline (queued /\n // parked) or the unknown hatch — each named by the statuses it stands for.\n const legendItems = useMemo((): ChartLegendItem[] => {\n const seen = new Map<string, { item: Omit<ChartLegendItem, 'label'>; names: Set<string> }>();\n for (const lane of lanes) for (const item of lane.items) {\n const tone = toneOf(item.status);\n const key = isOutline(item) ? 'outline' : tone === 'unknown' ? 'hatch' : tone;\n const style: Omit<ChartLegendItem, 'label'> = key === 'outline' ? { kind: 'empty' } : key === 'hatch' ? { kind: 'hatch' } : { color: toneColor(tone) };\n if (!seen.has(key)) seen.set(key, { item: style, names: new Set() });\n seen.get(key)!.names.add(item.status.toLowerCase());\n }\n return [...seen.values()].map(({ item, names }) => ({ ...item, label: [...names].sort().join(' / ') }));\n }, [lanes, toneOf]);\n const anyEngine = lanes.some((l) => l.engine !== undefined);\n\n const ticks = useMemo(() => {\n const count = Math.max(2, Math.floor(plotW / 90));\n const step = (to - from) / Math.max(1, count);\n return Array.from({ length: count + 1 }, (_, i) => from + step * i);\n }, [from, to, plotW]);\n\n const flat: FlatItem[] = useMemo(\n () => lanes.flatMap((lane) => lane.items.map((item) => ({ ...item, lane: lane.label, engine: lane.engine }))),\n [lanes],\n );\n\n function laneSummary(lane: SwimlaneLane): string {\n const counts = new Map<string, number>();\n for (const item of lane.items) counts.set(item.status, (counts.get(item.status) ?? 0) + 1);\n const parts = [...counts.entries()].sort((a, b) => b[1] - a[1]).map(([s, n]) => `${n} ${s}`);\n const engine = lane.engine ? ` (${lane.engine})` : '';\n return `${lane.label}${engine}: ${lane.items.length} run${lane.items.length === 1 ? '' : 's'}${parts.length ? ` (${parts.join(', ')})` : ''}`;\n }\n\n const summary = ariaLabel ?? `${title}: ${itemCount} runs across ${lanes.length} lanes from ${formatTime(from)} to ${formatTime(to)}.`;\n\n const columns: TableColumn<FlatItem>[] = [\n { key: 'lane', label: 'Lane', render: (r) => r.lane },\n ...(anyEngine ? [{ key: 'engine', label: 'Engine', render: (r: FlatItem) => r.engine ?? '—' }] : []),\n { key: 'status', label: 'Status', render: (r) => `${r.status}${r.stale ? ' (stale)' : ''}` },\n { key: 'start', label: 'Started', render: (r) => formatTime(r.start) },\n { key: 'dur', label: 'Duration', numeric: true, render: (r) => (r.end === null ? `${formatDuration(nowMs - r.start)}+` : formatDuration(r.end - r.start)) },\n { key: 'detail', label: 'Detail', render: (r) => r.detail ?? '' },\n ];\n\n const hovered = hover ? lanes[hover.lane]?.items[hover.item] : undefined;\n\n function renderLane(lane: SwimlaneLane, index: number) {\n const y = index * ROW_H;\n return (\n <g key={lane.id} data-lane={lane.id}>\n {index % 2 === 1 ? <rect className={styles.band} x={0} y={y} width={width} height={ROW_H} /> : null}\n {lane.engine ? <EngineTick engine={lane.engine} x={2} y={y + 5} height={ROW_H - 10} /> : null}\n <text className={plot.label} x={labelW - 8} y={y + ROW_H / 2} dy=\"0.32em\" textAnchor=\"end\">\n {truncateLabel(lane.label, labelChars)}\n </text>\n {lane.items.map((item, itemIndex) => {\n const start = Math.max(from, item.start);\n const endMs = Math.min(to, item.end ?? nowMs);\n if (endMs < from || start > to) return null;\n const x0 = xs(start);\n const w = Math.max(MIN_BAR_W, xs(Math.max(endMs, start)) - x0);\n const tone = toneOf(item.status);\n const outline = isOutline(item);\n const unknown = !outline && tone === 'unknown';\n return (\n <rect\n key={item.id}\n data-item={item.id}\n data-status={item.status}\n data-open={item.end === null ? 'true' : undefined}\n data-style={outline ? 'outline' : unknown ? 'hatch' : 'fill'}\n className={`${styles.bar} ${item.stale ? styles.stale : ''} ${item.end === null ? styles.open : ''} ${outline ? styles.outline : ''} ${unknown ? plot.unknownMark : ''}`}\n x={outline ? x0 + 0.5 : x0}\n y={outline ? y + 5.5 : y + 5}\n width={outline ? Math.max(MIN_BAR_W, w - 1) : w}\n height={outline ? ROW_H - 11 : ROW_H - 10}\n rx={3}\n fill={outline ? 'none' : unknown ? `url(#${hatchId})` : toneColor(tone)}\n stroke={outline ? CHART_QUEUED_OUTLINE : undefined}\n onPointerEnter={() => setHover({ lane: index, item: itemIndex })}\n onPointerLeave={() => setHover((h) => (h && h.lane === index && h.item === itemIndex ? null : h))}\n />\n );\n })}\n </g>\n );\n }\n\n // Tick labels never overprint: the window's end outranks its start, and an\n // interior tick whose label would touch a neighbour is dropped (its\n // gridline stays).\n const tickLabels = layoutAxisLabels(\n ticks.map((t, i) => ({\n key: String(i),\n x: xs(t),\n anchor: i === 0 ? 'start' as const : i === ticks.length - 1 ? 'end' as const : 'middle' as const,\n priority: i === ticks.length - 1 ? 3 : i === 0 ? 2 : 1,\n required: i === 0 || i === ticks.length - 1,\n variants: [tickLabel(t)],\n })),\n { min: labelW, max: labelW + plotW, charPx: labelCharPx(textScale) },\n );\n\n const axis = (\n <svg className={plot.svg} width={width} height={AXIS_H} viewBox={`0 0 ${width} ${AXIS_H}`} aria-hidden=\"true\">\n <line className={plot.axis} x1={labelW} x2={labelW + plotW} y1={AXIS_H - 1} y2={AXIS_H - 1} />\n {tickLabels.map((l) => (\n <text key={l.key} data-axis-label={l.key} className={plot.tick} x={l.x} y={AXIS_H - 7} textAnchor={l.anchor}>\n {l.text}\n </text>\n ))}\n </svg>\n );\n\n return (\n <ChartFrame\n title={title}\n description={description}\n caveat={caveat}\n status={resolvedStatus}\n table={<TableView caption={title} columns={columns} rows={flat} rowKey={(r) => r.id} />}\n footer={<ChartLegend min={1} items={legendItems} />}\n >\n <div ref={wrapRef} className={plot.plotWrap}>\n {axis}\n <div\n className={virtual ? styles.scroller : undefined}\n style={virtual ? { height: VIEWPORT_ROWS * ROW_H } : undefined}\n onScroll={virtual ? (e: UIEvent<HTMLDivElement>) => setScrollTop(e.currentTarget.scrollTop) : undefined}\n data-virtualized={virtual ? 'true' : undefined}\n >\n <svg className={plot.svg} width={width} height={bodyH} viewBox={`0 0 ${width} ${bodyH}`} role=\"img\" aria-label={summary}>\n <defs>\n <HatchPattern id={hatchId} />\n </defs>\n {ticks.map((t) => (\n <line key={t} className={plot.grid} x1={xs(t)} x2={xs(t)} y1={0} y2={bodyH} />\n ))}\n {nowMs >= from && nowMs <= to ? (\n <line className={styles.now} x1={xs(nowMs)} x2={xs(nowMs)} y1={0} y2={bodyH} />\n ) : null}\n {lanes.slice(first, last).map((lane, i) => renderLane(lane, first + i))}\n </svg>\n {/* Keyboard + screen-reader lane list, overlaid on the rows it describes. */}\n <ul className={styles.laneStops} style={{ height: bodyH }} aria-label={`${title} lanes`} aria-describedby={liveId}>\n {lanes.slice(first, last).map((lane, i) => (\n <li\n key={lane.id}\n tabIndex={0}\n className={`${styles.laneStop} ${plot.focusable}`}\n style={{ top: (first + i) * ROW_H, height: ROW_H }}\n aria-label={laneSummary(lane)}\n onFocus={() => setHover(lane.items.length ? { lane: first + i, item: lane.items.length - 1 } : null)}\n onBlur={() => setHover(null)}\n />\n ))}\n </ul>\n </div>\n <span id={liveId} className={plot.srOnly}>Each lane lists its runs by status; open the Table view for every run.</span>\n {hover && hovered ? (\n <ChartTooltip\n left={clampTooltipLeft(xs(Math.max(from, hovered.start)), width)}\n top={AXIS_H + hover.lane * ROW_H - (virtual ? scrollTop : 0)}\n title={lanes[hover.lane]!.label}\n rows={[\n {\n key: 's',\n label: 'Status',\n value: `${hovered.status}${hovered.stale ? ' (stale)' : ''}`,\n ...(isOutline(hovered) || toneOf(hovered.status) === 'unknown' ? {} : { color: toneColor(toneOf(hovered.status)) }),\n },\n { key: 't', label: 'Started', value: formatTime(hovered.start) },\n {\n key: 'd',\n label: 'Duration',\n value: hovered.end === null ? `${formatDuration(nowMs - hovered.start)} so far` : formatDuration(hovered.end - hovered.start),\n },\n ...(hovered.detail ? [{ key: 'x', label: 'Detail', value: hovered.detail }] : []),\n ]}\n />\n ) : null}\n </div>\n </ChartFrame>\n );\n}\n"],"mappings":"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"}
@@ -1,2 +1,2 @@
1
- import{n as e}from"./index-BVxOlseC.js";var t={wrapper:`_wrapper_1xq82_1`,label:`_label_1xq82_8`,track:`_track_1xq82_13`,knob:`_knob_1xq82_44`},n=e();function r({checked:e,onChange:r,label:i,disabled:a=!1,id:o,className:s,...c}){let l=(0,n.jsx)(`button`,{type:`button`,id:o,role:`switch`,"aria-checked":e,disabled:a,className:t.track,onClick:()=>r(!e),...c,children:(0,n.jsx)(`span`,{className:t.knob,"aria-hidden":`true`})});return i?(0,n.jsxs)(`label`,{className:`${t.wrapper} ${s??``}`,children:[l,(0,n.jsx)(`span`,{className:t.label,children:i})]}):(0,n.jsx)(`span`,{className:s,children:l})}export{r as t};
2
- //# sourceMappingURL=Switch-iveI-8NY.js.map
1
+ import{n as e}from"./index-QesfXBsb.js";var t={wrapper:`_wrapper_1xq82_1`,label:`_label_1xq82_8`,track:`_track_1xq82_13`,knob:`_knob_1xq82_44`},n=e();function r({checked:e,onChange:r,label:i,disabled:a=!1,id:o,className:s,...c}){let l=(0,n.jsx)(`button`,{type:`button`,id:o,role:`switch`,"aria-checked":e,disabled:a,className:t.track,onClick:()=>r(!e),...c,children:(0,n.jsx)(`span`,{className:t.knob,"aria-hidden":`true`})});return i?(0,n.jsxs)(`label`,{className:`${t.wrapper} ${s??``}`,children:[l,(0,n.jsx)(`span`,{className:t.label,children:i})]}):(0,n.jsx)(`span`,{className:s,children:l})}export{r as t};
2
+ //# sourceMappingURL=Switch-PMixU6b0.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Switch-iveI-8NY.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/Switch.module.css","../../../../../../src/web-ui/components/primitives/Switch.tsx"],"sourcesContent":[".wrapper {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n cursor: pointer;\n}\n\n.label {\n font-size: var(--text-sm-size);\n color: var(--text-primary);\n}\n\n.track {\n position: relative;\n flex: none;\n width: 34px;\n height: 18px;\n padding: 0;\n border: 1px solid var(--border-strong);\n border-radius: var(--radius-full);\n background: var(--bg-active);\n cursor: pointer;\n transition:\n background-color var(--duration-fast) var(--ease-standard),\n border-color var(--duration-fast) var(--ease-standard);\n}\n\n.track:hover:not(:disabled) {\n border-color: var(--text-tertiary);\n}\n\n.track[aria-checked='true'] {\n background: var(--accent-600);\n border-color: var(--accent-600);\n}\n\n.track[aria-checked='true']:hover:not(:disabled) {\n background: var(--accent-700);\n border-color: var(--accent-700);\n}\n\n/* Press: the knob narrows slightly toward the direction of travel. No bounce,\n no translate on the track itself. */\n.track:active:not(:disabled) .knob {\n width: 14px;\n}\n\n.track[aria-checked='true']:active:not(:disabled) .knob {\n transform: translateX(14px);\n}\n\n.track:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.knob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: var(--radius-full);\n background: var(--bg-surface);\n transition:\n transform var(--duration-fast) var(--ease-standard),\n width var(--duration-fast) var(--ease-standard);\n}\n\n.track[aria-checked='true'] .knob {\n transform: translateX(16px);\n background: var(--accent-contrast);\n}\n","/**\n * components/primitives/Switch.tsx — a binary setting that takes effect\n * immediately (no form submit). role=\"switch\" + aria-checked, so a screen\n * reader announces \"on\"/\"off\" rather than \"checkbox, checked\".\n *\n * State is never carried by color alone: the knob's POSITION is the primary\n * signal (design doc §6), the accent fill is reinforcement.\n */\nimport type { ReactNode } from 'react';\nimport styles from './Switch.module.css';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (next: boolean) => void;\n /** Visible label; when omitted, pass `aria-label`. */\n label?: ReactNode;\n 'aria-label'?: string;\n 'aria-describedby'?: string;\n disabled?: boolean;\n id?: string;\n className?: string;\n}\n\nexport function Switch({\n checked,\n onChange,\n label,\n disabled = false,\n id,\n className,\n ...aria\n}: SwitchProps) {\n const control = (\n <button\n type=\"button\"\n id={id}\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={styles.track}\n onClick={() => onChange(!checked)}\n {...aria}\n >\n <span className={styles.knob} aria-hidden=\"true\" />\n </button>\n );\n\n if (!label) return <span className={className}>{control}</span>;\n\n return (\n <label className={`${styles.wrapper} ${className ?? ''}`}>\n {control}\n <span className={styles.label}>{label}</span>\n </label>\n );\n}\n"],"mappings":"sJCuBA,SAAgB,EAAO,CACrB,UACA,WACA,QACA,WAAW,GACX,KACA,YACA,GAAG,GACW,CACd,IAAM,GACJ,EAAA,EAAA,IAAA,CAAC,SAAD,CACE,KAAK,SACD,KACJ,KAAK,SACL,eAAc,EACJ,WACV,UAAW,EAAO,MAClB,YAAe,EAAS,CAAC,CAAO,EAChC,GAAI,EAEJ,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,KAAM,cAAY,MAAQ,CAAA,CAC5C,CAAA,EAKV,OAFK,GAGH,EAAA,EAAA,KAAA,CAAC,QAAD,CAAO,UAAW,GAAG,EAAO,QAAQ,GAAG,GAAa,KAApD,SAAA,CACG,GACD,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,MAAQ,SAAA,CAAY,CAAA,CACvC,KANU,EAAA,EAAA,IAAA,CAAC,OAAD,CAAiB,YAAY,SAAA,CAAc,CAAA,CAQhE"}
1
+ {"version":3,"file":"Switch-PMixU6b0.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/Switch.module.css","../../../../../../src/web-ui/components/primitives/Switch.tsx"],"sourcesContent":[".wrapper {\n display: inline-flex;\n align-items: center;\n gap: var(--space-2);\n cursor: pointer;\n}\n\n.label {\n font-size: var(--text-sm-size);\n color: var(--text-primary);\n}\n\n.track {\n position: relative;\n flex: none;\n width: 34px;\n height: 18px;\n padding: 0;\n border: 1px solid var(--border-strong);\n border-radius: var(--radius-full);\n background: var(--bg-active);\n cursor: pointer;\n transition:\n background-color var(--duration-fast) var(--ease-standard),\n border-color var(--duration-fast) var(--ease-standard);\n}\n\n.track:hover:not(:disabled) {\n border-color: var(--text-tertiary);\n}\n\n.track[aria-checked='true'] {\n background: var(--accent-600);\n border-color: var(--accent-600);\n}\n\n.track[aria-checked='true']:hover:not(:disabled) {\n background: var(--accent-700);\n border-color: var(--accent-700);\n}\n\n/* Press: the knob narrows slightly toward the direction of travel. No bounce,\n no translate on the track itself. */\n.track:active:not(:disabled) .knob {\n width: 14px;\n}\n\n.track[aria-checked='true']:active:not(:disabled) .knob {\n transform: translateX(14px);\n}\n\n.track:disabled {\n cursor: not-allowed;\n opacity: 0.55;\n}\n\n.knob {\n position: absolute;\n top: 2px;\n left: 2px;\n width: 12px;\n height: 12px;\n border-radius: var(--radius-full);\n background: var(--bg-surface);\n transition:\n transform var(--duration-fast) var(--ease-standard),\n width var(--duration-fast) var(--ease-standard);\n}\n\n.track[aria-checked='true'] .knob {\n transform: translateX(16px);\n background: var(--accent-contrast);\n}\n","/**\n * components/primitives/Switch.tsx — a binary setting that takes effect\n * immediately (no form submit). role=\"switch\" + aria-checked, so a screen\n * reader announces \"on\"/\"off\" rather than \"checkbox, checked\".\n *\n * State is never carried by color alone: the knob's POSITION is the primary\n * signal (design doc §6), the accent fill is reinforcement.\n */\nimport type { ReactNode } from 'react';\nimport styles from './Switch.module.css';\n\nexport interface SwitchProps {\n checked: boolean;\n onChange: (next: boolean) => void;\n /** Visible label; when omitted, pass `aria-label`. */\n label?: ReactNode;\n 'aria-label'?: string;\n 'aria-describedby'?: string;\n disabled?: boolean;\n id?: string;\n className?: string;\n}\n\nexport function Switch({\n checked,\n onChange,\n label,\n disabled = false,\n id,\n className,\n ...aria\n}: SwitchProps) {\n const control = (\n <button\n type=\"button\"\n id={id}\n role=\"switch\"\n aria-checked={checked}\n disabled={disabled}\n className={styles.track}\n onClick={() => onChange(!checked)}\n {...aria}\n >\n <span className={styles.knob} aria-hidden=\"true\" />\n </button>\n );\n\n if (!label) return <span className={className}>{control}</span>;\n\n return (\n <label className={`${styles.wrapper} ${className ?? ''}`}>\n {control}\n <span className={styles.label}>{label}</span>\n </label>\n );\n}\n"],"mappings":"sJCuBA,SAAgB,EAAO,CACrB,UACA,WACA,QACA,WAAW,GACX,KACA,YACA,GAAG,GACW,CACd,IAAM,GACJ,EAAA,EAAA,IAAA,CAAC,SAAD,CACE,KAAK,SACD,KACJ,KAAK,SACL,eAAc,EACJ,WACV,UAAW,EAAO,MAClB,YAAe,EAAS,CAAC,CAAO,EAChC,GAAI,EAEJ,UAAA,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,KAAM,cAAY,MAAQ,CAAA,CAC5C,CAAA,EAKV,OAFK,GAGH,EAAA,EAAA,KAAA,CAAC,QAAD,CAAO,UAAW,GAAG,EAAO,QAAQ,GAAG,GAAa,KAApD,SAAA,CACG,GACD,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,EAAO,MAAQ,SAAA,CAAY,CAAA,CACvC,KANU,EAAA,EAAA,IAAA,CAAC,OAAD,CAAiB,YAAY,SAAA,CAAc,CAAA,CAQhE"}
@@ -1,2 +1,2 @@
1
- import{n as e}from"./index-BVxOlseC.js";var t={tag:`_tag_2eqdv_1`,sm:`_sm_2eqdv_19`,mono:`_mono_2eqdv_25`,dot:`_dot_2eqdv_30`,marker:`_marker_2eqdv_38`},n=e(),r={claude:`var(--engine-claude)`,codex:`var(--engine-codex)`,grok:`var(--engine-grok)`,local:`var(--engine-local)`};function i({children:e,engine:i,mono:a=!1,size:o=`md`,dot:s=!1,title:c,className:l}){let u=s||i!==void 0;return(0,n.jsxs)(`span`,{className:`${t.tag} ${t[o]} ${a?t.mono:``} ${l??``}`,title:c,"data-engine":i,children:[u?(0,n.jsx)(`span`,{className:t.dot,style:i?{background:r[i]}:void 0,"aria-hidden":`true`}):null,e]})}function a({engine:e,className:i}){return(0,n.jsx)(`span`,{className:`${t.marker} ${i??``}`,style:{background:r[e]},"aria-hidden":`true`})}function o(e){return r[e]}export{i as n,o as r,a as t};
2
- //# sourceMappingURL=Tag-DH15CUJp.js.map
1
+ import{n as e}from"./index-QesfXBsb.js";var t={tag:`_tag_2eqdv_1`,sm:`_sm_2eqdv_19`,mono:`_mono_2eqdv_25`,dot:`_dot_2eqdv_30`,marker:`_marker_2eqdv_38`},n=e(),r={claude:`var(--engine-claude)`,codex:`var(--engine-codex)`,grok:`var(--engine-grok)`,local:`var(--engine-local)`};function i({children:e,engine:i,mono:a=!1,size:o=`md`,dot:s=!1,title:c,className:l}){let u=s||i!==void 0;return(0,n.jsxs)(`span`,{className:`${t.tag} ${t[o]} ${a?t.mono:``} ${l??``}`,title:c,"data-engine":i,children:[u?(0,n.jsx)(`span`,{className:t.dot,style:i?{background:r[i]}:void 0,"aria-hidden":`true`}):null,e]})}function a({engine:e,className:i}){return(0,n.jsx)(`span`,{className:`${t.marker} ${i??``}`,style:{background:r[e]},"aria-hidden":`true`})}function o(e){return r[e]}export{i as n,o as r,a as t};
2
+ //# sourceMappingURL=Tag-fordBsrJ.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Tag-DH15CUJp.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/Tag.module.css","../../../../../../src/web-ui/components/primitives/Tag.tsx"],"sourcesContent":[".tag {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n max-width: 100%;\n height: var(--density-row-sm);\n padding: 0 var(--space-2);\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-xs);\n background: var(--bg-hover);\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sm {\n height: calc(var(--density-row-sm) - var(--space-2));\n padding: 0 var(--space-1);\n font-size: var(--text-2xs-size);\n}\n\n.mono {\n font-family: var(--font-mono);\n font-size: var(--text-2xs-size);\n}\n\n.dot {\n flex: none;\n width: 6px;\n height: 6px;\n border-radius: var(--radius-full);\n background: var(--status-neutral-solid);\n}\n\n.marker {\n display: inline-block;\n flex: none;\n width: 2px;\n height: 100%;\n min-height: var(--engine-marker-h);\n border-radius: var(--radius-full);\n}\n","/**\n * components/primitives/Tag.tsx — a small, quiet label: a seat pill, a model\n * name, a repo, a risk class. NOT a status badge (that is StatusBadge, which\n * owns the status-color mapping) and not a button.\n *\n * `engine` tints the leading dot with that provider's identity hue. Identity\n * hues are never used for the text itself (design doc §2) — the tag's label\n * stays in the normal text color so it keeps its contrast in both themes.\n */\nimport type { ReactNode } from 'react';\nimport type { VerseEngine } from '../../data/api-types.js';\nimport styles from './Tag.module.css';\n\nconst ENGINE_COLOR: Record<VerseEngine, string> = {\n claude: 'var(--engine-claude)',\n codex: 'var(--engine-codex)',\n grok: 'var(--engine-grok)',\n local: 'var(--engine-local)',\n};\n\nexport interface TagProps {\n children: ReactNode;\n /** Provider identity: tints the leading dot and the pill's edge. */\n engine?: VerseEngine;\n /** Monospace for ids, paths and model names. */\n mono?: boolean;\n size?: 'sm' | 'md';\n /** Show a leading dot even without an engine. */\n dot?: boolean;\n title?: string;\n className?: string;\n}\n\nexport function Tag({ children, engine, mono = false, size = 'md', dot = false, title, className }: TagProps) {\n const showDot = dot || engine !== undefined;\n return (\n <span\n className={`${styles.tag} ${styles[size]} ${mono ? styles.mono : ''} ${className ?? ''}`}\n title={title}\n data-engine={engine}\n >\n {showDot ? (\n <span\n className={styles.dot}\n style={engine ? { background: ENGINE_COLOR[engine] } : undefined}\n aria-hidden=\"true\"\n />\n ) : null}\n {children}\n </span>\n );\n}\n\n/** The 2px identity marker used on session rows and seat pills. */\nexport function EngineMarker({ engine, className }: { engine: VerseEngine; className?: string }) {\n return <span className={`${styles.marker} ${className ?? ''}`} style={{ background: ENGINE_COLOR[engine] }} aria-hidden=\"true\" />;\n}\n\nexport function engineColor(engine: VerseEngine): string {\n return ENGINE_COLOR[engine];\n}\n"],"mappings":"+JCaM,EAA4C,CAChD,OAAQ,uBACR,MAAO,sBACP,KAAM,qBACN,MAAO,qBACT,EAeA,SAAgB,EAAI,CAAE,WAAU,SAAQ,OAAO,GAAO,OAAO,KAAM,MAAM,GAAO,QAAO,aAAuB,CAC5G,IAAM,EAAU,GAAO,IAAW,IAAA,GAClC,OACE,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAW,GAAG,EAAO,IAAI,GAAG,EAAO,GAAM,GAAG,EAAO,EAAO,KAAO,GAAG,GAAG,GAAa,KAC7E,QACP,cAAa,EAHf,SAAA,CAKG,GACC,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,UAAW,EAAO,IAClB,MAAO,EAAS,CAAE,WAAY,EAAa,EAAQ,EAAI,IAAA,GACvD,cAAY,MACb,CAAA,EACC,KACH,CACG,GAEV,CAGA,SAAgB,EAAa,CAAE,SAAQ,aAA0D,CAC/F,OAAO,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,GAAG,EAAO,OAAO,GAAG,GAAa,KAAM,MAAO,CAAE,WAAY,EAAa,EAAQ,EAAG,cAAY,MAAQ,CAAA,CAClI,CAEA,SAAgB,EAAY,EAA6B,CACvD,OAAO,EAAa,EACtB"}
1
+ {"version":3,"file":"Tag-fordBsrJ.js","names":[],"sources":["../../../../../../src/web-ui/components/primitives/Tag.module.css","../../../../../../src/web-ui/components/primitives/Tag.tsx"],"sourcesContent":[".tag {\n display: inline-flex;\n align-items: center;\n gap: var(--space-1);\n max-width: 100%;\n height: var(--density-row-sm);\n padding: 0 var(--space-2);\n border: 1px solid var(--border-subtle);\n border-radius: var(--radius-xs);\n background: var(--bg-hover);\n color: var(--text-secondary);\n font-size: var(--text-xs-size);\n line-height: 1;\n white-space: nowrap;\n overflow: hidden;\n text-overflow: ellipsis;\n}\n\n.sm {\n height: calc(var(--density-row-sm) - var(--space-2));\n padding: 0 var(--space-1);\n font-size: var(--text-2xs-size);\n}\n\n.mono {\n font-family: var(--font-mono);\n font-size: var(--text-2xs-size);\n}\n\n.dot {\n flex: none;\n width: 6px;\n height: 6px;\n border-radius: var(--radius-full);\n background: var(--status-neutral-solid);\n}\n\n.marker {\n display: inline-block;\n flex: none;\n width: 2px;\n height: 100%;\n min-height: var(--engine-marker-h);\n border-radius: var(--radius-full);\n}\n","/**\n * components/primitives/Tag.tsx — a small, quiet label: a seat pill, a model\n * name, a repo, a risk class. NOT a status badge (that is StatusBadge, which\n * owns the status-color mapping) and not a button.\n *\n * `engine` tints the leading dot with that provider's identity hue. Identity\n * hues are never used for the text itself (design doc §2) — the tag's label\n * stays in the normal text color so it keeps its contrast in both themes.\n */\nimport type { ReactNode } from 'react';\nimport type { VerseEngine } from '../../data/api-types.js';\nimport styles from './Tag.module.css';\n\nconst ENGINE_COLOR: Record<VerseEngine, string> = {\n claude: 'var(--engine-claude)',\n codex: 'var(--engine-codex)',\n grok: 'var(--engine-grok)',\n local: 'var(--engine-local)',\n};\n\nexport interface TagProps {\n children: ReactNode;\n /** Provider identity: tints the leading dot and the pill's edge. */\n engine?: VerseEngine;\n /** Monospace for ids, paths and model names. */\n mono?: boolean;\n size?: 'sm' | 'md';\n /** Show a leading dot even without an engine. */\n dot?: boolean;\n title?: string;\n className?: string;\n}\n\nexport function Tag({ children, engine, mono = false, size = 'md', dot = false, title, className }: TagProps) {\n const showDot = dot || engine !== undefined;\n return (\n <span\n className={`${styles.tag} ${styles[size]} ${mono ? styles.mono : ''} ${className ?? ''}`}\n title={title}\n data-engine={engine}\n >\n {showDot ? (\n <span\n className={styles.dot}\n style={engine ? { background: ENGINE_COLOR[engine] } : undefined}\n aria-hidden=\"true\"\n />\n ) : null}\n {children}\n </span>\n );\n}\n\n/** The 2px identity marker used on session rows and seat pills. */\nexport function EngineMarker({ engine, className }: { engine: VerseEngine; className?: string }) {\n return <span className={`${styles.marker} ${className ?? ''}`} style={{ background: ENGINE_COLOR[engine] }} aria-hidden=\"true\" />;\n}\n\nexport function engineColor(engine: VerseEngine): string {\n return ENGINE_COLOR[engine];\n}\n"],"mappings":"+JCaM,EAA4C,CAChD,OAAQ,uBACR,MAAO,sBACP,KAAM,qBACN,MAAO,qBACT,EAeA,SAAgB,EAAI,CAAE,WAAU,SAAQ,OAAO,GAAO,OAAO,KAAM,MAAM,GAAO,QAAO,aAAuB,CAC5G,IAAM,EAAU,GAAO,IAAW,IAAA,GAClC,OACE,EAAA,EAAA,KAAA,CAAC,OAAD,CACE,UAAW,GAAG,EAAO,IAAI,GAAG,EAAO,GAAM,GAAG,EAAO,EAAO,KAAO,GAAG,GAAG,GAAa,KAC7E,QACP,cAAa,EAHf,SAAA,CAKG,GACC,EAAA,EAAA,IAAA,CAAC,OAAD,CACE,UAAW,EAAO,IAClB,MAAO,EAAS,CAAE,WAAY,EAAa,EAAQ,EAAI,IAAA,GACvD,cAAY,MACb,CAAA,EACC,KACH,CACG,GAEV,CAGA,SAAgB,EAAa,CAAE,SAAQ,aAA0D,CAC/F,OAAO,EAAA,EAAA,IAAA,CAAC,OAAD,CAAM,UAAW,GAAG,EAAO,OAAO,GAAG,GAAa,KAAM,MAAO,CAAE,WAAY,EAAa,EAAQ,EAAG,cAAY,MAAQ,CAAA,CAClI,CAEA,SAAgB,EAAY,EAA6B,CACvD,OAAO,EAAa,EACtB"}
@@ -0,0 +1,7 @@
1
+ const __vite__mapDeps=(i,m=__vite__mapDeps,d=(m.f||(m.f=["assets/xterm-B1njb2Cr.css"])))=>i.map(i=>d[i]);
2
+ import{a as e,c as t,n,t as r}from"./index-QesfXBsb.js";import{A as i,D as a,E as o,P as s,c,i as l,l as u,o as d}from"./global-CNNGMril.js";import{L as f,R as ee,_n as p,gn as m,hn as h,kt as g,tn as _}from"./VerseConsoleApp-BCY5uSok.js";import{_ as te}from"./verse-model-MMySehjj.js";import{n as ne}from"./format-Dk4Fmxax.js";import{n as v,t as y}from"./Button-BhO-WKPp.js";import{n as re,t as ie}from"./ActionMenu-B4-39f2S.js";import{C as ae,c as oe,g as se,y as ce}from"./icons-0haWy6nh.js";import{a as le,o as b}from"./command-catalog-CF0cQQac.js";import{t as x}from"./EmptyState-DPrd2aak.js";import{f as ue,r as de,u as fe}from"./terminal-icons-BvCvuXk2.js";import{t as pe}from"./pane-chrome.module-D7o-fVd0.js";var S=t(e(),1),C=class extends Error{constructor(){super(`Unlock actions with the mutation token to use the terminal.`),this.name=`TerminalLockedError`}};async function w(e,t){let n=o();if(!n)throw new C;let r=await u(e,t,n);return s(),r}function T(e,t){return`${_}/${encodeURIComponent(e)}/${t}`}var E={list:e=>c(_,e),create:async e=>(await w(_,e)).tab,input:(e,t)=>w(T(e,`input`),{dataBase64:t}),resize:(e,t,n)=>w(T(e,`resize`),{cols:t,rows:n}),kill:async e=>{await w(T(e,`kill`),{})},openExternal:async(e,t)=>{await w(`${_}/open-external`,t===void 0?{sessionId:e}:{sessionId:e,root:t})}};function me(e,t){let n=Number.isSafeInteger(t)&&t>0?`?after=${t}`:``;return`${T(e,`stream`)}${n}`}function he(e){let t=``;for(let n=0;n<e.length;n+=32768)t+=String.fromCharCode(...e.subarray(n,n+32768));return btoa(t)}function ge(e){let t=atob(e),n=new Uint8Array(t.length);for(let e=0;e<t.length;e++)n[e]=t.charCodeAt(e);return n}function _e(e){let t=e.replace(/\s+$/,``),n=Math.max(0,...Array.from(t.matchAll(/`+/g),e=>e[0].length)),r="`".repeat(Math.max(3,n+1));return`${r}\n${t}\n${r}`}function ve(e,t={}){let n=t.maxBytes??16384,r=new TextEncoder,i=[],a=0,o=null,s=!1,c=()=>{let e=new Uint8Array(a),t=0;for(let n of i)e.set(n,t),t+=n.length;let r=e.subarray(0,Math.min(n,e.length)),o=e.subarray(r.length);return i=o.length>0?[o]:[],a=o.length,r},l=async()=>{for(;!s&&a>0;){let n=c();try{await e(he(n))}catch(e){i=[],a=0,t.onError?.(e)}}o=null},u=e=>{s||e.length===0||(i.push(e),a+=e.length,o||=l())};return{pushText(e){u(r.encode(e))},pushBinary(e){let t=new Uint8Array(e.length);for(let n=0;n<e.length;n++)t[n]=e.charCodeAt(n)&255;u(t)},idle(){return o??Promise.resolve()},dispose(){s=!0,i=[],a=0}}}function ye(e){return Math.min(250*2**e,8e3)}function be(e){let t=``;for(let n of e.split(`
3
+ `))n.startsWith(`data:`)&&(t+=n.slice(n.startsWith(`data: `)?6:5));if(!t)return null;let n;try{n=JSON.parse(t)}catch{return null}if(typeof n!=`object`||!n)return null;let r=n;return r.type===`output`&&typeof r.seq==`number`&&typeof r.dataBase64==`string`?{type:`output`,seq:r.seq,dataBase64:r.dataBase64}:r.type===`title`&&typeof r.title==`string`?{type:`title`,title:r.title}:r.type===`exit`?{type:`exit`,code:typeof r.code==`number`?r.code:null,signal:typeof r.signal==`string`?r.signal:null}:null}function xe(e,t,n,r={}){let o=r.fetch??((e,t)=>fetch(e,t)),s=r.renew??i,c=r.proof??a,l=r.backoffMs??ye,u=!1,d=null,f=null,ee=0,p=!1,m=e=>{(!u||e===`closed`)&&n.onState?.(e)},h=()=>{u||(m(`reconnecting`),f=setTimeout(()=>{f=null,g()},l(ee++)))};async function g(){if(u)return;d=new AbortController;let r;try{r=await o(me(e,t()),{method:`GET`,credentials:`same-origin`,headers:{"x-ashlr-read-client":c(),Accept:`text/event-stream`},signal:d.signal,cache:`no-store`})}catch{h();return}if(u)return;if(r.status===404){m(`gone`),u=!0;return}if(r.status===401){if(!p&&await s().catch(()=>!1)){p=!0,g();return}m(`expired`),u=!0;return}if(!r.ok||!r.body){h();return}p=!1,m(`open`);let i=r.body.getReader(),a=new TextDecoder,l=``;try{for(;;){let{value:e,done:t}=await i.read();if(t)break;ee=0,l+=a.decode(e,{stream:!0});let r;for(;(r=l.indexOf(`
4
+
5
+ `))!==-1;){let e=l.slice(0,r);l=l.slice(r+2);let t=be(e);t&&!u&&n.onFrame(t)}}}catch{}h()}return m(`connecting`),g(),{close(){u||(u=!0,f&&clearTimeout(f),d?.abort(),n.onState?.(`closed`))}}}var Se=5e3,D=null;function O(){return D||(D=Promise.all([r(()=>import(`./xterm-ScmBfeDI.js`),[]),r(()=>import(`./addon-fit-DIOBYJe3.js`),[]),r(()=>Promise.resolve({}),__vite__mapDeps([0]))]).then(([e,t])=>[e,t]),D.catch(()=>{D=null})),D}var Ce=async e=>{let[{Terminal:t},{FitAddon:n}]=await O(),r=new t({fontFamily:e.fontFamily,fontSize:e.fontSize,lineHeight:1.2,cursorBlink:!0,cursorStyle:`bar`,scrollback:Se,theme:e.theme,screenReaderMode:e.screenReaderMode,macOptionIsMeta:!0,minimumContrastRatio:3,allowProposedApi:!1}),i=new n;r.loadAddon(i);let a=!1;return{get cols(){return r.cols},get rows(){return r.rows},open(e){a||(a=!0,r.open(e))},write(e){r.write(e)},reset(){r.reset()},focus(){r.focus()},fit(){let e=i.proposeDimensions();return!e||!Number.isFinite(e.cols)||!Number.isFinite(e.rows)||e.cols<2||e.rows<2?null:(i.fit(),{cols:r.cols,rows:r.rows})},onData:e=>r.onData(e),onBinary:e=>r.onBinary(e),onSelectionChange:e=>r.onSelectionChange(e),hasSelection:()=>r.hasSelection(),getSelection:()=>r.getSelection(),paste(e){r.paste(e)},bracketedPaste:()=>r.modes.bracketedPasteMode,setTheme(e){r.options.theme=e},setScreenReaderMode(e){r.options.screenReaderMode=e},setKeyFilter(e){r.attachCustomKeyEventHandler(e)},dispose(){r.dispose()}}},k={foreground:`--term-fg`,background:`--term-bg`,cursor:`--term-cursor`,cursorAccent:`--term-bg`,selectionBackground:`--term-selection`,selectionForeground:`--term-fg`,selectionInactiveBackground:`--term-selection-inactive`,scrollbarSliderBackground:`--term-scrollbar`,scrollbarSliderHoverBackground:`--term-scrollbar-hover`,scrollbarSliderActiveBackground:`--term-scrollbar-hover`,overviewRulerBorder:`--term-bg`,black:`--term-black`,red:`--term-red`,green:`--term-green`,yellow:`--term-yellow`,blue:`--term-blue`,magenta:`--term-magenta`,cyan:`--term-cyan`,white:`--term-white`,brightBlack:`--term-bright-black`,brightRed:`--term-bright-red`,brightGreen:`--term-bright-green`,brightYellow:`--term-bright-yellow`,brightBlue:`--term-bright-blue`,brightMagenta:`--term-bright-magenta`,brightCyan:`--term-bright-cyan`,brightWhite:`--term-bright-white`},A;function j(e){if(typeof document>`u`)return e;if(A===void 0)try{let e=document.createElement(`canvas`);e.width=1,e.height=1,A=e.getContext(`2d`,{willReadFrequently:!0})}catch{A=null}let t=A;if(!t)return e;try{t.clearRect(0,0,1,1),t.fillStyle=e,t.fillRect(0,0,1,1);let[n,r,i,a]=t.getImageData(0,0,1,1).data;return a===void 0?e:a===255?`rgb(${n}, ${r}, ${i})`:`rgba(${n}, ${r}, ${i}, ${(a/255).toFixed(3)})`}catch{return e}}function we(e){let t=document.createElement(`span`);t.style.display=`none`,e.appendChild(t);let n={};try{for(let[r,i]of Object.entries(k)){if(!getComputedStyle(e).getPropertyValue(i).trim())continue;t.style.color=``,t.style.color=`var(${i})`;let a=getComputedStyle(t).color;a&&(n[r]=j(a))}}finally{t.remove()}return n}function Te(e){let t=getComputedStyle(e),n=Number.parseFloat(t.fontSize);return{fontFamily:t.fontFamily||`ui-monospace, Menlo, monospace`,fontSize:Number.isFinite(n)&&n>=11?n:13}}function Ee(e){if(typeof window>`u`)return()=>{};let t=document.documentElement,n=typeof MutationObserver==`function`?new MutationObserver(()=>e()):null;n?.observe(t,{attributes:!0,attributeFilter:[`data-theme`,`data-accent`,`class`,`style`]});let r=typeof window.matchMedia==`function`?window.matchMedia(`(prefers-color-scheme: dark)`):null,i=()=>e();return r?.addEventListener?.(`change`,i),()=>{n?.disconnect(),r?.removeEventListener?.(`change`,i)}}var M={pane:`_pane_7fww7_15`,loading:`_loading_7fww7_91`,strip:`_strip_7fww7_100`,tabs:`_tabs_7fww7_109`,tab:`_tab_7fww7_109`,tabButton:`_tabButton_7fww7_142`,tabClose:`_tabClose_7fww7_159`,noticeClose:`_noticeClose_7fww7_160`,tabTitle:`_tabTitle_7fww7_165`,tabExited:`_tabExited_7fww7_171`,unseen:`_unseen_7fww7_180`,stripActions:`_stripActions_7fww7_215`,cwd:`_cwd_7fww7_227`,headerStatus:`_headerStatus_7fww7_229`,notice:`_notice_7fww7_160`,inlineNotice:`_inlineNotice_7fww7_267`,body:`_body_7fww7_275`,panel:`_panel_7fww7_285`,viewport:`_viewport_7fww7_294`,host:`_host_7fww7_301`,viewLoading:`_viewLoading_7fww7_318`,exitBar:`_exitBar_7fww7_323`,header:`_header_7fww7_229`},N=n(),De={api:E,createView:Ce,openStream:xe,platform:h(),writeClipboard:async e=>{await navigator.clipboard.writeText(e)}},Oe=3e3,P=`ashlr.verse.terminal.screenReader`,F=0;function I(){F=0}function ke(){try{return localStorage.getItem(P)===`1`}catch{return!1}}function Ae(e){try{localStorage.setItem(P,e?`1`:`0`)}catch{}}function je(e,t){if(e.type!==`keydown`||!b(e,[`chat`,`global`],t))return!1;let n=m(e),r=e.ctrlKey&&(n==="`"||n===`tab`);return t===`mac`?e.metaKey||r:r||e.ctrlKey&&e.shiftKey}function L(e,t){if(e instanceof C)return e.message;if(e instanceof d){if(e.status===401)return`Unlock actions with the mutation token to use the terminal.`;if(e.detail)return ne(e.detail)}return t}function Me({sessionId:e,roots:t,request:n,onSendToChat:r,visible:i,deps:a}){let o=(0,S.useMemo)(()=>({...De,...a}),[a]),s=ee(),c=i&&s,u=g().compact,[m,h]=(0,S.useState)(null),[_,ne]=(0,S.useState)(null),[b,C]=(0,S.useState)(null),[w,T]=(0,S.useState)(null),[E,me]=(0,S.useState)(!1),[he,ye]=(0,S.useState)(null),[be,xe]=(0,S.useState)(!1),[Se,D]=(0,S.useState)(!1),[O,Ce]=(0,S.useState)(ke),[k,A]=(0,S.useState)(!1),[j,P]=(0,S.useState)(()=>new Set),[I,Me]=(0,S.useState)(null),[Ne,Pe]=(0,S.useState)(()=>new Map),R=(0,S.useRef)(new Map),z=(0,S.useRef)(new Map),Fe=(0,S.useRef)(new Set),B=(0,S.useRef)(!1),V=(0,S.useRef)(null),Ie=(0,S.useRef)(null),Le=(0,S.useRef)(new Map),H=(0,S.useRef)(null),U=(0,S.useRef)(null),W=(0,S.useRef)(null),G=(0,S.useRef)(!0),Re=(0,S.useRef)(!1),K=(0,S.useMemo)(()=>m?.tabs??[],[m]),ze=(0,S.useRef)(new Set);ze.current=new Set(K.filter(e=>e.exited).map(e=>e.id));let q=(0,S.useMemo)(()=>K.filter(t=>t.sessionId===e),[K,e]),J=q.find(e=>e.id===b)??null,Be=K.length-q.length,Y=(0,S.useCallback)(async()=>{try{let e=await o.api.list();if(!G.current)return;h(e),ne(null)}catch(e){if(!G.current)return;ne(L(e,`The terminal list could not be loaded.`))}},[o.api]);(0,S.useEffect)(()=>(G.current=!0,Y(),()=>{G.current=!1}),[Y]),f(()=>{Y()},Oe,{enabled:i}),(0,S.useEffect)(()=>{m&&(b&&q.some(e=>e.id===b)||C(q.at(-1)?.id??null))},[m,q,b]),(0,S.useEffect)(()=>{if(!m)return;let e=new Set(m.tabs.map(e=>e.id));for(let[t,n]of R.current)e.has(t)||(Ve(n),R.current.delete(t),P(e=>{let n=new Set(e);return n.delete(t),n}))},[m]),(0,S.useEffect)(()=>{J&&c&&Pe(e=>e.get(J.id)===J.lastActivityAt?e:new Map(e).set(J.id,J.lastActivityAt))},[J,c]),(0,S.useEffect)(()=>()=>{for(let e of R.current.values())Ve(e);R.current.clear();for(let e of[H,U,W])e.current&&clearTimeout(e.current)},[]);function Ve(e){e.queue.dispose();for(let t of e.disposers)try{t.dispose()}catch{}try{e.view.dispose()}catch{}}let He=(0,S.useCallback)(()=>{for(let e of R.current.values())if(e.view.cols>1&&e.view.rows>1)return{cols:e.view.cols,rows:e.view.rows};return{cols:80,rows:24}},[]),X=(0,S.useCallback)(async(t={})=>{me(!0),T(null);try{let n=await o.api.create({sessionId:e,...t.root?{root:t.root}:{},...t.appId?{appId:t.appId}:{},...t.appId&&t.via?{via:t.via}:{},...t.appId&&t.model?{model:t.model}:{},...t.devServerId?{devServerId:t.devServerId}:{},...He()});return G.current?(h(e=>e&&{...e,tabs:[...e.tabs.filter(e=>e.id!==n.id),n]}),C(n.id),n):n}catch(e){return G.current&&T({tone:`error`,text:L(e,`The terminal could not be opened.`)}),null}finally{G.current&&me(!1)}},[o.api,e,He]),Z=(0,S.useCallback)(async e=>{try{await o.api.kill(e.id)}catch(e){if(!(e instanceof d&&e.status===404)){T({tone:`error`,text:L(e,`The terminal could not be closed.`)});return}}let t=R.current.get(e.id);if(t&&(Ve(t),R.current.delete(e.id)),h(t=>t&&{...t,tabs:t.tabs.filter(t=>t.id!==e.id)}),b===e.id){let t=q.findIndex(t=>t.id===e.id),n=q[t+1]??q[t-1]??null;C(n?.id??null)}},[b,o.api,q]),Ue=(0,S.useCallback)(async e=>{await X({root:e.root})&&await Z(e)},[Z,X]),We=(0,S.useRef)(e);We.current!==e&&(We.current=e,B.current=!1),(0,S.useEffect)(()=>{m&&m.available&&c&&!B.current&&!E&&(n&&n.nonce>F||(B.current=!0,q.length===0&&X({})))},[m,c,q.length,E,X,n]);let Ge=(0,S.useCallback)(async(e,t)=>{if(!(R.current.has(e)||Fe.current.has(e))){Fe.current.add(e);try{let n=await o.createView({...Te(t),theme:we(t),screenReaderMode:ke()});if(!G.current||!z.current.has(e)){n.dispose();return}n.open(t);let r=ve(t=>o.api.input(e,t),{onError:e=>{G.current&&T({tone:`error`,text:L(e,`That input did not reach the shell.`)})}}),i={view:n,host:t,lastSeq:0,queue:r,disposers:[]};i.disposers.push(n.onData(t=>{ze.current.has(e)||r.pushText(t)})),i.disposers.push(n.onBinary(t=>{ze.current.has(e)||r.pushBinary(t)})),i.disposers.push(n.onSelectionChange(()=>{let e=n.hasSelection();xe(e),e&&(W.current&&clearTimeout(W.current),W.current=setTimeout(()=>{let e=n.getSelection();e&&o.writeClipboard(e).then(()=>{G.current&&(D(!0),U.current&&clearTimeout(U.current),U.current=setTimeout(()=>D(!1),1200))},()=>{})},150))})),n.setKeyFilter(e=>!je(e,o.platform)),R.current.set(e,i),A(!1),P(t=>new Set(t).add(e))}catch(e){console.error(`[verse] terminal view failed to load`,e),G.current&&A(!0)}finally{Fe.current.delete(e)}}},[o]),Ke=(0,S.useRef)(Ge);Ke.current=Ge;let qe=(0,S.useRef)(new Map),Je=e=>{let t=qe.current.get(e);return t||(t=t=>{t?(z.current.set(e,t),Ke.current(e,t)):(z.current.delete(e),qe.current.delete(e))},qe.current.set(e,t)),t},Ye=(0,S.useCallback)(()=>{if(!b)return;let e=R.current.get(b);if(!e)return;let t={cols:e.view.cols,rows:e.view.rows},n=e.view.fit();if(!n||n.cols===t.cols&&n.rows===t.rows&&J&&J.cols===n.cols&&J.rows===n.rows)return;H.current&&clearTimeout(H.current);let r=b;H.current=setTimeout(()=>{o.api.resize(r,n.cols,n.rows).catch(()=>{})},100)},[J,b,o.api]);(0,S.useEffect)(()=>{if(!c||!b||!j.has(b))return;Ye();let e=Ie.current;if(!e||typeof ResizeObserver>`u`)return;let t=0,n=new ResizeObserver(()=>{cancelAnimationFrame(t),t=requestAnimationFrame(Ye)});return n.observe(e),()=>{cancelAnimationFrame(t),n.disconnect()}},[c,b,j,Ye]),(0,S.useEffect)(()=>Ee(()=>{for(let e of R.current.values())e.view.setTheme(we(e.host))}),[]);let Q=(0,S.useCallback)(e=>{let t=V.current;if(!t||t.tabId!==e)return;let n=R.current.get(e);if(!n)return;V.current=null;let r=t.text.replace(/[\r\n]+$/,``);r.includes(`
6
+ `)&&!n.view.bracketedPaste()?o.writeClipboard(r).then(()=>T({tone:`info`,text:`That command has several lines, so it was copied instead: paste it with ⌘V.`}),()=>T({tone:`error`,text:`That command has several lines and could not be pasted safely.`})):n.view.paste(r),n.view.focus()},[o]);(0,S.useEffect)(()=>{if(!c||!b||!j.has(b)){ye(null);return}let e=R.current.get(b);if(!e)return;let t=b,n=!0,r=o.openStream(t,()=>e.lastSeq,{onFrame:r=>{if(r.type===`output`){if(r.seq<=e.lastSeq)return;e.lastSeq>0&&r.seq>e.lastSeq+1&&e.view.reset(),e.view.write(ge(r.dataBase64)),e.lastSeq=r.seq,n&&(n=!1,V.current?.tabId===t&&setTimeout(()=>Q(t),120));return}h(e=>e&&{...e,tabs:e.tabs.map(e=>e.id===t?r.type===`title`?e.title===r.title?e:{...e,title:r.title}:{...e,exited:{code:r.code,signal:r.signal,at:new Date().toISOString()}}:e)})},onState:e=>{G.current&&(ye(e),e===`gone`&&Y())}});return V.current?.tabId===t&&e.lastSeq>0&&setTimeout(()=>Q(t),0),()=>r.close()},[c,b,j,o,Y,Q]);let Xe=(0,S.useCallback)(async e=>{let n=e.root??J?.root??t[0],r=e.newTab===!0||!!e.appId||!!e.devServerId,i=null;if(r||(i=(J&&!J.exited&&(!e.root||J.root===e.root)?J:null)??q.find(t=>!t.exited&&(!e.root||t.root===e.root))??null),i?C(i.id):i=await X({...n?{root:n}:{},...e.appId?{appId:e.appId}:{},...e.via?{via:e.via}:{},...e.model?{model:e.model}:{},...e.devServerId?{devServerId:e.devServerId}:{}}),i){if(e.paste){V.current={tabId:i.id,text:e.paste};let t=R.current.get(i.id);t&&t.lastSeq>0&&Q(i.id)}else R.current.get(i.id)?.view.focus()}},[J,Q,X,t,q]);(0,S.useEffect)(()=>{!n||!m||n.nonce<=F||(F=n.nonce,B.current=!0,m.available&&Xe(n))},[n,m,Xe]),(0,S.useEffect)(()=>{c&&b&&j.has(b)&&R.current.get(b)?.view.focus()},[c,b,j]);let Ze=()=>{if(!b)return;let e=R.current.get(b)?.view.getSelection()??``;e.trim()&&r(_e(e))},Qe=()=>{let e=!O;Ce(e),Ae(e);for(let t of R.current.values())t.view.setScreenReaderMode(e)},$e=async()=>{try{await o.api.openExternal(e,J?.root??t[0]),T({tone:`info`,text:`Opened in Terminal.`})}catch(e){T({tone:`error`,text:L(e,`Terminal could not be opened.`)})}},et=e=>{Re.current=!0,X(e).finally(()=>{Re.current=!1})},tt=()=>{et(J?.root?{root:J.root}:{})},nt=(e,t)=>{let n=-1;if(e.key===`ArrowRight`?n=(t+1)%q.length:e.key===`ArrowLeft`?n=(t-1+q.length)%q.length:e.key===`Home`?n=0:e.key===`End`&&(n=q.length-1),n<0)return;e.preventDefault();let r=q[n];C(r.id),Le.current.get(r.id)?.focus()};if(!m)return _?(0,N.jsx)(`div`,{className:M.pane,children:(0,N.jsx)(x,{compact:!0,tone:`error`,title:`Terminal is not reachable`,body:_,action:(0,N.jsx)(y,{size:`sm`,variant:`subtle`,onClick:()=>void Y(),children:`Try again`})})}):(0,N.jsxs)(`div`,{className:M.pane,"aria-busy":`true`,children:[(0,N.jsx)(`div`,{className:M.strip,"aria-hidden":`true`}),(0,N.jsxs)(`div`,{className:M.loading,children:[(0,N.jsx)(l,{width:`40%`}),(0,N.jsx)(l,{width:`70%`})]})]});if(!m.available)return(0,N.jsxs)(`div`,{className:M.pane,children:[(0,N.jsx)(x,{compact:!0,icon:(0,N.jsx)(ue,{size:20}),title:`Terminal needs the desktop app`,body:`This Verse server has no built-in terminal. Open the project in Terminal instead, or use the Ashlr desktop app.`,action:o.platform===`mac`?(0,N.jsx)(y,{size:`sm`,variant:`subtle`,icon:(0,N.jsx)(oe,{}),onClick:()=>void $e(),children:`Open in Terminal`}):void 0}),w?(0,N.jsx)(`p`,{className:M.inlineNotice,role:w.tone===`error`?`alert`:`status`,children:w.text}):null]});let rt=t.length>1,it=le(`dock.terminal-new`)?.keys[0],$=it?p(it,o.platform):null,at=q.length===0&&!k&&(!B.current||E&&!Re.current),ot=J?.root??q.at(-1)?.root??(at?t[0]??null:null);return(0,N.jsxs)(`div`,{className:M.pane,"data-compact":u||void 0,children:[(0,N.jsxs)(`div`,{className:M.strip,children:[(0,N.jsx)(`div`,{className:M.tabs,role:`tablist`,"aria-label":`Terminals`,children:q.map((e,t)=>{let n=e.id===b,r=!n&&(Ne.get(e.id)??e.createdAt)<e.lastActivityAt;return(0,N.jsxs)(`div`,{className:M.tab,"data-selected":n||void 0,role:`presentation`,children:[(0,N.jsxs)(`button`,{ref:t=>{t?Le.current.set(e.id,t):Le.current.delete(e.id)},type:`button`,role:`tab`,id:`terminal-tab-${e.id}`,"aria-selected":n,"aria-controls":`terminal-panel-${e.id}`,tabIndex:n?0:-1,className:M.tabButton,title:`${e.title} — ${e.root}`,onClick:()=>C(e.id),onKeyDown:e=>nt(e,t),children:[(0,N.jsx)(`span`,{className:M.tabTitle,children:e.title}),e.exited?(0,N.jsx)(`span`,{className:M.tabExited,children:`exited`}):null,r&&!e.exited?(0,N.jsx)(`span`,{className:M.unseen,"aria-label":`new output`,role:`img`}):null]}),(0,N.jsx)(`button`,{type:`button`,className:M.tabClose,"aria-label":`Close terminal ${e.title}`,title:`Close terminal`,onClick:()=>void Z(e),children:(0,N.jsx)(ae,{size:12})})]},e.id)})}),(0,N.jsxs)(`div`,{className:M.stripActions,children:[(0,N.jsx)(v,{variant:`ghost`,size:`sm`,icon:(0,N.jsx)(se,{}),"aria-label":`New terminal tab`,title:$?`New terminal tab (${$})`:`New terminal tab`,busy:E,onClick:tt}),rt?(0,N.jsx)(v,{variant:`ghost`,size:`sm`,icon:(0,N.jsx)(de,{}),"aria-label":`New terminal in…`,"aria-haspopup":`menu`,"aria-expanded":I!==null,title:`Choose the folder`,onClick:e=>Me({anchor:re(e.currentTarget),from:e.currentTarget})}):null]})]}),ot===null?null:(0,N.jsxs)(`div`,{className:`${pe.header} ${M.header}`,children:[(0,N.jsx)(`span`,{className:`${pe.title} ${M.cwd}`,title:ot,children:te(ot)}),(0,N.jsx)(`span`,{className:M.headerStatus,role:`status`,"aria-live":`polite`,children:he===`reconnecting`?`Reconnecting…`:he===`expired`?`Session expired — reload to reconnect`:Se?`Copied`:``}),(0,N.jsxs)(`div`,{className:pe.actions,children:[(0,N.jsx)(y,{variant:`ghost`,size:`sm`,icon:(0,N.jsx)(ce,{}),disabled:!be,"aria-label":`Send selection to chat`,title:be?`Send the selected text to the chat as a code block`:`Select text in the terminal first`,onClick:Ze,children:u?null:`Send to chat`}),(0,N.jsx)(v,{variant:`ghost`,size:`sm`,icon:(0,N.jsx)(fe,{}),"aria-label":`Screen reader mode`,"aria-pressed":O,title:O?`Screen reader mode is on`:`Screen reader mode`,onClick:Qe}),o.platform===`mac`?(0,N.jsx)(v,{variant:`ghost`,size:`sm`,icon:(0,N.jsx)(oe,{}),"aria-label":`Open in Terminal.app`,title:`Open this folder in Terminal.app`,onClick:()=>void $e()}):null]})]}),w?(0,N.jsxs)(`div`,{className:M.notice,"data-tone":w.tone,role:w.tone===`error`?`alert`:`status`,children:[(0,N.jsx)(`span`,{children:w.text}),(0,N.jsx)(`button`,{type:`button`,className:M.noticeClose,"aria-label":`Dismiss`,title:`Dismiss`,onClick:()=>T(null),children:(0,N.jsx)(ae,{size:12})})]}):null,(0,N.jsxs)(`div`,{className:M.body,ref:Ie,children:[k?(0,N.jsx)(x,{compact:!0,tone:`error`,title:`The terminal could not load`,body:`The rest of the chat still works.`,action:(0,N.jsx)(y,{size:`sm`,variant:`subtle`,onClick:()=>{A(!1);for(let[e,t]of z.current)Ge(e,t)},children:`Try again`})}):null,at?(0,N.jsx)(`div`,{className:M.loading,role:`status`,"aria-label":`Opening a shell`,children:(0,N.jsx)(l,{width:`30%`})}):null,q.length===0&&!k&&!at?(0,N.jsx)(x,{compact:!0,icon:(0,N.jsx)(ue,{size:20}),title:`No terminal open`,body:`Click New terminal${$?` or press ${$}`:``} to open a login shell in this chat's folder.${Be>0?` ${Be} ${Be===1?`terminal is`:`terminals are`} open in other chats.`:``}`,action:(0,N.jsx)(y,{size:`sm`,variant:`subtle`,icon:(0,N.jsx)(se,{}),busy:E,onClick:tt,children:`New terminal`})}):null,q.map(e=>{let t=e.id===b;return(0,N.jsxs)(`div`,{id:`terminal-panel-${e.id}`,role:`tabpanel`,"aria-labelledby":`terminal-tab-${e.id}`,className:M.panel,hidden:!t,children:[(0,N.jsxs)(`div`,{className:M.viewport,children:[(0,N.jsx)(`div`,{className:M.host,ref:Je(e.id),"data-testid":`terminal-host-${e.id}`}),!j.has(e.id)&&!k?(0,N.jsx)(`div`,{className:M.viewLoading,"aria-hidden":`true`,children:(0,N.jsx)(l,{width:`30%`})}):null]}),e.exited?(0,N.jsxs)(`div`,{className:M.exitBar,role:`status`,children:[(0,N.jsx)(`span`,{children:e.exited.signal&&e.exited.code===null?`Shell ended (${e.exited.signal}).`:`Shell exited${e.exited.code===null?``:` with code ${e.exited.code}`}.`}),(0,N.jsx)(y,{size:`sm`,variant:`subtle`,onClick:()=>void Ue(e),children:`Restart`}),(0,N.jsx)(y,{size:`sm`,variant:`ghost`,onClick:()=>void Z(e),children:`Close`})]}):null]},e.id)})]}),I?(0,N.jsx)(ie,{label:`New terminal in`,anchor:I.anchor,returnFocus:I.from,onClose:()=>Me(null),items:t.map(e=>({id:e,label:te(e),description:e,onSelect:()=>{et({root:e})}}))}):null]})}export{Oe as TERMINAL_LIST_POLL_MS,Me as TerminalPane,je as keyPassesToPage,I as resetTerminalPaneForTest};
7
+ //# sourceMappingURL=TerminalPane-BSnGdUuF.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"mappings":"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","names":[],"ignoreList":[],"sources":["../../../../../../src/web-ui/routes/verse/dock/terminal/terminal-client.ts","../../../../../../src/web-ui/routes/verse/dock/terminal/input-queue.ts","../../../../../../src/web-ui/routes/verse/dock/terminal/terminal-stream.ts","../../../../../../src/web-ui/routes/verse/dock/terminal/terminal-view.ts","../../../../../../src/web-ui/routes/verse/dock/terminal/TerminalPane.tsx"],"sourcesContent":["/**\n * dock/terminal/terminal-client.ts — the Terminal pane's HTTP calls (unit C4).\n *\n * Writes carry the held mutation token (auth-store), exactly like\n * verse-queries' writes; the stream is read with fetch() + the read-client\n * header rather than EventSource (see terminal-stream.ts for why).\n */\nimport type {\n VerseTerminalCreateRequest,\n VerseTerminalListResponse,\n VerseTerminalTab,\n} from '../../../../data/api-types.js';\nimport { getMutationToken, touchMutationHold } from '../../../../data/auth-store.js';\nimport { apiGet, apiPost } from '../../../../data/client.js';\nimport { VERSE_TERMINAL_PATH } from '../../../../../core/verse/workbench-types.js';\n\n/** Raised when a write is attempted with no mutation token held. */\nexport class TerminalLockedError extends Error {\n constructor() {\n super('Unlock actions with the mutation token to use the terminal.');\n this.name = 'TerminalLockedError';\n }\n}\n\nasync function post<T>(path: string, body: unknown): Promise<T> {\n const token = getMutationToken();\n if (!token) throw new TerminalLockedError();\n const result = await apiPost<T>(path, body, token);\n touchMutationHold();\n return result;\n}\n\nfunction tabPath(id: string, action: 'input' | 'resize' | 'kill' | 'stream'): string {\n return `${VERSE_TERMINAL_PATH}/${encodeURIComponent(id)}/${action}`;\n}\n\nexport interface TerminalApi {\n list(signal?: AbortSignal): Promise<VerseTerminalListResponse>;\n create(req: VerseTerminalCreateRequest): Promise<VerseTerminalTab>;\n input(id: string, dataBase64: string): Promise<void>;\n resize(id: string, cols: number, rows: number): Promise<void>;\n kill(id: string): Promise<void>;\n openExternal(sessionId: string, root?: string): Promise<void>;\n}\n\nexport const terminalApi: TerminalApi = {\n list: (signal) => apiGet<VerseTerminalListResponse>(VERSE_TERMINAL_PATH, signal),\n create: async (req) => (await post<{ tab: VerseTerminalTab }>(VERSE_TERMINAL_PATH, req)).tab,\n input: (id, dataBase64) => post<void>(tabPath(id, 'input'), { dataBase64 }),\n resize: (id, cols, rows) => post<void>(tabPath(id, 'resize'), { cols, rows }),\n kill: async (id) => { await post<unknown>(tabPath(id, 'kill'), {}); },\n openExternal: async (sessionId, root) => {\n await post<unknown>(`${VERSE_TERMINAL_PATH}/open-external`, root === undefined ? { sessionId } : { sessionId, root });\n },\n};\n\nexport function terminalStreamPath(id: string, after: number): string {\n const cursor = Number.isSafeInteger(after) && after > 0 ? `?after=${after}` : '';\n return `${tabPath(id, 'stream')}${cursor}`;\n}\n\n// ---------------------------------------------------------------------------\n// Bytes\n// ---------------------------------------------------------------------------\n\n/** Standard base64 of bytes (btoa over a binary string, chunked to stay off the arg-count limit). */\nexport function bytesToBase64(bytes: Uint8Array): string {\n let binary = '';\n for (let i = 0; i < bytes.length; i += 0x8000) {\n binary += String.fromCharCode(...bytes.subarray(i, i + 0x8000));\n }\n return btoa(binary);\n}\n\nexport function base64ToBytes(b64: string): Uint8Array {\n const binary = atob(b64);\n const out = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) out[i] = binary.charCodeAt(i);\n return out;\n}\n\n/**\n * The fence for \"Send selection to chat\": one backtick longer than the\n * longest run inside the text (at least three), so a selection that itself\n * contains a fenced block cannot close ours early.\n */\nexport function fenceSelection(text: string): string {\n const trimmed = text.replace(/\\s+$/, '');\n const longest = Math.max(0, ...Array.from(trimmed.matchAll(/`+/g), (m) => m[0].length));\n const fence = '`'.repeat(Math.max(3, longest + 1));\n return `${fence}\\n${trimmed}\\n${fence}`;\n}\n","/**\n * dock/terminal/input-queue.ts — keystrokes to the shell, in order (unit C4).\n *\n * Every keystroke is a POST. Two POSTs in flight at once may arrive in either\n * order, and a shell that receives `sl` for `ls` runs the wrong command. So\n * input is SINGLE-FLIGHT: while one request is out, everything typed after it\n * accumulates and goes as the next request — in order, and coalesced (a burst\n * of typing or a paste becomes one or a few requests, not hundreds). The\n * server takes at most 16 KB per request, so a long paste is sent in 16 KB\n * slices, one after another.\n */\nimport { VERSE_TERMINAL_INPUT_MAX_BYTES } from '../../../../../core/verse/workbench-types.js';\nimport { bytesToBase64 } from './terminal-client.js';\n\nexport interface InputQueue {\n /** Text as xterm reports it (a JS string — encoded as UTF-8). */\n pushText(text: string): void;\n /** xterm `onBinary` data: one char per byte (0–255). */\n pushBinary(binary: string): void;\n /** Resolves once everything pushed so far has been sent (or dropped on error). */\n idle(): Promise<void>;\n /** Stop sending; anything queued is dropped. */\n dispose(): void;\n}\n\nexport function createInputQueue(\n send: (dataBase64: string) => Promise<void>,\n opts: { maxBytes?: number; onError?: (err: unknown) => void } = {},\n): InputQueue {\n const maxBytes = opts.maxBytes ?? VERSE_TERMINAL_INPUT_MAX_BYTES;\n const encoder = new TextEncoder();\n let pending: Uint8Array[] = [];\n let pendingBytes = 0;\n let running: Promise<void> | null = null;\n let disposed = false;\n\n const take = (): Uint8Array => {\n const all = new Uint8Array(pendingBytes);\n let offset = 0;\n for (const chunk of pending) {\n all.set(chunk, offset);\n offset += chunk.length;\n }\n const head = all.subarray(0, Math.min(maxBytes, all.length));\n const rest = all.subarray(head.length);\n pending = rest.length > 0 ? [rest] : [];\n pendingBytes = rest.length;\n return head;\n };\n\n const pump = async (): Promise<void> => {\n while (!disposed && pendingBytes > 0) {\n const slice = take();\n try {\n await send(bytesToBase64(slice));\n } catch (err) {\n // A failed keystroke is not retried: replaying it later, after newer\n // input, is exactly the reordering this queue exists to prevent.\n pending = [];\n pendingBytes = 0;\n opts.onError?.(err);\n }\n }\n running = null;\n };\n\n const push = (bytes: Uint8Array): void => {\n if (disposed || bytes.length === 0) return;\n pending.push(bytes);\n pendingBytes += bytes.length;\n if (!running) running = pump();\n };\n\n return {\n pushText(text) {\n push(encoder.encode(text));\n },\n pushBinary(binary) {\n const bytes = new Uint8Array(binary.length);\n for (let i = 0; i < binary.length; i++) bytes[i] = binary.charCodeAt(i) & 0xff;\n push(bytes);\n },\n idle() {\n return running ?? Promise.resolve();\n },\n dispose() {\n disposed = true;\n pending = [];\n pendingBytes = 0;\n },\n };\n}\n","/**\n * dock/terminal/terminal-stream.ts — one terminal tab's live output (unit C4).\n *\n * WHY fetch() AND NOT EventSource. The server's read boundary accepts the\n * per-tab client proof as a query parameter ONLY on the three EventSource\n * paths it knows (read-session.ts); everywhere else it must be the\n * `x-ashlr-read-client` header, which EventSource cannot send. fetch() can,\n * and a streamed body reads the same `text/event-stream` frames. It also\n * lets the pane keep exactly ONE connection open — the visible tab's — which\n * matters because a browser allows about six per origin and Verse already\n * holds two (the app events and the open chat).\n *\n * RESUME. Each (re)connect asks for `?after=<the last seq written>`; the\n * server replays only newer frames from its 256 KB scrollback. A dropped\n * connection reconnects with backoff; a 401 renews the read session once;\n * a 404 means the tab is gone (killed, idle-closed, server restarted).\n */\nimport type { VerseTerminalFrame } from '../../../../data/api-types.js';\nimport { getReadClientProof, renewReadSession } from '../../../../data/auth-store.js';\nimport { terminalStreamPath } from './terminal-client.js';\n\nexport type TerminalStreamState = 'connecting' | 'open' | 'reconnecting' | 'gone' | 'expired' | 'closed';\n\nexport interface TerminalStreamHandlers {\n onFrame: (frame: VerseTerminalFrame) => void;\n onState?: (state: TerminalStreamState) => void;\n}\n\nexport interface TerminalStreamDeps {\n fetch?: typeof fetch;\n renew?: () => Promise<boolean>;\n proof?: () => string;\n /** Backoff before reconnect attempt `n` (0-based). */\n backoffMs?: (attempt: number) => number;\n}\n\nexport interface TerminalStream {\n close(): void;\n}\n\nfunction defaultBackoff(attempt: number): number {\n return Math.min(250 * 2 ** attempt, 8_000);\n}\n\n/** Parse one SSE block (`event:` / `data:` lines) into a frame; null for comments and junk. */\nexport function parseTerminalSseBlock(block: string): VerseTerminalFrame | null {\n let data = '';\n for (const line of block.split('\\n')) {\n if (line.startsWith('data:')) data += line.slice(line.startsWith('data: ') ? 6 : 5);\n }\n if (!data) return null;\n let parsed: unknown;\n try {\n parsed = JSON.parse(data);\n } catch {\n return null;\n }\n if (parsed === null || typeof parsed !== 'object') return null;\n const frame = parsed as Record<string, unknown>;\n if (frame['type'] === 'output' && typeof frame['seq'] === 'number' && typeof frame['dataBase64'] === 'string') {\n return { type: 'output', seq: frame['seq'], dataBase64: frame['dataBase64'] };\n }\n if (frame['type'] === 'title' && typeof frame['title'] === 'string') return { type: 'title', title: frame['title'] };\n if (frame['type'] === 'exit') {\n return {\n type: 'exit',\n code: typeof frame['code'] === 'number' ? frame['code'] : null,\n signal: typeof frame['signal'] === 'string' ? frame['signal'] : null,\n };\n }\n return null;\n}\n\n/**\n * Stream `tabId`'s frames, resuming after `after()` on every (re)connect.\n * Returns a handle whose close() aborts the request and stops reconnecting.\n */\nexport function openTerminalStream(\n tabId: string,\n after: () => number,\n handlers: TerminalStreamHandlers,\n deps: TerminalStreamDeps = {},\n): TerminalStream {\n const doFetch = deps.fetch ?? ((input: RequestInfo | URL, init?: RequestInit) => fetch(input, init));\n const renew = deps.renew ?? renewReadSession;\n const proof = deps.proof ?? getReadClientProof;\n const backoff = deps.backoffMs ?? defaultBackoff;\n let closed = false;\n let controller: AbortController | null = null;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let attempt = 0;\n let renewedOnce = false;\n\n const setState = (state: TerminalStreamState): void => {\n if (!closed || state === 'closed') handlers.onState?.(state);\n };\n\n const schedule = (): void => {\n if (closed) return;\n setState('reconnecting');\n timer = setTimeout(() => {\n timer = null;\n void connect();\n }, backoff(attempt++));\n };\n\n async function connect(): Promise<void> {\n if (closed) return;\n controller = new AbortController();\n let res: Response;\n try {\n res = await doFetch(terminalStreamPath(tabId, after()), {\n method: 'GET',\n credentials: 'same-origin',\n headers: { 'x-ashlr-read-client': proof(), Accept: 'text/event-stream' },\n signal: controller.signal,\n cache: 'no-store',\n });\n } catch {\n schedule();\n return;\n }\n if (closed) return;\n if (res.status === 404) {\n setState('gone');\n closed = true;\n return;\n }\n if (res.status === 401) {\n if (!renewedOnce && (await renew().catch(() => false))) {\n renewedOnce = true;\n void connect();\n return;\n }\n setState('expired');\n closed = true;\n return;\n }\n if (!res.ok || !res.body) {\n schedule();\n return;\n }\n renewedOnce = false;\n setState('open');\n const reader = res.body.getReader();\n const decoder = new TextDecoder();\n let buffer = '';\n try {\n for (;;) {\n const { value, done } = await reader.read();\n if (done) break;\n attempt = 0;\n buffer += decoder.decode(value, { stream: true });\n let idx: number;\n while ((idx = buffer.indexOf('\\n\\n')) !== -1) {\n const block = buffer.slice(0, idx);\n buffer = buffer.slice(idx + 2);\n const frame = parseTerminalSseBlock(block);\n if (frame && !closed) handlers.onFrame(frame);\n }\n }\n } catch {\n /* aborted, or the connection dropped: reconnect below unless closed */\n }\n // The server ends the stream when the tab is removed; the next connect\n // then answers 404 and reports 'gone'.\n schedule();\n }\n\n setState('connecting');\n void connect();\n\n return {\n close() {\n if (closed) return;\n closed = true;\n if (timer) clearTimeout(timer);\n controller?.abort();\n handlers.onState?.('closed');\n },\n };\n}\n","/**\n * dock/terminal/terminal-view.ts — the one seam between the Terminal pane and\n * xterm.js (unit C4).\n *\n * LAZY. `@xterm/xterm` (≈ 345 KB minified) and its stylesheet load only when\n * a terminal is first shown, as their own chunk — never on the chat's\n * critical path (SPEC-310C budget: chat critical JS ≤ 350 KB). The pane talks\n * to a small `TerminalView` interface, so tests inject a fake (jsdom has no\n * layout or canvas for xterm) and the pane never imports xterm itself.\n *\n * THEME FROM TOKENS. xterm wants concrete colours; the design system forbids\n * raw hex in new UI files and wants every colour to follow the theme. So the\n * palette is declared as CSS custom properties on the pane\n * (TerminalPane.module.css, mapped to design tokens for both themes) and\n * resolved here at runtime — a probe element turns `var(--x)` into a computed\n * colour, a 1×1 canvas normalises any colour syntax to rgb — and re-resolved\n * when the theme changes.\n */\nimport type { ITheme, Terminal as XtermTerminal } from '@xterm/xterm';\n\nexport interface TerminalViewDisposable {\n dispose(): void;\n}\n\nexport interface TerminalView {\n readonly cols: number;\n readonly rows: number;\n open(host: HTMLElement): void;\n write(data: Uint8Array): void;\n reset(): void;\n focus(): void;\n /** Fit to the host; returns the new size (or null when the host has no size — hidden). */\n fit(): { cols: number; rows: number } | null;\n onData(cb: (data: string) => void): TerminalViewDisposable;\n onBinary(cb: (data: string) => void): TerminalViewDisposable;\n onSelectionChange(cb: () => void): TerminalViewDisposable;\n hasSelection(): boolean;\n getSelection(): string;\n /** Paste as if typed (bracketed when the program asked for it). Never adds Enter. */\n paste(text: string): void;\n /** True while the program in the terminal has bracketed paste on (shells at a prompt do). */\n bracketedPaste(): boolean;\n setTheme(theme: TerminalTheme): void;\n setScreenReaderMode(on: boolean): void;\n /** Return false from `filter` to let a key pass to the page (app shortcuts). */\n setKeyFilter(filter: (event: KeyboardEvent) => boolean): void;\n dispose(): void;\n}\n\nexport type TerminalTheme = ITheme;\n\nexport interface TerminalViewOptions {\n fontFamily: string;\n fontSize: number;\n theme: TerminalTheme;\n screenReaderMode: boolean;\n}\n\nexport type TerminalViewFactory = (opts: TerminalViewOptions) => Promise<TerminalView>;\n\n/** Scrollback kept by the VIEW (lines). The server keeps its own 256 KB for reattach. */\nconst VIEW_SCROLLBACK_LINES = 5_000;\n\nlet xtermModules: Promise<[typeof import('@xterm/xterm'), typeof import('@xterm/addon-fit')]> | null = null;\n\nfunction loadXtermModules() {\n if (!xtermModules) {\n xtermModules = Promise.all([\n import('@xterm/xterm'),\n import('@xterm/addon-fit'),\n import('@xterm/xterm/css/xterm.css'),\n ]).then(([xterm, fit]) => [xterm, fit] as [typeof import('@xterm/xterm'), typeof import('@xterm/addon-fit')]);\n // A failed chunk load must be retryable (the pane offers \"Try again\").\n xtermModules.catch(() => { xtermModules = null; });\n }\n return xtermModules;\n}\n\n/** The real xterm.js view. */\nexport const createXtermView: TerminalViewFactory = async (opts) => {\n const [{ Terminal }, { FitAddon }] = await loadXtermModules();\n const term: XtermTerminal = new Terminal({\n fontFamily: opts.fontFamily,\n fontSize: opts.fontSize,\n lineHeight: 1.2,\n cursorBlink: true,\n cursorStyle: 'bar',\n scrollback: VIEW_SCROLLBACK_LINES,\n theme: opts.theme,\n screenReaderMode: opts.screenReaderMode,\n // ⌥ as Meta: word motions (⌥←/⌥→ → ESC b / ESC f) work as in Terminal.app\n // with \"Use Option as Meta key\".\n macOptionIsMeta: true,\n // Keep dim ANSI text legible on our surfaces in both themes.\n minimumContrastRatio: 3,\n allowProposedApi: false,\n });\n const fit = new FitAddon();\n term.loadAddon(fit);\n let opened = false;\n\n return {\n get cols() { return term.cols; },\n get rows() { return term.rows; },\n open(host) {\n if (opened) return;\n opened = true;\n term.open(host);\n },\n write(data) { term.write(data); },\n reset() { term.reset(); },\n focus() { term.focus(); },\n fit() {\n const dims = fit.proposeDimensions();\n if (!dims || !Number.isFinite(dims.cols) || !Number.isFinite(dims.rows) || dims.cols < 2 || dims.rows < 2) return null;\n fit.fit();\n return { cols: term.cols, rows: term.rows };\n },\n onData: (cb) => term.onData(cb),\n onBinary: (cb) => term.onBinary(cb),\n onSelectionChange: (cb) => term.onSelectionChange(cb),\n hasSelection: () => term.hasSelection(),\n getSelection: () => term.getSelection(),\n paste(text) { term.paste(text); },\n bracketedPaste: () => term.modes.bracketedPasteMode,\n setTheme(theme) { term.options.theme = theme; },\n setScreenReaderMode(on) { term.options.screenReaderMode = on; },\n setKeyFilter(filter) { term.attachCustomKeyEventHandler(filter); },\n dispose() { term.dispose(); },\n };\n};\n\n// ---------------------------------------------------------------------------\n// Theme resolution\n// ---------------------------------------------------------------------------\n\n/** ITheme key → the custom property TerminalPane.module.css declares for it. */\nexport const TERMINAL_THEME_VARS: Readonly<Record<keyof Omit<ITheme, 'extendedAnsi'>, string>> = {\n foreground: '--term-fg',\n background: '--term-bg',\n cursor: '--term-cursor',\n cursorAccent: '--term-bg',\n selectionBackground: '--term-selection',\n selectionForeground: '--term-fg',\n selectionInactiveBackground: '--term-selection-inactive',\n scrollbarSliderBackground: '--term-scrollbar',\n scrollbarSliderHoverBackground: '--term-scrollbar-hover',\n scrollbarSliderActiveBackground: '--term-scrollbar-hover',\n overviewRulerBorder: '--term-bg',\n black: '--term-black',\n red: '--term-red',\n green: '--term-green',\n yellow: '--term-yellow',\n blue: '--term-blue',\n magenta: '--term-magenta',\n cyan: '--term-cyan',\n white: '--term-white',\n brightBlack: '--term-bright-black',\n brightRed: '--term-bright-red',\n brightGreen: '--term-bright-green',\n brightYellow: '--term-bright-yellow',\n brightBlue: '--term-bright-blue',\n brightMagenta: '--term-bright-magenta',\n brightCyan: '--term-bright-cyan',\n brightWhite: '--term-bright-white',\n};\n\nlet canvasCtx: CanvasRenderingContext2D | null | undefined;\n\n/**\n * Any CSS colour → `rgb(r, g, b)` / `rgba(…)`, by painting one pixel. Canvas\n * accepts every syntax the browser does (hsl, color-mix, oklch) and the pixel\n * is plain sRGB, which is what xterm parses. Falls back to the input.\n */\nexport function normalizeCssColor(value: string): string {\n if (typeof document === 'undefined') return value;\n if (canvasCtx === undefined) {\n try {\n const canvas = document.createElement('canvas');\n canvas.width = 1;\n canvas.height = 1;\n canvasCtx = canvas.getContext('2d', { willReadFrequently: true });\n } catch {\n canvasCtx = null;\n }\n }\n const ctx = canvasCtx;\n if (!ctx) return value;\n try {\n ctx.clearRect(0, 0, 1, 1);\n ctx.fillStyle = value;\n ctx.fillRect(0, 0, 1, 1);\n const [r, g, b, a] = ctx.getImageData(0, 0, 1, 1).data;\n if (a === undefined) return value;\n return a === 255 ? `rgb(${r}, ${g}, ${b})` : `rgba(${r}, ${g}, ${b}, ${(a! / 255).toFixed(3)})`;\n } catch {\n return value;\n }\n}\n\n/**\n * Read the pane's `--term-*` properties as concrete colours. A probe child\n * with `color: var(--x)` makes the browser resolve every var() and\n * color-mix() for us; unset properties are left out (xterm keeps its default).\n */\nexport function resolveTerminalTheme(host: HTMLElement): TerminalTheme {\n const probe = document.createElement('span');\n probe.style.display = 'none';\n host.appendChild(probe);\n const theme: Record<string, string> = {};\n try {\n for (const [key, prop] of Object.entries(TERMINAL_THEME_VARS)) {\n const declared = getComputedStyle(host).getPropertyValue(prop).trim();\n if (!declared) continue;\n probe.style.color = '';\n probe.style.color = `var(${prop})`;\n const computed = getComputedStyle(probe).color;\n if (computed) theme[key] = normalizeCssColor(computed);\n }\n } finally {\n probe.remove();\n }\n return theme as TerminalTheme;\n}\n\n/** The host's computed monospace family and size (so the display-size setting reaches the terminal). */\nexport function resolveTerminalFont(host: HTMLElement): { fontFamily: string; fontSize: number } {\n const style = getComputedStyle(host);\n const size = Number.parseFloat(style.fontSize);\n return {\n fontFamily: style.fontFamily || 'ui-monospace, Menlo, monospace',\n fontSize: Number.isFinite(size) && size >= 11 ? size : 13,\n };\n}\n\n/** Call `onChange` when the effective colour theme changes (explicit toggle or OS appearance). */\nexport function watchThemeChanges(onChange: () => void): () => void {\n if (typeof window === 'undefined') return () => {};\n const root = document.documentElement;\n const observer = typeof MutationObserver === 'function'\n ? new MutationObserver(() => onChange())\n : null;\n observer?.observe(root, { attributes: true, attributeFilter: ['data-theme', 'data-accent', 'class', 'style'] });\n const media = typeof window.matchMedia === 'function' ? window.matchMedia('(prefers-color-scheme: dark)') : null;\n const onMedia = () => onChange();\n media?.addEventListener?.('change', onMedia);\n return () => {\n observer?.disconnect();\n media?.removeEventListener?.('change', onMedia);\n };\n}\n","/**\n * dock/terminal/TerminalPane.tsx — the chat dock's Terminal (unit C4;\n * SPEC-310C §3). Rendered by C2's Dock through C0's `terminal-pane` slot, so\n * this file (and xterm with it) loads only when a terminal is first opened.\n *\n * WHAT IT IS\n * - One tab per shell, each a LOGIN shell the sidecar runs on a real PTY\n * (core/verse/terminal.ts), opened in one of this chat's roots. Tabs\n * live on the server: a page reload reattaches to them and replays their\n * scrollback. The tab title follows the shell's own OSC title.\n * - Header: the working directory, \"Send selection to chat\" (as a fenced\n * block), a screen-reader mode, and \"Open in Terminal.app\".\n * - Selecting text copies it (the ⌘C you would otherwise type next).\n * - Under Node (no PTY) the pane says the terminal needs the desktop app\n * and still offers Terminal.app.\n *\n * WIRING\n * - Output: ONE live stream, the visible tab's (terminal-stream.ts). A\n * background tab catches up from its last seq when shown again; the\n * list poll (every 3 s, only while visible) marks unseen output with a dot.\n * - Input: keystrokes go through a single-flight queue (input-queue.ts) so\n * they reach the shell in the order they were typed.\n * - Keys: xterm owns the keyboard while focused, EXCEPT the app's own\n * chords (⌘K, ⌘J, ⌘1–5, ⌃`, ⌃Tab …, from command-catalog.ts), which it\n * passes to the page. ⌃C, ⌃R, Esc and ⌥-word motions stay in the shell.\n * - Requests from the dock (`request`, one per nonce): focus or open a tab\n * at a root, force a new one (⌃⇧`), paste a command WITHOUT running it\n * (\"Run in terminal\"), launch an app or start a dev server (the server\n * types that command — built from its own catalog, never from the page).\n */\nimport { useCallback, useEffect, useMemo, useRef, useState, type KeyboardEvent as ReactKeyboardEvent } from 'react';\nimport type { VerseTerminalFrame, VerseTerminalListResponse, VerseTerminalTab } from '../../../../data/api-types.js';\nimport { ApiError } from '../../../../data/client.js';\nimport { Button, IconButton } from '../../../../components/primitives/Button.js';\nimport { EmptyState } from '../../../../components/primitives/EmptyState.js';\nimport { SkeletonLine } from '../../../../components/primitives/Skeleton.js';\nimport { IconExternalLink, IconPlus, IconSend, IconX } from '../../../../components/primitives/icons.js';\nimport { asSentence } from '../../autonomy/format.js';\nimport { ActionMenu, anchorBelow, type MenuAnchor } from '../../chat/ActionMenu.js';\nimport { detectKeyPlatform, eventKeyName, findCommand, formatChord, matchCommand, type KeyPlatform } from '../../shell/command-catalog.js';\nimport { usePollWhileVisible, useSectionVisible } from '../../shell/section-visibility.js';\nimport type { VerseTerminalLaunchVia } from '../../../../../core/verse/workbench-types.js';\nimport type { TerminalPaneProps } from '../../shell/slots.js';\nimport type { TerminalRequest } from '../dock-store.js';\nimport { useViewport } from '../../shell/viewport.js';\nimport { projectName } from '../../verse-model.js';\nimport { createInputQueue, type InputQueue } from './input-queue.js';\nimport { base64ToBytes, fenceSelection, terminalApi, TerminalLockedError, type TerminalApi } from './terminal-client.js';\nimport { openTerminalStream, type TerminalStreamState } from './terminal-stream.js';\nimport {\n createXtermView,\n resolveTerminalFont,\n resolveTerminalTheme,\n watchThemeChanges,\n type TerminalView,\n type TerminalViewFactory,\n} from './terminal-view.js';\nimport { ChevronDownGlyph, ScreenReaderGlyph, TerminalGlyph } from './terminal-icons.js';\nimport chrome from '../pane-chrome.module.css';\nimport styles from './TerminalPane.module.css';\n\n// ---------------------------------------------------------------------------\n// Seams\n// ---------------------------------------------------------------------------\n\nexport interface TerminalPaneDeps {\n api: TerminalApi;\n createView: TerminalViewFactory;\n openStream: typeof openTerminalStream;\n platform: KeyPlatform;\n writeClipboard: (text: string) => Promise<void>;\n}\n\nconst DEFAULT_DEPS: TerminalPaneDeps = {\n api: terminalApi,\n createView: createXtermView,\n openStream: openTerminalStream,\n platform: detectKeyPlatform(),\n writeClipboard: async (text) => {\n await navigator.clipboard.writeText(text);\n },\n};\n\n/** How often the tab list is refreshed while the pane is on screen. */\nexport const TERMINAL_LIST_POLL_MS = 3_000;\nconst SCREEN_READER_PREF_KEY = 'ashlr.verse.terminal.screenReader';\n/** Requests already handled, across remounts (the dock keeps its last request around). */\nlet lastHandledNonce = 0;\n\n/** Test hygiene. */\nexport function resetTerminalPaneForTest(): void {\n lastHandledNonce = 0;\n}\n\nfunction readScreenReaderPref(): boolean {\n try {\n return localStorage.getItem(SCREEN_READER_PREF_KEY) === '1';\n } catch {\n return false;\n }\n}\n\nfunction writeScreenReaderPref(on: boolean): void {\n try {\n localStorage.setItem(SCREEN_READER_PREF_KEY, on ? '1' : '0');\n } catch {\n /* storage unavailable: the choice lasts for this page only */\n }\n}\n\n/**\n * Keys the PAGE handles even while the terminal has focus: a catalog command\n * whose chord uses ⌘ (macOS), or ⌃` / ⌃Tab. Everything else — ⌃C, ⌃R, Esc,\n * ⌥← — belongs to the shell. Off macOS `mod` is Ctrl, so only Ctrl+Shift\n * chords and ⌃` / ⌃Tab pass (Ctrl+K must still kill a line).\n */\nexport function keyPassesToPage(event: KeyboardEvent, platform: KeyPlatform): boolean {\n if (event.type !== 'keydown') return false;\n if (!matchCommand(event, ['chat', 'global'], platform)) return false;\n const key = eventKeyName(event);\n const shellChord = event.ctrlKey && (key === '`' || key === 'tab');\n if (platform === 'mac') return event.metaKey || shellChord;\n return shellChord || (event.ctrlKey && event.shiftKey);\n}\n\nfunction errorText(err: unknown, fallback: string): string {\n if (err instanceof TerminalLockedError) return err.message;\n if (err instanceof ApiError) {\n if (err.status === 401) return 'Unlock actions with the mutation token to use the terminal.';\n if (err.detail) return asSentence(err.detail);\n }\n return fallback;\n}\n\ninterface ViewRecord {\n view: TerminalView;\n host: HTMLDivElement;\n lastSeq: number;\n queue: InputQueue;\n disposers: Array<{ dispose(): void }>;\n}\n\ntype Notice = { tone: 'error' | 'info'; text: string };\n\n// ---------------------------------------------------------------------------\n// Component\n// ---------------------------------------------------------------------------\n\nexport function TerminalPane({ sessionId, roots, request, onSendToChat, visible, deps: depsOverride }: TerminalPaneProps & { deps?: Partial<TerminalPaneDeps> }) {\n const deps = useMemo<TerminalPaneDeps>(() => ({ ...DEFAULT_DEPS, ...depsOverride }), [depsOverride]);\n const sectionVisible = useSectionVisible();\n const shown = visible && sectionVisible;\n const compact = useViewport().compact;\n\n const [list, setList] = useState<VerseTerminalListResponse | null>(null);\n const [loadError, setLoadError] = useState<string | null>(null);\n const [activeId, setActiveId] = useState<string | null>(null);\n const [notice, setNotice] = useState<Notice | null>(null);\n const [creating, setCreating] = useState(false);\n const [streamState, setStreamState] = useState<TerminalStreamState | null>(null);\n const [hasSelection, setHasSelection] = useState(false);\n const [copied, setCopied] = useState(false);\n const [screenReader, setScreenReader] = useState(readScreenReaderPref);\n const [viewFailed, setViewFailed] = useState(false);\n const [readyIds, setReadyIds] = useState<ReadonlySet<string>>(() => new Set());\n const [rootMenu, setRootMenu] = useState<{ anchor: MenuAnchor; from: HTMLElement } | null>(null);\n const [seen, setSeen] = useState<ReadonlyMap<string, string>>(() => new Map());\n\n const views = useRef(new Map<string, ViewRecord>());\n const hosts = useRef(new Map<string, HTMLDivElement>());\n const creatingViews = useRef(new Set<string>());\n const autoCreated = useRef(false);\n const pendingPaste = useRef<{ tabId: string; text: string } | null>(null);\n const bodyRef = useRef<HTMLDivElement>(null);\n const tabRefs = useRef(new Map<string, HTMLButtonElement>());\n const resizeTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const copyTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const selectionTimer = useRef<ReturnType<typeof setTimeout> | null>(null);\n const mounted = useRef(true);\n /**\n * True while a shell the operator CLICKED for is opening (New terminal, the\n * folder menu). Any other open — the automatic first one, a dock request —\n * shows the pane opening instead of \"No terminal open\"; a click keeps the\n * empty state (and the focused, busy button) where it is.\n */\n const manualOpen = useRef(false);\n\n const allTabs = useMemo(() => list?.tabs ?? [], [list]);\n const exitedIds = useRef(new Set<string>());\n exitedIds.current = new Set(allTabs.filter((t) => t.exited).map((t) => t.id));\n const tabs = useMemo(() => allTabs.filter((t) => t.sessionId === sessionId), [allTabs, sessionId]);\n const active = tabs.find((t) => t.id === activeId) ?? null;\n const otherChats = allTabs.length - tabs.length;\n\n // -------------------------------------------------------------------------\n // The tab list\n // -------------------------------------------------------------------------\n\n const refresh = useCallback(async () => {\n try {\n const next = await deps.api.list();\n if (!mounted.current) return;\n setList(next);\n setLoadError(null);\n } catch (err) {\n if (!mounted.current) return;\n setLoadError(errorText(err, 'The terminal list could not be loaded.'));\n }\n }, [deps.api]);\n\n useEffect(() => {\n mounted.current = true;\n void refresh();\n return () => { mounted.current = false; };\n }, [refresh]);\n\n usePollWhileVisible(() => { void refresh(); }, TERMINAL_LIST_POLL_MS, { enabled: visible });\n\n // Keep the active tab valid: the first of this chat's tabs when it vanished.\n useEffect(() => {\n if (!list) return;\n if (activeId && tabs.some((t) => t.id === activeId)) return;\n setActiveId(tabs.at(-1)?.id ?? null);\n }, [list, tabs, activeId]);\n\n // Forget views of tabs that no longer exist (killed elsewhere, idle-closed).\n useEffect(() => {\n if (!list) return;\n const live = new Set(list.tabs.map((t) => t.id));\n for (const [id, rec] of views.current) {\n if (live.has(id)) continue;\n disposeRecord(rec);\n views.current.delete(id);\n setReadyIds((prev) => { const next = new Set(prev); next.delete(id); return next; });\n }\n }, [list]);\n\n // The active tab's output is seen as it arrives.\n useEffect(() => {\n if (!active || !shown) return;\n setSeen((prev) => (prev.get(active.id) === active.lastActivityAt ? prev : new Map(prev).set(active.id, active.lastActivityAt)));\n }, [active, shown]);\n\n // Dispose everything on unmount (the SERVER keeps the shells).\n useEffect(() => () => {\n for (const rec of views.current.values()) disposeRecord(rec);\n views.current.clear();\n for (const t of [resizeTimer, copyTimer, selectionTimer]) if (t.current) clearTimeout(t.current);\n }, []);\n\n function disposeRecord(rec: ViewRecord): void {\n rec.queue.dispose();\n for (const d of rec.disposers) {\n try { d.dispose(); } catch { /* already gone */ }\n }\n try { rec.view.dispose(); } catch { /* already gone */ }\n }\n\n // -------------------------------------------------------------------------\n // Creating, closing, restarting tabs\n // -------------------------------------------------------------------------\n\n const sizeHint = useCallback((): { cols: number; rows: number } => {\n for (const rec of views.current.values()) {\n if (rec.view.cols > 1 && rec.view.rows > 1) return { cols: rec.view.cols, rows: rec.view.rows };\n }\n return { cols: 80, rows: 24 };\n }, []);\n\n const createTab = useCallback(async (opts: { root?: string; appId?: string; via?: VerseTerminalLaunchVia; model?: string; devServerId?: string } = {}): Promise<VerseTerminalTab | null> => {\n setCreating(true);\n setNotice(null);\n try {\n const tab = await deps.api.create({\n sessionId,\n ...(opts.root ? { root: opts.root } : {}),\n ...(opts.appId ? { appId: opts.appId } : {}),\n // How the app launches (Ollama, a local model): only with an app — the server refuses them alone.\n ...(opts.appId && opts.via ? { via: opts.via } : {}),\n ...(opts.appId && opts.model ? { model: opts.model } : {}),\n ...(opts.devServerId ? { devServerId: opts.devServerId } : {}),\n ...sizeHint(),\n });\n if (!mounted.current) return tab;\n setList((prev) => (prev ? { ...prev, tabs: [...prev.tabs.filter((t) => t.id !== tab.id), tab] } : prev));\n setActiveId(tab.id);\n return tab;\n } catch (err) {\n if (mounted.current) setNotice({ tone: 'error', text: errorText(err, 'The terminal could not be opened.') });\n return null;\n } finally {\n if (mounted.current) setCreating(false);\n }\n }, [deps.api, sessionId, sizeHint]);\n\n const closeTab = useCallback(async (tab: VerseTerminalTab) => {\n try {\n await deps.api.kill(tab.id);\n } catch (err) {\n // Already gone on the server is as good as closed.\n if (!(err instanceof ApiError && err.status === 404)) {\n setNotice({ tone: 'error', text: errorText(err, 'The terminal could not be closed.') });\n return;\n }\n }\n const rec = views.current.get(tab.id);\n if (rec) {\n disposeRecord(rec);\n views.current.delete(tab.id);\n }\n setList((prev) => (prev ? { ...prev, tabs: prev.tabs.filter((t) => t.id !== tab.id) } : prev));\n if (activeId === tab.id) {\n const index = tabs.findIndex((t) => t.id === tab.id);\n const neighbour = tabs[index + 1] ?? tabs[index - 1] ?? null;\n setActiveId(neighbour?.id ?? null);\n }\n }, [activeId, deps.api, tabs]);\n\n const restartTab = useCallback(async (tab: VerseTerminalTab) => {\n const next = await createTab({ root: tab.root });\n if (next) await closeTab(tab);\n }, [closeTab, createTab]);\n\n // Another chat (the dock keeps this pane mounted across chats): its own\n // first look may open a shell again.\n const autoCreatedFor = useRef(sessionId);\n if (autoCreatedFor.current !== sessionId) {\n autoCreatedFor.current = sessionId;\n autoCreated.current = false;\n }\n\n // First look at an empty pane: open a shell in the chat's primary root.\n useEffect(() => {\n if (!list || !list.available || !shown || autoCreated.current || creating) return;\n if (request && request.nonce > lastHandledNonce) return; // the request decides\n autoCreated.current = true;\n if (tabs.length === 0) void createTab({});\n }, [list, shown, tabs.length, creating, createTab, request]);\n\n // -------------------------------------------------------------------------\n // Views (xterm) — one per tab, created when its panel mounts\n // -------------------------------------------------------------------------\n\n const attachView = useCallback(async (tabId: string, host: HTMLDivElement) => {\n if (views.current.has(tabId) || creatingViews.current.has(tabId)) return;\n creatingViews.current.add(tabId);\n try {\n const view = await deps.createView({ ...resolveTerminalFont(host), theme: resolveTerminalTheme(host), screenReaderMode: readScreenReaderPref() });\n if (!mounted.current || !hosts.current.has(tabId)) {\n view.dispose();\n return;\n }\n view.open(host);\n const queue = createInputQueue((b64) => deps.api.input(tabId, b64), {\n onError: (err) => {\n if (mounted.current) setNotice({ tone: 'error', text: errorText(err, 'That input did not reach the shell.') });\n },\n });\n const rec: ViewRecord = { view, host, lastSeq: 0, queue, disposers: [] };\n // Keystrokes into a shell that has exited go nowhere (the exit bar offers Restart).\n rec.disposers.push(view.onData((data) => { if (!exitedIds.current.has(tabId)) queue.pushText(data); }));\n rec.disposers.push(view.onBinary((data) => { if (!exitedIds.current.has(tabId)) queue.pushBinary(data); }));\n rec.disposers.push(view.onSelectionChange(() => {\n const selected = view.hasSelection();\n setHasSelection(selected);\n if (!selected) return;\n // Copy on select, once the drag settles.\n if (selectionTimer.current) clearTimeout(selectionTimer.current);\n selectionTimer.current = setTimeout(() => {\n const text = view.getSelection();\n if (!text) return;\n deps.writeClipboard(text).then(() => {\n if (!mounted.current) return;\n setCopied(true);\n if (copyTimer.current) clearTimeout(copyTimer.current);\n copyTimer.current = setTimeout(() => setCopied(false), 1_200);\n }, () => { /* clipboard refused (no user gesture): the selection still works with ⌘C */ });\n }, 150);\n }));\n view.setKeyFilter((event) => !keyPassesToPage(event, deps.platform));\n views.current.set(tabId, rec);\n setViewFailed(false);\n setReadyIds((prev) => new Set(prev).add(tabId));\n } catch (err) {\n console.error('[verse] terminal view failed to load', err);\n if (mounted.current) setViewFailed(true);\n } finally {\n creatingViews.current.delete(tabId);\n }\n }, [deps]);\n\n // One stable ref callback per tab: a fresh closure each render would make\n // React detach and re-attach the host on every render.\n const attachRef = useRef(attachView);\n attachRef.current = attachView;\n const hostRefs = useRef(new Map<string, (node: HTMLDivElement | null) => void>());\n const hostRef = (tabId: string) => {\n let ref = hostRefs.current.get(tabId);\n if (!ref) {\n ref = (node) => {\n if (node) {\n hosts.current.set(tabId, node);\n void attachRef.current(tabId, node);\n } else {\n hosts.current.delete(tabId);\n hostRefs.current.delete(tabId);\n }\n };\n hostRefs.current.set(tabId, ref);\n }\n return ref;\n };\n\n // Fit the visible view to its panel and tell the shell its size.\n const fitActive = useCallback(() => {\n if (!activeId) return;\n const rec = views.current.get(activeId);\n if (!rec) return;\n const before = { cols: rec.view.cols, rows: rec.view.rows };\n const size = rec.view.fit();\n if (!size || (size.cols === before.cols && size.rows === before.rows && active && active.cols === size.cols && active.rows === size.rows)) return;\n if (resizeTimer.current) clearTimeout(resizeTimer.current);\n const id = activeId;\n resizeTimer.current = setTimeout(() => {\n deps.api.resize(id, size.cols, size.rows).catch(() => { /* the next fit retries */ });\n }, 100);\n }, [active, activeId, deps.api]);\n\n useEffect(() => {\n if (!shown || !activeId || !readyIds.has(activeId)) return;\n fitActive();\n const body = bodyRef.current;\n if (!body || typeof ResizeObserver === 'undefined') return;\n let frame = 0;\n const observer = new ResizeObserver(() => {\n cancelAnimationFrame(frame);\n frame = requestAnimationFrame(fitActive);\n });\n observer.observe(body);\n return () => {\n cancelAnimationFrame(frame);\n observer.disconnect();\n };\n }, [shown, activeId, readyIds, fitActive]);\n\n // Theme follows the app (explicit toggle or OS appearance).\n useEffect(() => watchThemeChanges(() => {\n for (const rec of views.current.values()) rec.view.setTheme(resolveTerminalTheme(rec.host));\n }), []);\n\n // -------------------------------------------------------------------------\n // The live stream (visible tab only)\n // -------------------------------------------------------------------------\n\n const applyPaste = useCallback((tabId: string) => {\n const pending = pendingPaste.current;\n if (!pending || pending.tabId !== tabId) return;\n const rec = views.current.get(tabId);\n if (!rec) return;\n pendingPaste.current = null;\n const text = pending.text.replace(/[\\r\\n]+$/, '');\n if (text.includes('\\n') && !rec.view.bracketedPaste()) {\n // Without bracketed paste a shell would RUN each line as it arrives.\n deps.writeClipboard(text).then(\n () => setNotice({ tone: 'info', text: 'That command has several lines, so it was copied instead: paste it with ⌘V.' }),\n () => setNotice({ tone: 'error', text: 'That command has several lines and could not be pasted safely.' }),\n );\n } else {\n rec.view.paste(text);\n }\n rec.view.focus();\n }, [deps]);\n\n useEffect(() => {\n if (!shown || !activeId || !readyIds.has(activeId)) {\n setStreamState(null);\n return;\n }\n const rec = views.current.get(activeId);\n if (!rec) return;\n const tabId = activeId;\n let firstOutput = true;\n const onFrame = (frame: VerseTerminalFrame) => {\n if (frame.type === 'output') {\n if (frame.seq <= rec.lastSeq) return;\n // A gap means the scrollback ring dropped frames this view never got:\n // start over from what the server still has rather than draw a torn screen.\n if (rec.lastSeq > 0 && frame.seq > rec.lastSeq + 1) rec.view.reset();\n rec.view.write(base64ToBytes(frame.dataBase64));\n rec.lastSeq = frame.seq;\n if (firstOutput) {\n firstOutput = false;\n if (pendingPaste.current?.tabId === tabId) setTimeout(() => applyPaste(tabId), 120);\n }\n return;\n }\n setList((prev) => {\n if (!prev) return prev;\n return {\n ...prev,\n tabs: prev.tabs.map((t) => {\n if (t.id !== tabId) return t;\n if (frame.type === 'title') return t.title === frame.title ? t : { ...t, title: frame.title };\n return { ...t, exited: { code: frame.code, signal: frame.signal, at: new Date().toISOString() } };\n }),\n };\n });\n };\n const stream = deps.openStream(tabId, () => rec.lastSeq, {\n onFrame,\n onState: (state) => {\n if (!mounted.current) return;\n setStreamState(state);\n if (state === 'gone') void refresh();\n },\n });\n // An existing tab that already has output can take a paste right away.\n if (pendingPaste.current?.tabId === tabId && rec.lastSeq > 0) setTimeout(() => applyPaste(tabId), 0);\n return () => stream.close();\n }, [shown, activeId, readyIds, deps, refresh, applyPaste]);\n\n // -------------------------------------------------------------------------\n // Requests from the dock\n // -------------------------------------------------------------------------\n\n const handleRequest = useCallback(async (req: TerminalRequest) => {\n const root = req.root ?? active?.root ?? roots[0];\n const wantsNew = req.newTab === true || Boolean(req.appId) || Boolean(req.devServerId);\n let target: VerseTerminalTab | null = null;\n if (!wantsNew) {\n target = (active && !active.exited && (!req.root || active.root === req.root) ? active : null)\n ?? tabs.find((t) => !t.exited && (!req.root || t.root === req.root)) ?? null;\n }\n if (target) {\n setActiveId(target.id);\n } else {\n target = await createTab({\n ...(root ? { root } : {}),\n ...(req.appId ? { appId: req.appId } : {}),\n ...(req.via ? { via: req.via } : {}),\n ...(req.model ? { model: req.model } : {}),\n ...(req.devServerId ? { devServerId: req.devServerId } : {}),\n });\n }\n if (!target) return;\n if (req.paste) {\n pendingPaste.current = { tabId: target.id, text: req.paste };\n const rec = views.current.get(target.id);\n if (rec && rec.lastSeq > 0) applyPaste(target.id);\n } else {\n views.current.get(target.id)?.view.focus();\n }\n }, [active, applyPaste, createTab, roots, tabs]);\n\n useEffect(() => {\n if (!request || !list || request.nonce <= lastHandledNonce) return;\n lastHandledNonce = request.nonce;\n autoCreated.current = true;\n if (!list.available) return;\n void handleRequest(request);\n }, [request, list, handleRequest]);\n\n // Focus the terminal when its tab becomes the visible one.\n useEffect(() => {\n if (!shown || !activeId || !readyIds.has(activeId)) return;\n views.current.get(activeId)?.view.focus();\n }, [shown, activeId, readyIds]);\n\n // -------------------------------------------------------------------------\n // Header actions\n // -------------------------------------------------------------------------\n\n const sendSelection = () => {\n if (!activeId) return;\n const text = views.current.get(activeId)?.view.getSelection() ?? '';\n if (!text.trim()) return;\n onSendToChat(fenceSelection(text));\n };\n\n const toggleScreenReader = () => {\n const next = !screenReader;\n setScreenReader(next);\n writeScreenReaderPref(next);\n for (const rec of views.current.values()) rec.view.setScreenReaderMode(next);\n };\n\n const openExternal = async () => {\n try {\n await deps.api.openExternal(sessionId, active?.root ?? roots[0]);\n setNotice({ tone: 'info', text: 'Opened in Terminal.' });\n } catch (err) {\n setNotice({ tone: 'error', text: errorText(err, 'Terminal could not be opened.') });\n }\n };\n\n const openByClick = (opts: { root?: string }) => {\n manualOpen.current = true;\n void createTab(opts).finally(() => { manualOpen.current = false; });\n };\n\n const onNewTabClick = () => {\n openByClick(active?.root ? { root: active.root } : {});\n };\n\n // Tabs: ←/→ move and activate, Home/End jump (WAI-ARIA tabs, automatic activation).\n const onTabKeyDown = (event: ReactKeyboardEvent<HTMLButtonElement>, index: number) => {\n let next = -1;\n if (event.key === 'ArrowRight') next = (index + 1) % tabs.length;\n else if (event.key === 'ArrowLeft') next = (index - 1 + tabs.length) % tabs.length;\n else if (event.key === 'Home') next = 0;\n else if (event.key === 'End') next = tabs.length - 1;\n if (next < 0) return;\n event.preventDefault();\n const tab = tabs[next]!;\n setActiveId(tab.id);\n tabRefs.current.get(tab.id)?.focus();\n };\n\n // -------------------------------------------------------------------------\n // Render\n // -------------------------------------------------------------------------\n\n if (!list) {\n if (loadError) {\n return (\n <div className={styles.pane}>\n <EmptyState compact tone=\"error\" title=\"Terminal is not reachable\" body={loadError}\n action={<Button size=\"sm\" variant=\"subtle\" onClick={() => void refresh()}>Try again</Button>} />\n </div>\n );\n }\n return (\n <div className={styles.pane} aria-busy=\"true\">\n {/* The strip's row is held from the first frame so the chrome does not drop in under the dock's tabs. */}\n <div className={styles.strip} aria-hidden=\"true\" />\n <div className={styles.loading}>\n <SkeletonLine width=\"40%\" />\n <SkeletonLine width=\"70%\" />\n </div>\n </div>\n );\n }\n\n if (!list.available) {\n return (\n <div className={styles.pane}>\n <EmptyState\n compact\n icon={<TerminalGlyph size={20} />}\n title=\"Terminal needs the desktop app\"\n body=\"This Verse server has no built-in terminal. Open the project in Terminal instead, or use the Ashlr desktop app.\"\n action={deps.platform === 'mac' ? (\n <Button size=\"sm\" variant=\"subtle\" icon={<IconExternalLink />} onClick={() => void openExternal()}>Open in Terminal</Button>\n ) : undefined}\n />\n {notice ? <p className={styles.inlineNotice} role={notice.tone === 'error' ? 'alert' : 'status'}>{notice.text}</p> : null}\n </div>\n );\n }\n\n const canChooseRoot = roots.length > 1;\n const newTabChord = findCommand('dock.terminal-new')?.keys[0];\n const newTabKey = newTabChord ? formatChord(newTabChord, deps.platform) : null;\n // Before a chat's first shell is open — the automatic one on first sight,\n // or one a dock request asked for — the pane shows it opening instead of\n // flashing \"No terminal open\" for the moment the request takes.\n const opening = tabs.length === 0 && !viewFailed && (!autoCreated.current || (creating && !manualOpen.current));\n // The folder the header names: the visible tab's (or, for the render before\n // the active tab is chosen, the one that will be), or while the first shell\n // opens the chat's primary folder, where it opens — so the row does not\n // appear, or change, when the tab lands.\n const headerRoot = active?.root ?? tabs.at(-1)?.root ?? (opening ? roots[0] ?? null : null);\n\n return (\n <div className={styles.pane} data-compact={compact || undefined}>\n <div className={styles.strip}>\n <div className={styles.tabs} role=\"tablist\" aria-label=\"Terminals\">\n {tabs.map((tab, index) => {\n const selected = tab.id === activeId;\n const unseen = !selected && (seen.get(tab.id) ?? tab.createdAt) < tab.lastActivityAt;\n return (\n <div key={tab.id} className={styles.tab} data-selected={selected || undefined} role=\"presentation\">\n <button\n ref={(node) => { if (node) tabRefs.current.set(tab.id, node); else tabRefs.current.delete(tab.id); }}\n type=\"button\"\n role=\"tab\"\n id={`terminal-tab-${tab.id}`}\n aria-selected={selected}\n aria-controls={`terminal-panel-${tab.id}`}\n tabIndex={selected ? 0 : -1}\n className={styles.tabButton}\n title={`${tab.title} — ${tab.root}`}\n onClick={() => setActiveId(tab.id)}\n onKeyDown={(event) => onTabKeyDown(event, index)}\n >\n <span className={styles.tabTitle}>{tab.title}</span>\n {tab.exited ? <span className={styles.tabExited}>exited</span> : null}\n {unseen && !tab.exited ? <span className={styles.unseen} aria-label=\"new output\" role=\"img\" /> : null}\n </button>\n <button type=\"button\" className={styles.tabClose} aria-label={`Close terminal ${tab.title}`}\n title=\"Close terminal\" onClick={() => void closeTab(tab)}>\n <IconX size={12} />\n </button>\n </div>\n );\n })}\n </div>\n <div className={styles.stripActions}>\n <IconButton variant=\"ghost\" size=\"sm\" icon={<IconPlus />} aria-label=\"New terminal tab\"\n title={newTabKey ? `New terminal tab (${newTabKey})` : 'New terminal tab'}\n busy={creating} onClick={onNewTabClick} />\n {canChooseRoot ? (\n <IconButton variant=\"ghost\" size=\"sm\" icon={<ChevronDownGlyph />} aria-label=\"New terminal in…\" aria-haspopup=\"menu\"\n aria-expanded={rootMenu !== null} title=\"Choose the folder\"\n onClick={(event) => setRootMenu({ anchor: anchorBelow(event.currentTarget), from: event.currentTarget })} />\n ) : null}\n </div>\n </div>\n\n {headerRoot !== null ? (\n <div className={`${chrome.header} ${styles.header}`}>\n {/* The folder's NAME; the full path (a home or temp path) is the tooltip. */}\n <span className={`${chrome.title} ${styles.cwd}`} title={headerRoot}>{projectName(headerRoot)}</span>\n <span className={styles.headerStatus} role=\"status\" aria-live=\"polite\">\n {streamState === 'reconnecting' ? 'Reconnecting…' : streamState === 'expired' ? 'Session expired — reload to reconnect' : copied ? 'Copied' : ''}\n </span>\n <div className={chrome.actions}>\n <Button variant=\"ghost\" size=\"sm\" icon={<IconSend />} disabled={!hasSelection} aria-label=\"Send selection to chat\"\n title={hasSelection ? 'Send the selected text to the chat as a code block' : 'Select text in the terminal first'}\n onClick={sendSelection}>\n {compact ? null : 'Send to chat'}\n </Button>\n <IconButton variant=\"ghost\" size=\"sm\" icon={<ScreenReaderGlyph />} aria-label=\"Screen reader mode\" aria-pressed={screenReader}\n title={screenReader ? 'Screen reader mode is on' : 'Screen reader mode'} onClick={toggleScreenReader} />\n {deps.platform === 'mac' ? (\n <IconButton variant=\"ghost\" size=\"sm\" icon={<IconExternalLink />} aria-label=\"Open in Terminal.app\"\n title=\"Open this folder in Terminal.app\" onClick={() => void openExternal()} />\n ) : null}\n </div>\n </div>\n ) : null}\n\n {notice ? (\n <div className={styles.notice} data-tone={notice.tone} role={notice.tone === 'error' ? 'alert' : 'status'}>\n <span>{notice.text}</span>\n <button type=\"button\" className={styles.noticeClose} aria-label=\"Dismiss\" title=\"Dismiss\" onClick={() => setNotice(null)}>\n <IconX size={12} />\n </button>\n </div>\n ) : null}\n\n <div className={styles.body} ref={bodyRef}>\n {viewFailed ? (\n <EmptyState compact tone=\"error\" title=\"The terminal could not load\" body=\"The rest of the chat still works.\"\n action={<Button size=\"sm\" variant=\"subtle\" onClick={() => {\n setViewFailed(false);\n for (const [id, host] of hosts.current) void attachView(id, host);\n }}>Try again</Button>} />\n ) : null}\n {opening ? (\n <div className={styles.loading} role=\"status\" aria-label=\"Opening a shell\">\n <SkeletonLine width=\"30%\" />\n </div>\n ) : null}\n {tabs.length === 0 && !viewFailed && !opening ? (\n <EmptyState compact icon={<TerminalGlyph size={20} />} title=\"No terminal open\"\n body={`Click New terminal${newTabKey ? ` or press ${newTabKey}` : ''} to open a login shell in this chat's folder.${otherChats > 0 ? ` ${otherChats} ${otherChats === 1 ? 'terminal is' : 'terminals are'} open in other chats.` : ''}`}\n action={<Button size=\"sm\" variant=\"subtle\" icon={<IconPlus />} busy={creating} onClick={onNewTabClick}>New terminal</Button>} />\n ) : null}\n {tabs.map((tab) => {\n const selected = tab.id === activeId;\n return (\n <div\n key={tab.id}\n id={`terminal-panel-${tab.id}`}\n role=\"tabpanel\"\n aria-labelledby={`terminal-tab-${tab.id}`}\n className={styles.panel}\n hidden={!selected}\n >\n <div className={styles.viewport}>\n <div className={styles.host} ref={hostRef(tab.id)} data-testid={`terminal-host-${tab.id}`} />\n {!readyIds.has(tab.id) && !viewFailed ? (\n <div className={styles.viewLoading} aria-hidden=\"true\"><SkeletonLine width=\"30%\" /></div>\n ) : null}\n </div>\n {tab.exited ? (\n <div className={styles.exitBar} role=\"status\">\n <span>\n {tab.exited.signal && tab.exited.code === null\n ? `Shell ended (${tab.exited.signal}).`\n : `Shell exited${tab.exited.code === null ? '' : ` with code ${tab.exited.code}`}.`}\n </span>\n <Button size=\"sm\" variant=\"subtle\" onClick={() => void restartTab(tab)}>Restart</Button>\n <Button size=\"sm\" variant=\"ghost\" onClick={() => void closeTab(tab)}>Close</Button>\n </div>\n ) : null}\n </div>\n );\n })}\n </div>\n\n {rootMenu ? (\n <ActionMenu\n label=\"New terminal in\"\n anchor={rootMenu.anchor}\n returnFocus={rootMenu.from}\n onClose={() => setRootMenu(null)}\n items={roots.map((root) => ({\n id: root,\n label: projectName(root),\n description: root,\n onSelect: () => { openByClick({ root }); },\n }))}\n />\n ) : null}\n </div>\n );\n}\n"],"file":"TerminalPane-BSnGdUuF.js"}