specrails-desktop 2.20.1 → 2.22.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 (540) hide show
  1. package/README.md +3 -2
  2. package/client/dist/assets/{ActivityFeedPage-3WSqRYVx.js → ActivityFeedPage-roDyKGuv.js} +1 -1
  3. package/client/dist/assets/AgentBrowserCapture-BsXnWa4j.js +1 -0
  4. package/client/dist/assets/{AgentModeCodePane-Cnsea6eZ.js → AgentModeCodePane-o97EJvbJ.js} +2 -2
  5. package/client/dist/assets/AgentModeJobsPane-CLtpPxPM.js +1 -0
  6. package/client/dist/assets/AgentsPage-eNSo_ZcC.js +86 -0
  7. package/client/dist/assets/AnalyticsPage-cAJ60_Ex.js +1 -0
  8. package/client/dist/assets/{BarChart-C6If656N.js → BarChart-NLtK7xAY.js} +1 -1
  9. package/client/dist/assets/CodePage-B5rum8ZB.js +2 -0
  10. package/client/dist/assets/DesktopAnalyticsPage-DSuvG6Tq.js +1 -0
  11. package/client/dist/assets/DocsDialog-Bo38G3Yc.js +11 -0
  12. package/client/dist/assets/DocsPage-BNkiBBrC.js +11 -0
  13. package/client/dist/assets/{ExportDropdown-CezTK0EX.js → ExportDropdown-DCV8PN4-.js} +1 -1
  14. package/client/dist/assets/IntegrationsPage-BMJOzpPz.js +3 -0
  15. package/client/dist/assets/InteractiveJobComposer-aLduNs5R.js +19 -0
  16. package/client/dist/assets/JobDetailModal-kpkUWJIS.js +1 -0
  17. package/client/dist/assets/JobDetailPage-CFeqlrPU.js +1 -0
  18. package/client/dist/assets/JobsPage-fuwhXy2I.js +1 -0
  19. package/client/dist/assets/LoopBuilderPage-DP66322C.js +7 -0
  20. package/client/dist/assets/LoopPreviewModal-CpmBhE31.js +1 -0
  21. package/client/dist/assets/LoopsPage-CvQ18VUx.js +1 -0
  22. package/client/dist/assets/ProjectSettingsDialog-Deq4pwvq.js +1 -0
  23. package/client/dist/assets/TemplatePreviewModal-DziOj2Ct.js +1 -0
  24. package/client/dist/assets/agent-Csh4kP2S.js +1 -0
  25. package/client/dist/assets/agent-Cz_jgQX32.js +1 -0
  26. package/client/dist/assets/agent-D3vcIvaz2.js +1 -0
  27. package/client/dist/assets/agent-Dnbt0V4e.js +1 -0
  28. package/client/dist/assets/agent-HolR7QrZ.js +1 -0
  29. package/client/dist/assets/agent-Ka0rRWJy.js +1 -0
  30. package/client/dist/assets/agent-Te3yysMd.js +1 -0
  31. package/client/dist/assets/agent-vM4_iLDk2.js +1 -0
  32. package/client/dist/assets/{upload-CRtTj4Co.js → brain-kFJuEDNH.js} +1 -1
  33. package/client/dist/assets/{browser-DEEO-OSi.js → browser-BPkhILSJ.js} +1 -1
  34. package/client/dist/assets/{browser-BTivfZKE2.js → browser-BijVYG0Y2.js} +1 -1
  35. package/client/dist/assets/{browser-bpO3onlS.js → browser-BqLqJVVT.js} +1 -1
  36. package/client/dist/assets/{browser-DlSXtfu5.js → browser-Cc0iDqUi.js} +1 -1
  37. package/client/dist/assets/browser-CdS6O1Qb.js +1 -0
  38. package/client/dist/assets/{browser-BKP6hqQC2.js → browser-Cvg-QHvd2.js} +1 -1
  39. package/client/dist/assets/{browser-INCUyduh.js → browser-FRv8P02E.js} +1 -1
  40. package/client/dist/assets/{browser-DlKLfT612.js → browser-rWKj-RR_2.js} +1 -1
  41. package/client/dist/assets/code-BRcDlze52.js +1 -0
  42. package/client/dist/assets/code-BdMy3Ffq.js +1 -0
  43. package/client/dist/assets/code-CeQ0FZpC.js +1 -0
  44. package/client/dist/assets/code-CqCcRThR.js +1 -0
  45. package/client/dist/assets/code-DgeHz9CB.js +1 -0
  46. package/client/dist/assets/code-DzC1rMk12.js +1 -0
  47. package/client/dist/assets/code-UPVvmAKM2.js +1 -0
  48. package/client/dist/assets/code-thSEptMx.js +1 -0
  49. package/client/dist/assets/{common-QjVnq9XP2.js → common-BM3LFLCE2.js} +1 -1
  50. package/client/dist/assets/{common-CeQUwuHt2.js → common-Bwafujnc2.js} +1 -1
  51. package/client/dist/assets/{common-Bb64s3Bm.js → common-C-vU-j-I.js} +1 -1
  52. package/client/dist/assets/{common-KbQuTSGg.js → common-C5HKSbbz.js} +1 -1
  53. package/client/dist/assets/{common-BPQQkgJZ.js → common-CYaT2yHp.js} +1 -1
  54. package/client/dist/assets/{common-DPxotRK9.js → common-DhWTkocg.js} +1 -1
  55. package/client/dist/assets/{common-k5MTOHpn.js → common-DiPTT7V_2.js} +1 -1
  56. package/client/dist/assets/{common-C8ZD5upH2.js → common-DmqBPwZG.js} +1 -1
  57. package/client/dist/assets/{cssMode-DsArsSCT.js → cssMode-DBHbkBvI.js} +1 -1
  58. package/client/dist/assets/dashboard-BaStj_a_.js +1 -0
  59. package/client/dist/assets/dashboard-Bi6ugu5Q.js +1 -0
  60. package/client/dist/assets/dashboard-BmqTn3L02.js +1 -0
  61. package/client/dist/assets/dashboard-CvT8lOCT.js +1 -0
  62. package/client/dist/assets/dashboard-D7Pmeavq2.js +1 -0
  63. package/client/dist/assets/dashboard-DAnWdAac2.js +1 -0
  64. package/client/dist/assets/dashboard-JnYy2WLg.js +1 -0
  65. package/client/dist/assets/dashboard-L47YsFS_.js +1 -0
  66. package/client/dist/assets/{dist-js-BQn4yxaw.js → dist-js-BZSiJDbG.js} +1 -1
  67. package/client/dist/assets/{dist-js-BAWSqVtr.js → dist-js-DKpmIJlQ.js} +1 -1
  68. package/client/dist/assets/{editor.main-G3Sl9C67.js → editor.main-C9J2ikJK.js} +2 -2
  69. package/client/dist/assets/{freemarker2-pBzQNgFi.js → freemarker2-J5iIIIK-.js} +1 -1
  70. package/client/dist/assets/{handlebars-CtBTCnBI.js → handlebars-DSw1l_tw.js} +1 -1
  71. package/client/dist/assets/{html-Dx3DYBzY.js → html-h2-wE1Lj.js} +1 -1
  72. package/client/dist/assets/{htmlMode-In7frFOo.js → htmlMode-Cc_ij7lW.js} +1 -1
  73. package/client/dist/assets/index-DM6heiGa.js +155 -0
  74. package/client/dist/assets/index-DPX6_xIC.css +2 -0
  75. package/client/dist/assets/{javascript-BKcn-YkN.js → javascript-C1q3xv6N.js} +1 -1
  76. package/client/dist/assets/jira-B3613-gj.js +1 -0
  77. package/client/dist/assets/jira-BHAKtc4B.js +1 -0
  78. package/client/dist/assets/jira-Be369RIR2.js +1 -0
  79. package/client/dist/assets/jira-CPpgA-5z2.js +1 -0
  80. package/client/dist/assets/jira-D5efgwp_.js +1 -0
  81. package/client/dist/assets/jira-DS7ownDy.js +1 -0
  82. package/client/dist/assets/jira-bDs7Im2C.js +1 -0
  83. package/client/dist/assets/jira-uNH1gETL2.js +1 -0
  84. package/client/dist/assets/jobs-1GV2-4zd2.js +1 -0
  85. package/client/dist/assets/jobs-26F9gGcE.js +1 -0
  86. package/client/dist/assets/jobs-BgQzB0Sx2.js +1 -0
  87. package/client/dist/assets/jobs-BqWui9_f.js +1 -0
  88. package/client/dist/assets/jobs-CE8qeIYj.js +1 -0
  89. package/client/dist/assets/jobs-D5sZzgLs.js +1 -0
  90. package/client/dist/assets/jobs-DzeuASRf.js +1 -0
  91. package/client/dist/assets/jobs-Wh7dn28q2.js +1 -0
  92. package/client/dist/assets/{jsonMode-jNREoQ3C.js → jsonMode-CeaCdEhr.js} +1 -1
  93. package/client/dist/assets/{lib-C-g8QbZl.js → lib-B2nCKzmA.js} +1 -1
  94. package/client/dist/assets/{liquid-CtRkGqBu.js → liquid-eFsVK0V-.js} +1 -1
  95. package/client/dist/assets/loops-BvEenWBy.js +1 -0
  96. package/client/dist/assets/loops-CBiWd9Hf.js +1 -0
  97. package/client/dist/assets/loops-DNGiYKll2.js +1 -0
  98. package/client/dist/assets/{loops-Y3FQsUCh.js → loops-DjOtVXRo.js} +1 -1
  99. package/client/dist/assets/loops-HTHf-xu32.js +1 -0
  100. package/client/dist/assets/loops-YYV2bwjd.js +1 -0
  101. package/client/dist/assets/loops-hXgncEpF2.js +1 -0
  102. package/client/dist/assets/loops-kYbydDyN.js +1 -0
  103. package/client/dist/assets/{lspLanguageFeatures-Cl3gvD_W.js → lspLanguageFeatures-DT3-bbhn.js} +1 -1
  104. package/client/dist/assets/{mdx-B_nJldHz.js → mdx-Fuwnh1cX.js} +1 -1
  105. package/client/dist/assets/{monaco.contribution-PUeaZk8T.js → monaco.contribution-Desq7oq4.js} +2 -2
  106. package/client/dist/assets/{python-DS1Ce-A6.js → python-BgoEs6Cj.js} +1 -1
  107. package/client/dist/assets/{razor-L41Qg9OK.js → razor-CM1sPMMq.js} +1 -1
  108. package/client/dist/assets/{settings-BPq9nCJm.js → settings-BOHOmHkb.js} +1 -1
  109. package/client/dist/assets/{settings-r8Qq2Gzp2.js → settings-BlEA_7h02.js} +1 -1
  110. package/client/dist/assets/{settings-C-m3yEZ2.js → settings-BsJMsWGc.js} +1 -1
  111. package/client/dist/assets/{settings-zZr7NzuB.js → settings-D6qY9_UI.js} +1 -1
  112. package/client/dist/assets/{settings-VgCsjaYf.js → settings-DZJeXoRV.js} +1 -1
  113. package/client/dist/assets/settings-Mr7MnJbf.js +1 -0
  114. package/client/dist/assets/{settings-BWHGtmU12.js → settings-TNga5gIF2.js} +1 -1
  115. package/client/dist/assets/{settings-DZj7Uqy32.js → settings-lFoaYT-s2.js} +1 -1
  116. package/client/dist/assets/setup-B590KsTX.js +1 -0
  117. package/client/dist/assets/setup-BkyGoby6.js +1 -0
  118. package/client/dist/assets/setup-CEj6uY3-2.js +1 -0
  119. package/client/dist/assets/setup-CbIerFGf2.js +1 -0
  120. package/client/dist/assets/setup-CmU6bTCV2.js +1 -0
  121. package/client/dist/assets/setup-D674kWQH.js +1 -0
  122. package/client/dist/assets/setup-VNqXyB6Y.js +1 -0
  123. package/client/dist/assets/setup-iY8vH8pB.js +1 -0
  124. package/client/dist/assets/specs-C9Sd7BhH2.js +1 -0
  125. package/client/dist/assets/specs-CBDvEYKv.js +1 -0
  126. package/client/dist/assets/specs-CIPr9reA2.js +1 -0
  127. package/client/dist/assets/specs-CWtKcVDC.js +1 -0
  128. package/client/dist/assets/specs-CmEZY57v.js +1 -0
  129. package/client/dist/assets/specs-D2clrt2c2.js +1 -0
  130. package/client/dist/assets/specs-DTplt2XM.js +1 -0
  131. package/client/dist/assets/specs-PozUNhqb.js +1 -0
  132. package/client/dist/assets/{tsMode-BC1g186U.js → tsMode-BmT8WogI.js} +1 -1
  133. package/client/dist/assets/{typescript-BGlRGvJW.js → typescript-CQrQPsoW.js} +1 -1
  134. package/client/dist/assets/upload-CLAzW1mS.js +1 -0
  135. package/client/dist/assets/{value-D9aLbxw-.js → value-DSwzyyWR.js} +1 -1
  136. package/client/dist/assets/{workers-CXcXtO3b.js → workers-U0UXyLUf.js} +1 -1
  137. package/client/dist/assets/{xml-JdZZaIhJ.js → xml-WRxJs8_I.js} +1 -1
  138. package/client/dist/assets/{yaml-Cm82BVBt.js → yaml-CjpSTjJU.js} +1 -1
  139. package/client/dist/index.html +14 -14
  140. package/docs/customizing.md +2 -2
  141. package/docs/gemini.md +15 -4
  142. package/docs/guide/de/insights/3-code-explorer.md +6 -0
  143. package/docs/guide/de/integrations/3-jira-integration.md +1 -1
  144. package/docs/guide/de/integrations/6-agent-chat.md +5 -0
  145. package/docs/guide/de/pipeline/1-rails-and-jobs.md +6 -6
  146. package/docs/guide/de/pipeline/2-the-job-detail-view.md +27 -2
  147. package/docs/guide/de/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  148. package/docs/guide/de/pipeline/5-the-loop-builder.md +1 -1
  149. package/docs/guide/de/specs/1-specs-and-the-backlog.md +3 -2
  150. package/docs/guide/en/insights/3-code-explorer.md +6 -0
  151. package/docs/guide/en/integrations/3-jira-integration.md +1 -1
  152. package/docs/guide/en/integrations/6-agent-chat.md +5 -0
  153. package/docs/guide/en/pipeline/1-rails-and-jobs.md +6 -6
  154. package/docs/guide/en/pipeline/2-the-job-detail-view.md +27 -2
  155. package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +10 -4
  156. package/docs/guide/en/pipeline/5-the-loop-builder.md +1 -1
  157. package/docs/guide/en/specs/1-specs-and-the-backlog.md +3 -2
  158. package/docs/guide/es/insights/3-code-explorer.md +6 -0
  159. package/docs/guide/es/integrations/3-jira-integration.md +1 -1
  160. package/docs/guide/es/integrations/6-agent-chat.md +5 -0
  161. package/docs/guide/es/pipeline/1-rails-and-jobs.md +6 -6
  162. package/docs/guide/es/pipeline/2-the-job-detail-view.md +27 -2
  163. package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  164. package/docs/guide/es/pipeline/5-the-loop-builder.md +1 -1
  165. package/docs/guide/es/specs/1-specs-and-the-backlog.md +3 -2
  166. package/docs/guide/fr/insights/3-code-explorer.md +6 -0
  167. package/docs/guide/fr/integrations/3-jira-integration.md +1 -1
  168. package/docs/guide/fr/integrations/6-agent-chat.md +5 -0
  169. package/docs/guide/fr/pipeline/1-rails-and-jobs.md +6 -6
  170. package/docs/guide/fr/pipeline/2-the-job-detail-view.md +27 -2
  171. package/docs/guide/fr/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  172. package/docs/guide/fr/pipeline/5-the-loop-builder.md +1 -1
  173. package/docs/guide/fr/specs/1-specs-and-the-backlog.md +3 -2
  174. package/docs/guide/it/insights/3-code-explorer.md +6 -0
  175. package/docs/guide/it/integrations/3-jira-integration.md +1 -1
  176. package/docs/guide/it/integrations/6-agent-chat.md +5 -0
  177. package/docs/guide/it/pipeline/1-rails-and-jobs.md +6 -6
  178. package/docs/guide/it/pipeline/2-the-job-detail-view.md +27 -2
  179. package/docs/guide/it/pipeline/3-batch-implement-and-multi-feature.md +10 -6
  180. package/docs/guide/it/pipeline/5-the-loop-builder.md +1 -1
  181. package/docs/guide/it/specs/1-specs-and-the-backlog.md +3 -2
  182. package/docs/guide/ja/insights/3-code-explorer.md +6 -0
  183. package/docs/guide/ja/integrations/3-jira-integration.md +1 -1
  184. package/docs/guide/ja/integrations/6-agent-chat.md +5 -0
  185. package/docs/guide/ja/pipeline/1-rails-and-jobs.md +6 -6
  186. package/docs/guide/ja/pipeline/2-the-job-detail-view.md +27 -2
  187. package/docs/guide/ja/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  188. package/docs/guide/ja/pipeline/5-the-loop-builder.md +1 -1
  189. package/docs/guide/ja/specs/1-specs-and-the-backlog.md +3 -2
  190. package/docs/guide/pt/insights/3-code-explorer.md +6 -0
  191. package/docs/guide/pt/integrations/3-jira-integration.md +1 -1
  192. package/docs/guide/pt/integrations/6-agent-chat.md +5 -0
  193. package/docs/guide/pt/pipeline/1-rails-and-jobs.md +6 -6
  194. package/docs/guide/pt/pipeline/2-the-job-detail-view.md +27 -2
  195. package/docs/guide/pt/pipeline/3-batch-implement-and-multi-feature.md +9 -5
  196. package/docs/guide/pt/pipeline/5-the-loop-builder.md +1 -1
  197. package/docs/guide/pt/specs/1-specs-and-the-backlog.md +3 -2
  198. package/docs/guide/zh/insights/3-code-explorer.md +6 -0
  199. package/docs/guide/zh/integrations/3-jira-integration.md +1 -1
  200. package/docs/guide/zh/integrations/6-agent-chat.md +5 -0
  201. package/docs/guide/zh/pipeline/1-rails-and-jobs.md +6 -6
  202. package/docs/guide/zh/pipeline/2-the-job-detail-view.md +27 -2
  203. package/docs/guide/zh/pipeline/3-batch-implement-and-multi-feature.md +10 -6
  204. package/docs/guide/zh/pipeline/5-the-loop-builder.md +1 -1
  205. package/docs/guide/zh/specs/1-specs-and-the-backlog.md +3 -2
  206. package/docs/internals/README.md +5 -0
  207. package/docs/internals/adding-a-provider.md +15 -3
  208. package/docs/internals/api-reference.md +6 -5
  209. package/docs/internals/browser-capture-performance.md +93 -0
  210. package/docs/internals/code-explorer-story.md +135 -0
  211. package/docs/internals/gemini-mcp-registration.md +53 -0
  212. package/docs/internals/interactive-jobs.md +212 -0
  213. package/docs/internals/loop-step-log-explorer.md +146 -0
  214. package/docs/internals/safe-pr-review-flow.md +367 -0
  215. package/docs/mcp.md +1 -1
  216. package/docs/running-pipelines.md +6 -2
  217. package/package.json +1 -1
  218. package/server/dist/agent-chat-manager.js +211 -0
  219. package/server/dist/agent-chat-registry.js +20 -0
  220. package/server/dist/agent-chat-router.js +22 -0
  221. package/server/dist/agent-mcp-config.js +45 -4
  222. package/server/dist/agent-operator-prompt.js +149 -56
  223. package/server/dist/agent-store.js +25 -0
  224. package/server/dist/agent-tier.js +6 -1
  225. package/server/dist/browser-capture-manager.js +184 -34
  226. package/server/dist/browser-playwright.js +98 -13
  227. package/server/dist/code-explorer-router.js +92 -0
  228. package/server/dist/db.js +102 -0
  229. package/server/dist/file-provenance.js +54 -1
  230. package/server/dist/file-story-manager.js +170 -0
  231. package/server/dist/file-story.js +148 -0
  232. package/server/dist/file-summary-generator.js +5 -4
  233. package/server/dist/git-guardrails.js +62 -0
  234. package/server/dist/index.js +5 -0
  235. package/server/dist/integration-branch.js +63 -0
  236. package/server/dist/interactive-job-session.js +226 -18
  237. package/server/dist/jira/jira-adf.js +9 -0
  238. package/server/dist/jira/jira-materializer.js +27 -4
  239. package/server/dist/jira/jira-status-resolver.js +12 -4
  240. package/server/dist/jira/jira-sync-manager.js +130 -2
  241. package/server/dist/jira-router.js +1 -1
  242. package/server/dist/loop-effect.js +12 -0
  243. package/server/dist/loop-executors.js +92 -22
  244. package/server/dist/loop-run-manager.js +354 -28
  245. package/server/dist/mcp/guide.js +18 -7
  246. package/server/dist/mcp/tools/jira.js +1 -1
  247. package/server/dist/mcp/tools/jobs.js +14 -5
  248. package/server/dist/mcp/tools/rails.js +137 -12
  249. package/server/dist/mcp/tools/specs.js +35 -9
  250. package/server/dist/mcp/tools/types.js +49 -0
  251. package/server/dist/mobile/mobile-ws.js +4 -0
  252. package/server/dist/path-resolver.js +46 -0
  253. package/server/dist/pr-body.js +240 -0
  254. package/server/dist/pr-naming.js +210 -0
  255. package/server/dist/pr-publisher.js +68 -0
  256. package/server/dist/project-registry.js +77 -17
  257. package/server/dist/project-router-jobs.js +53 -13
  258. package/server/dist/project-router-settings.js +33 -0
  259. package/server/dist/project-router-terminals.js +16 -0
  260. package/server/dist/project-router-tickets.js +57 -3
  261. package/server/dist/project-router.js +52 -13
  262. package/server/dist/queue-manager.js +268 -83
  263. package/server/dist/rail-isolated-launch.js +324 -34
  264. package/server/dist/rail-isolation.js +32 -5
  265. package/server/dist/rail-pr-decision.js +519 -0
  266. package/server/dist/rail-pr-delivery.js +75 -0
  267. package/server/dist/rail-pr-store.js +175 -0
  268. package/server/dist/rail-worktrees-store.js +18 -0
  269. package/server/dist/rails-router.js +241 -17
  270. package/server/dist/rails-store.js +78 -1
  271. package/server/dist/setup-prerequisites.js +105 -0
  272. package/server/dist/smash-runner.js +3 -1
  273. package/server/dist/ticket-store.js +7 -3
  274. package/server/dist/workspace-resolution.js +27 -0
  275. package/server/dist/worktree-manager.js +42 -7
  276. package/server/dist/worktree-overlay.js +261 -0
  277. package/client/dist/assets/AgentBrowserCapture-BlGDZahz.js +0 -1
  278. package/client/dist/assets/AgentModeJobsPane-CyNR-9BO.js +0 -1
  279. package/client/dist/assets/AgentsPage-dNsEsY_x.js +0 -86
  280. package/client/dist/assets/AnalyticsPage-BAxmR0HQ.js +0 -1
  281. package/client/dist/assets/CodePage-Crc4BBQN.js +0 -2
  282. package/client/dist/assets/DesktopAnalyticsPage-IXSnbCce.js +0 -1
  283. package/client/dist/assets/DocsDialog-Bc4hx7oW.js +0 -11
  284. package/client/dist/assets/DocsPage-bEU4t9c6.js +0 -11
  285. package/client/dist/assets/IntegrationsPage-wq2CezEL.js +0 -3
  286. package/client/dist/assets/JobDetailPage-BBcPk3j8.js +0 -1
  287. package/client/dist/assets/JobsPage-DXrSPlwa.js +0 -1
  288. package/client/dist/assets/LogViewer-BoYbwvbU.js +0 -16
  289. package/client/dist/assets/LoopBuilderPage-CiUMAuWz.js +0 -7
  290. package/client/dist/assets/LoopsPage-Xrp6W5XW.js +0 -1
  291. package/client/dist/assets/ProjectSettingsDialog-BU98L5JD.js +0 -1
  292. package/client/dist/assets/agent-B7GdHP3Z.js +0 -1
  293. package/client/dist/assets/agent-BHmcgoJf.js +0 -1
  294. package/client/dist/assets/agent-BdY_fii4.js +0 -1
  295. package/client/dist/assets/agent-C32FOi9v.js +0 -1
  296. package/client/dist/assets/agent-CiFQxoaZ2.js +0 -1
  297. package/client/dist/assets/agent-CtAag7V6.js +0 -1
  298. package/client/dist/assets/agent-DE4Mp1fY2.js +0 -1
  299. package/client/dist/assets/agent-DK8qovyG2.js +0 -1
  300. package/client/dist/assets/browser-ZB1afzjZ.js +0 -1
  301. package/client/dist/assets/code-BFxE1Yt62.js +0 -1
  302. package/client/dist/assets/code-BefYOm5Q.js +0 -1
  303. package/client/dist/assets/code-BkXpJt99.js +0 -1
  304. package/client/dist/assets/code-C6Sq7_t8.js +0 -1
  305. package/client/dist/assets/code-CGj3w-2N.js +0 -1
  306. package/client/dist/assets/code-Dfsxc9o82.js +0 -1
  307. package/client/dist/assets/code-Y5urks5s2.js +0 -1
  308. package/client/dist/assets/code-wtcs0ivb.js +0 -1
  309. package/client/dist/assets/dashboard-B8032psZ.js +0 -1
  310. package/client/dist/assets/dashboard-BHGKtxty2.js +0 -1
  311. package/client/dist/assets/dashboard-CXnoUgN22.js +0 -1
  312. package/client/dist/assets/dashboard-Ccyxqy7d.js +0 -1
  313. package/client/dist/assets/dashboard-CoED_41r.js +0 -1
  314. package/client/dist/assets/dashboard-Dc5ZAgMN.js +0 -1
  315. package/client/dist/assets/dashboard-JMY8ueD3.js +0 -1
  316. package/client/dist/assets/dashboard-tkWr1aHD2.js +0 -1
  317. package/client/dist/assets/index-BHPbzyg6.css +0 -2
  318. package/client/dist/assets/index-n2PmJGF6.js +0 -152
  319. package/client/dist/assets/jira-BcZzX9122.js +0 -1
  320. package/client/dist/assets/jira-CTYs7LA12.js +0 -1
  321. package/client/dist/assets/jira-D2nN39e92.js +0 -1
  322. package/client/dist/assets/jira-DJxmIkyr.js +0 -1
  323. package/client/dist/assets/jira-DXMoAKWD.js +0 -1
  324. package/client/dist/assets/jira-IhC1ROIc.js +0 -1
  325. package/client/dist/assets/jira-Iw575fN8.js +0 -1
  326. package/client/dist/assets/jira-kbWZY7jH.js +0 -1
  327. package/client/dist/assets/jobs-BqF79kHz2.js +0 -1
  328. package/client/dist/assets/jobs-C1XM5urS.js +0 -1
  329. package/client/dist/assets/jobs-C5UjG0262.js +0 -1
  330. package/client/dist/assets/jobs-DBfaHTxC.js +0 -1
  331. package/client/dist/assets/jobs-DM4BDPdg.js +0 -1
  332. package/client/dist/assets/jobs-Da5OkZmf2.js +0 -1
  333. package/client/dist/assets/jobs-JJdnuQ03.js +0 -1
  334. package/client/dist/assets/jobs-SI34ML8I.js +0 -1
  335. package/client/dist/assets/loops-BR4FmOv12.js +0 -1
  336. package/client/dist/assets/loops-BgX_uudn.js +0 -1
  337. package/client/dist/assets/loops-Bpl2j2LP.js +0 -1
  338. package/client/dist/assets/loops-CQuuMlyZ.js +0 -1
  339. package/client/dist/assets/loops-DW8hSMdS2.js +0 -1
  340. package/client/dist/assets/loops-Q2muu8hW2.js +0 -1
  341. package/client/dist/assets/loops-q7CNDvfK.js +0 -1
  342. package/client/dist/assets/settings-CY8udi0e.js +0 -1
  343. package/client/dist/assets/setup-CNMdCHHt2.js +0 -1
  344. package/client/dist/assets/setup-Cag4XrbL2.js +0 -1
  345. package/client/dist/assets/setup-D9IHGoWU.js +0 -1
  346. package/client/dist/assets/setup-Dg6Ba3JT.js +0 -1
  347. package/client/dist/assets/setup-DyK36RIW.js +0 -1
  348. package/client/dist/assets/setup-G4ZvDKxX.js +0 -1
  349. package/client/dist/assets/setup-aTlGxuwi2.js +0 -1
  350. package/client/dist/assets/setup-kWsoAeHQ.js +0 -1
  351. package/client/dist/assets/specs-BFSUPa122.js +0 -1
  352. package/client/dist/assets/specs-BMzip1WY2.js +0 -1
  353. package/client/dist/assets/specs-BYeAbIEy.js +0 -1
  354. package/client/dist/assets/specs-C-mtLcXw.js +0 -1
  355. package/client/dist/assets/specs-CAzpvADd2.js +0 -1
  356. package/client/dist/assets/specs-CyRIw_IR.js +0 -1
  357. package/client/dist/assets/specs-DMm7gB_l.js +0 -1
  358. package/client/dist/assets/specs-DuottM0Z.js +0 -1
  359. /package/client/dist/assets/{abap-CpHUwCVK.js → abap-D0E4FfVW.js} +0 -0
  360. /package/client/dist/assets/{activity-DemHQS7l.js → activity--iN4Ad2R2.js} +0 -0
  361. /package/client/dist/assets/{activity-B_71BWg3.js → activity-6hM_ZSg9.js} +0 -0
  362. /package/client/dist/assets/{activity-DHv2V5Oi.js → activity-BZNfOdiS.js} +0 -0
  363. /package/client/dist/assets/{activity-D0rfjQzT2.js → activity-BuVo5sPB.js} +0 -0
  364. /package/client/dist/assets/{activity-BpTTj_PH.js → activity-CIOLxGvh.js} +0 -0
  365. /package/client/dist/assets/{activity-D2e62vbV2.js → activity-D2r2h3SE2.js} +0 -0
  366. /package/client/dist/assets/{activity-Ch-wbr0C2.js → activity-DtxrAUMo2.js} +0 -0
  367. /package/client/dist/assets/{addon-image-Ba-TY3wr.js → addon-image-CwoZj17F.js} +0 -0
  368. /package/client/dist/assets/{addon-ligatures-T4ARLiuu.js → addon-ligatures-CWDrED80.js} +0 -0
  369. /package/client/dist/assets/{addon-webgl-Cd73n8eh.js → addon-webgl-DMbGeI_u.js} +0 -0
  370. /package/client/dist/assets/{addspec-xwRX_Pnf.js → addspec-BMtLZLW62.js} +0 -0
  371. /package/client/dist/assets/{addspec-l_zU5gla.js → addspec-CP0HRuxY.js} +0 -0
  372. /package/client/dist/assets/{addspec-Dio-H5z0.js → addspec-CRuvWn8d.js} +0 -0
  373. /package/client/dist/assets/{addspec-D6L4ZteP.js → addspec-D-JLDsUV.js} +0 -0
  374. /package/client/dist/assets/{addspec-CrEm6Fzr2.js → addspec-DfhDbg5c.js} +0 -0
  375. /package/client/dist/assets/{addspec-B6Ns8KU02.js → addspec-bsNDdqRm2.js} +0 -0
  376. /package/client/dist/assets/{addspec-qGyH7MHy2.js → addspec-mgPOt5q02.js} +0 -0
  377. /package/client/dist/assets/{agents-OzxCLVW1.js → agents-78bTZGZh.js} +0 -0
  378. /package/client/dist/assets/{agents-hv3sqmPm2.js → agents-BLhWCmDS2.js} +0 -0
  379. /package/client/dist/assets/{agents-CHgCudUV.js → agents-BUdEi3-N.js} +0 -0
  380. /package/client/dist/assets/{agents-Dumx4JiM2.js → agents-BpoUaoW92.js} +0 -0
  381. /package/client/dist/assets/{agents-CnaPeSyw.js → agents-CWo-KyAB.js} +0 -0
  382. /package/client/dist/assets/{agents-Xh-zYHUx2.js → agents-DDtCJ5M02.js} +0 -0
  383. /package/client/dist/assets/{agents-DuhLEaQ_.js → agents-bvyRLczL.js} +0 -0
  384. /package/client/dist/assets/{agentstudio-CCthUdzR.js → agentstudio-BMQxc_bz.js} +0 -0
  385. /package/client/dist/assets/{agentstudio-CcH8Ckql2.js → agentstudio-COZriimI2.js} +0 -0
  386. /package/client/dist/assets/{agentstudio-Bo91kfUd2.js → agentstudio-CWgXG5W52.js} +0 -0
  387. /package/client/dist/assets/{agentstudio-VJOa_NVO.js → agentstudio-C_Jq8Tl4.js} +0 -0
  388. /package/client/dist/assets/{agentstudio-BIxikDf_.js → agentstudio-Dtq3dGYk.js} +0 -0
  389. /package/client/dist/assets/{agentstudio-Bz8cP8_c.js → agentstudio-jKMTdT70.js} +0 -0
  390. /package/client/dist/assets/{agentstudio-DARgYg5Z2.js → agentstudio-sI27TpBu2.js} +0 -0
  391. /package/client/dist/assets/{aiedit-5ZXN4cep2.js → aiedit-6CHdb_iv2.js} +0 -0
  392. /package/client/dist/assets/{aiedit-B7gAJZVC.js → aiedit-B03pD_Na.js} +0 -0
  393. /package/client/dist/assets/{aiedit-D92V-kUW.js → aiedit-BtRqRxML.js} +0 -0
  394. /package/client/dist/assets/{aiedit-D9ualLVJ.js → aiedit-eMN4eQPF.js} +0 -0
  395. /package/client/dist/assets/{aiedit-h48tJU0V2.js → aiedit-hknZlly82.js} +0 -0
  396. /package/client/dist/assets/{aiedit-xkA_mR2a2.js → aiedit-igmw-ZoZ2.js} +0 -0
  397. /package/client/dist/assets/{aiedit-7B2dvCv-.js → aiedit-pc5JDUq1.js} +0 -0
  398. /package/client/dist/assets/{analytics-slx4X1mu2.js → analytics-BWMUZ2Pq2.js} +0 -0
  399. /package/client/dist/assets/{analytics-uRNP6yAJ.js → analytics-Bj-SmKHa.js} +0 -0
  400. /package/client/dist/assets/{analytics-WF1I49ln.js → analytics-C5dpiS0o.js} +0 -0
  401. /package/client/dist/assets/{analytics-CBvaxOId.js → analytics-CCprAqk3.js} +0 -0
  402. /package/client/dist/assets/{analytics-BakymH7Z2.js → analytics-CR1TJqUi2.js} +0 -0
  403. /package/client/dist/assets/{analytics-B7bPj6u_2.js → analytics-DfNdXR0y2.js} +0 -0
  404. /package/client/dist/assets/{analytics-DZ74aQ54.js → analytics-rmHuJv0V.js} +0 -0
  405. /package/client/dist/assets/{apex-DlD7oJX6.js → apex-D_X_8J4d.js} +0 -0
  406. /package/client/dist/assets/{atom-one-dark-BrRN8wBy.js → atom-one-dark-BMDPFwRZ.js} +0 -0
  407. /package/client/dist/assets/{attachments-C11tOKZ_.js → attachments-BgBNSqQd.js} +0 -0
  408. /package/client/dist/assets/{attachments-Bnbyj2PN.js → attachments-BjyMmrwE.js} +0 -0
  409. /package/client/dist/assets/{attachments-CIeLa8l12.js → attachments-C9GTTJsx2.js} +0 -0
  410. /package/client/dist/assets/{attachments-DslHfa-L.js → attachments-DCZOL1RU.js} +0 -0
  411. /package/client/dist/assets/{attachments-C-gyrCOb.js → attachments-DL-bPy9E.js} +0 -0
  412. /package/client/dist/assets/{attachments-Cxrs0pyL2.js → attachments-DPCmkFZu2.js} +0 -0
  413. /package/client/dist/assets/{attachments-TTPsc0a52.js → attachments-rNn1ekRy2.js} +0 -0
  414. /package/client/dist/assets/{azcli-CmXFAbc-.js → azcli-PZLnZ3jH.js} +0 -0
  415. /package/client/dist/assets/{bat-DdNJq4hH.js → bat-KlBOxpO4.js} +0 -0
  416. /package/client/dist/assets/{bicep-Bppz7WOA.js → bicep-CgG9oF3V.js} +0 -0
  417. /package/client/dist/assets/{cameligo-0MRMdSmg.js → cameligo-6R45j6Ph.js} +0 -0
  418. /package/client/dist/assets/{chat-BvHrebKC2.js → chat-BgL3zv6x2.js} +0 -0
  419. /package/client/dist/assets/{chat-CZyiLJvQ.js → chat-Bh3NdgJs.js} +0 -0
  420. /package/client/dist/assets/{chat-DKYP7NnC.js → chat-Bom6bqK3.js} +0 -0
  421. /package/client/dist/assets/{chat-5mdg_YIc2.js → chat-DdwZjT8K2.js} +0 -0
  422. /package/client/dist/assets/{chat-wkTIy9rX.js → chat-Dnwg-NpQ.js} +0 -0
  423. /package/client/dist/assets/{chat-BpYxnkr4.js → chat-DsbwJhus.js} +0 -0
  424. /package/client/dist/assets/{chat-BGax2nV62.js → chat-vylxqR0P2.js} +0 -0
  425. /package/client/dist/assets/{clojure-B5dKj863.js → clojure-CLAAMO7J.js} +0 -0
  426. /package/client/dist/assets/{clsx-1dnHRn8W.js → clsx-CNmW0Nip.js} +0 -0
  427. /package/client/dist/assets/{coffee-DSbWjzk7.js → coffee-AruSygo-.js} +0 -0
  428. /package/client/dist/assets/{commands-uz_uKT242.js → commands-C4Y3C-PF2.js} +0 -0
  429. /package/client/dist/assets/{commands-Bb7MnPqn2.js → commands-CSDs9q_2.js} +0 -0
  430. /package/client/dist/assets/{commands-C_7zZwJf.js → commands-DkU0qliq.js} +0 -0
  431. /package/client/dist/assets/{commands-D_6B8lfU.js → commands-JWMfGDmr.js} +0 -0
  432. /package/client/dist/assets/{commands-DBc5llLi2.js → commands-RHOchN4n2.js} +0 -0
  433. /package/client/dist/assets/{commands-CQkdthjF.js → commands-u-4eEHCN.js} +0 -0
  434. /package/client/dist/assets/{commands-DhZNhSbl.js → commands-xHDDGfcP2.js} +0 -0
  435. /package/client/dist/assets/{cpp-SBF8SAh9.js → cpp-DEE5r4Pw.js} +0 -0
  436. /package/client/dist/assets/{csharp-Lzuq_1t-.js → csharp-BVXJUvbK.js} +0 -0
  437. /package/client/dist/assets/{csp-BEzxZqi1.js → csp-cXOF0JoV.js} +0 -0
  438. /package/client/dist/assets/{css-C3D3PKln.js → css-C_zQuAoy.js} +0 -0
  439. /package/client/dist/assets/{cypher-CQ3dEPmv.js → cypher-t95m_Q-O.js} +0 -0
  440. /package/client/dist/assets/{dart-DCPmxolI.js → dart-B4r1Tg-e.js} +0 -0
  441. /package/client/dist/assets/{dockerfile-B_2_aaTO.js → dockerfile-6mt7zHQw.js} +0 -0
  442. /package/client/dist/assets/{ecl-rADUeXsV.js → ecl-DEY_Fz_Q.js} +0 -0
  443. /package/client/dist/assets/{editor.api2-T7u8kQWG.js → editor.api2-C3B0tp2x.js} +0 -0
  444. /package/client/dist/assets/{elixir-DOd-TuJO.js → elixir-R6-q1c5t.js} +0 -0
  445. /package/client/dist/assets/{explore-BHEhNekP2.js → explore-B7fblXBb2.js} +0 -0
  446. /package/client/dist/assets/{explore-DAsroA482.js → explore-BHtEpoNN2.js} +0 -0
  447. /package/client/dist/assets/{explore-UwHHj2ux.js → explore-C0k8HrkN.js} +0 -0
  448. /package/client/dist/assets/{explore-DaXiW9-6.js → explore-CNBzrEPS.js} +0 -0
  449. /package/client/dist/assets/{explore-CWlAXx0f2.js → explore-D_mWBYCS2.js} +0 -0
  450. /package/client/dist/assets/{explore-DG1CtYqT.js → explore-Dahc1lOx.js} +0 -0
  451. /package/client/dist/assets/{explore-DMSGAnhK.js → explore-UvW1jEMa.js} +0 -0
  452. /package/client/dist/assets/{flow9-Bf7zg_j0.js → flow9-CNQvHBOt.js} +0 -0
  453. /package/client/dist/assets/{format-command-BHymDa4r.js → format-command-CuWuRvka.js} +0 -0
  454. /package/client/dist/assets/{fsharp-BqROZjbA.js → fsharp-vPZkFXwv.js} +0 -0
  455. /package/client/dist/assets/{go-oQTP5uLe.js → go-KUzBMYJ_.js} +0 -0
  456. /package/client/dist/assets/{graphql-CSHfTU3q.js → graphql-C3W0rCsD.js} +0 -0
  457. /package/client/dist/assets/{hcl-CeG-RoFJ.js → hcl-BOOMFSNX.js} +0 -0
  458. /package/client/dist/assets/{ini-B2Dv4ohc.js → ini-CFat1WJr.js} +0 -0
  459. /package/client/dist/assets/{integrations-CAF21FbQ.js → integrations-4KZnYECp.js} +0 -0
  460. /package/client/dist/assets/{integrations-CHCgning2.js → integrations-7W266oqF2.js} +0 -0
  461. /package/client/dist/assets/{integrations-B-JVE1_D.js → integrations-BNuauK3o.js} +0 -0
  462. /package/client/dist/assets/{integrations-BAujIDoE.js → integrations-CHy8tnpV.js} +0 -0
  463. /package/client/dist/assets/{integrations-DS5FFMes.js → integrations-Cl_wD5AI.js} +0 -0
  464. /package/client/dist/assets/{integrations-axZN4--n2.js → integrations-Cy8nZ_dv2.js} +0 -0
  465. /package/client/dist/assets/{integrations-CtsOpq2D2.js → integrations-zMqY4VU12.js} +0 -0
  466. /package/client/dist/assets/{java-aUDDeufb.js → java-Dee-CNAM.js} +0 -0
  467. /package/client/dist/assets/{julia-C5LbruO5.js → julia-CGNlLYuU.js} +0 -0
  468. /package/client/dist/assets/{kotlin-C6mOuSKk.js → kotlin-CY7lhknJ.js} +0 -0
  469. /package/client/dist/assets/{less-D5qC3caW.js → less-D0KN7hfJ.js} +0 -0
  470. /package/client/dist/assets/{lexon-Dr2La-fj.js → lexon-CuRJufPs.js} +0 -0
  471. /package/client/dist/assets/{lua-Zy6u5z6Z.js → lua-DHvH62Zf.js} +0 -0
  472. /package/client/dist/assets/{m3-C7XHeDz_.js → m3-tlthQ8Fo.js} +0 -0
  473. /package/client/dist/assets/{markdown-PiF7r-2h.js → markdown-Dbx1LgUZ.js} +0 -0
  474. /package/client/dist/assets/{mcp-B_nWlxZa2.js → mcp-CjVKXAhD2.js} +0 -0
  475. /package/client/dist/assets/{mcp-B8omp_Cd.js → mcp-Dcl-XxkR.js} +0 -0
  476. /package/client/dist/assets/{mcp-DTCCrYHz2.js → mcp-DtbxuH3V2.js} +0 -0
  477. /package/client/dist/assets/{mcp-DytBbASZ.js → mcp-H-gnQUdN.js} +0 -0
  478. /package/client/dist/assets/{mcp-D_oPS6Zc.js → mcp-N1nzp8oL.js} +0 -0
  479. /package/client/dist/assets/{mcp-Cb2jtHP72.js → mcp-XJNRfxVp2.js} +0 -0
  480. /package/client/dist/assets/{mcp-DPqm2C8-.js → mcp-sRmWE8WJ.js} +0 -0
  481. /package/client/dist/assets/{mips-nn07GiyE.js → mips-D_O3IUz_.js} +0 -0
  482. /package/client/dist/assets/{msdax-DaKFVMST.js → msdax-C_ZmCnRt.js} +0 -0
  483. /package/client/dist/assets/{mysql-C6d6xrbU.js → mysql-C-dCEYSX.js} +0 -0
  484. /package/client/dist/assets/{nav-Cibp2KWF.js → nav-40HzpIFb.js} +0 -0
  485. /package/client/dist/assets/{nav-DtTnF9xd.js → nav-8yPhBn00.js} +0 -0
  486. /package/client/dist/assets/{nav-Danf5sRf2.js → nav-B6PkGfTk2.js} +0 -0
  487. /package/client/dist/assets/{nav-Bqhyfbcj2.js → nav-BHqMLrS72.js} +0 -0
  488. /package/client/dist/assets/{nav-CQb9y1km.js → nav-CGy4yx3C.js} +0 -0
  489. /package/client/dist/assets/{nav-BAsYcqdw2.js → nav-CXEDcRdv2.js} +0 -0
  490. /package/client/dist/assets/{nav-BRrNlZkr.js → nav-EI_OhEAo.js} +0 -0
  491. /package/client/dist/assets/{objective-c-B6KMtI-k.js → objective-c-DZY9Aqxd.js} +0 -0
  492. /package/client/dist/assets/{pascal-DYr8MPE7.js → pascal-BVHLXoor.js} +0 -0
  493. /package/client/dist/assets/{pascaligo-B3pd-jJ_.js → pascaligo-XdG_6u3k.js} +0 -0
  494. /package/client/dist/assets/{perl-z2xUzoaL.js → perl-b9QV0BcD.js} +0 -0
  495. /package/client/dist/assets/{pgsql-DUvT-09-.js → pgsql-Du5FDOgT.js} +0 -0
  496. /package/client/dist/assets/{php-CGyOmJfy.js → php-WJD0z2Z_.js} +0 -0
  497. /package/client/dist/assets/{pla-CMqgvyD0.js → pla-CbciTf2w.js} +0 -0
  498. /package/client/dist/assets/{postiats-Dx5LUn4Z.js → postiats-C1QxmvVq.js} +0 -0
  499. /package/client/dist/assets/{powerquery-DazYxvJ6.js → powerquery-BEYDhPLZ.js} +0 -0
  500. /package/client/dist/assets/{powershell-B3nwlDka.js → powershell-CfaYw4XL.js} +0 -0
  501. /package/client/dist/assets/{protobuf-BGuu2u2s.js → protobuf-pwZEDOYa.js} +0 -0
  502. /package/client/dist/assets/{pug-Dbte1MXA.js → pug-5ftqSPVe.js} +0 -0
  503. /package/client/dist/assets/{qsharp-DJLwBOvG.js → qsharp-uI6qZMq4.js} +0 -0
  504. /package/client/dist/assets/{r-DmGBRSHj.js → r-BK54P1EG.js} +0 -0
  505. /package/client/dist/assets/{redis-VvUYn0a4.js → redis-DI0yd7kN.js} +0 -0
  506. /package/client/dist/assets/{redshift-6GdDrxg3.js → redshift-Dov26eyI.js} +0 -0
  507. /package/client/dist/assets/{restructuredtext-CfAB8aRU.js → restructuredtext-QqJ_1dC-.js} +0 -0
  508. /package/client/dist/assets/{ruby-CIYK6MXY.js → ruby-5WjveeVb.js} +0 -0
  509. /package/client/dist/assets/{rust-CTHZfjj9.js → rust-BzVSfqFH.js} +0 -0
  510. /package/client/dist/assets/{sb-CkKTdkz_.js → sb-DMIUfT-3.js} +0 -0
  511. /package/client/dist/assets/{scala-Bx-Wr9TM.js → scala-CSKA7lqt.js} +0 -0
  512. /package/client/dist/assets/{scheme-Dcfi6f83.js → scheme-CojOP2Qc.js} +0 -0
  513. /package/client/dist/assets/{scss-ByL-7PFQ.js → scss-DoBZGJG6.js} +0 -0
  514. /package/client/dist/assets/{shell-Csnb9Yqd.js → shell-YOaE4udl.js} +0 -0
  515. /package/client/dist/assets/{solidity-Dbw5-0QP.js → solidity-l3jSyVLu.js} +0 -0
  516. /package/client/dist/assets/{sophia-ZQ3saZQx.js → sophia-BhSGTaQJ.js} +0 -0
  517. /package/client/dist/assets/{sparql-BEtOel8u.js → sparql-qhk6QD9w.js} +0 -0
  518. /package/client/dist/assets/{sql-DGPDbzB7.js → sql-DoO3y21-.js} +0 -0
  519. /package/client/dist/assets/{st-GeW2MOgh.js → st-ChZAY8oG.js} +0 -0
  520. /package/client/dist/assets/{swift-BVYTN8jq.js → swift-D290Tr7_.js} +0 -0
  521. /package/client/dist/assets/{systemverilog-Deg2a8Lr.js → systemverilog-DsxzgJ-o.js} +0 -0
  522. /package/client/dist/assets/{tcl-6DnLmROF.js → tcl-BKDUHAAR.js} +0 -0
  523. /package/client/dist/assets/{terminal-CDiOAmBd2.js → terminal-BRm03iFA2.js} +0 -0
  524. /package/client/dist/assets/{terminal-CJN-mQMc.js → terminal-De2Brd23.js} +0 -0
  525. /package/client/dist/assets/{terminal-CYB4TiAd.js → terminal-DxQWCqSD2.js} +0 -0
  526. /package/client/dist/assets/{terminal-DsaDTq5N2.js → terminal-WSAvHXoU.js} +0 -0
  527. /package/client/dist/assets/{terminal-DTQ_dPqi2.js → terminal-Z7KsDM_n.js} +0 -0
  528. /package/client/dist/assets/{terminal-58ReNaya.js → terminal-cqfd3EDV.js} +0 -0
  529. /package/client/dist/assets/{terminal-DawP8xNL.js → terminal-xGbCZJHg.js} +0 -0
  530. /package/client/dist/assets/{tickets-DoRTUYRT.js → tickets-B7zT4IRf.js} +0 -0
  531. /package/client/dist/assets/{tickets-DBfFePwk2.js → tickets-BoXom7l8.js} +0 -0
  532. /package/client/dist/assets/{tickets-DvohTziT2.js → tickets-C3b8cHhd2.js} +0 -0
  533. /package/client/dist/assets/{tickets-Da15iaRw.js → tickets-CFXnJsYF.js} +0 -0
  534. /package/client/dist/assets/{tickets-CujsZvkf.js → tickets-CWYFvx1W2.js} +0 -0
  535. /package/client/dist/assets/{tickets-Df6pee-O2.js → tickets-DTHo9c3C.js} +0 -0
  536. /package/client/dist/assets/{tickets-CNvIilmP.js → tickets-SuX_HkK4.js} +0 -0
  537. /package/client/dist/assets/{twig-XbbXW9Yz.js → twig-UpZQaM8G.js} +0 -0
  538. /package/client/dist/assets/{typespec-CRlV8GhI.js → typespec-DzaKvN8i.js} +0 -0
  539. /package/client/dist/assets/{vb-BHE2izPH.js → vb-CZpbb7tk.js} +0 -0
  540. /package/client/dist/assets/{wgsl-Bf5vkfmY.js → wgsl-CNt3OIvl.js} +0 -0
@@ -21,6 +21,13 @@ function isTargetClosedError(err) {
21
21
  const MAX_SESSIONS_PER_PROJECT = 4;
22
22
  const DOM_HTML_BYTE_CAP = 100_000;
23
23
  const LAST_URL_KEY = 'config.browser_last_url';
24
+ /** Conflation threshold for the screencast fan-out: skip sending a frame to a
25
+ * client whose WS send-buffer already holds this many bytes. A slow consumer
26
+ * otherwise accumulates seconds of stale frames (ever-growing latency), which is
27
+ * what "sluggish" feels like. Every frame is an independent, complete JPEG, so
28
+ * dropping intermediates is lossless — the client simply paints the next fresh
29
+ * frame (newest-wins). `lastFrame` is still always updated. */
30
+ const MAX_CLIENT_BUFFERED_BYTES = 1_000_000;
24
31
  /** How far back from capture time to include buffered network requests. */
25
32
  const NETWORK_WINDOW_MS = 30_000;
26
33
  /**
@@ -167,13 +174,15 @@ class BrowserCaptureManager {
167
174
  id,
168
175
  projectId: this.projectId,
169
176
  page,
177
+ popups: [],
178
+ popupView: false,
170
179
  clients: new Set(),
171
180
  lastFrame: null,
172
181
  url: null,
173
182
  title: null,
174
183
  viewport: { ...DEFAULT_VIEWPORT },
175
184
  createdAt: opts?.createdAtMs ?? this.now(),
176
- screencasting: false,
185
+ screencastPage: null,
177
186
  screencastDesired: false,
178
187
  screencastOp: null,
179
188
  closed: false,
@@ -181,6 +190,18 @@ class BrowserCaptureManager {
181
190
  this.sessions.set(id, session);
182
191
  // The reservation is now realised as a committed session — release it.
183
192
  this._reserved--;
193
+ // Adopt popups the page opens (OAuth login windows etc.) as secondary pages
194
+ // of this session, and keep the client's URL bar live on in-page navigation
195
+ // (link clicks / redirects the REST navigate path never sees).
196
+ this.watchPopups(session, page);
197
+ page.onNavigated?.((url) => {
198
+ if (session.closed || this.disposed)
199
+ return;
200
+ session.url = url;
201
+ if (url && url !== 'about:blank')
202
+ this.setLastUrl(url);
203
+ this.broadcastControl(session, { type: 'nav', url, title: session.title });
204
+ });
184
205
  // Start capturing the page's network requests before the first navigation so
185
206
  // XHR/fetch made during page load are available at capture time. Best-effort:
186
207
  // a handle that doesn't support it (or a failure) just yields no network data.
@@ -188,13 +209,106 @@ class BrowserCaptureManager {
188
209
  await page.enableNetwork?.();
189
210
  }
190
211
  catch { /* network capture is best-effort */ }
212
+ // Kick the initial navigation WITHOUT blocking session creation. The old
213
+ // `await page.goto(...)` here held the create POST — and therefore the whole
214
+ // modal spinner — hostage to `domcontentloaded` (up to 30s on a slow site).
215
+ // Returning immediately lets the client attach and start the screencast right
216
+ // away, so the user watches the page paint progressively instead of staring
217
+ // at "opening…". The URL is set optimistically to the target; the resolved
218
+ // URL/title land via the `nav` control broadcast every client already handles.
191
219
  const target = opts?.initialUrl?.trim() || this.getLastUrl() || 'about:blank';
192
- const result = await page.goto(target);
193
- session.url = result.url;
194
- session.title = result.title;
220
+ session.url = target;
221
+ void this.runInitialNavigation(session, target);
222
+ return this.toMeta(session);
223
+ }
224
+ /** Complete the initial `goto` in the background (see create()). Never throws;
225
+ * a session killed mid-navigation is simply left alone. */
226
+ async runInitialNavigation(s, target) {
227
+ let result;
228
+ try {
229
+ result = await s.page.goto(target);
230
+ }
231
+ catch {
232
+ return; // the page keeps whatever it settled on; nav failures are non-fatal
233
+ }
234
+ if (s.closed || this.disposed)
235
+ return;
236
+ s.url = result.url;
237
+ s.title = result.title;
195
238
  if (result.url && result.url !== 'about:blank')
196
239
  this.setLastUrl(result.url);
197
- return this.toMeta(session);
240
+ this.broadcastControl(s, { type: 'nav', url: result.url, title: result.title });
241
+ }
242
+ // ─── Popup support (OAuth login windows etc.) ───────────────────────────────
243
+ topPopup(s) {
244
+ return s.popups.length > 0 ? s.popups[s.popups.length - 1] : null;
245
+ }
246
+ /** The page the screencast + interactive input should target: the top popup
247
+ * while one is open and being viewed, else the root page. */
248
+ activePage(s) {
249
+ return (s.popupView && this.topPopup(s)) || s.page;
250
+ }
251
+ watchPopups(s, opener) {
252
+ opener.onPopup?.((popup) => this.adoptPopup(s, popup));
253
+ }
254
+ /** Register a popup as a secondary page of the session: inherit the viewport,
255
+ * reroute the screencast + input to it (latest-wins), and auto-return to the
256
+ * opener when it closes (the typical OAuth self-close). */
257
+ adoptPopup(s, popup) {
258
+ if (s.closed || this.disposed) {
259
+ void popup.close().catch(() => { });
260
+ return;
261
+ }
262
+ s.popups.push(popup);
263
+ s.popupView = true;
264
+ // Popups inherit the session viewport so coordinate mapping + screencast
265
+ // dimensions stay identical to the root page.
266
+ void popup.setViewport(s.viewport.width, s.viewport.height).catch(() => { });
267
+ popup.onClose?.(() => this.dropPopup(s, popup));
268
+ popup.onNavigated?.(() => {
269
+ // Keep the "Login window — <origin>" label fresh while the top popup
270
+ // walks its redirect chain.
271
+ if (!s.closed && this.topPopup(s) === popup)
272
+ this.broadcastPopupState(s);
273
+ });
274
+ // Popups can themselves open popups (rare, but some IdPs chain windows).
275
+ this.watchPopups(s, popup);
276
+ this.broadcastPopupState(s);
277
+ void this.applyScreencast(s);
278
+ }
279
+ dropPopup(s, popup) {
280
+ const i = s.popups.indexOf(popup);
281
+ if (i === -1)
282
+ return;
283
+ s.popups.splice(i, 1);
284
+ if (s.popups.length === 0)
285
+ s.popupView = false;
286
+ if (s.closed)
287
+ return;
288
+ this.broadcastPopupState(s);
289
+ // Re-routes the screencast to the next popup down or back to the opener;
290
+ // startScreencast emits a frame immediately, so the switch paints at once.
291
+ void this.applyScreencast(s);
292
+ }
293
+ broadcastPopupState(s) {
294
+ const top = this.topPopup(s);
295
+ this.broadcastControl(s, {
296
+ type: 'popup',
297
+ count: s.popups.length,
298
+ active: s.popupView && top != null,
299
+ url: top ? top.currentUrl() : null,
300
+ });
301
+ }
302
+ /** Switch the viewed page between the root page and the top popup ("back to
303
+ * page" / "show login window"). Returns false for an unknown session. */
304
+ setPopupView(sessionId, target) {
305
+ const s = this.getSession(sessionId);
306
+ if (!s)
307
+ return false;
308
+ s.popupView = target === 'popup' && s.popups.length > 0;
309
+ this.broadcastPopupState(s);
310
+ void this.applyScreencast(s);
311
+ return true;
198
312
  }
199
313
  // ─── WS attach / detach + screencast fan-out ────────────────────────────────
200
314
  async attach(sessionId, ws) {
@@ -207,6 +321,12 @@ class BrowserCaptureManager {
207
321
  this.safeSend(ws, JSON.stringify({ type: 'ready', id: s.id, url: s.url, title: s.title, viewport: s.viewport }));
208
322
  if (s.lastFrame)
209
323
  this.safeSend(ws, s.lastFrame);
324
+ // A (re)joining client must learn about a live popup immediately, or it
325
+ // would render popup frames with the root-page chrome.
326
+ if (s.popups.length > 0) {
327
+ const top = this.topPopup(s);
328
+ this.safeSend(ws, JSON.stringify({ type: 'popup', count: s.popups.length, active: s.popupView && top != null, url: top ? top.currentUrl() : null }));
329
+ }
210
330
  s.screencastDesired = true;
211
331
  await this.applyScreencast(s);
212
332
  return this.toMeta(s);
@@ -224,45 +344,48 @@ class BrowserCaptureManager {
224
344
  /**
225
345
  * Serialise screencast start/stop transitions on a per-session promise chain so
226
346
  * a rapid detach→attach (stop fired async, then start) can't double-initialise
227
- * the CDP screencast. The chain always reconciles `screencasting` to
228
- * `screencastDesired`.
347
+ * the CDP screencast. The chain reconciles the page the screencast runs on
348
+ * (`screencastPage`) to the DESIRED page — the active page (top popup while one
349
+ * is viewed, else the root page) when `screencastDesired`, or none. A popup
350
+ * open/close/focus switch therefore stops the cast on the old page and starts
351
+ * it on the new one; the same frame callback fans out to the same clients.
229
352
  */
230
353
  applyScreencast(s) {
231
354
  const prev = s.screencastOp ?? Promise.resolve();
232
355
  s.screencastOp = prev.then(async () => {
233
- if (s.closed) {
234
- if (s.screencasting) {
235
- s.screencasting = false;
236
- try {
237
- await s.page.stopScreencast();
238
- }
239
- catch { /* ignore */ }
240
- }
356
+ const desired = !s.closed && s.screencastDesired ? this.activePage(s) : null;
357
+ if (s.screencastPage === desired)
241
358
  return;
359
+ if (s.screencastPage) {
360
+ const old = s.screencastPage;
361
+ s.screencastPage = null;
362
+ try {
363
+ await old.stopScreencast();
364
+ }
365
+ catch { /* ignore */ }
242
366
  }
243
- if (s.screencastDesired && !s.screencasting) {
244
- s.screencasting = true;
245
- await s.page.startScreencast((frame) => {
367
+ if (desired) {
368
+ s.screencastPage = desired;
369
+ await desired.startScreencast((frame) => {
246
370
  if (s.closed)
247
371
  return;
248
372
  s.lastFrame = frame.data;
249
373
  for (const client of s.clients) {
250
- if (client.readyState === WS_OPEN) {
251
- try {
252
- client.send(frame.data);
253
- }
254
- catch { /* drop */ }
374
+ if (client.readyState !== WS_OPEN)
375
+ continue;
376
+ // Conflate for slow consumers: when the socket's send-buffer is
377
+ // already backed up, skip this frame for that client instead of
378
+ // queueing ever-staler frames behind the backlog (latency, not
379
+ // fps, is what makes a screencast feel sluggish).
380
+ if ((client.bufferedAmount ?? 0) > MAX_CLIENT_BUFFERED_BYTES)
381
+ continue;
382
+ try {
383
+ client.send(frame.data);
255
384
  }
385
+ catch { /* drop */ }
256
386
  }
257
387
  });
258
388
  }
259
- else if (!s.screencastDesired && s.screencasting) {
260
- s.screencasting = false;
261
- try {
262
- await s.page.stopScreencast();
263
- }
264
- catch { /* ignore */ }
265
- }
266
389
  }).catch(() => { });
267
390
  return s.screencastOp;
268
391
  }
@@ -308,8 +431,20 @@ class BrowserCaptureManager {
308
431
  width: Math.max(1, Math.round(event.width)),
309
432
  height: Math.max(1, Math.round(event.height)),
310
433
  };
434
+ // Keep every page of the session (root + popups) at the same viewport so
435
+ // switching between them never re-maps coordinates or resizes the canvas.
436
+ await s.page.dispatchInput(event);
437
+ for (const popup of s.popups) {
438
+ try {
439
+ await popup.dispatchInput(event);
440
+ }
441
+ catch { /* ignore */ }
442
+ }
443
+ return;
311
444
  }
312
- await s.page.dispatchInput(event);
445
+ // Interactive input (mouse/wheel/keys) goes to the page being VIEWED — the
446
+ // top popup during an OAuth login, else the root page.
447
+ await this.activePage(s).dispatchInput(event);
313
448
  }
314
449
  async navigate(sessionId, action, url) {
315
450
  if (this.disposed)
@@ -414,14 +549,17 @@ class BrowserCaptureManager {
414
549
  const s = this.getSession(sessionId);
415
550
  if (!s)
416
551
  return null;
552
+ // Clipboard follows the viewed page: pasting credentials into an OAuth
553
+ // popup must land in the popup, not the opener behind it.
554
+ const page = this.activePage(s);
417
555
  if (action === 'paste') {
418
556
  if (text)
419
- await s.page.insertText?.(text);
557
+ await page.insertText?.(text);
420
558
  return { text: '' };
421
559
  }
422
- const sel = (await s.page.getSelectionText?.()) ?? '';
560
+ const sel = (await page.getSelectionText?.()) ?? '';
423
561
  if (action === 'cut' && sel)
424
- await s.page.deleteSelection?.();
562
+ await page.deleteSelection?.();
425
563
  return { text: sel };
426
564
  }
427
565
  // ─── Multi-breakpoint capture ───────────────────────────────────────────────
@@ -551,6 +689,12 @@ class BrowserCaptureManager {
551
689
  catch { /* ignore */ }
552
690
  }
553
691
  s.clients.clear();
692
+ for (const popup of s.popups.splice(0)) {
693
+ try {
694
+ await popup.close();
695
+ }
696
+ catch { /* ignore */ }
697
+ }
554
698
  try {
555
699
  await s.page.close();
556
700
  }
@@ -577,6 +721,12 @@ class BrowserCaptureManager {
577
721
  catch { /* ignore */ }
578
722
  }
579
723
  s.clients.clear();
724
+ for (const popup of s.popups.splice(0)) {
725
+ try {
726
+ await popup.close();
727
+ }
728
+ catch { /* ignore */ }
729
+ }
580
730
  try {
581
731
  await s.page.close();
582
732
  }
@@ -9,6 +9,7 @@
9
9
  // screencast API; input + screenshot + DOM use Playwright's high-level page API.
10
10
  Object.defineProperty(exports, "__esModule", { value: true });
11
11
  exports.isNavigableUrl = isNavigableUrl;
12
+ exports.screencastParams = screencastParams;
12
13
  exports.normalizeUrl = normalizeUrl;
13
14
  exports.chromiumLaunchArgs = chromiumLaunchArgs;
14
15
  exports.createPlaywrightLauncher = createPlaywrightLauncher;
@@ -94,6 +95,30 @@ function isBlockedHost(host) {
94
95
  }
95
96
  return false;
96
97
  }
98
+ /**
99
+ * CDP `Page.startScreencast` parameters, centralised and env-tunable.
100
+ *
101
+ * - `quality` (JPEG, default 70) can be tuned via
102
+ * `SPECRAILS_BROWSER_SCREENCAST_QUALITY` (clamped to [1, 100]; non-numeric
103
+ * values fall back to the default). Lower = smaller frames = higher fps on
104
+ * slow links; higher = crisper at more bandwidth/decode cost.
105
+ * - `everyNthFrame: 1` — never skip source frames; the client-side pipeline
106
+ * drops stale frames instead (newest-wins), which keeps latency minimal.
107
+ * - `maxWidth`/`maxHeight` are a GUARD, not a scaler: the session viewport is
108
+ * sized to the displayed canvas (fit mode) or a device preset, so frames are
109
+ * already ≤ display size. The caps only prevent a pathological viewport from
110
+ * producing multi-megabyte frames. Chromium preserves aspect when clamping.
111
+ */
112
+ function screencastParams(env = process.env) {
113
+ let quality = 70;
114
+ const raw = env.SPECRAILS_BROWSER_SCREENCAST_QUALITY;
115
+ if (raw !== undefined && raw !== '') {
116
+ const n = Number(raw);
117
+ if (Number.isFinite(n))
118
+ quality = Math.min(100, Math.max(1, Math.round(n)));
119
+ }
120
+ return { format: 'jpeg', quality, everyNthFrame: 1, maxWidth: 3840, maxHeight: 2400 };
121
+ }
97
122
  /**
98
123
  * Normalize a user-supplied address into a safe, navigable URL. A bare host
99
124
  * (`example.com`) is upgraded to `https://`. The result is then validated by
@@ -125,6 +150,10 @@ class PlaywrightPageHandle {
125
150
  netCdp = null;
126
151
  netEnabled = false;
127
152
  netBuffer = new browser_network_1.NetworkRingBuffer();
153
+ // Last position the page's virtual mouse was moved to. Lets the wheel path skip
154
+ // the redundant `mouse.move` a scroll gesture would otherwise re-issue for
155
+ // every tick at the same cursor position (halves the CDP commands per wheel).
156
+ lastMouse = null;
128
157
  constructor(page) {
129
158
  this.page = page;
130
159
  }
@@ -187,16 +216,30 @@ class PlaywrightPageHandle {
187
216
  async dispatchInput(event) {
188
217
  try {
189
218
  if (event.type === 'mouse') {
190
- if (event.action === 'move')
219
+ if (event.action === 'move') {
220
+ this.lastMouse = { x: event.x, y: event.y };
191
221
  await this.page.mouse.move(event.x, event.y);
192
- else if (event.action === 'down')
222
+ }
223
+ else if (event.action === 'down') {
193
224
  await this.page.mouse.down({ button: event.button ?? 'left', clickCount: event.clickCount ?? 1 });
194
- else
225
+ }
226
+ else {
195
227
  await this.page.mouse.up({ button: event.button ?? 'left', clickCount: event.clickCount ?? 1 });
228
+ }
196
229
  }
197
230
  else if (event.type === 'wheel') {
198
- await this.page.mouse.move(event.x, event.y);
199
- await this.page.mouse.wheel(event.deltaX, event.deltaY);
231
+ // Scroll fast-path: skip the redundant reposition when the cursor hasn't
232
+ // moved since the last event (the common case mid-gesture), and dispatch
233
+ // move+wheel back-to-back without a sequential await gap — the Playwright
234
+ // driver sends commands in call order, so Chromium still sees move→wheel,
235
+ // but a concurrent wheel can no longer interleave between the two.
236
+ const ops = [];
237
+ if (!this.lastMouse || this.lastMouse.x !== event.x || this.lastMouse.y !== event.y) {
238
+ this.lastMouse = { x: event.x, y: event.y };
239
+ ops.push(this.page.mouse.move(event.x, event.y));
240
+ }
241
+ ops.push(this.page.mouse.wheel(event.deltaX, event.deltaY));
242
+ await Promise.all(ops);
200
243
  }
201
244
  else if (event.type === 'key') {
202
245
  if (event.action === 'down') {
@@ -227,7 +270,16 @@ class PlaywrightPageHandle {
227
270
  this.screencastHandler = onFrame;
228
271
  const ctx = this.page.context();
229
272
  this.cdp = await ctx.newCDPSession(this.page);
230
- this.cdp.on('Page.screencastFrame', async (evt) => {
273
+ this.cdp.on('Page.screencastFrame', (evt) => {
274
+ // Ack FIRST, fire-and-forget: Chromium throttles the screencast on unacked
275
+ // frames, so acking before the fan-out lets it capture+compress the next
276
+ // frame while this one is being delivered (pipeline overlap → higher fps,
277
+ // lower frame age). The frames are independent JPEGs, so there is no
278
+ // ordering hazard in acking early.
279
+ try {
280
+ this.cdp?.send('Page.screencastFrameAck', { sessionId: evt.sessionId })?.catch?.(() => { });
281
+ }
282
+ catch { /* ignore */ }
231
283
  try {
232
284
  this.screencastHandler?.({
233
285
  data: Buffer.from(evt.data, 'base64'),
@@ -235,14 +287,9 @@ class PlaywrightPageHandle {
235
287
  height: evt.metadata?.deviceHeight ?? 0,
236
288
  });
237
289
  }
238
- finally {
239
- try {
240
- await this.cdp.send('Page.screencastFrameAck', { sessionId: evt.sessionId });
241
- }
242
- catch { /* ignore */ }
243
- }
290
+ catch { /* never let a handler error kill the CDP session */ }
244
291
  });
245
- await this.cdp.send('Page.startScreencast', { format: 'jpeg', quality: 70, everyNthFrame: 1 });
292
+ await this.cdp.send('Page.startScreencast', screencastParams());
246
293
  }
247
294
  async stopScreencast() {
248
295
  this.screencastHandler = null;
@@ -443,6 +490,44 @@ class PlaywrightPageHandle {
443
490
  }
444
491
  catch { /* ignore */ }
445
492
  }
493
+ onPopup(cb) {
494
+ // Playwright fires 'popup' for pages this page opens (window.open,
495
+ // target=_blank, OAuth login windows). The popup lives in the SAME browser
496
+ // context — cookies and the window.opener/postMessage relationship are
497
+ // intact, which is exactly what an OAuth redirect/popup flow needs.
498
+ try {
499
+ this.page.on('popup', (p) => {
500
+ try {
501
+ cb(new PlaywrightPageHandle(p));
502
+ }
503
+ catch { /* never break the event loop */ }
504
+ });
505
+ }
506
+ catch { /* ignore */ }
507
+ }
508
+ onClose(cb) {
509
+ try {
510
+ this.page.on('close', () => {
511
+ try {
512
+ cb();
513
+ }
514
+ catch { /* ignore */ }
515
+ });
516
+ }
517
+ catch { /* ignore */ }
518
+ }
519
+ onNavigated(cb) {
520
+ try {
521
+ this.page.on('framenavigated', (frame) => {
522
+ try {
523
+ if (frame === this.page.mainFrame())
524
+ cb(frame.url());
525
+ }
526
+ catch { /* ignore */ }
527
+ });
528
+ }
529
+ catch { /* ignore */ }
530
+ }
446
531
  async getSelectionText() {
447
532
  try {
448
533
  return await this.page.evaluate(() => window.getSelection()?.toString() ?? '');
@@ -12,6 +12,7 @@ const feature_flags_1 = require("./feature-flags");
12
12
  const build_dirs_1 = require("./build-dirs");
13
13
  const file_provenance_1 = require("./file-provenance");
14
14
  const file_summary_manager_1 = require("./file-summary-manager");
15
+ const file_story_1 = require("./file-story");
15
16
  const MAX_TREE_PAGE = 2000;
16
17
  const MAX_FILE_BYTES = 2 * 1024 * 1024;
17
18
  const BINARY_PROBE_BYTES = 8 * 1024;
@@ -661,6 +662,97 @@ function createCodeExplorerRouter(deps) {
661
662
  }
662
663
  res.json({ summary, summaryStale });
663
664
  });
665
+ // Construction story: the chronological list of interventions (specs/jobs)
666
+ // that built this file — provenance rows enriched with diff stats, the AI
667
+ // contribution paragraph when generated, and the spec's live title/status.
668
+ // Same guards as every sibling content endpoint. Works for deleted files too
669
+ // (their story is still worth telling), so no stat/existence requirement.
670
+ router.get('/file/story', (req, res) => {
671
+ const relRaw = req.query.path;
672
+ if (!relRaw || typeof relRaw !== 'string') {
673
+ res.status(400).json({ error: 'path query parameter is required' });
674
+ return;
675
+ }
676
+ const guard = resolveSafePath(deps.projectPath, relRaw);
677
+ if (!guard) {
678
+ res.status(400).json({ error: 'path traversal not allowed' });
679
+ return;
680
+ }
681
+ if (isDeniedRelPath(relRaw)) {
682
+ res.status(403).json({ error: 'path is excluded by the code-explorer deny-list' });
683
+ return;
684
+ }
685
+ const rel = normalizeRel(relRaw);
686
+ if (isGitIgnored(deps.projectPath, rel)) {
687
+ res.status(403).json({ error: 'path is gitignored' });
688
+ return;
689
+ }
690
+ res.json({ path: rel, story: (0, file_story_1.getFileStory)(deps.db, rel, deps.getTicketSpec) });
691
+ });
692
+ // Construction story: generate (budget-gated) the plain-language "what this
693
+ // spec contributed" paragraph for ONE intervention. Awaits the single model
694
+ // turn; the file.story_updated WS event fires too so other open viewers of
695
+ // the same file refresh.
696
+ router.post('/file/story/explain', async (req, res) => {
697
+ const relRaw = req.query.path;
698
+ if (!relRaw || typeof relRaw !== 'string') {
699
+ res.status(400).json({ error: 'path query parameter is required' });
700
+ return;
701
+ }
702
+ const guard = resolveSafePath(deps.projectPath, relRaw);
703
+ if (!guard) {
704
+ res.status(400).json({ error: 'path traversal not allowed' });
705
+ return;
706
+ }
707
+ if (isDeniedRelPath(relRaw)) {
708
+ res.status(403).json({ error: 'path is excluded by the code-explorer deny-list' });
709
+ return;
710
+ }
711
+ const rel = normalizeRel(relRaw);
712
+ if (isGitIgnored(deps.projectPath, rel)) {
713
+ res.status(403).json({ error: 'path is gitignored' });
714
+ return;
715
+ }
716
+ if (!deps.fileStoryManager) {
717
+ res.status(404).json({ error: 'story generation not available' });
718
+ return;
719
+ }
720
+ const body = (req.body ?? {});
721
+ const provenanceId = typeof body.provenanceId === 'number' && Number.isInteger(body.provenanceId) && body.provenanceId > 0
722
+ ? body.provenanceId
723
+ : null;
724
+ if (provenanceId == null) {
725
+ res.status(400).json({ error: 'provenanceId (positive integer) is required' });
726
+ return;
727
+ }
728
+ try {
729
+ const result = await deps.fileStoryManager.explain({
730
+ projectId: deps.projectId,
731
+ relPath: rel,
732
+ provenanceId,
733
+ overrideBudget: body.overrideBudget === true,
734
+ });
735
+ if (result === 'generated') {
736
+ res.json({ ok: true });
737
+ return;
738
+ }
739
+ if (result === 'skipped:budget') {
740
+ // 200 (not 4xx) so the client's budget-override prompt is reachable
741
+ // (mirrors /file/regenerate-summary).
742
+ res.status(200).json({ skipped: 'budget' });
743
+ return;
744
+ }
745
+ if (result === 'skipped:not-found') {
746
+ res.status(404).json({ error: 'intervention not found for this file' });
747
+ return;
748
+ }
749
+ res.status(500).json({ error: 'story generation failed' });
750
+ }
751
+ catch (err) {
752
+ console.error('[code-explorer-router] story explain failed:', err);
753
+ res.status(500).json({ error: 'story generation failed', message: err.message });
754
+ }
755
+ });
664
756
  router.post('/file/regenerate-summary', async (req, res) => {
665
757
  const relRaw = req.query.path;
666
758
  if (!relRaw || typeof relRaw !== 'string') {