specrails-desktop 2.21.0 → 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 (533) hide show
  1. package/README.md +3 -3
  2. package/client/dist/assets/{ActivityFeedPage-BPkf89Xk.js → ActivityFeedPage-roDyKGuv.js} +1 -1
  3. package/client/dist/assets/AgentBrowserCapture-BsXnWa4j.js +1 -0
  4. package/client/dist/assets/{AgentModeCodePane-DhVkOSdv.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-9_p1-qtv.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-Clt8DyCs.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-DPRq2dC-.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-4mmVovCB.js → dist-js-BZSiJDbG.js} +1 -1
  67. package/client/dist/assets/{dist-js-wMFtEMAw.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-Cz65p1sn.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/setup-B590KsTX.js +1 -0
  109. package/client/dist/assets/setup-BkyGoby6.js +1 -0
  110. package/client/dist/assets/setup-CEj6uY3-2.js +1 -0
  111. package/client/dist/assets/setup-CbIerFGf2.js +1 -0
  112. package/client/dist/assets/setup-CmU6bTCV2.js +1 -0
  113. package/client/dist/assets/setup-D674kWQH.js +1 -0
  114. package/client/dist/assets/setup-VNqXyB6Y.js +1 -0
  115. package/client/dist/assets/setup-iY8vH8pB.js +1 -0
  116. package/client/dist/assets/specs-C9Sd7BhH2.js +1 -0
  117. package/client/dist/assets/specs-CBDvEYKv.js +1 -0
  118. package/client/dist/assets/specs-CIPr9reA2.js +1 -0
  119. package/client/dist/assets/specs-CWtKcVDC.js +1 -0
  120. package/client/dist/assets/specs-CmEZY57v.js +1 -0
  121. package/client/dist/assets/specs-D2clrt2c2.js +1 -0
  122. package/client/dist/assets/specs-DTplt2XM.js +1 -0
  123. package/client/dist/assets/specs-PozUNhqb.js +1 -0
  124. package/client/dist/assets/{tsMode-BC1g186U.js → tsMode-BmT8WogI.js} +1 -1
  125. package/client/dist/assets/{typescript-BGlRGvJW.js → typescript-CQrQPsoW.js} +1 -1
  126. package/client/dist/assets/upload-CLAzW1mS.js +1 -0
  127. package/client/dist/assets/{value-DJMRojPA.js → value-DSwzyyWR.js} +1 -1
  128. package/client/dist/assets/{workers-CXcXtO3b.js → workers-U0UXyLUf.js} +1 -1
  129. package/client/dist/assets/{xml-JdZZaIhJ.js → xml-WRxJs8_I.js} +1 -1
  130. package/client/dist/assets/{yaml-Cm82BVBt.js → yaml-CjpSTjJU.js} +1 -1
  131. package/client/dist/index.html +13 -13
  132. package/docs/customizing.md +2 -2
  133. package/docs/gemini.md +15 -4
  134. package/docs/guide/de/insights/3-code-explorer.md +6 -0
  135. package/docs/guide/de/integrations/3-jira-integration.md +1 -1
  136. package/docs/guide/de/integrations/6-agent-chat.md +5 -0
  137. package/docs/guide/de/pipeline/1-rails-and-jobs.md +6 -6
  138. package/docs/guide/de/pipeline/2-the-job-detail-view.md +27 -2
  139. package/docs/guide/de/pipeline/3-batch-implement-and-multi-feature.md +5 -4
  140. package/docs/guide/de/pipeline/5-the-loop-builder.md +1 -1
  141. package/docs/guide/de/specs/1-specs-and-the-backlog.md +3 -2
  142. package/docs/guide/en/insights/3-code-explorer.md +6 -0
  143. package/docs/guide/en/integrations/3-jira-integration.md +1 -1
  144. package/docs/guide/en/integrations/6-agent-chat.md +5 -0
  145. package/docs/guide/en/pipeline/1-rails-and-jobs.md +6 -6
  146. package/docs/guide/en/pipeline/2-the-job-detail-view.md +27 -2
  147. package/docs/guide/en/pipeline/3-batch-implement-and-multi-feature.md +5 -4
  148. package/docs/guide/en/pipeline/5-the-loop-builder.md +1 -1
  149. package/docs/guide/en/specs/1-specs-and-the-backlog.md +3 -2
  150. package/docs/guide/es/insights/3-code-explorer.md +6 -0
  151. package/docs/guide/es/integrations/3-jira-integration.md +1 -1
  152. package/docs/guide/es/integrations/6-agent-chat.md +5 -0
  153. package/docs/guide/es/pipeline/1-rails-and-jobs.md +6 -6
  154. package/docs/guide/es/pipeline/2-the-job-detail-view.md +27 -2
  155. package/docs/guide/es/pipeline/3-batch-implement-and-multi-feature.md +5 -4
  156. package/docs/guide/es/pipeline/5-the-loop-builder.md +1 -1
  157. package/docs/guide/es/specs/1-specs-and-the-backlog.md +3 -2
  158. package/docs/guide/fr/insights/3-code-explorer.md +6 -0
  159. package/docs/guide/fr/integrations/3-jira-integration.md +1 -1
  160. package/docs/guide/fr/integrations/6-agent-chat.md +5 -0
  161. package/docs/guide/fr/pipeline/1-rails-and-jobs.md +6 -6
  162. package/docs/guide/fr/pipeline/2-the-job-detail-view.md +27 -2
  163. package/docs/guide/fr/pipeline/3-batch-implement-and-multi-feature.md +5 -4
  164. package/docs/guide/fr/pipeline/5-the-loop-builder.md +1 -1
  165. package/docs/guide/fr/specs/1-specs-and-the-backlog.md +3 -2
  166. package/docs/guide/it/insights/3-code-explorer.md +6 -0
  167. package/docs/guide/it/integrations/3-jira-integration.md +1 -1
  168. package/docs/guide/it/integrations/6-agent-chat.md +5 -0
  169. package/docs/guide/it/pipeline/1-rails-and-jobs.md +6 -6
  170. package/docs/guide/it/pipeline/2-the-job-detail-view.md +27 -2
  171. package/docs/guide/it/pipeline/3-batch-implement-and-multi-feature.md +5 -4
  172. package/docs/guide/it/pipeline/5-the-loop-builder.md +1 -1
  173. package/docs/guide/it/specs/1-specs-and-the-backlog.md +3 -2
  174. package/docs/guide/ja/insights/3-code-explorer.md +6 -0
  175. package/docs/guide/ja/integrations/3-jira-integration.md +1 -1
  176. package/docs/guide/ja/integrations/6-agent-chat.md +5 -0
  177. package/docs/guide/ja/pipeline/1-rails-and-jobs.md +6 -6
  178. package/docs/guide/ja/pipeline/2-the-job-detail-view.md +27 -2
  179. package/docs/guide/ja/pipeline/3-batch-implement-and-multi-feature.md +5 -4
  180. package/docs/guide/ja/pipeline/5-the-loop-builder.md +1 -1
  181. package/docs/guide/ja/specs/1-specs-and-the-backlog.md +3 -2
  182. package/docs/guide/pt/insights/3-code-explorer.md +6 -0
  183. package/docs/guide/pt/integrations/3-jira-integration.md +1 -1
  184. package/docs/guide/pt/integrations/6-agent-chat.md +5 -0
  185. package/docs/guide/pt/pipeline/1-rails-and-jobs.md +6 -6
  186. package/docs/guide/pt/pipeline/2-the-job-detail-view.md +27 -2
  187. package/docs/guide/pt/pipeline/3-batch-implement-and-multi-feature.md +5 -4
  188. package/docs/guide/pt/pipeline/5-the-loop-builder.md +1 -1
  189. package/docs/guide/pt/specs/1-specs-and-the-backlog.md +3 -2
  190. package/docs/guide/zh/insights/3-code-explorer.md +6 -0
  191. package/docs/guide/zh/integrations/3-jira-integration.md +1 -1
  192. package/docs/guide/zh/integrations/6-agent-chat.md +5 -0
  193. package/docs/guide/zh/pipeline/1-rails-and-jobs.md +6 -6
  194. package/docs/guide/zh/pipeline/2-the-job-detail-view.md +27 -2
  195. package/docs/guide/zh/pipeline/3-batch-implement-and-multi-feature.md +5 -4
  196. package/docs/guide/zh/pipeline/5-the-loop-builder.md +1 -1
  197. package/docs/guide/zh/specs/1-specs-and-the-backlog.md +3 -2
  198. package/docs/internals/README.md +5 -0
  199. package/docs/internals/adding-a-provider.md +15 -3
  200. package/docs/internals/api-reference.md +6 -5
  201. package/docs/internals/browser-capture-performance.md +93 -0
  202. package/docs/internals/code-explorer-story.md +135 -0
  203. package/docs/internals/gemini-mcp-registration.md +53 -0
  204. package/docs/internals/interactive-jobs.md +212 -0
  205. package/docs/internals/loop-step-log-explorer.md +146 -0
  206. package/docs/internals/safe-pr-review-flow.md +367 -0
  207. package/docs/mcp.md +1 -1
  208. package/docs/running-pipelines.md +5 -3
  209. package/package.json +1 -1
  210. package/server/dist/agent-chat-manager.js +211 -0
  211. package/server/dist/agent-chat-registry.js +20 -0
  212. package/server/dist/agent-chat-router.js +22 -0
  213. package/server/dist/agent-mcp-config.js +45 -4
  214. package/server/dist/agent-operator-prompt.js +149 -56
  215. package/server/dist/agent-store.js +25 -0
  216. package/server/dist/agent-tier.js +6 -1
  217. package/server/dist/browser-capture-manager.js +184 -34
  218. package/server/dist/browser-playwright.js +98 -13
  219. package/server/dist/code-explorer-router.js +92 -0
  220. package/server/dist/db.js +92 -0
  221. package/server/dist/file-provenance.js +54 -1
  222. package/server/dist/file-story-manager.js +170 -0
  223. package/server/dist/file-story.js +148 -0
  224. package/server/dist/file-summary-generator.js +5 -4
  225. package/server/dist/index.js +5 -0
  226. package/server/dist/interactive-job-session.js +226 -18
  227. package/server/dist/jira/jira-adf.js +9 -0
  228. package/server/dist/jira/jira-materializer.js +27 -4
  229. package/server/dist/jira/jira-status-resolver.js +12 -4
  230. package/server/dist/jira/jira-sync-manager.js +130 -2
  231. package/server/dist/jira-router.js +1 -1
  232. package/server/dist/loop-executors.js +91 -28
  233. package/server/dist/loop-run-manager.js +354 -28
  234. package/server/dist/mcp/guide.js +18 -7
  235. package/server/dist/mcp/tools/jira.js +1 -1
  236. package/server/dist/mcp/tools/jobs.js +14 -5
  237. package/server/dist/mcp/tools/rails.js +137 -12
  238. package/server/dist/mcp/tools/specs.js +35 -9
  239. package/server/dist/mcp/tools/types.js +49 -0
  240. package/server/dist/mobile/mobile-ws.js +4 -0
  241. package/server/dist/path-resolver.js +46 -0
  242. package/server/dist/pr-body.js +240 -0
  243. package/server/dist/pr-naming.js +210 -0
  244. package/server/dist/project-registry.js +77 -17
  245. package/server/dist/project-router-jobs.js +53 -13
  246. package/server/dist/project-router-terminals.js +16 -0
  247. package/server/dist/project-router-tickets.js +57 -3
  248. package/server/dist/project-router.js +52 -13
  249. package/server/dist/queue-manager.js +261 -84
  250. package/server/dist/rail-isolated-launch.js +315 -66
  251. package/server/dist/rail-isolation.js +18 -5
  252. package/server/dist/rail-pr-decision.js +519 -0
  253. package/server/dist/rail-pr-delivery.js +21 -18
  254. package/server/dist/rail-pr-store.js +175 -0
  255. package/server/dist/rail-worktrees-store.js +18 -0
  256. package/server/dist/rails-router.js +224 -37
  257. package/server/dist/rails-store.js +78 -1
  258. package/server/dist/setup-prerequisites.js +105 -0
  259. package/server/dist/smash-runner.js +3 -1
  260. package/server/dist/ticket-store.js +7 -3
  261. package/server/dist/workspace-resolution.js +27 -0
  262. package/server/dist/worktree-manager.js +42 -7
  263. package/server/dist/worktree-overlay.js +261 -0
  264. package/client/dist/assets/AgentBrowserCapture-DkA8FLp8.js +0 -1
  265. package/client/dist/assets/AgentModeJobsPane-TLYCqNAw.js +0 -1
  266. package/client/dist/assets/AgentsPage-BKsPH-l1.js +0 -86
  267. package/client/dist/assets/AnalyticsPage-Da9pDQrq.js +0 -1
  268. package/client/dist/assets/CodePage-DlwvWKCo.js +0 -2
  269. package/client/dist/assets/DesktopAnalyticsPage-DpVVhXKF.js +0 -1
  270. package/client/dist/assets/DocsDialog-BSdgftgR.js +0 -11
  271. package/client/dist/assets/DocsPage-9SGL4_zz.js +0 -11
  272. package/client/dist/assets/IntegrationsPage-BW5mofSA.js +0 -3
  273. package/client/dist/assets/JobDetailPage-CqiJ9vwR.js +0 -1
  274. package/client/dist/assets/JobsPage-CVinOe6p.js +0 -1
  275. package/client/dist/assets/LogViewer-Cf6s1TDs.js +0 -16
  276. package/client/dist/assets/LoopBuilderPage-CqgUH5Vw.js +0 -7
  277. package/client/dist/assets/LoopsPage-C6h2gjPP.js +0 -1
  278. package/client/dist/assets/ProjectSettingsDialog-BU-JR7wI.js +0 -1
  279. package/client/dist/assets/agent-B7GdHP3Z.js +0 -1
  280. package/client/dist/assets/agent-BHmcgoJf.js +0 -1
  281. package/client/dist/assets/agent-BdY_fii4.js +0 -1
  282. package/client/dist/assets/agent-C32FOi9v.js +0 -1
  283. package/client/dist/assets/agent-CiFQxoaZ2.js +0 -1
  284. package/client/dist/assets/agent-CtAag7V6.js +0 -1
  285. package/client/dist/assets/agent-DE4Mp1fY2.js +0 -1
  286. package/client/dist/assets/agent-DK8qovyG2.js +0 -1
  287. package/client/dist/assets/browser-ZB1afzjZ.js +0 -1
  288. package/client/dist/assets/code-BFxE1Yt62.js +0 -1
  289. package/client/dist/assets/code-BefYOm5Q.js +0 -1
  290. package/client/dist/assets/code-BkXpJt99.js +0 -1
  291. package/client/dist/assets/code-C6Sq7_t8.js +0 -1
  292. package/client/dist/assets/code-CGj3w-2N.js +0 -1
  293. package/client/dist/assets/code-Dfsxc9o82.js +0 -1
  294. package/client/dist/assets/code-Y5urks5s2.js +0 -1
  295. package/client/dist/assets/code-wtcs0ivb.js +0 -1
  296. package/client/dist/assets/dashboard-B-AiVq5X.js +0 -1
  297. package/client/dist/assets/dashboard-BpYYrPl8.js +0 -1
  298. package/client/dist/assets/dashboard-Bunv-uon2.js +0 -1
  299. package/client/dist/assets/dashboard-CYciEbov.js +0 -1
  300. package/client/dist/assets/dashboard-CvFg-_JQ.js +0 -1
  301. package/client/dist/assets/dashboard-DAyPERCJ.js +0 -1
  302. package/client/dist/assets/dashboard-DJ-6T44N2.js +0 -1
  303. package/client/dist/assets/dashboard-DnBGqZkZ2.js +0 -1
  304. package/client/dist/assets/index-BHPbzyg6.css +0 -2
  305. package/client/dist/assets/index-D4R3rVF5.js +0 -152
  306. package/client/dist/assets/jira-BcZzX9122.js +0 -1
  307. package/client/dist/assets/jira-CTYs7LA12.js +0 -1
  308. package/client/dist/assets/jira-D2nN39e92.js +0 -1
  309. package/client/dist/assets/jira-DJxmIkyr.js +0 -1
  310. package/client/dist/assets/jira-DXMoAKWD.js +0 -1
  311. package/client/dist/assets/jira-IhC1ROIc.js +0 -1
  312. package/client/dist/assets/jira-Iw575fN8.js +0 -1
  313. package/client/dist/assets/jira-kbWZY7jH.js +0 -1
  314. package/client/dist/assets/jobs-BqF79kHz2.js +0 -1
  315. package/client/dist/assets/jobs-C1XM5urS.js +0 -1
  316. package/client/dist/assets/jobs-C5UjG0262.js +0 -1
  317. package/client/dist/assets/jobs-DBfaHTxC.js +0 -1
  318. package/client/dist/assets/jobs-DM4BDPdg.js +0 -1
  319. package/client/dist/assets/jobs-Da5OkZmf2.js +0 -1
  320. package/client/dist/assets/jobs-JJdnuQ03.js +0 -1
  321. package/client/dist/assets/jobs-SI34ML8I.js +0 -1
  322. package/client/dist/assets/loops-BR4FmOv12.js +0 -1
  323. package/client/dist/assets/loops-BgX_uudn.js +0 -1
  324. package/client/dist/assets/loops-Bpl2j2LP.js +0 -1
  325. package/client/dist/assets/loops-CQuuMlyZ.js +0 -1
  326. package/client/dist/assets/loops-DW8hSMdS2.js +0 -1
  327. package/client/dist/assets/loops-Q2muu8hW2.js +0 -1
  328. package/client/dist/assets/loops-q7CNDvfK.js +0 -1
  329. package/client/dist/assets/setup-CNMdCHHt2.js +0 -1
  330. package/client/dist/assets/setup-Cag4XrbL2.js +0 -1
  331. package/client/dist/assets/setup-D9IHGoWU.js +0 -1
  332. package/client/dist/assets/setup-Dg6Ba3JT.js +0 -1
  333. package/client/dist/assets/setup-DyK36RIW.js +0 -1
  334. package/client/dist/assets/setup-G4ZvDKxX.js +0 -1
  335. package/client/dist/assets/setup-aTlGxuwi2.js +0 -1
  336. package/client/dist/assets/setup-kWsoAeHQ.js +0 -1
  337. package/client/dist/assets/specs-BFSUPa122.js +0 -1
  338. package/client/dist/assets/specs-BMzip1WY2.js +0 -1
  339. package/client/dist/assets/specs-BYeAbIEy.js +0 -1
  340. package/client/dist/assets/specs-C-mtLcXw.js +0 -1
  341. package/client/dist/assets/specs-CAzpvADd2.js +0 -1
  342. package/client/dist/assets/specs-CyRIw_IR.js +0 -1
  343. package/client/dist/assets/specs-DMm7gB_l.js +0 -1
  344. package/client/dist/assets/specs-DuottM0Z.js +0 -1
  345. /package/client/dist/assets/{abap-CpHUwCVK.js → abap-D0E4FfVW.js} +0 -0
  346. /package/client/dist/assets/{activity-DemHQS7l.js → activity--iN4Ad2R2.js} +0 -0
  347. /package/client/dist/assets/{activity-B_71BWg3.js → activity-6hM_ZSg9.js} +0 -0
  348. /package/client/dist/assets/{activity-DHv2V5Oi.js → activity-BZNfOdiS.js} +0 -0
  349. /package/client/dist/assets/{activity-D0rfjQzT2.js → activity-BuVo5sPB.js} +0 -0
  350. /package/client/dist/assets/{activity-BpTTj_PH.js → activity-CIOLxGvh.js} +0 -0
  351. /package/client/dist/assets/{activity-D2e62vbV2.js → activity-D2r2h3SE2.js} +0 -0
  352. /package/client/dist/assets/{activity-Ch-wbr0C2.js → activity-DtxrAUMo2.js} +0 -0
  353. /package/client/dist/assets/{addon-image-Ba-TY3wr.js → addon-image-CwoZj17F.js} +0 -0
  354. /package/client/dist/assets/{addon-ligatures-T4ARLiuu.js → addon-ligatures-CWDrED80.js} +0 -0
  355. /package/client/dist/assets/{addon-webgl-Cd73n8eh.js → addon-webgl-DMbGeI_u.js} +0 -0
  356. /package/client/dist/assets/{addspec-xwRX_Pnf.js → addspec-BMtLZLW62.js} +0 -0
  357. /package/client/dist/assets/{addspec-l_zU5gla.js → addspec-CP0HRuxY.js} +0 -0
  358. /package/client/dist/assets/{addspec-Dio-H5z0.js → addspec-CRuvWn8d.js} +0 -0
  359. /package/client/dist/assets/{addspec-D6L4ZteP.js → addspec-D-JLDsUV.js} +0 -0
  360. /package/client/dist/assets/{addspec-CrEm6Fzr2.js → addspec-DfhDbg5c.js} +0 -0
  361. /package/client/dist/assets/{addspec-B6Ns8KU02.js → addspec-bsNDdqRm2.js} +0 -0
  362. /package/client/dist/assets/{addspec-qGyH7MHy2.js → addspec-mgPOt5q02.js} +0 -0
  363. /package/client/dist/assets/{agents-OzxCLVW1.js → agents-78bTZGZh.js} +0 -0
  364. /package/client/dist/assets/{agents-hv3sqmPm2.js → agents-BLhWCmDS2.js} +0 -0
  365. /package/client/dist/assets/{agents-CHgCudUV.js → agents-BUdEi3-N.js} +0 -0
  366. /package/client/dist/assets/{agents-Dumx4JiM2.js → agents-BpoUaoW92.js} +0 -0
  367. /package/client/dist/assets/{agents-CnaPeSyw.js → agents-CWo-KyAB.js} +0 -0
  368. /package/client/dist/assets/{agents-Xh-zYHUx2.js → agents-DDtCJ5M02.js} +0 -0
  369. /package/client/dist/assets/{agents-DuhLEaQ_.js → agents-bvyRLczL.js} +0 -0
  370. /package/client/dist/assets/{agentstudio-CCthUdzR.js → agentstudio-BMQxc_bz.js} +0 -0
  371. /package/client/dist/assets/{agentstudio-CcH8Ckql2.js → agentstudio-COZriimI2.js} +0 -0
  372. /package/client/dist/assets/{agentstudio-Bo91kfUd2.js → agentstudio-CWgXG5W52.js} +0 -0
  373. /package/client/dist/assets/{agentstudio-VJOa_NVO.js → agentstudio-C_Jq8Tl4.js} +0 -0
  374. /package/client/dist/assets/{agentstudio-BIxikDf_.js → agentstudio-Dtq3dGYk.js} +0 -0
  375. /package/client/dist/assets/{agentstudio-Bz8cP8_c.js → agentstudio-jKMTdT70.js} +0 -0
  376. /package/client/dist/assets/{agentstudio-DARgYg5Z2.js → agentstudio-sI27TpBu2.js} +0 -0
  377. /package/client/dist/assets/{aiedit-5ZXN4cep2.js → aiedit-6CHdb_iv2.js} +0 -0
  378. /package/client/dist/assets/{aiedit-B7gAJZVC.js → aiedit-B03pD_Na.js} +0 -0
  379. /package/client/dist/assets/{aiedit-D92V-kUW.js → aiedit-BtRqRxML.js} +0 -0
  380. /package/client/dist/assets/{aiedit-D9ualLVJ.js → aiedit-eMN4eQPF.js} +0 -0
  381. /package/client/dist/assets/{aiedit-h48tJU0V2.js → aiedit-hknZlly82.js} +0 -0
  382. /package/client/dist/assets/{aiedit-xkA_mR2a2.js → aiedit-igmw-ZoZ2.js} +0 -0
  383. /package/client/dist/assets/{aiedit-7B2dvCv-.js → aiedit-pc5JDUq1.js} +0 -0
  384. /package/client/dist/assets/{analytics-slx4X1mu2.js → analytics-BWMUZ2Pq2.js} +0 -0
  385. /package/client/dist/assets/{analytics-uRNP6yAJ.js → analytics-Bj-SmKHa.js} +0 -0
  386. /package/client/dist/assets/{analytics-WF1I49ln.js → analytics-C5dpiS0o.js} +0 -0
  387. /package/client/dist/assets/{analytics-CBvaxOId.js → analytics-CCprAqk3.js} +0 -0
  388. /package/client/dist/assets/{analytics-BakymH7Z2.js → analytics-CR1TJqUi2.js} +0 -0
  389. /package/client/dist/assets/{analytics-B7bPj6u_2.js → analytics-DfNdXR0y2.js} +0 -0
  390. /package/client/dist/assets/{analytics-DZ74aQ54.js → analytics-rmHuJv0V.js} +0 -0
  391. /package/client/dist/assets/{apex-DlD7oJX6.js → apex-D_X_8J4d.js} +0 -0
  392. /package/client/dist/assets/{atom-one-dark-BrRN8wBy.js → atom-one-dark-BMDPFwRZ.js} +0 -0
  393. /package/client/dist/assets/{attachments-C11tOKZ_.js → attachments-BgBNSqQd.js} +0 -0
  394. /package/client/dist/assets/{attachments-Bnbyj2PN.js → attachments-BjyMmrwE.js} +0 -0
  395. /package/client/dist/assets/{attachments-CIeLa8l12.js → attachments-C9GTTJsx2.js} +0 -0
  396. /package/client/dist/assets/{attachments-DslHfa-L.js → attachments-DCZOL1RU.js} +0 -0
  397. /package/client/dist/assets/{attachments-C-gyrCOb.js → attachments-DL-bPy9E.js} +0 -0
  398. /package/client/dist/assets/{attachments-Cxrs0pyL2.js → attachments-DPCmkFZu2.js} +0 -0
  399. /package/client/dist/assets/{attachments-TTPsc0a52.js → attachments-rNn1ekRy2.js} +0 -0
  400. /package/client/dist/assets/{azcli-CmXFAbc-.js → azcli-PZLnZ3jH.js} +0 -0
  401. /package/client/dist/assets/{bat-DdNJq4hH.js → bat-KlBOxpO4.js} +0 -0
  402. /package/client/dist/assets/{bicep-Bppz7WOA.js → bicep-CgG9oF3V.js} +0 -0
  403. /package/client/dist/assets/{cameligo-0MRMdSmg.js → cameligo-6R45j6Ph.js} +0 -0
  404. /package/client/dist/assets/{chat-BvHrebKC2.js → chat-BgL3zv6x2.js} +0 -0
  405. /package/client/dist/assets/{chat-CZyiLJvQ.js → chat-Bh3NdgJs.js} +0 -0
  406. /package/client/dist/assets/{chat-DKYP7NnC.js → chat-Bom6bqK3.js} +0 -0
  407. /package/client/dist/assets/{chat-5mdg_YIc2.js → chat-DdwZjT8K2.js} +0 -0
  408. /package/client/dist/assets/{chat-wkTIy9rX.js → chat-Dnwg-NpQ.js} +0 -0
  409. /package/client/dist/assets/{chat-BpYxnkr4.js → chat-DsbwJhus.js} +0 -0
  410. /package/client/dist/assets/{chat-BGax2nV62.js → chat-vylxqR0P2.js} +0 -0
  411. /package/client/dist/assets/{clojure-B5dKj863.js → clojure-CLAAMO7J.js} +0 -0
  412. /package/client/dist/assets/{clsx-1dnHRn8W.js → clsx-CNmW0Nip.js} +0 -0
  413. /package/client/dist/assets/{coffee-DSbWjzk7.js → coffee-AruSygo-.js} +0 -0
  414. /package/client/dist/assets/{commands-uz_uKT242.js → commands-C4Y3C-PF2.js} +0 -0
  415. /package/client/dist/assets/{commands-Bb7MnPqn2.js → commands-CSDs9q_2.js} +0 -0
  416. /package/client/dist/assets/{commands-C_7zZwJf.js → commands-DkU0qliq.js} +0 -0
  417. /package/client/dist/assets/{commands-D_6B8lfU.js → commands-JWMfGDmr.js} +0 -0
  418. /package/client/dist/assets/{commands-DBc5llLi2.js → commands-RHOchN4n2.js} +0 -0
  419. /package/client/dist/assets/{commands-CQkdthjF.js → commands-u-4eEHCN.js} +0 -0
  420. /package/client/dist/assets/{commands-DhZNhSbl.js → commands-xHDDGfcP2.js} +0 -0
  421. /package/client/dist/assets/{cpp-SBF8SAh9.js → cpp-DEE5r4Pw.js} +0 -0
  422. /package/client/dist/assets/{csharp-Lzuq_1t-.js → csharp-BVXJUvbK.js} +0 -0
  423. /package/client/dist/assets/{csp-BEzxZqi1.js → csp-cXOF0JoV.js} +0 -0
  424. /package/client/dist/assets/{css-C3D3PKln.js → css-C_zQuAoy.js} +0 -0
  425. /package/client/dist/assets/{cypher-CQ3dEPmv.js → cypher-t95m_Q-O.js} +0 -0
  426. /package/client/dist/assets/{dart-DCPmxolI.js → dart-B4r1Tg-e.js} +0 -0
  427. /package/client/dist/assets/{dockerfile-B_2_aaTO.js → dockerfile-6mt7zHQw.js} +0 -0
  428. /package/client/dist/assets/{ecl-rADUeXsV.js → ecl-DEY_Fz_Q.js} +0 -0
  429. /package/client/dist/assets/{editor.api2-T7u8kQWG.js → editor.api2-C3B0tp2x.js} +0 -0
  430. /package/client/dist/assets/{elixir-DOd-TuJO.js → elixir-R6-q1c5t.js} +0 -0
  431. /package/client/dist/assets/{explore-BHEhNekP2.js → explore-B7fblXBb2.js} +0 -0
  432. /package/client/dist/assets/{explore-DAsroA482.js → explore-BHtEpoNN2.js} +0 -0
  433. /package/client/dist/assets/{explore-UwHHj2ux.js → explore-C0k8HrkN.js} +0 -0
  434. /package/client/dist/assets/{explore-DaXiW9-6.js → explore-CNBzrEPS.js} +0 -0
  435. /package/client/dist/assets/{explore-CWlAXx0f2.js → explore-D_mWBYCS2.js} +0 -0
  436. /package/client/dist/assets/{explore-DG1CtYqT.js → explore-Dahc1lOx.js} +0 -0
  437. /package/client/dist/assets/{explore-DMSGAnhK.js → explore-UvW1jEMa.js} +0 -0
  438. /package/client/dist/assets/{flow9-Bf7zg_j0.js → flow9-CNQvHBOt.js} +0 -0
  439. /package/client/dist/assets/{format-command-BHymDa4r.js → format-command-CuWuRvka.js} +0 -0
  440. /package/client/dist/assets/{fsharp-BqROZjbA.js → fsharp-vPZkFXwv.js} +0 -0
  441. /package/client/dist/assets/{go-oQTP5uLe.js → go-KUzBMYJ_.js} +0 -0
  442. /package/client/dist/assets/{graphql-CSHfTU3q.js → graphql-C3W0rCsD.js} +0 -0
  443. /package/client/dist/assets/{hcl-CeG-RoFJ.js → hcl-BOOMFSNX.js} +0 -0
  444. /package/client/dist/assets/{ini-B2Dv4ohc.js → ini-CFat1WJr.js} +0 -0
  445. /package/client/dist/assets/{integrations-CAF21FbQ.js → integrations-4KZnYECp.js} +0 -0
  446. /package/client/dist/assets/{integrations-CHCgning2.js → integrations-7W266oqF2.js} +0 -0
  447. /package/client/dist/assets/{integrations-B-JVE1_D.js → integrations-BNuauK3o.js} +0 -0
  448. /package/client/dist/assets/{integrations-BAujIDoE.js → integrations-CHy8tnpV.js} +0 -0
  449. /package/client/dist/assets/{integrations-DS5FFMes.js → integrations-Cl_wD5AI.js} +0 -0
  450. /package/client/dist/assets/{integrations-axZN4--n2.js → integrations-Cy8nZ_dv2.js} +0 -0
  451. /package/client/dist/assets/{integrations-CtsOpq2D2.js → integrations-zMqY4VU12.js} +0 -0
  452. /package/client/dist/assets/{java-aUDDeufb.js → java-Dee-CNAM.js} +0 -0
  453. /package/client/dist/assets/{julia-C5LbruO5.js → julia-CGNlLYuU.js} +0 -0
  454. /package/client/dist/assets/{kotlin-C6mOuSKk.js → kotlin-CY7lhknJ.js} +0 -0
  455. /package/client/dist/assets/{less-D5qC3caW.js → less-D0KN7hfJ.js} +0 -0
  456. /package/client/dist/assets/{lexon-Dr2La-fj.js → lexon-CuRJufPs.js} +0 -0
  457. /package/client/dist/assets/{lua-Zy6u5z6Z.js → lua-DHvH62Zf.js} +0 -0
  458. /package/client/dist/assets/{m3-C7XHeDz_.js → m3-tlthQ8Fo.js} +0 -0
  459. /package/client/dist/assets/{markdown-PiF7r-2h.js → markdown-Dbx1LgUZ.js} +0 -0
  460. /package/client/dist/assets/{mcp-B_nWlxZa2.js → mcp-CjVKXAhD2.js} +0 -0
  461. /package/client/dist/assets/{mcp-B8omp_Cd.js → mcp-Dcl-XxkR.js} +0 -0
  462. /package/client/dist/assets/{mcp-DTCCrYHz2.js → mcp-DtbxuH3V2.js} +0 -0
  463. /package/client/dist/assets/{mcp-DytBbASZ.js → mcp-H-gnQUdN.js} +0 -0
  464. /package/client/dist/assets/{mcp-D_oPS6Zc.js → mcp-N1nzp8oL.js} +0 -0
  465. /package/client/dist/assets/{mcp-Cb2jtHP72.js → mcp-XJNRfxVp2.js} +0 -0
  466. /package/client/dist/assets/{mcp-DPqm2C8-.js → mcp-sRmWE8WJ.js} +0 -0
  467. /package/client/dist/assets/{mips-nn07GiyE.js → mips-D_O3IUz_.js} +0 -0
  468. /package/client/dist/assets/{msdax-DaKFVMST.js → msdax-C_ZmCnRt.js} +0 -0
  469. /package/client/dist/assets/{mysql-C6d6xrbU.js → mysql-C-dCEYSX.js} +0 -0
  470. /package/client/dist/assets/{nav-Cibp2KWF.js → nav-40HzpIFb.js} +0 -0
  471. /package/client/dist/assets/{nav-DtTnF9xd.js → nav-8yPhBn00.js} +0 -0
  472. /package/client/dist/assets/{nav-Danf5sRf2.js → nav-B6PkGfTk2.js} +0 -0
  473. /package/client/dist/assets/{nav-Bqhyfbcj2.js → nav-BHqMLrS72.js} +0 -0
  474. /package/client/dist/assets/{nav-CQb9y1km.js → nav-CGy4yx3C.js} +0 -0
  475. /package/client/dist/assets/{nav-BAsYcqdw2.js → nav-CXEDcRdv2.js} +0 -0
  476. /package/client/dist/assets/{nav-BRrNlZkr.js → nav-EI_OhEAo.js} +0 -0
  477. /package/client/dist/assets/{objective-c-B6KMtI-k.js → objective-c-DZY9Aqxd.js} +0 -0
  478. /package/client/dist/assets/{pascal-DYr8MPE7.js → pascal-BVHLXoor.js} +0 -0
  479. /package/client/dist/assets/{pascaligo-B3pd-jJ_.js → pascaligo-XdG_6u3k.js} +0 -0
  480. /package/client/dist/assets/{perl-z2xUzoaL.js → perl-b9QV0BcD.js} +0 -0
  481. /package/client/dist/assets/{pgsql-DUvT-09-.js → pgsql-Du5FDOgT.js} +0 -0
  482. /package/client/dist/assets/{php-CGyOmJfy.js → php-WJD0z2Z_.js} +0 -0
  483. /package/client/dist/assets/{pla-CMqgvyD0.js → pla-CbciTf2w.js} +0 -0
  484. /package/client/dist/assets/{postiats-Dx5LUn4Z.js → postiats-C1QxmvVq.js} +0 -0
  485. /package/client/dist/assets/{powerquery-DazYxvJ6.js → powerquery-BEYDhPLZ.js} +0 -0
  486. /package/client/dist/assets/{powershell-B3nwlDka.js → powershell-CfaYw4XL.js} +0 -0
  487. /package/client/dist/assets/{protobuf-BGuu2u2s.js → protobuf-pwZEDOYa.js} +0 -0
  488. /package/client/dist/assets/{pug-Dbte1MXA.js → pug-5ftqSPVe.js} +0 -0
  489. /package/client/dist/assets/{qsharp-DJLwBOvG.js → qsharp-uI6qZMq4.js} +0 -0
  490. /package/client/dist/assets/{r-DmGBRSHj.js → r-BK54P1EG.js} +0 -0
  491. /package/client/dist/assets/{redis-VvUYn0a4.js → redis-DI0yd7kN.js} +0 -0
  492. /package/client/dist/assets/{redshift-6GdDrxg3.js → redshift-Dov26eyI.js} +0 -0
  493. /package/client/dist/assets/{restructuredtext-CfAB8aRU.js → restructuredtext-QqJ_1dC-.js} +0 -0
  494. /package/client/dist/assets/{ruby-CIYK6MXY.js → ruby-5WjveeVb.js} +0 -0
  495. /package/client/dist/assets/{rust-CTHZfjj9.js → rust-BzVSfqFH.js} +0 -0
  496. /package/client/dist/assets/{sb-CkKTdkz_.js → sb-DMIUfT-3.js} +0 -0
  497. /package/client/dist/assets/{scala-Bx-Wr9TM.js → scala-CSKA7lqt.js} +0 -0
  498. /package/client/dist/assets/{scheme-Dcfi6f83.js → scheme-CojOP2Qc.js} +0 -0
  499. /package/client/dist/assets/{scss-ByL-7PFQ.js → scss-DoBZGJG6.js} +0 -0
  500. /package/client/dist/assets/{settings-D3rfdI1i.js → settings-BOHOmHkb.js} +0 -0
  501. /package/client/dist/assets/{settings-DoUJb93K2.js → settings-BlEA_7h02.js} +0 -0
  502. /package/client/dist/assets/{settings-CgjmTpR8.js → settings-BsJMsWGc.js} +0 -0
  503. /package/client/dist/assets/{settings-BbxrZlv7.js → settings-D6qY9_UI.js} +0 -0
  504. /package/client/dist/assets/{settings-BmA06FIJ.js → settings-DZJeXoRV.js} +0 -0
  505. /package/client/dist/assets/{settings-C2_QJA8f2.js → settings-TNga5gIF2.js} +0 -0
  506. /package/client/dist/assets/{settings-BJ6fj67y2.js → settings-lFoaYT-s2.js} +0 -0
  507. /package/client/dist/assets/{shell-Csnb9Yqd.js → shell-YOaE4udl.js} +0 -0
  508. /package/client/dist/assets/{solidity-Dbw5-0QP.js → solidity-l3jSyVLu.js} +0 -0
  509. /package/client/dist/assets/{sophia-ZQ3saZQx.js → sophia-BhSGTaQJ.js} +0 -0
  510. /package/client/dist/assets/{sparql-BEtOel8u.js → sparql-qhk6QD9w.js} +0 -0
  511. /package/client/dist/assets/{sql-DGPDbzB7.js → sql-DoO3y21-.js} +0 -0
  512. /package/client/dist/assets/{st-GeW2MOgh.js → st-ChZAY8oG.js} +0 -0
  513. /package/client/dist/assets/{swift-BVYTN8jq.js → swift-D290Tr7_.js} +0 -0
  514. /package/client/dist/assets/{systemverilog-Deg2a8Lr.js → systemverilog-DsxzgJ-o.js} +0 -0
  515. /package/client/dist/assets/{tcl-6DnLmROF.js → tcl-BKDUHAAR.js} +0 -0
  516. /package/client/dist/assets/{terminal-CDiOAmBd2.js → terminal-BRm03iFA2.js} +0 -0
  517. /package/client/dist/assets/{terminal-CJN-mQMc.js → terminal-De2Brd23.js} +0 -0
  518. /package/client/dist/assets/{terminal-CYB4TiAd.js → terminal-DxQWCqSD2.js} +0 -0
  519. /package/client/dist/assets/{terminal-DsaDTq5N2.js → terminal-WSAvHXoU.js} +0 -0
  520. /package/client/dist/assets/{terminal-DTQ_dPqi2.js → terminal-Z7KsDM_n.js} +0 -0
  521. /package/client/dist/assets/{terminal-58ReNaya.js → terminal-cqfd3EDV.js} +0 -0
  522. /package/client/dist/assets/{terminal-DawP8xNL.js → terminal-xGbCZJHg.js} +0 -0
  523. /package/client/dist/assets/{tickets-DoRTUYRT.js → tickets-B7zT4IRf.js} +0 -0
  524. /package/client/dist/assets/{tickets-DBfFePwk2.js → tickets-BoXom7l8.js} +0 -0
  525. /package/client/dist/assets/{tickets-DvohTziT2.js → tickets-C3b8cHhd2.js} +0 -0
  526. /package/client/dist/assets/{tickets-Da15iaRw.js → tickets-CFXnJsYF.js} +0 -0
  527. /package/client/dist/assets/{tickets-CujsZvkf.js → tickets-CWYFvx1W2.js} +0 -0
  528. /package/client/dist/assets/{tickets-Df6pee-O2.js → tickets-DTHo9c3C.js} +0 -0
  529. /package/client/dist/assets/{tickets-CNvIilmP.js → tickets-SuX_HkK4.js} +0 -0
  530. /package/client/dist/assets/{twig-XbbXW9Yz.js → twig-UpZQaM8G.js} +0 -0
  531. /package/client/dist/assets/{typespec-CRlV8GhI.js → typespec-DzaKvN8i.js} +0 -0
  532. /package/client/dist/assets/{vb-BHE2izPH.js → vb-CZpbb7tk.js} +0 -0
  533. /package/client/dist/assets/{wgsl-Bf5vkfmY.js → wgsl-CNt3OIvl.js} +0 -0
@@ -0,0 +1,175 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.ACTIVE_PR_DECISIONS = exports.TERMINAL_PR_DECISIONS = void 0;
4
+ exports.isTerminalPrDecision = isTerminalPrDecision;
5
+ exports.createPrDelivery = createPrDelivery;
6
+ exports.getPrDelivery = getPrDelivery;
7
+ exports.getActivePrDeliveryByRail = getActivePrDeliveryByRail;
8
+ exports.listActivePrDeliveries = listActivePrDeliveries;
9
+ exports.transitionDecision = transitionDecision;
10
+ exports.toPrDeliverySnapshot = toPrDeliverySnapshot;
11
+ exports.toRailPrStateMessage = toRailPrStateMessage;
12
+ exports.toPrDecisionCardEnvelope = toPrDecisionCardEnvelope;
13
+ const ids_1 = require("./ids");
14
+ /** States after which the delivery is closed (no further decision possible). */
15
+ exports.TERMINAL_PR_DECISIONS = new Set(['merged', 'discarded']);
16
+ /** States in which the delivery still awaits (or is executing) a user decision. */
17
+ exports.ACTIVE_PR_DECISIONS = new Set([
18
+ 'building',
19
+ 'on_review',
20
+ 'pr_draft',
21
+ 'pr_ready',
22
+ 'pr_failed',
23
+ ]);
24
+ function isTerminalPrDecision(s) {
25
+ return exports.TERMINAL_PR_DECISIONS.has(s);
26
+ }
27
+ /**
28
+ * Insert a new delivery row for a rail launch. The row starts at
29
+ * decision='building', pr_state='none' with empty branches/worktree_ids —
30
+ * settle patches those via transitionDecision.
31
+ */
32
+ function createPrDelivery(db, input) {
33
+ const id = input.id ?? (0, ids_1.newId)();
34
+ db.prepare(`INSERT INTO rail_pr_deliveries (
35
+ id, rail_index, loop_id, rail_key, ticket_ids, base_branch,
36
+ loop_name, origin_surface, origin_conversation_id
37
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`).run(id, input.railIndex, input.loopId ?? null, input.railKey, JSON.stringify(input.ticketIds), input.baseBranch, input.loopName, input.originSurface, input.originConversationId ?? null);
38
+ return getPrDelivery(db, id);
39
+ }
40
+ function getPrDelivery(db, id) {
41
+ return db.prepare('SELECT * FROM rail_pr_deliveries WHERE id = ?').get(id);
42
+ }
43
+ /**
44
+ * The newest non-terminal delivery for a rail slot (a slot can be relaunched;
45
+ * older terminal rows are history). Used by the relaunch-collision guard and
46
+ * the GET /rails snapshot.
47
+ */
48
+ function getActivePrDeliveryByRail(db, railIndex) {
49
+ return db
50
+ .prepare(`SELECT * FROM rail_pr_deliveries
51
+ WHERE rail_index = ? AND decision NOT IN ('merged','discarded')
52
+ ORDER BY created_at DESC, rowid DESC LIMIT 1`)
53
+ .get(railIndex);
54
+ }
55
+ /** Every non-terminal delivery — hydrates the GET /rails prDeliveries snapshot. */
56
+ function listActivePrDeliveries(db) {
57
+ return db
58
+ .prepare(`SELECT * FROM rail_pr_deliveries
59
+ WHERE decision NOT IN ('merged','discarded')
60
+ ORDER BY rail_index, created_at DESC, rowid DESC`)
61
+ .all();
62
+ }
63
+ // Column allow-list — patch keys are interpolated into the SET clause, so gate
64
+ // them to prevent any future caller injecting SQL via an object key (values
65
+ // are always parameterized). Mirrors loop-runs-store's COUNTER_COLUMNS.
66
+ const PATCH_COLUMNS = {
67
+ branch: 'branch',
68
+ prUrl: 'pr_url',
69
+ prNumber: 'pr_number',
70
+ prState: 'pr_state',
71
+ branches: 'branches',
72
+ worktreeIds: 'worktree_ids',
73
+ runIds: 'run_ids',
74
+ };
75
+ function patchValue(key, patch) {
76
+ const raw = patch[key];
77
+ if (key === 'branches' || key === 'worktreeIds' || key === 'runIds')
78
+ return JSON.stringify(raw);
79
+ return raw;
80
+ }
81
+ /**
82
+ * COMPARE-AND-SET decision transition: one atomic
83
+ * `UPDATE … WHERE id = ? AND decision = ?` (no read-modify-write), so two
84
+ * surfaces racing on the same delivery cannot both win. Returns `false` (row
85
+ * untouched) when `expected` is stale — the caller maps that to a 409.
86
+ * `patch` may set delivery columns alongside the transition; `updated_at` is
87
+ * always bumped.
88
+ */
89
+ function transitionDecision(db, id, expected, next, patch = {}) {
90
+ const keys = Object.keys(patch).filter((k) => patch[k] !== undefined);
91
+ const patchClause = keys.map((k) => `, ${PATCH_COLUMNS[k]} = ?`).join('');
92
+ const values = keys.map((k) => patchValue(k, patch));
93
+ return (db
94
+ .prepare(`UPDATE rail_pr_deliveries
95
+ SET decision = ?, updated_at = datetime('now')${patchClause}
96
+ WHERE id = ? AND decision = ?`)
97
+ .run(next, ...values, id, expected).changes > 0);
98
+ }
99
+ function parseJsonArray(raw) {
100
+ try {
101
+ const parsed = JSON.parse(raw);
102
+ return Array.isArray(parsed) ? parsed : [];
103
+ }
104
+ catch {
105
+ return [];
106
+ }
107
+ }
108
+ function toPrDeliverySnapshot(row) {
109
+ return {
110
+ id: row.id,
111
+ railIndex: row.rail_index,
112
+ loopId: row.loop_id,
113
+ railKey: row.rail_key,
114
+ ticketIds: parseJsonArray(row.ticket_ids),
115
+ baseBranch: row.base_branch,
116
+ branch: row.branch,
117
+ prUrl: row.pr_url,
118
+ prNumber: row.pr_number,
119
+ prState: row.pr_state,
120
+ decision: row.decision,
121
+ branches: parseJsonArray(row.branches),
122
+ loopName: row.loop_name,
123
+ worktreeIds: parseJsonArray(row.worktree_ids),
124
+ runIds: parseJsonArray(row.run_ids ?? '[]'),
125
+ originSurface: row.origin_surface,
126
+ originConversationId: row.origin_conversation_id,
127
+ createdAt: row.created_at,
128
+ updatedAt: row.updated_at,
129
+ };
130
+ }
131
+ /**
132
+ * Build the durable `rail.pr_state` broadcast payload from a delivery snapshot
133
+ * — the ONE message shape every mutation of the row re-broadcasts (launch
134
+ * insert, build-settle, decision-endpoint transitions), so both decision
135
+ * surfaces converge on the same state.
136
+ */
137
+ function toRailPrStateMessage(projectId, snap) {
138
+ return {
139
+ type: 'rail.pr_state',
140
+ projectId,
141
+ railIndex: snap.railIndex,
142
+ prDeliveryId: snap.id,
143
+ railKey: snap.railKey,
144
+ ticketIds: snap.ticketIds,
145
+ baseBranch: snap.baseBranch,
146
+ branch: snap.branch,
147
+ prUrl: snap.prUrl,
148
+ prNumber: snap.prNumber,
149
+ prState: snap.prState,
150
+ decision: snap.decision,
151
+ runIds: snap.runIds,
152
+ originConversationId: snap.originConversationId,
153
+ };
154
+ }
155
+ /**
156
+ * Build the agent-chat PR-decision card envelope from a delivery snapshot —
157
+ * the ONE mapper both card writers (rail-isolated-launch's origin-card sync
158
+ * and rail-pr-decision's finalizeTransition) share, so the persisted card and
159
+ * the `agent_pr_decision` broadcast can never drift between the two sites.
160
+ */
161
+ function toPrDecisionCardEnvelope(projectId, snap) {
162
+ return {
163
+ kind: 'pr_decision',
164
+ prDeliveryId: snap.id,
165
+ railIndex: snap.railIndex,
166
+ projectId,
167
+ baseBranch: snap.baseBranch,
168
+ ticketIds: snap.ticketIds,
169
+ decision: snap.decision,
170
+ prUrl: snap.prUrl,
171
+ prState: snap.prState,
172
+ branch: snap.branch,
173
+ runIds: snap.runIds,
174
+ };
175
+ }
@@ -9,6 +9,8 @@ exports.setRailWorktreeRunId = setRailWorktreeRunId;
9
9
  exports.listRailWorktrees = listRailWorktrees;
10
10
  exports.listNonTerminalRailWorktrees = listNonTerminalRailWorktrees;
11
11
  exports.deleteRailWorktree = deleteRailWorktree;
12
+ exports.listRailWorktreesForTicket = listRailWorktreesForTicket;
13
+ exports.railWorktreeBranchExistsForTicket = railWorktreeBranchExistsForTicket;
12
14
  /** States after which the worktree is done (eligible for cleanup/reconciliation). */
13
15
  exports.TERMINAL_MERGE_STATES = new Set(['merged', 'needs-review', 'failed']);
14
16
  function isTerminalMergeState(s) {
@@ -50,3 +52,19 @@ function listNonTerminalRailWorktrees(db) {
50
52
  function deleteRailWorktree(db, id) {
51
53
  return db.prepare('DELETE FROM rail_worktrees WHERE id = ?').run(id).changes > 0;
52
54
  }
55
+ /** Every rail allocation ever made for a ticket, newest first — the recovery
56
+ * input for create-pr's pre-flight: when a delivery row records a branch that
57
+ * no longer exists, any OTHER branch a rail allocated for the same ticket that
58
+ * still exists with commits ahead of base is the real carrier of the work. */
59
+ function listRailWorktreesForTicket(db, ticketId) {
60
+ return db
61
+ .prepare('SELECT * FROM rail_worktrees WHERE ticket_id = ? ORDER BY created_at DESC, rowid DESC')
62
+ .all(ticketId);
63
+ }
64
+ /** True when a prior rail allocation for this ticket used exactly this branch —
65
+ * i.e. an existing branch of that name is OURS to resume (partial work from a
66
+ * stopped run), not a foreign collision to suffix away from. */
67
+ function railWorktreeBranchExistsForTicket(db, ticketId, branch) {
68
+ return (db.prepare('SELECT 1 FROM rail_worktrees WHERE ticket_id = ? AND branch = ? LIMIT 1').get(ticketId, branch) !==
69
+ undefined);
70
+ }
@@ -6,6 +6,8 @@ const rails_store_1 = require("./rails-store");
6
6
  const queue_manager_1 = require("./queue-manager");
7
7
  const provider_selection_1 = require("./provider-selection");
8
8
  const feature_flags_1 = require("./feature-flags");
9
+ const file_provenance_1 = require("./file-provenance");
10
+ const file_story_1 = require("./file-story");
9
11
  const loops_store_1 = require("./loops-store");
10
12
  const loop_runs_store_1 = require("./loop-runs-store");
11
13
  const providers_1 = require("./providers");
@@ -16,7 +18,9 @@ const loop_constants_1 = require("./loop-constants");
16
18
  const loop_command_catalog_1 = require("./loop-command-catalog");
17
19
  const loop_graph_1 = require("./loop-graph");
18
20
  const rail_isolation_1 = require("./rail-isolation");
21
+ const rail_pr_store_1 = require("./rail-pr-store");
19
22
  const loop_effect_1 = require("./loop-effect");
23
+ const rail_pr_decision_1 = require("./rail-pr-decision");
20
24
  const rail_isolated_launch_1 = require("./rail-isolated-launch");
21
25
  const worktree_manager_1 = require("./worktree-manager");
22
26
  const pr_publisher_1 = require("./pr-publisher");
@@ -87,17 +91,103 @@ function createRailsRouter() {
87
91
  const counts = (0, loop_runs_store_1.getRunEventCounts)(c.db, run.id);
88
92
  activeLoopRuns[run.rail_index] = { loopRunId: run.id, loopId: run.loop_id, loopName: run.loop_name, provider: run.provider, model: run.model, iteration: run.iteration_count, startedAt: run.started_at, steps: counts.steps, lines: counts.lines };
89
93
  }
90
- res.json({ rails, activeJobs, activeLoopRuns });
94
+ // Pending ask-first PR decisions (safe-pr-review-flow): the newest ACTIVE
95
+ // (non-terminal) delivery per rail slot, so a refreshed client re-renders
96
+ // the decision surface without waiting for a broadcast. The store lists
97
+ // newest-first within each rail — keep the first per index.
98
+ const prDeliveries = {};
99
+ for (const row of (0, rail_pr_store_1.listActivePrDeliveries)(c.db)) {
100
+ if (!(row.rail_index in prDeliveries))
101
+ prDeliveries[row.rail_index] = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
102
+ }
103
+ res.json({ rails, activeJobs, activeLoopRuns, prDeliveries });
91
104
  }
92
105
  catch (err) {
93
106
  console.error('[rails-router] get rails error:', err);
94
107
  res.status(500).json({ error: 'Failed to fetch rails' });
95
108
  }
96
109
  });
110
+ // POST /rails — create a new rail slot (dynamic rails). Body: { name? }.
111
+ // Allocates the lowest free index; capped at MAX_RAILS per project so the
112
+ // railIndex-keyed maps (metrics, PR deliveries, worktree progress) stay
113
+ // bounded. Broadcast rides the existing rail.updated shape (changed:'name')
114
+ // so every client — including the mobile companion — adopts the new slot
115
+ // without a new wire message.
116
+ router.post('/', (req, res) => {
117
+ const c = ctx(req);
118
+ const body = req.body ?? {};
119
+ const name = body.name;
120
+ if (name !== undefined && name !== null && typeof name !== 'string') {
121
+ res.status(400).json({ error: 'name must be a string or null' });
122
+ return;
123
+ }
124
+ if (typeof name === 'string' && name.length > 60) {
125
+ res.status(400).json({ error: 'name must be 60 characters or fewer' });
126
+ return;
127
+ }
128
+ try {
129
+ if ((0, rails_store_1.railCount)(c.db) >= rails_store_1.MAX_RAILS) {
130
+ res.status(400).json({ error: 'rail_limit_reached', maxRails: rails_store_1.MAX_RAILS });
131
+ return;
132
+ }
133
+ const rail = (0, rails_store_1.createRail)(c.db, typeof name === 'string' ? name : null);
134
+ broadcastRailUpdated(c, rail.railIndex, 'name');
135
+ res.status(201).json({ rail });
136
+ }
137
+ catch (err) {
138
+ console.error('[rails-router] create rail error:', err);
139
+ res.status(500).json({ error: 'Failed to create rail' });
140
+ }
141
+ });
142
+ // DELETE /rails/:railIndex — remove a rail slot. Guarded: the rail must
143
+ // exist, hold no tickets, have no active job/loop run, no undecided PR
144
+ // delivery, and must not be the last remaining rail. Indices are identity —
145
+ // deleting a middle rail leaves a gap (never re-numbered).
146
+ router.delete('/:railIndex', (req, res) => {
147
+ const railIndex = parseInt(req.params.railIndex, 10);
148
+ if (isNaN(railIndex) || railIndex < 0 || railIndex >= rails_store_1.MAX_RAILS) {
149
+ res.status(400).json({ error: 'Invalid rail index' });
150
+ return;
151
+ }
152
+ const c = ctx(req);
153
+ try {
154
+ if (!(0, rails_store_1.railExists)(c.db, railIndex)) {
155
+ res.status(404).json({ error: 'Rail not found' });
156
+ return;
157
+ }
158
+ if ((0, rails_store_1.railCount)(c.db) <= 1) {
159
+ res.status(400).json({ error: 'cannot_delete_last_rail' });
160
+ return;
161
+ }
162
+ const hasActiveJob = Array.from(c.railJobs.values()).some((m) => m.railIndex === railIndex);
163
+ const hasActiveRun = Array.from(c.railLoopRuns.values()).some((m) => m.railIndex === railIndex);
164
+ if (hasActiveJob || hasActiveRun) {
165
+ res.status(409).json({ error: 'rail_active' });
166
+ return;
167
+ }
168
+ if ((0, rails_store_1.getRail)(c.db, railIndex).ticketIds.length > 0) {
169
+ res.status(409).json({ error: 'rail_not_empty' });
170
+ return;
171
+ }
172
+ const pending = (0, rail_pr_store_1.getActivePrDeliveryByRail)(c.db, railIndex);
173
+ if (pending) {
174
+ res.status(409).json({ error: 'pr_decision_pending', prDeliveryId: pending.id });
175
+ return;
176
+ }
177
+ (0, rails_store_1.deleteRail)(c.db, railIndex);
178
+ const msg = { type: 'rail.removed', projectId: c.project.id, railIndex };
179
+ c.broadcast(msg);
180
+ res.json({ ok: true, railIndex });
181
+ }
182
+ catch (err) {
183
+ console.error('[rails-router] delete rail error:', err);
184
+ res.status(500).json({ error: 'Failed to delete rail' });
185
+ }
186
+ });
97
187
  // PUT /rails/:railIndex/tickets — set ticket assignments for a rail
98
188
  router.put('/:railIndex/tickets', (req, res) => {
99
189
  const railIndex = parseInt(req.params.railIndex, 10);
100
- if (isNaN(railIndex) || railIndex < 0) {
190
+ if (isNaN(railIndex) || railIndex < 0 || railIndex >= rails_store_1.MAX_RAILS) {
101
191
  res.status(400).json({ error: 'Invalid rail index' });
102
192
  return;
103
193
  }
@@ -132,7 +222,7 @@ function createRailsRouter() {
132
222
  // Body: { profileName: string | null } (null = force legacy mode for this rail)
133
223
  router.put('/:railIndex/profile', (req, res) => {
134
224
  const railIndex = parseInt(req.params.railIndex, 10);
135
- if (isNaN(railIndex) || railIndex < 0) {
225
+ if (isNaN(railIndex) || railIndex < 0 || railIndex >= rails_store_1.MAX_RAILS) {
136
226
  res.status(400).json({ error: 'Invalid rail index' });
137
227
  return;
138
228
  }
@@ -161,7 +251,7 @@ function createRailsRouter() {
161
251
  // Body: { aiEngine: string | null } (null = use the project's primary provider)
162
252
  router.put('/:railIndex/engine', (req, res) => {
163
253
  const railIndex = parseInt(req.params.railIndex, 10);
164
- if (isNaN(railIndex) || railIndex < 0) {
254
+ if (isNaN(railIndex) || railIndex < 0 || railIndex >= rails_store_1.MAX_RAILS) {
165
255
  res.status(400).json({ error: 'Invalid rail index' });
166
256
  return;
167
257
  }
@@ -194,7 +284,7 @@ function createRailsRouter() {
194
284
  // Body: { name: string | null } (empty/null clears it back to the default label)
195
285
  router.put('/:railIndex/name', (req, res) => {
196
286
  const railIndex = parseInt(req.params.railIndex, 10);
197
- if (isNaN(railIndex) || railIndex < 0) {
287
+ if (isNaN(railIndex) || railIndex < 0 || railIndex >= rails_store_1.MAX_RAILS) {
198
288
  res.status(400).json({ error: 'Invalid rail index' });
199
289
  return;
200
290
  }
@@ -227,16 +317,29 @@ function createRailsRouter() {
227
317
  // POST /rails/:railIndex/launch — launch job(s) for a rail
228
318
  router.post('/:railIndex/launch', async (req, res) => {
229
319
  const railIndex = parseInt(req.params.railIndex, 10);
230
- if (isNaN(railIndex) || railIndex < 0) {
320
+ if (isNaN(railIndex) || railIndex < 0 || railIndex >= rails_store_1.MAX_RAILS) {
231
321
  res.status(400).json({ error: 'Invalid rail index' });
232
322
  return;
233
323
  }
234
324
  let { mode = 'implement' } = req.body ?? {};
235
- const { profileName, aiEngine, model, loopId, reasoning_effort } = req.body ?? {};
325
+ const { profileName, aiEngine, model, loopId: rawLoopId, reasoning_effort, originConversationId, originSurface } = req.body ?? {};
326
+ let loopId = rawLoopId;
327
+ // Origin link (safe-pr-review-flow): an agent-chat/MCP launch tags itself so
328
+ // the PR decision can later be posted back into the launching conversation.
329
+ // Both fields are optional; malformed values are rejected outright.
330
+ if (originConversationId !== undefined && originConversationId !== null) {
331
+ if (typeof originConversationId !== 'string' || !/^[A-Za-z0-9-]{1,64}$/.test(originConversationId)) {
332
+ res.status(400).json({ error: 'originConversationId must be 1-64 chars of [A-Za-z0-9-]' });
333
+ return;
334
+ }
335
+ }
336
+ if (originSurface !== undefined && originSurface !== 'dashboard' && originSurface !== 'agent-chat') {
337
+ res.status(400).json({ error: "originSurface must be 'dashboard' or 'agent-chat'" });
338
+ return;
339
+ }
236
340
  // rails-as-loops: a FACTORY loop id (`factory:implement` etc.) maps to its
237
- // legacy mode and runs through the EXISTING engine (QueueManager) — the rail
238
- // "picks a Loop", the plumbing is unchanged. A CUSTOM loop id keeps mode='loop'
239
- // (LoopRunManager). Legacy callers that still send a bare `mode` are unchanged.
341
+ // legacy mode for validation/back-compat; the loop branch below still runs
342
+ // it through the LoopRunManager. A CUSTOM loop id keeps mode='loop'.
240
343
  if (typeof loopId === 'string' && (0, loop_factory_1.isFactoryLoopId)(loopId)) {
241
344
  const fmode = (0, loop_factory_1.factoryLoopMode)(loopId);
242
345
  if (!fmode) {
@@ -249,6 +352,15 @@ function createRailsRouter() {
249
352
  res.status(400).json({ error: 'mode must be "implement", "batch-implement", "ultracode" or "loop"' });
250
353
  return;
251
354
  }
355
+ // A bare legacy mode (MCP tools, mobile, direct REST — no loopId) must run
356
+ // through the SAME factory loop the dashboard sends, so worktree isolation
357
+ // and the ask-first PR flow apply identically regardless of the launch door.
358
+ // Without this, an agent-launched implement lands in the bare QueueManager
359
+ // branch: shared cwd, SPECRAILS_GIT_AUTO=false, no delivery row — stranded
360
+ // uncommitted work. Loops off ⇒ legacy QueueManager path, unchanged.
361
+ if ((0, feature_flags_1.isLoopsEnabled)() && (typeof loopId !== 'string' || !loopId) && mode !== 'loop') {
362
+ loopId = (0, loop_factory_1.factoryLoopForMode)(mode)?.id;
363
+ }
252
364
  if (mode === 'loop' && !(0, feature_flags_1.isLoopsEnabled)()) {
253
365
  res.status(403).json({ error: 'Loops are disabled on this server' });
254
366
  return;
@@ -261,8 +373,9 @@ function createRailsRouter() {
261
373
  return;
262
374
  }
263
375
  }
264
- // Interactive in-job chat is ON by default for every Freestyle (ultracode)
265
- // job whenever the feature is enabled — the per-rail toggle is gone. A
376
+ // Interactive in-job chat is ON by default for EVERY claude job — the
377
+ // spawn-time gate in QueueManager (kill-switch + persistent-stdin
378
+ // capability) decides, so the launch no longer passes an explicit flag. A
266
379
  // legacy `interactive` body param is accepted and ignored (wire compat).
267
380
  const c = ctx(req);
268
381
  const rail = (0, rails_store_1.getRail)(c.db, railIndex);
@@ -270,6 +383,24 @@ function createRailsRouter() {
270
383
  res.status(400).json({ error: 'Rail has no tickets assigned' });
271
384
  return;
272
385
  }
386
+ // Concurrent-launch safety (parallel rails): a ticket already worked by an
387
+ // ACTIVE run — this rail relaunched mid-run, or the same ticket sitting on
388
+ // two rails — must not spawn a second concurrent writer. The per-ticket
389
+ // worktree path is keyed by ticketId, so a duplicate launch would silently
390
+ // reuse (and corrupt) the in-flight run's checkout. 409 so Launch-all and
391
+ // agent-driven fan-outs surface a clean per-rail skip instead of a clash.
392
+ const inFlightTickets = new Set();
393
+ for (const meta of c.railJobs.values())
394
+ for (const id of meta.ticketIds)
395
+ inFlightTickets.add(id);
396
+ for (const meta of c.railLoopRuns.values())
397
+ for (const id of meta.ticketIds)
398
+ inFlightTickets.add(id);
399
+ const inFlightOverlap = rail.ticketIds.filter((id) => inFlightTickets.has(id));
400
+ if (inFlightOverlap.length > 0) {
401
+ res.status(409).json({ error: 'tickets_in_flight', ticketIds: inFlightOverlap });
402
+ return;
403
+ }
273
404
  // AI engine precedence: explicit body param > stored rail engine > primary.
274
405
  // `undefined`/empty in both means "run on the project's primary provider".
275
406
  const requestedEngine = aiEngine === undefined ? (rail.aiEngine ?? undefined) : aiEngine;
@@ -386,6 +517,17 @@ function createRailsRouter() {
386
517
  // so it is not isolated; anything that can write is.
387
518
  const loopReadOnly = (0, loop_effect_1.classifyLoopEffect)(loopGraph) === 'read-only';
388
519
  if ((0, rail_isolation_1.isolationApplies)({ loopsEnabled: (0, feature_flags_1.isLoopsEnabled)(), scope, ticketCount: rail.ticketIds.length, readOnly: loopReadOnly })) {
520
+ // Relaunch collision (ask-first PR delivery): a still-undecided
521
+ // delivery on this slot references the slot's ticket branches, and a
522
+ // relaunch would append new commits to them (createWorktree resumes
523
+ // existing branches). Block until the user resolves or discards it.
524
+ if ((0, rail_isolation_1.isRailPrDeliveryEnabled)()) {
525
+ const pending = (0, rail_pr_store_1.getActivePrDeliveryByRail)(c.db, railIndex);
526
+ if (pending) {
527
+ res.status(409).json({ error: 'pr_decision_pending', prDeliveryId: pending.id });
528
+ return;
529
+ }
530
+ }
389
531
  // Worktree isolation needs a git repo WITH at least one commit (an
390
532
  // unborn HEAD can't be branched). Fall back (with a message) otherwise.
391
533
  const status = await (0, worktree_manager_1.repoIsolationStatus)(worktree_manager_1.defaultGitRunner, c.project.path);
@@ -397,7 +539,9 @@ function createRailsRouter() {
397
539
  try {
398
540
  const ids = await (0, rail_isolated_launch_1.launchIsolatedRail)({
399
541
  ctx: c, railIndex, ticketIds: [...rail.ticketIds], loopId, loopName, loopGraph,
400
- provider: loopProvider, model: loopModel, effort,
542
+ provider: loopProvider, model: loopModel, effort, scope,
543
+ originSurface: originSurface ?? 'dashboard',
544
+ originConversationId: originConversationId ?? null,
401
545
  });
402
546
  res.status(202).json({ loopRunIds: ids, railIndex, mode, isolated: true });
403
547
  return;
@@ -415,6 +559,36 @@ function createRailsRouter() {
415
559
  const loopRunIds = [];
416
560
  const launchLoopRun = (runId, ticketIds, spec) => {
417
561
  c.railLoopRuns.set(runId, { railIndex, ticketIds });
562
+ // Code-Explorer provenance for shared-cwd loop runs (isolated runs
563
+ // record inside rail-isolated-launch): snapshot the REPO before the
564
+ // run, diff + record at settle. Loop runs settle outside QueueManager,
565
+ // so without this they leave no file_provenance at all. Best-effort;
566
+ // diffs the repo (never the workspace) exactly like QueueManager.
567
+ const provenanceRepoDir = loopExec.relocated && loopExec.repoDir ? loopExec.repoDir : loopExec.cwd;
568
+ let provenanceSnapshot = null;
569
+ if ((0, feature_flags_1.isCodeExplorerEnabled)()) {
570
+ try {
571
+ provenanceSnapshot = (0, file_provenance_1.snapshotWorkingTree)(provenanceRepoDir);
572
+ }
573
+ catch (err) {
574
+ console.warn(`[rails-router] provenance snapshot failed: ${err.message}`);
575
+ }
576
+ }
577
+ let provenanceRecorded = false;
578
+ const recordRunProvenance = () => {
579
+ if (provenanceRecorded)
580
+ return;
581
+ provenanceRecorded = true;
582
+ (0, file_story_1.recordLoopRunProvenance)({
583
+ db: c.db,
584
+ projectId: c.project.id,
585
+ runId,
586
+ ticketId: ticketIds[0] ?? null,
587
+ repoDir: provenanceRepoDir,
588
+ snapshot: provenanceSnapshot,
589
+ broadcast: (msg) => c.broadcast(msg),
590
+ });
591
+ };
418
592
  c.loopRunManager
419
593
  .run({
420
594
  runId,
@@ -432,9 +606,13 @@ function createRailsRouter() {
432
606
  model: loopModel,
433
607
  effort,
434
608
  })
435
- .then((r) => c.onLoopRunFinished(r.runId, r.outcome))
609
+ .then((r) => {
610
+ recordRunProvenance();
611
+ c.onLoopRunFinished(r.runId, r.outcome);
612
+ })
436
613
  .catch((err) => {
437
614
  console.error('[rails-router] loop run failed:', err);
615
+ recordRunProvenance();
438
616
  c.onLoopRunFinished(runId, 'failed');
439
617
  });
440
618
  loopRunIds.push(runId);
@@ -481,7 +659,9 @@ function createRailsRouter() {
481
659
  profileName: null,
482
660
  provider: 'claude',
483
661
  ...(ultracodeModel ? { model: ultracodeModel } : {}),
484
- ...((0, feature_flags_1.isInteractiveJobsEnabled)() ? { interactive: true } : {}),
662
+ // No explicit `interactive` — QueueManager's spawn-time default
663
+ // (kill-switch + persistent-stdin capability) covers it, and the
664
+ // decision survives a restart that way.
485
665
  });
486
666
  jobIds.push(job.id);
487
667
  c.railJobs.set(job.id, { railIndex, mode, ticketIds: [ticketId] });
@@ -544,7 +724,7 @@ function createRailsRouter() {
544
724
  // POST /rails/:railIndex/stop — kill the running job for a rail
545
725
  router.post('/:railIndex/stop', (req, res) => {
546
726
  const railIndex = parseInt(req.params.railIndex, 10);
547
- if (isNaN(railIndex) || railIndex < 0) {
727
+ if (isNaN(railIndex) || railIndex < 0 || railIndex >= rails_store_1.MAX_RAILS) {
548
728
  res.status(400).json({ error: 'Invalid rail index' });
549
729
  return;
550
730
  }
@@ -607,35 +787,42 @@ function createRailsRouter() {
607
787
  }
608
788
  res.json({ ok: true, jobIds: targetJobIds, loopRunIds: targetLoopRunIds, canceled: canceledCount });
609
789
  });
610
- // POST /rails/pr-review — the product builder's Approve / Discard action on a
611
- // draft PR a rail delivered (safe-pr-workflow). Approve promotes the draft to
612
- // ready-for-review (hands off to the engineer's GitHub review); Discard closes
613
- // it and drops the branch. specrails never merges — the engineer owns the merge.
614
- router.post('/pr-review', async (req, res) => {
790
+ // POST /rails/pr-decision — the ONE decision action (safe-pr-review-flow) both
791
+ // surfaces (dashboard rail row + agent-chat card) call on a rail_pr_deliveries
792
+ // row: create-pr | publish | discard | poll-merge, compare-and-set-guarded by
793
+ // expectedDecision (a raced concurrent answer loses with 409 stale_decision).
794
+ // Replaces the stateless v1 POST /rails/pr-review passthrough. The route only
795
+ // validates and delegates — the action logic lives in rail-pr-decision.ts.
796
+ // specrails never merges — the engineer owns the merge.
797
+ router.post('/pr-decision', async (req, res) => {
615
798
  const c = ctx(req);
616
- const prUrl = (req.body ?? {}).prUrl;
617
- const action = (req.body ?? {}).action;
618
- if (typeof prUrl !== 'string' || !/^https?:\/\/[^\s]+\/pull\/\d+$/.test(prUrl)) {
619
- res.status(400).json({ error: 'prUrl must be a valid pull-request URL' });
799
+ const { prDeliveryId, action, expectedDecision } = req.body ?? {};
800
+ if (typeof prDeliveryId !== 'string' || !prDeliveryId) {
801
+ res.status(400).json({ error: 'prDeliveryId is required' });
620
802
  return;
621
803
  }
622
- if (action !== 'ready' && action !== 'discard') {
623
- res.status(400).json({ error: "action must be 'ready' or 'discard'" });
804
+ if (!(0, rail_pr_decision_1.isPrDecisionAction)(action)) {
805
+ res.status(400).json({ error: "action must be 'create-pr', 'publish', 'discard' or 'poll-merge'" });
806
+ return;
807
+ }
808
+ if (typeof expectedDecision !== 'string' || !expectedDecision) {
809
+ res.status(400).json({ error: 'expectedDecision is required' });
624
810
  return;
625
811
  }
626
- const args = action === 'ready'
627
- ? ['pr', 'ready', prUrl]
628
- : ['pr', 'close', prUrl, '--delete-branch'];
629
812
  try {
630
- const r = await pr_publisher_1.defaultExec.run('gh', args, c.project.path);
631
- if (r.code !== 0) {
632
- res.status(502).json({ error: `gh pr ${action} failed`, detail: (r.stderr.trim() || r.stdout.trim()).split('\n')[0] || `exit ${r.code}` });
633
- return;
634
- }
635
- res.json({ ok: true, action });
813
+ const result = await (0, rail_pr_decision_1.executePrDecision)({
814
+ db: c.db,
815
+ project: { id: c.project.id, slug: c.project.slug, path: c.project.path },
816
+ git: worktree_manager_1.defaultGitRunner,
817
+ exec: pr_publisher_1.defaultExec,
818
+ broadcast: c.broadcast,
819
+ jiraSyncManager: c.jiraSyncManager,
820
+ }, { prDeliveryId, action, expectedDecision });
821
+ res.status(result.status).json(result.body);
636
822
  }
637
823
  catch (err) {
638
- res.status(500).json({ error: 'pr-review failed', detail: err.message });
824
+ console.error('[rails-router] pr-decision error:', err);
825
+ res.status(500).json({ error: 'pr-decision failed', detail: err.message });
639
826
  }
640
827
  });
641
828
  return router;