specrails-desktop 2.36.0 → 2.42.2

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 (510) hide show
  1. package/README.md +94 -247
  2. package/client/dist/assets/ActivityFeedPage-DoEMumQS.js +1 -0
  3. package/client/dist/assets/AgentBrowserCapture-DIh4K0gh.js +1 -0
  4. package/client/dist/assets/AgentModeAnalyticsPane-mbq4WEoO.js +2 -0
  5. package/client/dist/assets/AgentModeCodePane-CKh7zuA4.js +2 -0
  6. package/client/dist/assets/AgentModeJobsPane-BDokPiLJ.js +1 -0
  7. package/client/dist/assets/AgentsPage-BFVAZbBj.js +87 -0
  8. package/client/dist/assets/AnalyticsPage-3Y9LuWwz.js +1 -0
  9. package/client/dist/assets/CodePage-C9KyuV_C.js +3 -0
  10. package/client/dist/assets/DesktopAnalyticsPage-Bhi54bXQ.js +1 -0
  11. package/client/dist/assets/{DocsDialog-C76VdBJC.js → DocsDialog-Dj6mt4ga.js} +2 -2
  12. package/client/dist/assets/{DocsPage-ziMlj6B6.js → DocsPage-24yWglNI.js} +1 -1
  13. package/client/dist/assets/ExportDropdown-ophapHrT.js +1 -0
  14. package/client/dist/assets/InteractiveJobComposer-C1ucmxQh.js +19 -0
  15. package/client/dist/assets/JobDetailModal-DNWmgVHD.js +1 -0
  16. package/client/dist/assets/JobDetailPage-BcajZyuu.js +1 -0
  17. package/client/dist/assets/JobsPage-B9nTZw6e.js +1 -0
  18. package/client/dist/assets/LoopBuilderPage-Oc48iOFW.js +7 -0
  19. package/client/dist/assets/LoopPreviewModal-ae0Fr6SU.js +1 -0
  20. package/client/dist/assets/LoopsPage-CUEqzUBI.js +1 -0
  21. package/client/dist/assets/MinimizedChatsContext-Deg39peL.js +1 -0
  22. package/client/dist/assets/PluginsPage-C1xtARIx.js +2 -0
  23. package/client/dist/assets/ProjectSettingsDialog-JZzrXFBN.js +1 -0
  24. package/client/dist/assets/RepositoryDeliveries-CSDsiVUz.js +5 -0
  25. package/client/dist/assets/RepositoryScopeSelector-D-RCaknl.js +1 -0
  26. package/client/dist/assets/ReviewPacketPage-x5EfGTiL.js +1 -0
  27. package/client/dist/assets/TemplatePreviewModal-BSyuZxGq.js +1 -0
  28. package/client/dist/assets/TicketDetailModalContext-DqyF0so-.js +14 -0
  29. package/client/dist/assets/Trans-SnMX4MhW.js +1 -0
  30. package/client/dist/assets/agent-BdT0SB1D.js +1 -0
  31. package/client/dist/assets/agent-Bh9K7iEt.js +1 -0
  32. package/client/dist/assets/agent-C4ibdFk9.js +1 -0
  33. package/client/dist/assets/agent-CSFY22Zo.js +1 -0
  34. package/client/dist/assets/agent-DAnqxUn8.js +1 -0
  35. package/client/dist/assets/agent-DTQiu0Mi.js +1 -0
  36. package/client/dist/assets/agent-T54WuR_Y.js +1 -0
  37. package/client/dist/assets/agent-i75WDZOA.js +1 -0
  38. package/client/dist/assets/browser-05vRDg_y.js +1 -0
  39. package/client/dist/assets/browser-Bulb-cB1.js +1 -0
  40. package/client/dist/assets/browser-C7f-Jsg1.js +1 -0
  41. package/client/dist/assets/browser-CG0PE1j_.js +1 -0
  42. package/client/dist/assets/browser-CMzaqAjo.js +1 -0
  43. package/client/dist/assets/browser-DMajYdNX.js +1 -0
  44. package/client/dist/assets/browser-DxcOHrdP.js +1 -0
  45. package/client/dist/assets/browser-ObE7xVo3.js +1 -0
  46. package/client/dist/assets/builder-765NeYTp.js +1 -0
  47. package/client/dist/assets/builder-8MG3V6ea.js +1 -0
  48. package/client/dist/assets/builder-B-1UBs5K.js +1 -0
  49. package/client/dist/assets/builder-BTiGnPT0.js +1 -0
  50. package/client/dist/assets/builder-Cx9Rz-7u.js +1 -0
  51. package/client/dist/assets/builder-DKFMELBl.js +1 -0
  52. package/client/dist/assets/builder-OcmKrC0h.js +1 -0
  53. package/client/dist/assets/builder-P9qVBXFZ.js +1 -0
  54. package/client/dist/assets/{button-CJqFnUOL.js → button-DCBqEaZl.js} +1 -1
  55. package/client/dist/assets/{code-CkUuW4m9.js → code-B37GRg9C.js} +1 -1
  56. package/client/dist/assets/{code-B0O8-p8k.js → code-BBOEZbf9.js} +1 -1
  57. package/client/dist/assets/{code-B1VLZDhS.js → code-BRm-jcyx.js} +1 -1
  58. package/client/dist/assets/{code-Bpj4Ddml.js → code-CF7w62CR.js} +1 -1
  59. package/client/dist/assets/{code-BykBZ5-e.js → code-CLuvJt2r.js} +1 -1
  60. package/client/dist/assets/{code-B86IMAfz.js → code-D0RCm59f.js} +1 -1
  61. package/client/dist/assets/code-DaZ-ZwCT.js +1 -0
  62. package/client/dist/assets/{code-cAqaqMTx.js → code-iIHkGaCL.js} +1 -1
  63. package/client/dist/assets/commands-0XjAftla.js +1 -0
  64. package/client/dist/assets/commands-BAWSYHjQ.js +1 -0
  65. package/client/dist/assets/commands-BBwowgiE.js +1 -0
  66. package/client/dist/assets/commands-BacjIZLN.js +1 -0
  67. package/client/dist/assets/commands-Bs62IAZ3.js +1 -0
  68. package/client/dist/assets/commands-CLPdh-Hh.js +1 -0
  69. package/client/dist/assets/commands-DlbFzgrp.js +1 -0
  70. package/client/dist/assets/commands-LjPSsi5F.js +1 -0
  71. package/client/dist/assets/common-B5AZNYMH.js +1 -0
  72. package/client/dist/assets/common-BFZ0c_vN.js +1 -0
  73. package/client/dist/assets/common-BrlwEnL7.js +1 -0
  74. package/client/dist/assets/common-BttQx3z4.js +1 -0
  75. package/client/dist/assets/common-CM65k_-e.js +1 -0
  76. package/client/dist/assets/common-D4mvFFlu.js +1 -0
  77. package/client/dist/assets/common-TZ9Ny96S.js +1 -0
  78. package/client/dist/assets/common-nFpSF4GC.js +1 -0
  79. package/client/dist/assets/dashboard-B14uYXkG.js +1 -0
  80. package/client/dist/assets/dashboard-BK_mez-z.js +1 -0
  81. package/client/dist/assets/dashboard-BfBir_6o.js +1 -0
  82. package/client/dist/assets/dashboard-Bt0cCzeG.js +1 -0
  83. package/client/dist/assets/dashboard-BwkjxI6H.js +1 -0
  84. package/client/dist/assets/{dashboard-C8WOEiPu.js → dashboard-C3bDKf7s.js} +1 -1
  85. package/client/dist/assets/dashboard-CdvjGfog.js +1 -0
  86. package/client/dist/assets/dashboard-fRrP0Kv0.js +1 -0
  87. package/client/dist/assets/dialog-SRw01_QU.js +45 -0
  88. package/client/dist/assets/dist-js-CJ_2XX1Y.js +1 -0
  89. package/client/dist/assets/formatDistanceToNow-DSj5DprF.js +1 -0
  90. package/client/dist/assets/getTimezoneOffsetInMilliseconds-YhD8rIEs.js +1 -0
  91. package/client/dist/assets/index-DwAmL7m5.css +2 -0
  92. package/client/dist/assets/index-EzrkUb8B.js +76 -0
  93. package/client/dist/assets/{jira-api-B1-MUehg.js → jira-api-CSCqGr-Q.js} +1 -1
  94. package/client/dist/assets/{jobs-CN_zv4Gr.js → jobs-B8rrzfyZ.js} +1 -1
  95. package/client/dist/assets/{jobs-DUlWSYq2.js → jobs-BS6RTurf.js} +1 -1
  96. package/client/dist/assets/{jobs-Bpks6doU.js → jobs-BTT0Bsks.js} +1 -1
  97. package/client/dist/assets/{jobs-Bgq-PZkC.js → jobs-CezU69AE.js} +1 -1
  98. package/client/dist/assets/{jobs-SwYS2M-B.js → jobs-ClFJae0s.js} +1 -1
  99. package/client/dist/assets/{jobs-BAls3bWq.js → jobs-DJSFIFVy.js} +1 -1
  100. package/client/dist/assets/{jobs-DhxKgWFq.js → jobs-DhgGr8vm.js} +1 -1
  101. package/client/dist/assets/{jobs-B_TeSQxb.js → jobs-DzMjUcaN.js} +1 -1
  102. package/client/dist/assets/mcp-6rMoZfEO.js +1 -0
  103. package/client/dist/assets/mcp-BD8sL5mP.js +1 -0
  104. package/client/dist/assets/mcp-BkcA3I5s.js +1 -0
  105. package/client/dist/assets/mcp-CCpSelOh.js +1 -0
  106. package/client/dist/assets/mcp-CUAN6ORK.js +1 -0
  107. package/client/dist/assets/mcp-CqbRxRTE.js +1 -0
  108. package/client/dist/assets/mcp-DP2YfVhO.js +1 -0
  109. package/client/dist/assets/mcp-DUVQamDz.js +1 -0
  110. package/client/dist/assets/narration-B-ynWTpn.js +1 -0
  111. package/client/dist/assets/narration-Bj_laZwg.js +1 -0
  112. package/client/dist/assets/narration-BxHpmMv_.js +1 -0
  113. package/client/dist/assets/narration-C1Px0-0j.js +1 -0
  114. package/client/dist/assets/narration-CAXhGbzM.js +1 -0
  115. package/client/dist/assets/narration-DQ1l_Kq6.js +1 -0
  116. package/client/dist/assets/narration-XISXwqZd.js +1 -0
  117. package/client/dist/assets/narration-kwzfglQo.js +1 -0
  118. package/client/dist/assets/nav-1-Hh2kOz.js +1 -0
  119. package/client/dist/assets/nav-B34QkESm.js +1 -0
  120. package/client/dist/assets/nav-Bap_UXAq.js +1 -0
  121. package/client/dist/assets/{nav-pYuXq7sf.js → nav-BwxXIB24.js} +1 -1
  122. package/client/dist/assets/nav-Ch-zHBG5.js +1 -0
  123. package/client/dist/assets/nav-CygC_WN-.js +1 -0
  124. package/client/dist/assets/{nav-iwjCg5FR.js → nav-KnnLQtOQ.js} +1 -1
  125. package/client/dist/assets/nav-m00uxYUG.js +1 -0
  126. package/client/dist/assets/packet-BQ2tXfJI.js +1 -0
  127. package/client/dist/assets/packet-BdpOJ1Cy.js +1 -0
  128. package/client/dist/assets/packet-C3Ievb9R.js +1 -0
  129. package/client/dist/assets/packet-C4zJIG0Y.js +1 -0
  130. package/client/dist/assets/packet-Cx-zRuWn.js +1 -0
  131. package/client/dist/assets/packet-DUTGX52M.js +1 -0
  132. package/client/dist/assets/packet-DhsKtUPB.js +1 -0
  133. package/client/dist/assets/packet-z3LJ8Zyy.js +1 -0
  134. package/client/dist/assets/project-repositories-DYhTvwQ1.js +1 -0
  135. package/client/dist/assets/provider-capabilities-B-wOHfLP.js +1 -0
  136. package/client/dist/assets/settings-BBt2xtDQ.js +1 -0
  137. package/client/dist/assets/settings-BJB9RKJj.js +1 -0
  138. package/client/dist/assets/settings-CHwQR2rB.js +1 -0
  139. package/client/dist/assets/settings-CrMi3kSi.js +1 -0
  140. package/client/dist/assets/settings-DKyhDGD1.js +1 -0
  141. package/client/dist/assets/settings-Deupji9c.js +1 -0
  142. package/client/dist/assets/settings-DqRMmwAM.js +1 -0
  143. package/client/dist/assets/settings-J4rj6vo-.js +1 -0
  144. package/client/dist/assets/setup-2xGgu4Sk.js +1 -0
  145. package/client/dist/assets/setup-Ba11l2JA.js +1 -0
  146. package/client/dist/assets/setup-BzW4kMok.js +1 -0
  147. package/client/dist/assets/setup-COzwYhkJ.js +1 -0
  148. package/client/dist/assets/setup-CRVULhtF.js +1 -0
  149. package/client/dist/assets/setup-DgvlxwpE.js +1 -0
  150. package/client/dist/assets/setup-Dw_wYeEY.js +1 -0
  151. package/client/dist/assets/setup-ZPtEeJPW.js +1 -0
  152. package/client/dist/assets/spending-BqbdPm_4.js +1 -0
  153. package/client/dist/assets/square-Ci-PFcFe.js +1 -0
  154. package/client/dist/assets/{terminal-BFRZnMPP.js → terminal-BAzpHtpY.js} +1 -1
  155. package/client/dist/assets/{terminal-IahE4LW9.js → terminal-C7dHeR3x.js} +1 -1
  156. package/client/dist/assets/{terminal-tITa81iz.js → terminal-CMla5Qsz.js} +1 -1
  157. package/client/dist/assets/{terminal-BZiIu3rf.js → terminal-CdNXH-n9.js} +1 -1
  158. package/client/dist/assets/{terminal-ScjyXNxQ.js → terminal-Cw5bZsmV.js} +1 -1
  159. package/client/dist/assets/{terminal-C2NAd7BW.js → terminal-DFUP4eNv.js} +1 -1
  160. package/client/dist/assets/{terminal-d7GadXbN.js → terminal-DGqljeK_.js} +1 -1
  161. package/client/dist/assets/{terminal-QpXZU2Bn.js → terminal-cU70NodO.js} +1 -1
  162. package/client/dist/assets/useDesktop-RSMTyy7V.js +1 -0
  163. package/client/dist/assets/useSharedWebSocket-BOdS5_Iz.js +2 -0
  164. package/client/dist/index.html +34 -35
  165. package/docs/README.md +3 -0
  166. package/docs/agent-live-steering.md +57 -0
  167. package/docs/ci-cd.md +57 -0
  168. package/docs/code-explorer.md +48 -0
  169. package/docs/codex.md +12 -1
  170. package/docs/features/detachable-mission-windows.md +59 -0
  171. package/docs/guide/de/integrations/5-mcp-server.md +13 -9
  172. package/docs/guide/de/integrations/6-agent-chat.md +1 -0
  173. package/docs/guide/en/integrations/5-mcp-server.md +13 -9
  174. package/docs/guide/en/integrations/6-agent-chat.md +1 -0
  175. package/docs/guide/es/integrations/5-mcp-server.md +13 -9
  176. package/docs/guide/es/integrations/6-agent-chat.md +1 -0
  177. package/docs/guide/fr/integrations/5-mcp-server.md +13 -9
  178. package/docs/guide/fr/integrations/6-agent-chat.md +1 -0
  179. package/docs/guide/it/integrations/5-mcp-server.md +13 -9
  180. package/docs/guide/it/integrations/6-agent-chat.md +1 -0
  181. package/docs/guide/ja/integrations/5-mcp-server.md +13 -9
  182. package/docs/guide/ja/integrations/6-agent-chat.md +1 -0
  183. package/docs/guide/pt/integrations/5-mcp-server.md +13 -9
  184. package/docs/guide/pt/integrations/6-agent-chat.md +1 -0
  185. package/docs/guide/zh/integrations/5-mcp-server.md +13 -9
  186. package/docs/guide/zh/integrations/6-agent-chat.md +1 -0
  187. package/docs/internals/README.md +1 -0
  188. package/docs/internals/browser-capture-performance.md +55 -3
  189. package/docs/internals/browser-login-popups.md +45 -0
  190. package/docs/internals/browser-native-retina-audit.md +39 -0
  191. package/docs/internals/ci-cd-audit.md +39 -0
  192. package/docs/internals/core-runtime-updates.md +68 -0
  193. package/docs/internals/embedded-browser-native-webview-evaluation.md +2 -0
  194. package/docs/internals/implementation-reliability-audit.md +93 -0
  195. package/docs/internals/interactive-jobs.md +110 -6
  196. package/docs/internals/mcp-mission-audit.md +76 -0
  197. package/docs/internals/project-builder.md +404 -42
  198. package/docs/internals/safe-pr-review-flow.md +52 -10
  199. package/docs/internals/startup-recovery-audit.md +58 -0
  200. package/docs/mcp.md +74 -41
  201. package/docs/mission-processes.md +59 -0
  202. package/docs/multi-repo-projects.md +51 -0
  203. package/docs/platforms/windows-parity.md +70 -0
  204. package/docs/platforms/windows.md +13 -11
  205. package/docs/running-pipelines.md +14 -0
  206. package/mcp-bridge/dist/specrails-mcp.js +7186 -0
  207. package/package.json +9 -4
  208. package/server/dist/agent-chat-manager.js +537 -68
  209. package/server/dist/agent-chat-router.js +87 -6
  210. package/server/dist/agent-context-resolver.js +129 -25
  211. package/server/dist/agent-defaults.js +19 -11
  212. package/server/dist/agent-input-store.js +206 -0
  213. package/server/dist/agent-mcp-config.js +54 -15
  214. package/server/dist/agent-operator-prompt.js +255 -65
  215. package/server/dist/agent-spec-framing.js +202 -0
  216. package/server/dist/agent-steering.js +218 -0
  217. package/server/dist/agent-store.js +153 -0
  218. package/server/dist/api-not-found.js +8 -0
  219. package/server/dist/background-process-control.js +164 -0
  220. package/server/dist/background-process-service.js +61 -0
  221. package/server/dist/background-process-store.js +242 -0
  222. package/server/dist/background-windows-bootstrap.js +238 -0
  223. package/server/dist/blueprint-chat-manager.js +476 -62
  224. package/server/dist/blueprint-commit.js +21 -1
  225. package/server/dist/blueprint-draft-parser.js +122 -17
  226. package/server/dist/blueprint-generation.js +238 -0
  227. package/server/dist/blueprint-operator-prompt.js +91 -63
  228. package/server/dist/blueprint-router.js +55 -3
  229. package/server/dist/blueprint-spec-fixtures.js +85 -0
  230. package/server/dist/blueprint-spec-quality.js +57 -16
  231. package/server/dist/blueprint-store.js +92 -1
  232. package/server/dist/browser-capture-manager.js +86 -30
  233. package/server/dist/browser-playwright.js +168 -45
  234. package/server/dist/browser-viewport.js +26 -0
  235. package/server/dist/chat-manager.js +23 -15
  236. package/server/dist/chromium-archive.cjs +83 -0
  237. package/server/dist/chromium-resolver.js +72 -64
  238. package/server/dist/code-activity.js +145 -0
  239. package/server/dist/code-explorer-router.js +714 -114
  240. package/server/dist/core-compat.js +28 -1
  241. package/server/dist/core-execution.js +111 -0
  242. package/server/dist/core-package.js +4 -16
  243. package/server/dist/core-runtime.js +202 -0
  244. package/server/dist/core-update-manager.js +161 -60
  245. package/server/dist/core-update-state.js +29 -0
  246. package/server/dist/db.js +66 -35
  247. package/server/dist/delivery-evidence.js +142 -39
  248. package/server/dist/desktop-db.js +239 -43
  249. package/server/dist/desktop-router.js +109 -9
  250. package/server/dist/dev-ports.js +8 -3
  251. package/server/dist/file-provenance.js +34 -22
  252. package/server/dist/file-story-manager.js +62 -64
  253. package/server/dist/file-story.js +118 -35
  254. package/server/dist/file-summary-generator.js +46 -5
  255. package/server/dist/file-summary-manager.js +355 -106
  256. package/server/dist/framework-manager.js +98 -110
  257. package/server/dist/framework-reseed.js +76 -10
  258. package/server/dist/git-diagnostics.js +2 -2
  259. package/server/dist/headroom-manager.js +38 -3
  260. package/server/dist/host-control.js +52 -0
  261. package/server/dist/index.js +43 -2
  262. package/server/dist/interactive-job-session.js +149 -16
  263. package/server/dist/internal-api.js +48 -0
  264. package/server/dist/jira/jira-materializer.js +1 -0
  265. package/server/dist/json-tolerant.js +174 -0
  266. package/server/dist/legacy-migration.js +4 -2
  267. package/server/dist/loop-command-catalog.js +83 -21
  268. package/server/dist/loop-constants.js +6 -1
  269. package/server/dist/loop-decider.js +11 -1
  270. package/server/dist/loop-executors.js +194 -45
  271. package/server/dist/loop-factory.js +11 -4
  272. package/server/dist/loop-graph.js +90 -4
  273. package/server/dist/loop-run-manager.js +301 -69
  274. package/server/dist/loop-shell-invocation.js +21 -0
  275. package/server/dist/loop-step-idle.js +55 -0
  276. package/server/dist/loop-templates.js +31 -7
  277. package/server/dist/mcp/agent-capability.js +37 -4
  278. package/server/dist/mcp/guide.js +149 -36
  279. package/server/dist/mcp/mcp-admin-router.js +20 -4
  280. package/server/dist/mcp/mcp-server.js +89 -43
  281. package/server/dist/mcp/mcp-tiers.js +6 -5
  282. package/server/dist/mcp/mcp-token.js +3 -1
  283. package/server/dist/mcp/resources.js +5 -4
  284. package/server/dist/mcp/tools/catalog.js +4 -0
  285. package/server/dist/mcp/tools/code.js +125 -14
  286. package/server/dist/mcp/tools/context.js +153 -0
  287. package/server/dist/mcp/tools/git.js +15 -5
  288. package/server/dist/mcp/tools/jobs.js +84 -71
  289. package/server/dist/mcp/tools/loops.js +17 -6
  290. package/server/dist/mcp/tools/meta.js +74 -27
  291. package/server/dist/mcp/tools/mission.js +29 -0
  292. package/server/dist/mcp/tools/projects.js +22 -6
  293. package/server/dist/mcp/tools/rails.js +48 -11
  294. package/server/dist/mcp/tools/specs.js +86 -14
  295. package/server/dist/mcp/tools/support.js +1 -1
  296. package/server/dist/mcp/tools/types.js +117 -43
  297. package/server/dist/mcp/tools/watch.js +144 -51
  298. package/server/dist/milestone-chain-store.js +164 -0
  299. package/server/dist/milestone-chain.js +487 -0
  300. package/server/dist/milestone-progress.js +348 -0
  301. package/server/dist/mobile/mobile-devices.js +10 -7
  302. package/server/dist/mobile/mobile-gateway.js +2 -0
  303. package/server/dist/mobile/mobile-missions.js +214 -0
  304. package/server/dist/mobile/mobile-redact.js +17 -3
  305. package/server/dist/mobile/mobile-router.js +46 -4
  306. package/server/dist/mobile/mobile-ws.js +49 -4
  307. package/server/dist/multi-repo-bases.js +56 -0
  308. package/server/dist/multi-repo-checkout.js +101 -0
  309. package/server/dist/multi-repo-delivery.js +100 -0
  310. package/server/dist/multi-repo-execution-store.js +65 -0
  311. package/server/dist/multi-repo-execution.js +453 -0
  312. package/server/dist/offline-assemble.js +10 -8
  313. package/server/dist/openspec-runtime-plugin-commands.json +18 -0
  314. package/server/dist/openspec-runtime-plugin.js +120 -0
  315. package/server/dist/plugins/codex-spawn.js +49 -0
  316. package/server/dist/plugins/serena/manifest.js +2 -2
  317. package/server/dist/plugins/serena/templates/instructions.md +16 -0
  318. package/server/dist/pr-publisher.js +1 -1
  319. package/server/dist/profiles-router.js +3 -18
  320. package/server/dist/project-code-discovery.js +142 -0
  321. package/server/dist/project-git.js +19 -21
  322. package/server/dist/project-registry.js +272 -20
  323. package/server/dist/project-repositories.js +157 -0
  324. package/server/dist/project-repository-provenance.js +31 -0
  325. package/server/dist/project-router-background-processes.js +105 -0
  326. package/server/dist/project-router-git.js +75 -16
  327. package/server/dist/project-router-jobs.js +2 -126
  328. package/server/dist/project-router-loop-runs.js +72 -2
  329. package/server/dist/project-router-tickets.js +53 -8
  330. package/server/dist/project-router.js +239 -38
  331. package/server/dist/provider-detection.js +18 -6
  332. package/server/dist/provider-limit.js +64 -0
  333. package/server/dist/providers/claude-adapter.js +26 -1
  334. package/server/dist/providers/claude-background-tasks.js +18 -0
  335. package/server/dist/providers/claude-live-session.js +383 -0
  336. package/server/dist/providers/codex-adapter.js +19 -0
  337. package/server/dist/providers/codex-live-session.js +545 -0
  338. package/server/dist/providers/gemini-adapter.js +1 -0
  339. package/server/dist/providers/live-session-types.js +12 -0
  340. package/server/dist/providers/live-session.js +13 -0
  341. package/server/dist/providers/terminal-result.js +24 -0
  342. package/server/dist/queue-manager.js +2 -0
  343. package/server/dist/rail-isolated-launch.js +141 -16
  344. package/server/dist/rail-pr-decision.js +364 -99
  345. package/server/dist/rail-pr-store.js +24 -10
  346. package/server/dist/rail-worktree-release.js +34 -2
  347. package/server/dist/rail-worktrees-store.js +4 -4
  348. package/server/dist/rails-router.js +249 -55
  349. package/server/dist/repo-lock.js +92 -17
  350. package/server/dist/review-packet.js +23 -13
  351. package/server/dist/schemas/file-summary.v1.json +59 -59
  352. package/server/dist/schemas/profile.v1.json +137 -137
  353. package/server/dist/setup-manager.js +52 -8
  354. package/server/dist/shell-integration/bash-shim.bash +45 -0
  355. package/server/dist/shell-integration/fish-shim.fish +36 -0
  356. package/server/dist/shell-integration/powershell-shim.ps1 +48 -0
  357. package/server/dist/shell-integration/zsh-shim.zsh +47 -0
  358. package/server/dist/smash-runner.js +1 -0
  359. package/server/dist/spawn-lifecycle.js +44 -27
  360. package/server/dist/spec-contract-prompt.js +143 -0
  361. package/server/dist/spec-draft-parser.js +6 -1
  362. package/server/dist/spec-models.js +1 -0
  363. package/server/dist/stuck-run-detector.js +1 -0
  364. package/server/dist/terminal-manager.js +21 -1
  365. package/server/dist/terminal-shell-integration.js +4 -1
  366. package/server/dist/transient-children.js +619 -230
  367. package/server/dist/util/cli-prompt.js +78 -5
  368. package/server/dist/util/sqlite-migrations.js +20 -0
  369. package/server/dist/util/win-spawn.js +18 -3
  370. package/server/dist/util/windows-provider-shell.js +29 -0
  371. package/server/dist/verification-sentinel.js +14 -0
  372. package/server/dist/vitest-setup.js +2 -0
  373. package/server/dist/windows-job-supervisor.js +133 -0
  374. package/server/dist/workspace-manager.js +9 -30
  375. package/server/dist/worktree-manager.js +17 -2
  376. package/server/dist/worktree-overlay.js +3 -1
  377. package/client/dist/assets/ActivityFeedPage-tAQcWs1R.js +0 -1
  378. package/client/dist/assets/AgentBrowserCapture-BX8BNae5.js +0 -1
  379. package/client/dist/assets/AgentModeAnalyticsPane-BVAqCL0K.js +0 -2
  380. package/client/dist/assets/AgentModeCodePane-9XfqQc9c.js +0 -2
  381. package/client/dist/assets/AgentModeJobsPane-BCjLsPhc.js +0 -1
  382. package/client/dist/assets/AgentsPage-C8J_42sm.js +0 -87
  383. package/client/dist/assets/AnalyticsPage-BtQuyfJm.js +0 -1
  384. package/client/dist/assets/CodePage-BZ2MwdCu.js +0 -2
  385. package/client/dist/assets/DesktopAnalyticsPage-Bh_29V4g.js +0 -1
  386. package/client/dist/assets/ExportDropdown-BrtfWzEG.js +0 -1
  387. package/client/dist/assets/InteractiveJobComposer-BCZiSfzc.js +0 -19
  388. package/client/dist/assets/JobDetailModal-NAJmuYIT.js +0 -1
  389. package/client/dist/assets/JobDetailPage-fE0ZycUX.js +0 -1
  390. package/client/dist/assets/JobsPage-z5M_HVJG.js +0 -1
  391. package/client/dist/assets/LoopBuilderPage-j1FQS47c.js +0 -7
  392. package/client/dist/assets/LoopPreviewModal-DhDJjdCe.js +0 -1
  393. package/client/dist/assets/LoopsPage-Ll7zORZb.js +0 -1
  394. package/client/dist/assets/MinimizedChatsContext-Bd3OqR_S.js +0 -1
  395. package/client/dist/assets/PluginsPage-DN4kGvJt.js +0 -2
  396. package/client/dist/assets/ProjectSettingsDialog-OgsgxjzF.js +0 -1
  397. package/client/dist/assets/ReviewPacketPage-DFog4sXn.js +0 -1
  398. package/client/dist/assets/TemplatePreviewModal-L2XxqiOD.js +0 -1
  399. package/client/dist/assets/TicketDetailModal-CsF-AWZX.js +0 -14
  400. package/client/dist/assets/Trans-Bsz9_gyq.js +0 -1
  401. package/client/dist/assets/agent-BQgKv_2F.js +0 -1
  402. package/client/dist/assets/agent-C1NRDJqL.js +0 -1
  403. package/client/dist/assets/agent-CLNleiy6.js +0 -1
  404. package/client/dist/assets/agent-CmceArkQ.js +0 -1
  405. package/client/dist/assets/agent-D3UxQ3SR.js +0 -1
  406. package/client/dist/assets/agent-DB1JeE64.js +0 -1
  407. package/client/dist/assets/agent-DXkHcQ-D.js +0 -1
  408. package/client/dist/assets/agent-DjJJJ2M8.js +0 -1
  409. package/client/dist/assets/auth-D_5bQv5W.js +0 -1
  410. package/client/dist/assets/ban-E4EaZe3a.js +0 -1
  411. package/client/dist/assets/bot-DzuuuC5R.js +0 -1
  412. package/client/dist/assets/browser-BgqHDMXP.js +0 -1
  413. package/client/dist/assets/browser-CsKJtrpv.js +0 -1
  414. package/client/dist/assets/browser-Cu58EpZU.js +0 -1
  415. package/client/dist/assets/browser-CvXOJm-j.js +0 -1
  416. package/client/dist/assets/browser-DOrFh1c7.js +0 -1
  417. package/client/dist/assets/browser-DQv_Jo7x.js +0 -1
  418. package/client/dist/assets/browser-LPgxvJu2.js +0 -1
  419. package/client/dist/assets/browser-eL-3MIEI.js +0 -1
  420. package/client/dist/assets/builder-0IWtosUm.js +0 -1
  421. package/client/dist/assets/builder-Bf2N6XWn.js +0 -1
  422. package/client/dist/assets/builder-BnqaaBkT.js +0 -1
  423. package/client/dist/assets/builder-BxxfGgAO.js +0 -1
  424. package/client/dist/assets/builder-C5IIgWsq.js +0 -1
  425. package/client/dist/assets/builder-CHuahItu.js +0 -1
  426. package/client/dist/assets/builder-CjWosXL_.js +0 -1
  427. package/client/dist/assets/builder-CpCIOoKj.js +0 -1
  428. package/client/dist/assets/code-CHPkOkDS.js +0 -1
  429. package/client/dist/assets/commands-6tYQih5m.js +0 -1
  430. package/client/dist/assets/commands-BK2QinXN.js +0 -1
  431. package/client/dist/assets/commands-C2Nca76h.js +0 -1
  432. package/client/dist/assets/commands-CKdLihNX.js +0 -1
  433. package/client/dist/assets/commands-CYIBTAlc.js +0 -1
  434. package/client/dist/assets/commands-CjUtYJIM.js +0 -1
  435. package/client/dist/assets/commands-Cq_u_8y9.js +0 -1
  436. package/client/dist/assets/commands-D_ZHYQug.js +0 -1
  437. package/client/dist/assets/common-6MLbD-jM.js +0 -1
  438. package/client/dist/assets/common-BKGEu4rm.js +0 -1
  439. package/client/dist/assets/common-BNbnv8cE.js +0 -1
  440. package/client/dist/assets/common-BqGWtDbt.js +0 -1
  441. package/client/dist/assets/common-DBtTzeYm.js +0 -1
  442. package/client/dist/assets/common-DEW3Nr8n.js +0 -1
  443. package/client/dist/assets/common-DHsv9N5d.js +0 -1
  444. package/client/dist/assets/common-mkrEcW-Y.js +0 -1
  445. package/client/dist/assets/dashboard-B9GhC5ku.js +0 -1
  446. package/client/dist/assets/dashboard-CBnv6zOI.js +0 -1
  447. package/client/dist/assets/dashboard-CaP0fU87.js +0 -1
  448. package/client/dist/assets/dashboard-D4ZZ4x84.js +0 -1
  449. package/client/dist/assets/dashboard-DmuTQBX8.js +0 -1
  450. package/client/dist/assets/dashboard-DynLYj3d.js +0 -1
  451. package/client/dist/assets/dashboard-zj4gGFJ1.js +0 -1
  452. package/client/dist/assets/dialog-CdWCb02j.js +0 -45
  453. package/client/dist/assets/dist-bVqfYmby.js +0 -1
  454. package/client/dist/assets/dist-js-CWeUdf5Z.js +0 -1
  455. package/client/dist/assets/formatDistanceToNow-DQCvMgUc.js +0 -1
  456. package/client/dist/assets/getTimezoneOffsetInMilliseconds-C16cxSe1.js +0 -1
  457. package/client/dist/assets/git-refresh-wTW0rO0Z.js +0 -1
  458. package/client/dist/assets/i18n-hnX2DPmo.js +0 -2
  459. package/client/dist/assets/index-DIhMEAVw.js +0 -66
  460. package/client/dist/assets/index-DwygcU7s.css +0 -2
  461. package/client/dist/assets/mcp-B8X8wBLu.js +0 -1
  462. package/client/dist/assets/mcp-C2AojZZN.js +0 -1
  463. package/client/dist/assets/mcp-D8BT78_L.js +0 -1
  464. package/client/dist/assets/mcp-Df5RWBNk.js +0 -1
  465. package/client/dist/assets/mcp-Dj7BgMQW.js +0 -1
  466. package/client/dist/assets/mcp-Q7iT7rcz.js +0 -1
  467. package/client/dist/assets/mcp-YlvNvJbW.js +0 -1
  468. package/client/dist/assets/mcp-mKFpTSRb.js +0 -1
  469. package/client/dist/assets/narration-4Z2VUhZw.js +0 -1
  470. package/client/dist/assets/narration-BGuiEDj3.js +0 -1
  471. package/client/dist/assets/narration-BuSoqRmv.js +0 -1
  472. package/client/dist/assets/narration-CB9t29fy.js +0 -1
  473. package/client/dist/assets/narration-CU3x8FHD.js +0 -1
  474. package/client/dist/assets/narration-CWeXhfP5.js +0 -1
  475. package/client/dist/assets/narration-DRaDnhT5.js +0 -1
  476. package/client/dist/assets/narration-DtEbQgCw.js +0 -1
  477. package/client/dist/assets/nav-ApJVg3xu.js +0 -1
  478. package/client/dist/assets/nav-BKNky1Bg.js +0 -1
  479. package/client/dist/assets/nav-C6vWWKYx.js +0 -1
  480. package/client/dist/assets/nav-CXJ6Aw89.js +0 -1
  481. package/client/dist/assets/nav-CsmFBIDf.js +0 -1
  482. package/client/dist/assets/nav-DjkmQJjd.js +0 -1
  483. package/client/dist/assets/packet-B1IxaL5f.js +0 -1
  484. package/client/dist/assets/packet-Bh5kkbiB.js +0 -1
  485. package/client/dist/assets/packet-By8fqYxW.js +0 -1
  486. package/client/dist/assets/packet-CZdvA44E.js +0 -1
  487. package/client/dist/assets/packet-CrjHRQCP.js +0 -1
  488. package/client/dist/assets/packet-Dwi2pTtx.js +0 -1
  489. package/client/dist/assets/packet-_-ZIa0IR.js +0 -1
  490. package/client/dist/assets/packet-n0W6E1Hn.js +0 -1
  491. package/client/dist/assets/play-DNlrawbS.js +0 -1
  492. package/client/dist/assets/provider-capabilities-Doej9lfa.js +0 -1
  493. package/client/dist/assets/settings-Bd0x4TBa.js +0 -1
  494. package/client/dist/assets/settings-C1-7cXzC.js +0 -1
  495. package/client/dist/assets/settings-CAFaT38b.js +0 -1
  496. package/client/dist/assets/settings-Ct3v1nW2.js +0 -1
  497. package/client/dist/assets/settings-DHh7_IF5.js +0 -1
  498. package/client/dist/assets/settings-DQXAmdcv.js +0 -1
  499. package/client/dist/assets/settings-guzlhpup.js +0 -1
  500. package/client/dist/assets/settings-sZfTPMEH.js +0 -1
  501. package/client/dist/assets/setup-3jWaoVUO.js +0 -1
  502. package/client/dist/assets/setup-BjgRneb2.js +0 -1
  503. package/client/dist/assets/setup-BzFIjv-f.js +0 -1
  504. package/client/dist/assets/setup-C4VfQsxE.js +0 -1
  505. package/client/dist/assets/setup-DfUkpDbN.js +0 -1
  506. package/client/dist/assets/setup-ECe90Pmu.js +0 -1
  507. package/client/dist/assets/setup-dlqC4Jmm.js +0 -1
  508. package/client/dist/assets/setup-jwfLMiM2.js +0 -1
  509. package/client/dist/assets/spending-EC9xqio-.js +0 -1
  510. package/client/dist/assets/useDesktop-BQVt8lFd.js +0 -1
@@ -1,25 +1,100 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
14
+ Object.defineProperty(o, "default", { enumerable: true, value: v });
15
+ }) : function(o, v) {
16
+ o["default"] = v;
17
+ });
18
+ var __importStar = (this && this.__importStar) || (function () {
19
+ var ownKeys = function(o) {
20
+ ownKeys = Object.getOwnPropertyNames || function (o) {
21
+ var ar = [];
22
+ for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
23
+ return ar;
24
+ };
25
+ return ownKeys(o);
26
+ };
27
+ return function (mod) {
28
+ if (mod && mod.__esModule) return mod;
29
+ var result = {};
30
+ if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
31
+ __setModuleDefault(result, mod);
32
+ return result;
33
+ };
34
+ })();
2
35
  Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.repositoryLockKey = repositoryLockKey;
3
37
  exports.withRepoLock = withRepoLock;
38
+ exports.withRepoLocks = withRepoLocks;
4
39
  exports.__resetRepoLocks = __resetRepoLocks;
5
- /**
6
- * Process-local per-key async mutex. Serialises work for a given key by chaining:
7
- * a new call waits for the previous one on the same key before running. Used so
8
- * concurrent rail merge-backs never run `git merge`/`reset` on the SAME base repo
9
- * at the same time (two single-ticket rails launched together are concurrent
10
- * writers). Different keys run in parallel.
11
- */
40
+ const fs = __importStar(require("fs"));
41
+ const path = __importStar(require("path"));
12
42
  const chains = new Map();
13
- function withRepoLock(key, fn) {
14
- const prev = chains.get(key) ?? Promise.resolve();
15
- // Run after the previous holder settles (regardless of its outcome). The
16
- // caller still sees fn's own result/rejection.
17
- const run = prev.catch(() => undefined).then(() => fn());
18
- // Keep the chain alive but swallow errors so one failure never poisons the lock.
19
- chains.set(key, run.catch(() => undefined));
43
+ function canonicalPath(value) {
44
+ try {
45
+ return fs.realpathSync.native(value);
46
+ }
47
+ catch {
48
+ return path.resolve(value);
49
+ }
50
+ }
51
+ /** A worktree, symlink and main checkout share the same Git object/ref store.
52
+ * Resolve it on every admission: a moved checkout must not inherit a stale key. */
53
+ function repositoryLockKey(repositoryPath) {
54
+ if (!fs.existsSync(repositoryPath))
55
+ return canonicalPath(repositoryPath);
56
+ let current = canonicalPath(repositoryPath);
57
+ while (true) {
58
+ const dotGit = path.join(current, '.git');
59
+ try {
60
+ let gitDir = dotGit;
61
+ if (fs.statSync(dotGit).isFile()) {
62
+ const match = /^gitdir:\s*(.+)\s*$/m.exec(fs.readFileSync(dotGit, 'utf8'));
63
+ if (!match)
64
+ break;
65
+ gitDir = path.resolve(current, match[1].trim());
66
+ }
67
+ const commonFile = path.join(gitDir, 'commondir');
68
+ if (fs.existsSync(commonFile))
69
+ gitDir = path.resolve(gitDir, fs.readFileSync(commonFile, 'utf8').trim());
70
+ return canonicalPath(gitDir);
71
+ }
72
+ catch { /* walk upward for paths inside a checkout */ }
73
+ const parent = path.dirname(current);
74
+ if (parent === current)
75
+ break;
76
+ current = parent;
77
+ }
78
+ return canonicalPath(repositoryPath);
79
+ }
80
+ function withKeyLock(key, fn) {
81
+ const previous = chains.get(key) ?? Promise.resolve();
82
+ const run = previous.catch(() => undefined).then(fn);
83
+ const tail = run.then(() => undefined, () => undefined);
84
+ chains.set(key, tail);
85
+ void tail.then(() => { if (chains.get(key) === tail)
86
+ chains.delete(key); });
20
87
  return run;
21
88
  }
22
- /** Test helper: forget all chains (avoids cross-test leakage). */
23
- function __resetRepoLocks() {
24
- chains.clear();
89
+ /** Process-local mutex over the canonical Git common directory. */
90
+ function withRepoLock(repositoryPath, fn) {
91
+ return withKeyLock(repositoryLockKey(repositoryPath), fn);
92
+ }
93
+ /** Acquire each physical repository exactly once, in stable order. Callers must
94
+ * not re-enter withRepoLock from fn; compose effects under this one admission. */
95
+ function withRepoLocks(repositoryPaths, fn) {
96
+ const keys = [...new Set(repositoryPaths.map(repositoryLockKey))].sort();
97
+ const enter = (index) => index === keys.length ? Promise.resolve().then(fn) : withKeyLock(keys[index], () => enter(index + 1));
98
+ return enter(0);
25
99
  }
100
+ function __resetRepoLocks() { chains.clear(); }
@@ -9,23 +9,31 @@ const delivery_evidence_1 = require("./delivery-evidence");
9
9
  const rail_pr_store_1 = require("./rail-pr-store");
10
10
  const pr_body_1 = require("./pr-body");
11
11
  const ai_invocations_1 = require("./ai-invocations");
12
+ const project_repository_provenance_1 = require("./project-repository-provenance");
12
13
  const TEST_FILE_RE = /(\.test\.|\.spec\.|(^|\/)__tests__\/)/;
13
- function churnForRuns(db, runIds) {
14
+ function churnForRuns(db, runIds, repository) {
14
15
  const ids = [...new Set(runIds.filter((id) => typeof id === 'string' && id.length > 0))];
15
16
  if (ids.length === 0)
16
17
  return [];
17
18
  const placeholders = ids.map(() => '?').join(', ');
18
19
  try {
20
+ const scope = (0, project_repository_provenance_1.provenanceRepositoryFilter)(db, repository, 'p');
21
+ const hasRepository = db.prepare('PRAGMA table_info(file_provenance)').all().some(column => column.name === 'repository_id');
19
22
  return db.prepare(`
20
- SELECT job_id, file_path, added_lines, removed_lines
21
- FROM file_story_contributions
22
- WHERE job_id IN (${placeholders})
23
- `).all(...ids);
23
+ SELECT c.job_id, c.file_path, c.added_lines, c.removed_lines,
24
+ ${hasRepository ? 'p.repository_id' : 'NULL'} AS repository_id
25
+ FROM file_story_contributions c
26
+ LEFT JOIN file_provenance p ON p.id = c.provenance_id
27
+ WHERE c.job_id IN (${placeholders}) AND ${scope.sql}
28
+ `).all(...ids, ...scope.params);
24
29
  }
25
30
  catch {
26
31
  return [];
27
32
  }
28
33
  }
34
+ function churnIdentity(row) {
35
+ return JSON.stringify([row.repository_id ?? null, row.file_path]);
36
+ }
29
37
  /**
30
38
  * Variant selection reads ONLY durable outcomes. `no-changes` must win over
31
39
  * `success` (a run that changed nothing has nothing to show), and a mixed batch
@@ -57,8 +65,8 @@ exports.HUMAN_REVIEW_BAND = { min: 50, max: 69 };
57
65
  function buildProof(units, evidence, churn, confidence) {
58
66
  const proof = [];
59
67
  // ── Tier 1: what Specrails measured itself ────────────────────────────────
60
- const testFiles = [...new Set(churn.filter((row) => TEST_FILE_RE.test(row.file_path)).map((row) => row.file_path))];
61
- const totalFiles = new Set(churn.map((row) => row.file_path)).size;
68
+ const testFiles = [...new Set(churn.filter((row) => TEST_FILE_RE.test(row.file_path)).map(churnIdentity))];
69
+ const totalFiles = new Set(churn.map(churnIdentity)).size;
62
70
  const added = churn.reduce((sum, row) => sum + (row.added_lines || 0), 0);
63
71
  const removed = churn.reduce((sum, row) => sum + (row.removed_lines || 0), 0);
64
72
  if (totalFiles > 0) {
@@ -203,13 +211,14 @@ function computeDriftNudges(input) {
203
211
  }
204
212
  return nudges;
205
213
  }
206
- function composeReviewPacket({ db, row }) {
214
+ function composeReviewPacket({ db, row, repositoryId = row.repository_id ?? undefined, includeLegacyProvenance = false }) {
215
+ const repository = repositoryId ? { repositoryId, includeLegacy: includeLegacyProvenance } : undefined;
207
216
  const ticketIds = safeParse(row.ticket_ids, []);
208
217
  const units = safeParse(row.branches, []);
209
218
  const runIds = safeParse(row.run_ids, []);
210
219
  const snapshot = (0, rail_pr_store_1.readSpecSnapshot)(row.spec_snapshot);
211
220
  const evidence = (0, delivery_evidence_1.readSettleEvidence)(row.settle_evidence);
212
- const churn = churnForRuns(db, runIds);
221
+ const churn = churnForRuns(db, runIds, repository);
213
222
  const variant = selectVariant(row, units);
214
223
  const confidence = (evidence?.units ?? [])
215
224
  .map((unit) => unit.confidence)
@@ -236,10 +245,10 @@ function composeReviewPacket({ db, row }) {
236
245
  deliveryOutcome: unitRows[0]?.deliveryOutcome ?? null,
237
246
  changed: unitRows[0]?.changed ?? null,
238
247
  churn: unitChurn === null ? null : {
239
- filesTouched: new Set(unitChurn.map((c) => c.file_path)).size,
248
+ filesTouched: new Set(unitChurn.map(churnIdentity)).size,
240
249
  addedLines: unitChurn.reduce((sum, c) => sum + (c.added_lines || 0), 0),
241
250
  removedLines: unitChurn.reduce((sum, c) => sum + (c.removed_lines || 0), 0),
242
- testFilesTouched: [...new Set(unitChurn.filter((c) => TEST_FILE_RE.test(c.file_path)).map((c) => c.file_path))],
251
+ testFilesTouched: [...new Set(unitChurn.filter((c) => TEST_FILE_RE.test(c.file_path)).map((c) => !repositoryId && c.repository_id ? `${c.repository_id}:${c.file_path}` : c.file_path))],
243
252
  },
244
253
  runIds: unitRunIds,
245
254
  };
@@ -270,15 +279,16 @@ function composeReviewPacket({ db, row }) {
270
279
  // a revision touching mostly new files is the honest signal that the spec no
271
280
  // longer describes the work.
272
281
  const originalFiles = chain.length > 1
273
- ? new Set(churnForRuns(db, safeParse(chain[0].run_ids, [])).map((entry) => entry.file_path))
282
+ ? new Set(churnForRuns(db, safeParse(chain[0].run_ids, []), repository).map(churnIdentity))
274
283
  : new Set();
275
284
  const driftNudges = computeDriftNudges({
276
285
  versions,
277
286
  originalFileSet: originalFiles,
278
- currentFiles: new Set(churn.map((entry) => entry.file_path)),
287
+ currentFiles: new Set(churn.map(churnIdentity)),
279
288
  });
280
289
  return {
281
290
  schemaVersion: 1,
291
+ ...(repositoryId ? { repositoryId } : {}),
282
292
  prDeliveryId: row.id,
283
293
  railIndex: row.rail_index,
284
294
  variant,
@@ -1,62 +1,62 @@
1
1
  {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://raw.githubusercontent.com/fjpulidop/specrails-desktop/main/server/schemas/file-summary.v1.json",
4
- "title": "specrails-desktop file summary (v1)",
5
- "description": "On-disk JSON shape for an AI-generated file summary persisted under <project>/.specrails/file-summaries/<sha256-of-rel-path>.json.",
6
- "type": "object",
7
- "required": [
8
- "schemaVersion",
9
- "path",
10
- "fileHash",
11
- "summary",
12
- "language",
13
- "generatedAt",
14
- "generatedBy",
15
- "triggeredBy"
16
- ],
17
- "additionalProperties": false,
18
- "properties": {
19
- "schemaVersion": {
20
- "const": 1
21
- },
22
- "path": {
23
- "type": "string",
24
- "minLength": 1
25
- },
26
- "fileHash": {
27
- "type": "string",
28
- "pattern": "^[0-9a-f]{64}$"
29
- },
30
- "summary": {
31
- "type": "string"
32
- },
33
- "language": {
34
- "type": "string",
35
- "enum": ["en", "es"]
36
- },
37
- "generatedAt": {
38
- "type": "string",
39
- "format": "date-time"
40
- },
41
- "generatedBy": {
42
- "type": "object",
43
- "required": ["model", "promptVersion"],
44
- "additionalProperties": false,
45
- "properties": {
46
- "model": { "type": "string", "minLength": 1 },
47
- "promptVersion": { "const": 1 },
48
- "truncated": { "type": "boolean" }
49
- }
50
- },
51
- "triggeredBy": {
52
- "type": "object",
53
- "required": ["kind", "id", "ticketId"],
54
- "additionalProperties": false,
55
- "properties": {
56
- "kind": { "type": "string", "enum": ["job", "user"] },
57
- "id": { "type": "string", "minLength": 1 },
58
- "ticketId": { "type": ["integer", "null"] }
59
- }
60
- }
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/fjpulidop/specrails-desktop/main/server/schemas/file-summary.v1.json",
4
+ "title": "specrails-desktop file summary (v1)",
5
+ "description": "On-disk JSON shape for an AI-generated file summary persisted under <project>/.specrails/file-summaries/<sha256-of-rel-path>.json.",
6
+ "type": "object",
7
+ "required": [
8
+ "schemaVersion",
9
+ "path",
10
+ "fileHash",
11
+ "summary",
12
+ "language",
13
+ "generatedAt",
14
+ "generatedBy",
15
+ "triggeredBy"
16
+ ],
17
+ "additionalProperties": false,
18
+ "properties": {
19
+ "schemaVersion": {
20
+ "const": 1
21
+ },
22
+ "path": {
23
+ "type": "string",
24
+ "minLength": 1
25
+ },
26
+ "fileHash": {
27
+ "type": "string",
28
+ "pattern": "^[0-9a-f]{64}$"
29
+ },
30
+ "summary": {
31
+ "type": "string"
32
+ },
33
+ "language": {
34
+ "type": "string",
35
+ "enum": ["en", "es"]
36
+ },
37
+ "generatedAt": {
38
+ "type": "string",
39
+ "format": "date-time"
40
+ },
41
+ "generatedBy": {
42
+ "type": "object",
43
+ "required": ["model", "promptVersion"],
44
+ "additionalProperties": false,
45
+ "properties": {
46
+ "model": { "type": "string", "minLength": 1 },
47
+ "promptVersion": { "type": "integer", "minimum": 1 },
48
+ "truncated": { "type": "boolean" }
49
+ }
50
+ },
51
+ "triggeredBy": {
52
+ "type": "object",
53
+ "required": ["kind", "id", "ticketId"],
54
+ "additionalProperties": false,
55
+ "properties": {
56
+ "kind": { "type": "string", "enum": ["job", "user"] },
57
+ "id": { "type": "string", "minLength": 1 },
58
+ "ticketId": { "type": ["integer", "null"] }
59
+ }
61
60
  }
61
+ }
62
62
  }
@@ -1,150 +1,150 @@
1
1
  {
2
- "$schema": "https://json-schema.org/draft/2020-12/schema",
3
- "$id": "https://raw.githubusercontent.com/fjpulidop/specrails-desktop/main/server/schemas/profile.v1.json",
4
- "title": "specrails agent profile (v1)",
5
- "description": "Declarative configuration for the specrails implement pipeline. Describes which agents participate, which models they run with, and how tasks are routed to specialists. Consumed by `implement.md` and produced by tools like specrails-desktop. This is specrails-desktop's derivative of specrails-core's canonical v1 profile schema: it adds the optional top-level `provider` field and relaxes `modelAlias` to any non-empty string (provider-catalog validation happens in profile-manager.validateStructural). Per core's schema-identity contract, a diverging vendored copy must carry its own $id — only byte-identical copies may share the canonical core $id.",
6
- "type": "object",
7
- "required": ["schemaVersion", "name", "orchestrator", "agents", "routing"],
8
- "additionalProperties": false,
9
- "properties": {
10
- "schemaVersion": {
11
- "const": 1,
12
- "description": "Profile schema version. v1 is the only supported value at this time."
13
- },
14
- "name": {
15
- "type": "string",
16
- "pattern": "^[a-z0-9][a-z0-9-]*$",
17
- "minLength": 1,
18
- "maxLength": 64,
19
- "description": "Human-readable identifier for this profile (kebab-case)."
20
- },
21
- "description": {
22
- "type": "string",
23
- "maxLength": 512,
24
- "description": "Optional short summary of when to use this profile."
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://raw.githubusercontent.com/fjpulidop/specrails-desktop/main/server/schemas/profile.v1.json",
4
+ "title": "specrails agent profile (v1)",
5
+ "description": "Declarative configuration for the specrails implement pipeline. Describes which agents participate, which models they run with, and how tasks are routed to specialists. Consumed by `implement.md` and produced by tools like specrails-desktop. This is specrails-desktop's derivative of specrails-core's canonical v1 profile schema: it adds the optional top-level `provider` field and relaxes `modelAlias` to any non-empty string (provider-catalog validation happens in profile-manager.validateStructural). Per core's schema-identity contract, a diverging vendored copy must carry its own $id — only byte-identical copies may share the canonical core $id.",
6
+ "type": "object",
7
+ "required": ["schemaVersion", "name", "orchestrator", "agents", "routing"],
8
+ "additionalProperties": false,
9
+ "properties": {
10
+ "schemaVersion": {
11
+ "const": 1,
12
+ "description": "Profile schema version. v1 is the only supported value at this time."
13
+ },
14
+ "name": {
15
+ "type": "string",
16
+ "pattern": "^[a-z0-9][a-z0-9-]*$",
17
+ "minLength": 1,
18
+ "maxLength": 64,
19
+ "description": "Human-readable identifier for this profile (kebab-case)."
20
+ },
21
+ "description": {
22
+ "type": "string",
23
+ "maxLength": 512,
24
+ "description": "Optional short summary of when to use this profile."
25
+ },
26
+ "provider": {
27
+ "type": "string",
28
+ "pattern": "^[a-z0-9][a-z0-9-]*$",
29
+ "description": "Optional registered provider id (for example `claude`, `codex`, `gemini`, or `kimi`). When set, the profile's model values are validated according to that provider adapter: normally against its catalog, while adapters that support configured aliases (such as Kimi) accept any schema-valid non-empty alias. When omitted, validation falls back to the project's resolved provider."
30
+ },
31
+ "orchestrator": {
32
+ "type": "object",
33
+ "required": ["model"],
34
+ "additionalProperties": false,
35
+ "properties": {
36
+ "model": {
37
+ "$ref": "#/$defs/modelAlias",
38
+ "description": "Model used to run the top-level implement orchestrator. The JSON schema accepts any non-empty string; provider-specific validation runs at the structural-check layer (see profile-manager.validateStructural)."
39
+ }
40
+ }
41
+ },
42
+ "agents": {
43
+ "type": "array",
44
+ "minItems": 1,
45
+ "items": { "$ref": "#/$defs/agentEntry" },
46
+ "description": "Ordered chain of agents that participate in the pipeline when this profile is active. Every profile (default + custom) must include the baseline trio (sr-architect, sr-developer, sr-reviewer) — the pipeline depends on all three. Custom profiles add optional agents on top of the baseline. sr-merge-resolver is an optional utility agent and is no longer required.",
47
+ "allOf": [
48
+ {
49
+ "description": "Required baseline agent: sr-architect",
50
+ "contains": {
51
+ "type": "object",
52
+ "properties": { "id": { "const": "sr-architect" } },
53
+ "required": ["id"]
54
+ }
25
55
  },
26
- "provider": {
27
- "type": "string",
28
- "pattern": "^[a-z0-9][a-z0-9-]*$",
29
- "description": "Optional registered provider id (for example `claude`, `codex`, `gemini`, or `kimi`). When set, the profile's model values are validated according to that provider adapter: normally against its catalog, while adapters that support configured aliases (such as Kimi) accept any schema-valid non-empty alias. When omitted, validation falls back to the project's resolved provider."
56
+ {
57
+ "description": "Required baseline agent: sr-developer",
58
+ "contains": {
59
+ "type": "object",
60
+ "properties": { "id": { "const": "sr-developer" } },
61
+ "required": ["id"]
62
+ }
30
63
  },
31
- "orchestrator": {
64
+ {
65
+ "description": "Required baseline agent: sr-reviewer",
66
+ "contains": {
32
67
  "type": "object",
33
- "required": ["model"],
34
- "additionalProperties": false,
35
- "properties": {
36
- "model": {
37
- "$ref": "#/$defs/modelAlias",
38
- "description": "Model used to run the top-level implement orchestrator. The JSON schema accepts any non-empty string; provider-specific validation runs at the structural-check layer (see profile-manager.validateStructural)."
39
- }
40
- }
68
+ "properties": { "id": { "const": "sr-reviewer" } },
69
+ "required": ["id"]
70
+ }
71
+ }
72
+ ]
73
+ },
74
+ "routing": {
75
+ "type": "array",
76
+ "minItems": 0,
77
+ "description": "Ordered routing rules. The first rule whose `tags` intersects the task's tag set wins. If a `default: true` entry is present it MUST be the last element. Custom profiles may omit routing entirely — tasks then fall through to the first developer-shaped agent in the chain.",
78
+ "items": { "$ref": "#/$defs/routingRule" }
79
+ }
80
+ },
81
+ "$defs": {
82
+ "modelAlias": {
83
+ "type": "string",
84
+ "minLength": 1,
85
+ "description": "Accepted model alias. JSON schema accepts any non-empty string without truncating provider-configured aliases; provider-specific catalog enforcement runs at runtime (see profile-manager.validateStructural)."
86
+ },
87
+ "agentEntry": {
88
+ "type": "object",
89
+ "required": ["id"],
90
+ "additionalProperties": false,
91
+ "properties": {
92
+ "id": {
93
+ "type": "string",
94
+ "pattern": "^(sr|custom)-[a-z0-9][a-z0-9-]*$",
95
+ "description": "Agent identifier. MUST correspond to the selected provider's provider-native role artifact. File-based providers use their own agents catalog (for example `.claude/agents/<id>.md`); Kimi uses the directly discoverable `.kimi-code/skills/<id>/SKILL.md` layout."
41
96
  },
42
- "agents": {
43
- "type": "array",
44
- "minItems": 1,
45
- "items": { "$ref": "#/$defs/agentEntry" },
46
- "description": "Ordered chain of agents that participate in the pipeline when this profile is active. Every profile (default + custom) must include the baseline trio (sr-architect, sr-developer, sr-reviewer) — the pipeline depends on all three. Custom profiles add optional agents on top of the baseline. sr-merge-resolver is an optional utility agent and is no longer required.",
47
- "allOf": [
48
- {
49
- "description": "Required baseline agent: sr-architect",
50
- "contains": {
51
- "type": "object",
52
- "properties": { "id": { "const": "sr-architect" } },
53
- "required": ["id"]
54
- }
55
- },
56
- {
57
- "description": "Required baseline agent: sr-developer",
58
- "contains": {
59
- "type": "object",
60
- "properties": { "id": { "const": "sr-developer" } },
61
- "required": ["id"]
62
- }
63
- },
64
- {
65
- "description": "Required baseline agent: sr-reviewer",
66
- "contains": {
67
- "type": "object",
68
- "properties": { "id": { "const": "sr-reviewer" } },
69
- "required": ["id"]
70
- }
71
- }
72
- ]
97
+ "model": {
98
+ "$ref": "#/$defs/modelAlias",
99
+ "description": "Model override for this agent when this profile is active. When omitted, the agent's frontmatter `model:` is used as a fallback."
73
100
  },
74
- "routing": {
75
- "type": "array",
76
- "minItems": 0,
77
- "description": "Ordered routing rules. The first rule whose `tags` intersects the task's tag set wins. If a `default: true` entry is present it MUST be the last element. Custom profiles may omit routing entirely — tasks then fall through to the first developer-shaped agent in the chain.",
78
- "items": { "$ref": "#/$defs/routingRule" }
101
+ "required": {
102
+ "type": "boolean",
103
+ "default": false,
104
+ "description": "If true, the agent cannot be routed past. Baseline agents (sr-architect, sr-developer, sr-reviewer) SHOULD be marked required. sr-merge-resolver is optional and defaults to required: false."
79
105
  }
106
+ }
80
107
  },
81
- "$defs": {
82
- "modelAlias": {
83
- "type": "string",
84
- "minLength": 1,
85
- "description": "Accepted model alias. JSON schema accepts any non-empty string without truncating provider-configured aliases; provider-specific catalog enforcement runs at runtime (see profile-manager.validateStructural)."
86
- },
87
- "agentEntry": {
88
- "type": "object",
89
- "required": ["id"],
90
- "additionalProperties": false,
91
- "properties": {
92
- "id": {
93
- "type": "string",
94
- "pattern": "^(sr|custom)-[a-z0-9][a-z0-9-]*$",
95
- "description": "Agent identifier. MUST correspond to the selected provider's provider-native role artifact. File-based providers use their own agents catalog (for example `.claude/agents/<id>.md`); Kimi uses the directly discoverable `.kimi-code/skills/<id>/SKILL.md` layout."
96
- },
97
- "model": {
98
- "$ref": "#/$defs/modelAlias",
99
- "description": "Model override for this agent when this profile is active. When omitted, the agent's frontmatter `model:` is used as a fallback."
100
- },
101
- "required": {
102
- "type": "boolean",
103
- "default": false,
104
- "description": "If true, the agent cannot be routed past. Baseline agents (sr-architect, sr-developer, sr-reviewer) SHOULD be marked required. sr-merge-resolver is optional and defaults to required: false."
105
- }
108
+ "routingRule": {
109
+ "oneOf": [
110
+ {
111
+ "type": "object",
112
+ "required": ["tags", "agent"],
113
+ "additionalProperties": false,
114
+ "properties": {
115
+ "tags": {
116
+ "type": "array",
117
+ "minItems": 1,
118
+ "items": {
119
+ "type": "string",
120
+ "pattern": "^[a-z0-9][a-z0-9-]*$"
121
+ },
122
+ "description": "Task tags that trigger this rule. Rule wins if any tag intersects."
123
+ },
124
+ "agent": {
125
+ "type": "string",
126
+ "pattern": "^(sr|custom)-[a-z0-9][a-z0-9-]*$",
127
+ "description": "Agent to route the task to when this rule wins."
106
128
  }
129
+ }
107
130
  },
108
- "routingRule": {
109
- "oneOf": [
110
- {
111
- "type": "object",
112
- "required": ["tags", "agent"],
113
- "additionalProperties": false,
114
- "properties": {
115
- "tags": {
116
- "type": "array",
117
- "minItems": 1,
118
- "items": {
119
- "type": "string",
120
- "pattern": "^[a-z0-9][a-z0-9-]*$"
121
- },
122
- "description": "Task tags that trigger this rule. Rule wins if any tag intersects."
123
- },
124
- "agent": {
125
- "type": "string",
126
- "pattern": "^(sr|custom)-[a-z0-9][a-z0-9-]*$",
127
- "description": "Agent to route the task to when this rule wins."
128
- }
129
- }
130
- },
131
- {
132
- "type": "object",
133
- "required": ["default", "agent"],
134
- "additionalProperties": false,
135
- "properties": {
136
- "default": {
137
- "const": true,
138
- "description": "Marks this rule as the terminal catch-all. Exactly one entry with `default: true` is allowed, and it MUST be the last element of `routing`."
139
- },
140
- "agent": {
141
- "type": "string",
142
- "pattern": "^(sr|custom)-[a-z0-9][a-z0-9-]*$",
143
- "description": "Agent to route the task to when no earlier rule matched."
144
- }
145
- }
146
- }
147
- ]
131
+ {
132
+ "type": "object",
133
+ "required": ["default", "agent"],
134
+ "additionalProperties": false,
135
+ "properties": {
136
+ "default": {
137
+ "const": true,
138
+ "description": "Marks this rule as the terminal catch-all. Exactly one entry with `default: true` is allowed, and it MUST be the last element of `routing`."
139
+ },
140
+ "agent": {
141
+ "type": "string",
142
+ "pattern": "^(sr|custom)-[a-z0-9][a-z0-9-]*$",
143
+ "description": "Agent to route the task to when no earlier rule matched."
144
+ }
145
+ }
148
146
  }
147
+ ]
149
148
  }
149
+ }
150
150
  }