specrails-desktop 2.55.0 → 2.55.1

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 (360) hide show
  1. package/cli/dist/args.js +80 -0
  2. package/cli/dist/desktop-client.js +125 -0
  3. package/cli/dist/desktop-control.js +339 -0
  4. package/cli/dist/format.js +45 -0
  5. package/cli/dist/help.js +68 -0
  6. package/cli/dist/output.js +47 -0
  7. package/cli/dist/run-command.js +340 -0
  8. package/cli/dist/specrails-desktop.js +41 -1107
  9. package/cli/dist/status.js +111 -0
  10. package/client/dist/assets/{ActivityFeedPage-ILXMZXcb.js → ActivityFeedPage-DmJcQpNe.js} +1 -1
  11. package/client/dist/assets/{AgentBrowserCapture-UcsupCy7.js → AgentBrowserCapture-NxBHrU-V.js} +1 -1
  12. package/client/dist/assets/{AgentModeAnalyticsPane-CQuxYh8B.js → AgentModeAnalyticsPane-CGAKTJfU.js} +2 -2
  13. package/client/dist/assets/{AgentModeCodePane-zPWbW7ei.js → AgentModeCodePane-DNSs5_oe.js} +2 -2
  14. package/client/dist/assets/{AgentModeJobsPane-CInByIdl.js → AgentModeJobsPane-DLoVYDnG.js} +1 -1
  15. package/client/dist/assets/{AgentsPage-BWvgxaBv.js → AgentsPage-CAzMn9Gg.js} +1 -1
  16. package/client/dist/assets/{AnalyticsPage-DP3jakv-.js → AnalyticsPage-C06KT4Y0.js} +1 -1
  17. package/client/dist/assets/{CodePage-BKXiwE5a.js → CodePage-aX1mxGyT.js} +1 -1
  18. package/client/dist/assets/{DesktopAnalyticsPage-DryJOaMz.js → DesktopAnalyticsPage-BtscfiQD.js} +1 -1
  19. package/client/dist/assets/{DocsDialog-BsCG9ksG.js → DocsDialog-CNOcXhp-.js} +1 -1
  20. package/client/dist/assets/{DocsPage-Cc-GeKYl.js → DocsPage-C2BugxaI.js} +1 -1
  21. package/client/dist/assets/{ExportDropdown-ClahJdDn.js → ExportDropdown-BVGKEgkd.js} +1 -1
  22. package/client/dist/assets/{InteractiveJobComposer-DfLF6N0f.js → InteractiveJobComposer-CCncBqNu.js} +1 -1
  23. package/client/dist/assets/{JobDetailModal-DHeur9YK.js → JobDetailModal-Cn_k3-RM.js} +1 -1
  24. package/client/dist/assets/{JobDetailPage-CraDKzeG.js → JobDetailPage-BogJFBsk.js} +1 -1
  25. package/client/dist/assets/{JobsPage-CcbuSwj7.js → JobsPage-DL4E8ZyU.js} +1 -1
  26. package/client/dist/assets/{LoopBuilderPage-BKtNp494.js → LoopBuilderPage-9L6URQLY.js} +1 -1
  27. package/client/dist/assets/{LoopPreviewModal-DbZd9isy.js → LoopPreviewModal-CAPqTIgL.js} +1 -1
  28. package/client/dist/assets/{LoopsPage-DEg6sIkG.js → LoopsPage-aU8dYw7L.js} +1 -1
  29. package/client/dist/assets/{MinimizedChatsContext-BGtEjWsc.js → MinimizedChatsContext-D3QzgV0B.js} +1 -1
  30. package/client/dist/assets/{PluginsPage-BVqSsPzL.js → PluginsPage-D_tsW9B5.js} +1 -1
  31. package/client/dist/assets/{ProjectSettingsDialog-CAjLgJAZ.js → ProjectSettingsDialog-_ZbNuspP.js} +1 -1
  32. package/client/dist/assets/{RepositoryDeliveries-DrcrxLe0.js → RepositoryDeliveries-Du2UCf1a.js} +1 -1
  33. package/client/dist/assets/{RepositoryScopeSelector-CAGY3xW6.js → RepositoryScopeSelector-hPGZNRBm.js} +1 -1
  34. package/client/dist/assets/ReviewPacketPage-CG-Dv0El.js +4 -0
  35. package/client/dist/assets/{TemplatePreviewModal-Bqs-9fhn.js → TemplatePreviewModal-C19H2b2o.js} +1 -1
  36. package/client/dist/assets/{TicketDetailModalContext-C0jQ5yOk.js → TicketDetailModalContext-DAK-NoK6.js} +1 -1
  37. package/client/dist/assets/{Trans-DtWlCJN9.js → Trans-DEbgkuAY.js} +1 -1
  38. package/client/dist/assets/{dashboard-CTfEtkqX.js → dashboard-B9uWNGO2.js} +1 -1
  39. package/client/dist/assets/{dashboard-DMklepmz.js → dashboard-BIwmO9wc.js} +1 -1
  40. package/client/dist/assets/{dashboard-DBAP2_SQ.js → dashboard-BV4vOZkR.js} +1 -1
  41. package/client/dist/assets/{dashboard-D40HP2ks.js → dashboard-Bf6MPVsM.js} +1 -1
  42. package/client/dist/assets/{dashboard-Csf1yGSN.js → dashboard-C8klWVvZ.js} +1 -1
  43. package/client/dist/assets/{dashboard-C29Qwa-L.js → dashboard-D1ORhPF0.js} +1 -1
  44. package/client/dist/assets/{dashboard-Cr4D8oMn.js → dashboard-DSubvs9x.js} +1 -1
  45. package/client/dist/assets/{dashboard-CSJzf5OT.js → dashboard-px_vlRx_.js} +1 -1
  46. package/client/dist/assets/{formatDistanceToNow-DYmvOA3R.js → formatDistanceToNow-Cc2u5FwQ.js} +1 -1
  47. package/client/dist/assets/{getTimezoneOffsetInMilliseconds-BAhW5E6V.js → getTimezoneOffsetInMilliseconds-BHm2U-w1.js} +1 -1
  48. package/client/dist/assets/{index-BfAZg5DG.js → index-BcligJ3-.js} +29 -29
  49. package/client/dist/assets/index-C51x61Bz.css +2 -0
  50. package/client/dist/assets/{jira-api-B27Za5FP.js → jira-api-DrGxiD9p.js} +1 -1
  51. package/client/dist/assets/packet-8nn9RsU7.js +1 -0
  52. package/client/dist/assets/packet-B0H15elv.js +1 -0
  53. package/client/dist/assets/packet-BQvBgrwh.js +1 -0
  54. package/client/dist/assets/packet-BR7mO0-a.js +1 -0
  55. package/client/dist/assets/packet-BgcQ6q_K.js +1 -0
  56. package/client/dist/assets/packet-D2s92Jnn.js +1 -0
  57. package/client/dist/assets/packet-YbtcD1HS.js +1 -0
  58. package/client/dist/assets/packet-c0Qj_9eX.js +1 -0
  59. package/client/dist/assets/{project-repositories-DixIZHTA.js → project-repositories-9Wzs0coQ.js} +1 -1
  60. package/client/dist/assets/{spending-BGmZBX5B.js → spending-T5GM7wpn.js} +1 -1
  61. package/client/dist/assets/{useDesktop-CPB4cnwI.js → useDesktop-QogiN0zR.js} +1 -1
  62. package/client/dist/assets/{useRuntimeRuns-DEQ9HdAM.js → useRuntimeRuns-Dqmz9fS9.js} +1 -1
  63. package/client/dist/assets/{useSharedWebSocket-DcPRKR8R.js → useSharedWebSocket-Dz-HI6De.js} +2 -2
  64. package/client/dist/index.html +17 -17
  65. package/docs/codex.md +5 -5
  66. package/docs/customizing.md +1 -1
  67. package/docs/gemini-cli-provider-study.md +14 -14
  68. package/docs/gemini-core-support-evaluation.md +1 -1
  69. package/docs/gemini.md +5 -5
  70. package/docs/internals/README.md +6 -2
  71. package/docs/internals/adding-a-provider.md +15 -15
  72. package/docs/internals/agent-runtime-framework-evaluation.md +8 -8
  73. package/docs/internals/api-reference.md +2 -2
  74. package/docs/internals/architecture.md +9 -9
  75. package/docs/internals/browser-capture-performance.md +3 -3
  76. package/docs/internals/code-explorer-story.md +2 -2
  77. package/docs/internals/companion-rails-as-loops-contract.md +2 -2
  78. package/docs/internals/embedded-browser-native-webview-evaluation.md +5 -5
  79. package/docs/internals/gemini-mcp-registration.md +2 -2
  80. package/docs/internals/global-artifacts-alignment-contract.md +1 -1
  81. package/docs/internals/global-artifacts-relocation-evaluation.md +1 -1
  82. package/docs/internals/interactive-jobs.md +8 -8
  83. package/docs/internals/legacy-implementation-notes.md +722 -0
  84. package/docs/internals/loop-step-log-explorer.md +8 -8
  85. package/docs/internals/mission-rail-cards.md +14 -14
  86. package/docs/internals/modular-architecture.md +107 -0
  87. package/docs/internals/profiles.md +1 -1
  88. package/docs/internals/project-builder.md +18 -18
  89. package/docs/internals/review-packet.md +8 -8
  90. package/docs/internals/safe-pr-review-flow.md +11 -11
  91. package/docs/internals/source-architecture.md +131 -0
  92. package/docs/internals/source-map.md +1354 -0
  93. package/docs/internals/spec-addenda.md +65 -9
  94. package/docs/internals/switch-to-agent-mode-design.md +11 -11
  95. package/docs/tracking-cost.md +1 -1
  96. package/package.json +5 -2
  97. package/server/dist/agent-mcp-config.js +1 -1
  98. package/server/dist/attachment-manager.js +1 -1
  99. package/server/dist/build-dirs.js +2 -2
  100. package/server/dist/config.js +0 -3
  101. package/server/dist/core-completion.js +1 -1
  102. package/server/dist/core-execution.js +1 -1
  103. package/server/dist/db/activity.js +39 -0
  104. package/server/dist/db/connection.js +41 -0
  105. package/server/dist/db/conversations.js +48 -0
  106. package/server/dist/db/jobs.js +251 -0
  107. package/server/dist/db/migrations.js +1521 -0
  108. package/server/dist/db/proposals.js +50 -0
  109. package/server/dist/db/settings.js +15 -0
  110. package/server/dist/db/stats.js +61 -0
  111. package/server/dist/db/telemetry.js +56 -0
  112. package/server/dist/db/templates.js +37 -0
  113. package/server/dist/db/types.js +2 -0
  114. package/server/dist/db.js +66 -2224
  115. package/server/dist/desktop-db.js +3 -3
  116. package/server/dist/desktop-router.js +8 -8
  117. package/server/dist/git-diagnostics.js +1 -1
  118. package/server/dist/index.js +11 -11
  119. package/server/dist/integration-branch.js +3 -14
  120. package/server/dist/jira/jira-issue-fields.js +0 -1
  121. package/server/dist/jira/jira-materializer.js +1 -1
  122. package/server/dist/jira/jira-sync-manager.js +1 -1
  123. package/server/dist/mcp/mcp-admin-router.js +1 -1
  124. package/server/dist/mcp/mcp-server.js +1 -1
  125. package/server/dist/mcp/tools/jobs.js +1 -1
  126. package/server/dist/mcp/tools/rails.js +2 -2
  127. package/server/dist/mcp/tools/specs.js +2 -2
  128. package/server/dist/mcp/tools/types.js +3 -3
  129. package/server/dist/mobile/mobile-gateway.js +1 -1
  130. package/server/dist/mobile/mobile-missions.js +1 -1
  131. package/server/dist/{desktop-analytics.js → modules/accounting/runtime/desktop-analytics.js} +2 -2
  132. package/server/dist/{pricing.js → modules/accounting/runtime/pricing.js} +1 -1
  133. package/server/dist/{result-event.js → modules/accounting/runtime/result-event.js} +3 -3
  134. package/server/dist/{spending.js → modules/accounting/runtime/spending.js} +0 -3
  135. package/server/dist/{telemetry-compactor.js → modules/accounting/runtime/telemetry-compactor.js} +1 -1
  136. package/server/dist/{telemetry-receiver.js → modules/accounting/runtime/telemetry-receiver.js} +2 -2
  137. package/server/dist/{agent-runtime-bridge.js → modules/agent-runtime/runtime/agent-runtime-bridge.js} +2 -2
  138. package/server/dist/{agent-runtime-controls.js → modules/agent-runtime/runtime/agent-runtime-controls.js} +7 -7
  139. package/server/dist/{agent-runtime-effective-config.js → modules/agent-runtime/runtime/agent-runtime-effective-config.js} +1 -1
  140. package/server/dist/{agent-runtime-loader.js → modules/agent-runtime/runtime/agent-runtime-loader.js} +3 -3
  141. package/server/dist/{agent-runtime-paths.js → modules/agent-runtime/runtime/agent-runtime-paths.js} +1 -1
  142. package/server/dist/{agent-runtime-settings-router.js → modules/agent-runtime/runtime/agent-runtime-settings-router.js} +2 -2
  143. package/server/dist/{agent-runtime-settings.js → modules/agent-runtime/runtime/agent-runtime-settings.js} +3 -3
  144. package/server/dist/{agent-runtime-settlement.js → modules/agent-runtime/runtime/agent-runtime-settlement.js} +6 -6
  145. package/server/dist/{agent-defaults.js → modules/agents/runtime/agent-defaults.js} +3 -3
  146. package/server/dist/{agent-generator.js → modules/agents/runtime/agent-generator.js} +7 -7
  147. package/server/dist/{agent-refine-manager.js → modules/agents/runtime/agent-refine-manager.js} +5 -5
  148. package/server/dist/{agent-store.js → modules/agents/runtime/agent-store.js} +1 -1
  149. package/server/dist/{profile-manager.js → modules/agents/runtime/profile-manager.js} +2 -2
  150. package/server/dist/{profiles-router.js → modules/agents/runtime/profiles-router.js} +5 -5
  151. package/server/dist/{browser-capture-manager.js → modules/browser/runtime/browser-capture-manager.js} +2 -4
  152. package/server/dist/{browser-playwright.js → modules/browser/runtime/browser-playwright.js} +1 -1
  153. package/server/dist/{blueprint-chat-manager.js → modules/builder/runtime/blueprint-chat-manager.js} +7 -7
  154. package/server/dist/{blueprint-commit.js → modules/builder/runtime/blueprint-commit.js} +8 -8
  155. package/server/dist/{blueprint-draft-parser.js → modules/builder/runtime/blueprint-draft-parser.js} +1 -1
  156. package/server/dist/{blueprint-generation.js → modules/builder/runtime/blueprint-generation.js} +1 -1
  157. package/server/dist/{blueprint-operator-prompt.js → modules/builder/runtime/blueprint-operator-prompt.js} +1 -1
  158. package/server/dist/{blueprint-router.js → modules/builder/runtime/blueprint-router.js} +3 -3
  159. package/server/dist/{blueprint-spec-quality.js → modules/builder/runtime/blueprint-spec-quality.js} +1 -1
  160. package/server/dist/{milestone-chain.js → modules/builder/runtime/milestone-chain.js} +1 -1
  161. package/server/dist/{milestone-progress.js → modules/builder/runtime/milestone-progress.js} +6 -6
  162. package/server/dist/{code-activity.js → modules/code/runtime/code-activity.js} +1 -1
  163. package/server/dist/{code-explorer-router.js → modules/code/runtime/code-explorer-router.js} +5 -5
  164. package/server/dist/{file-provenance.js → modules/code/runtime/file-provenance.js} +1 -1
  165. package/server/dist/{file-story-manager.js → modules/code/runtime/file-story-manager.js} +2 -2
  166. package/server/dist/{file-story.js → modules/code/runtime/file-story.js} +2 -2
  167. package/server/dist/{file-summary-generator.js → modules/code/runtime/file-summary-generator.js} +3 -3
  168. package/server/dist/{file-summary-manager.js → modules/code/runtime/file-summary-manager.js} +3 -3
  169. package/server/dist/{project-code-discovery.js → modules/code/runtime/project-code-discovery.js} +2 -2
  170. package/server/dist/modules/conversations/domain/draft-stream.js +91 -0
  171. package/server/dist/modules/conversations/domain/recovery-context.js +101 -0
  172. package/server/dist/modules/conversations/index.js +10 -0
  173. package/server/dist/{chat-manager.js → modules/conversations/runtime/chat-manager.js} +32 -216
  174. package/server/dist/{context-budget.js → modules/conversations/runtime/context-budget.js} +1 -1
  175. package/server/dist/{explore-cwd-manager.js → modules/conversations/runtime/explore-cwd-manager.js} +1 -1
  176. package/server/dist/{explore-smash.js → modules/conversations/runtime/explore-smash.js} +1 -1
  177. package/server/dist/{explore-stdin-session.js → modules/conversations/runtime/explore-stdin-session.js} +1 -1
  178. package/server/dist/modules/delivery/adapters/decisions/chains.js +138 -0
  179. package/server/dist/modules/delivery/adapters/decisions/contracts.js +2 -0
  180. package/server/dist/modules/delivery/adapters/decisions/create.js +234 -0
  181. package/server/dist/modules/delivery/adapters/decisions/discard.js +251 -0
  182. package/server/dist/modules/delivery/adapters/decisions/dispatch.js +107 -0
  183. package/server/dist/modules/delivery/adapters/decisions/evidence.js +205 -0
  184. package/server/dist/modules/delivery/adapters/decisions/merge-local.js +338 -0
  185. package/server/dist/modules/delivery/adapters/decisions/metadata.js +109 -0
  186. package/server/dist/modules/delivery/adapters/decisions/observations.js +260 -0
  187. package/server/dist/modules/delivery/adapters/decisions/ownership.js +83 -0
  188. package/server/dist/modules/delivery/adapters/decisions/publish.js +242 -0
  189. package/server/dist/modules/delivery/adapters/decisions/recovery.js +425 -0
  190. package/server/dist/modules/delivery/adapters/decisions/retry.js +112 -0
  191. package/server/dist/modules/delivery/adapters/decisions/transitions.js +94 -0
  192. package/server/dist/modules/delivery/domain/decision-policy.js +50 -0
  193. package/server/dist/modules/delivery/domain/state.js +2 -0
  194. package/server/dist/modules/delivery/index.js +7 -0
  195. package/server/dist/{active-pr-continuation.js → modules/delivery/runtime/active-pr-continuation.js} +2 -2
  196. package/server/dist/{delivery-evidence.js → modules/delivery/runtime/delivery-evidence.js} +3 -3
  197. package/server/dist/{multi-repo-bases.js → modules/delivery/runtime/multi-repo-bases.js} +1 -1
  198. package/server/dist/{multi-repo-checkout.js → modules/delivery/runtime/multi-repo-checkout.js} +4 -4
  199. package/server/dist/{multi-repo-delivery.js → modules/delivery/runtime/multi-repo-delivery.js} +4 -4
  200. package/server/dist/{multi-repo-execution.js → modules/delivery/runtime/multi-repo-execution.js} +8 -8
  201. package/server/dist/{pr-body.js → modules/delivery/runtime/pr-body.js} +1 -1
  202. package/server/dist/{pr-follow-up-scope.js → modules/delivery/runtime/pr-follow-up-scope.js} +2 -2
  203. package/server/dist/{pr-follow-up.js → modules/delivery/runtime/pr-follow-up.js} +1 -1
  204. package/server/dist/{pr-naming.js → modules/delivery/runtime/pr-naming.js} +1 -1
  205. package/server/dist/{pr-publisher.js → modules/delivery/runtime/pr-publisher.js} +2 -2
  206. package/server/dist/{rail-isolated-launch.js → modules/delivery/runtime/rail-isolated-launch.js} +29 -27
  207. package/server/dist/{rail-launch-parser.js → modules/delivery/runtime/rail-launch-parser.js} +2 -2
  208. package/server/dist/{rail-merge-orchestrator.js → modules/delivery/runtime/rail-merge-orchestrator.js} +5 -5
  209. package/server/dist/modules/delivery/runtime/rail-pr-decision.js +12 -0
  210. package/server/dist/{rail-pr-delivery.js → modules/delivery/runtime/rail-pr-delivery.js} +1 -1
  211. package/server/dist/{rail-pr-store.js → modules/delivery/runtime/rail-pr-store.js} +2 -2
  212. package/server/dist/{rail-pr-ticket-effects.js → modules/delivery/runtime/rail-pr-ticket-effects.js} +3 -3
  213. package/server/dist/{rail-worktree-release.js → modules/delivery/runtime/rail-worktree-release.js} +4 -4
  214. package/server/dist/{rails-router.js → modules/delivery/runtime/rails-router.js} +66 -67
  215. package/server/dist/{review-packet.js → modules/delivery/runtime/review-packet.js} +3 -3
  216. package/server/dist/modules/execution/adapters/budget-storage.js +21 -0
  217. package/server/dist/modules/execution/adapters/usage-reader.js +38 -0
  218. package/server/dist/modules/execution/application/enforce-budget.js +14 -0
  219. package/server/dist/modules/execution/application/record-job-invocations.js +64 -0
  220. package/server/dist/modules/execution/application/recover-job-usage.js +200 -0
  221. package/server/dist/modules/execution/domain/job-accounting.js +2 -0
  222. package/server/dist/modules/execution/domain/scheduling.js +24 -0
  223. package/server/dist/modules/execution/domain/usage.js +21 -0
  224. package/server/dist/modules/execution/index.js +14 -0
  225. package/server/dist/modules/execution/ports.js +2 -0
  226. package/server/dist/{accept-ladder.js → modules/execution/runtime/accept-ladder.js} +1 -1
  227. package/server/dist/{interactive-job-session.js → modules/execution/runtime/interactive-job-session.js} +11 -11
  228. package/server/dist/{job-phase-breakdown.js → modules/execution/runtime/job-phase-breakdown.js} +1 -1
  229. package/server/dist/{queue-manager.js → modules/execution/runtime/queue-manager.js} +74 -491
  230. package/server/dist/{revision-seed.js → modules/execution/runtime/revision-seed.js} +1 -1
  231. package/server/dist/{spawn-lifecycle.js → modules/execution/runtime/spawn-lifecycle.js} +3 -3
  232. package/server/dist/{stuck-run-detector.js → modules/execution/runtime/stuck-run-detector.js} +1 -1
  233. package/server/dist/{loop-command-catalog.js → modules/loops/runtime/loop-command-catalog.js} +1 -1
  234. package/server/dist/{loop-executors.js → modules/loops/runtime/loop-executors.js} +17 -17
  235. package/server/dist/{loop-factory.js → modules/loops/runtime/loop-factory.js} +2 -21
  236. package/server/dist/{loop-graph.js → modules/loops/runtime/loop-graph.js} +25 -0
  237. package/server/dist/{loop-role-engines.js → modules/loops/runtime/loop-role-engines.js} +4 -4
  238. package/server/dist/{loop-run-manager.js → modules/loops/runtime/loop-run-manager.js} +101 -26
  239. package/server/dist/{loop-runs-store.js → modules/loops/runtime/loop-runs-store.js} +1 -1
  240. package/server/dist/{loop-shell-invocation.js → modules/loops/runtime/loop-shell-invocation.js} +2 -2
  241. package/server/dist/{loop-step-idle.js → modules/loops/runtime/loop-step-idle.js} +1 -1
  242. package/server/dist/{loop-templates.js → modules/loops/runtime/loop-templates.js} +24 -29
  243. package/server/dist/{loops-router.js → modules/loops/runtime/loops-router.js} +2 -2
  244. package/server/dist/{agent-chat-manager.js → modules/missions/runtime/agent-chat-manager.js} +19 -19
  245. package/server/dist/{agent-chat-router.js → modules/missions/runtime/agent-chat-router.js} +6 -6
  246. package/server/dist/{agent-context-resolver.js → modules/missions/runtime/agent-context-resolver.js} +8 -8
  247. package/server/dist/{agent-fence-promotion.js → modules/missions/runtime/agent-fence-promotion.js} +1 -1
  248. package/server/dist/{agent-input-store.js → modules/missions/runtime/agent-input-store.js} +1 -1
  249. package/server/dist/{agent-operator-prompt.js → modules/missions/runtime/agent-operator-prompt.js} +17 -7
  250. package/server/dist/{agent-spec-framing.js → modules/missions/runtime/agent-spec-framing.js} +4 -4
  251. package/server/dist/{agent-steering.js → modules/missions/runtime/agent-steering.js} +1 -1
  252. package/server/dist/{mission-run-notify.js → modules/missions/runtime/mission-run-notify.js} +1 -1
  253. package/server/dist/modules/project-settings/adapters/http.js +24 -0
  254. package/server/dist/modules/project-settings/adapters/sqlite.js +120 -0
  255. package/server/dist/modules/project-settings/application.js +11 -0
  256. package/server/dist/modules/project-settings/domain.js +95 -0
  257. package/server/dist/modules/project-settings/index.js +11 -0
  258. package/server/dist/modules/project-settings/ports.js +2 -0
  259. package/server/dist/{contract-refine-runner.js → modules/specs/runtime/contract-refine-runner.js} +12 -12
  260. package/server/dist/{proposal-manager.js → modules/specs/runtime/proposal-manager.js} +8 -8
  261. package/server/dist/{smash-runner.js → modules/specs/runtime/smash-runner.js} +26 -58
  262. package/server/dist/{spec-addenda-core.js → modules/specs/runtime/spec-addenda-core.js} +2 -2
  263. package/server/dist/{spec-addenda.js → modules/specs/runtime/spec-addenda.js} +3 -3
  264. package/server/dist/{spec-launcher-manager.js → modules/specs/runtime/spec-launcher-manager.js} +8 -8
  265. package/server/dist/{spec-models.js → modules/specs/runtime/spec-models.js} +1 -1
  266. package/server/dist/{ticket-watcher.js → modules/specs/runtime/ticket-watcher.js} +1 -1
  267. package/server/dist/{background-process-control.js → modules/terminals/runtime/background-process-control.js} +1 -1
  268. package/server/dist/{background-process-service.js → modules/terminals/runtime/background-process-service.js} +3 -3
  269. package/server/dist/{background-process-store.js → modules/terminals/runtime/background-process-store.js} +1 -1
  270. package/server/dist/{background-windows-bootstrap.js → modules/terminals/runtime/background-windows-bootstrap.js} +3 -3
  271. package/server/dist/{terminal-manager.js → modules/terminals/runtime/terminal-manager.js} +3 -3
  272. package/server/dist/project-git.js +1 -1
  273. package/server/dist/project-profile-support.js +32 -0
  274. package/server/dist/project-registry.js +34 -40
  275. package/server/dist/project-router-background-processes.js +1 -1
  276. package/server/dist/project-router-chat.js +6 -6
  277. package/server/dist/project-router-git.js +1 -1
  278. package/server/dist/project-router-helpers.js +2 -2
  279. package/server/dist/project-router-jobs.js +14 -12
  280. package/server/dist/project-router-loop-runs.js +12 -12
  281. package/server/dist/project-router-settings.js +15 -75
  282. package/server/dist/project-router-setup.js +2 -2
  283. package/server/dist/project-router-spending.js +4 -4
  284. package/server/dist/project-router-terminals.js +4 -4
  285. package/server/dist/project-router-tickets.js +14 -14
  286. package/server/dist/project-router.js +13 -13
  287. package/server/dist/providers/codex-adapter.js +3 -3
  288. package/server/dist/providers/gemini-adapter.js +1 -1
  289. package/server/dist/providers/telemetry-env.js +55 -0
  290. package/server/dist/runtime-role-prompts-router.js +2 -2
  291. package/server/dist/setup-manager.js +2 -48
  292. package/server/dist/shared/git-branch-name.js +16 -0
  293. package/server/dist/transient-children.js +3 -3
  294. package/server/dist/util/distribute-int.js +33 -0
  295. package/client/dist/assets/ReviewPacketPage-D-UjTef3.js +0 -4
  296. package/client/dist/assets/index-BAtqmAZR.css +0 -2
  297. package/client/dist/assets/packet-CjS_478C.js +0 -1
  298. package/client/dist/assets/packet-D69dKsHN.js +0 -1
  299. package/client/dist/assets/packet-D9rU6Oxo.js +0 -1
  300. package/client/dist/assets/packet-DMDFoamg.js +0 -1
  301. package/client/dist/assets/packet-Dd2RMs1h.js +0 -1
  302. package/client/dist/assets/packet-DjC9OibC.js +0 -1
  303. package/client/dist/assets/packet-DwPtJoDz.js +0 -1
  304. package/client/dist/assets/packet-ceahDg8_.js +0 -1
  305. package/server/dist/rail-pr-decision.js +0 -2377
  306. package/server/dist/ticket-broadcast.js +0 -47
  307. /package/server/dist/{ai-invocations.js → modules/accounting/runtime/ai-invocations.js} +0 -0
  308. /package/server/dist/{codex-otel-bridge.js → modules/accounting/runtime/codex-otel-bridge.js} +0 -0
  309. /package/server/dist/{metrics.js → modules/accounting/runtime/metrics.js} +0 -0
  310. /package/server/dist/{telemetry-export.js → modules/accounting/runtime/telemetry-export.js} +0 -0
  311. /package/server/dist/{agent-runtime-accounting.js → modules/agent-runtime/runtime/agent-runtime-accounting.js} +0 -0
  312. /package/server/dist/{agent-runtime-controls-router.js → modules/agent-runtime/runtime/agent-runtime-controls-router.js} +0 -0
  313. /package/server/dist/{agent-runtime-events.js → modules/agent-runtime/runtime/agent-runtime-events.js} +0 -0
  314. /package/server/dist/{agent-runtime-history.js → modules/agent-runtime/runtime/agent-runtime-history.js} +0 -0
  315. /package/server/dist/{agent-runtime-metrics.js → modules/agent-runtime/runtime/agent-runtime-metrics.js} +0 -0
  316. /package/server/dist/{agent-runtime-package.js → modules/agent-runtime/runtime/agent-runtime-package.js} +0 -0
  317. /package/server/dist/{agent-runtime-repositories.js → modules/agent-runtime/runtime/agent-runtime-repositories.js} +0 -0
  318. /package/server/dist/{agent-runtime-verification-suggestions.js → modules/agent-runtime/runtime/agent-runtime-verification-suggestions.js} +0 -0
  319. /package/server/dist/{agent-refine-db.js → modules/agents/runtime/agent-refine-db.js} +0 -0
  320. /package/server/dist/{browser-capture-types.js → modules/browser/runtime/browser-capture-types.js} +0 -0
  321. /package/server/dist/{browser-context-pool.js → modules/browser/runtime/browser-context-pool.js} +0 -0
  322. /package/server/dist/{browser-network.js → modules/browser/runtime/browser-network.js} +0 -0
  323. /package/server/dist/{browser-viewport.js → modules/browser/runtime/browser-viewport.js} +0 -0
  324. /package/server/dist/{blueprint-render.js → modules/builder/runtime/blueprint-render.js} +0 -0
  325. /package/server/dist/{blueprint-spec-fixtures.js → modules/builder/runtime/blueprint-spec-fixtures.js} +0 -0
  326. /package/server/dist/{blueprint-store.js → modules/builder/runtime/blueprint-store.js} +0 -0
  327. /package/server/dist/{blueprint-types.js → modules/builder/runtime/blueprint-types.js} +0 -0
  328. /package/server/dist/{builder-cwd-manager.js → modules/builder/runtime/builder-cwd-manager.js} +0 -0
  329. /package/server/dist/{milestone-chain-store.js → modules/builder/runtime/milestone-chain-store.js} +0 -0
  330. /package/server/dist/{changes-reader.js → modules/code/runtime/changes-reader.js} +0 -0
  331. /package/server/dist/{context-scope.js → modules/conversations/runtime/context-scope.js} +0 -0
  332. /package/server/dist/{explore-contract-refine.js → modules/conversations/runtime/explore-contract-refine.js} +0 -0
  333. /package/server/dist/{explore-draft-title.js → modules/conversations/runtime/explore-draft-title.js} +0 -0
  334. /package/server/dist/{merge-manager.js → modules/delivery/runtime/merge-manager.js} +0 -0
  335. /package/server/dist/{multi-repo-execution-store.js → modules/delivery/runtime/multi-repo-execution-store.js} +0 -0
  336. /package/server/dist/{pr-lifecycle.js → modules/delivery/runtime/pr-lifecycle.js} +0 -0
  337. /package/server/dist/{rail-isolation.js → modules/delivery/runtime/rail-isolation.js} +0 -0
  338. /package/server/dist/{rail-pr-recovery-git.js → modules/delivery/runtime/rail-pr-recovery-git.js} +0 -0
  339. /package/server/dist/{rail-worktrees-store.js → modules/delivery/runtime/rail-worktrees-store.js} +0 -0
  340. /package/server/dist/{rails-store.js → modules/delivery/runtime/rails-store.js} +0 -0
  341. /package/server/dist/{job-listing.js → modules/execution/runtime/job-listing.js} +0 -0
  342. /package/server/dist/{job-spawn-idempotency.js → modules/execution/runtime/job-spawn-idempotency.js} +0 -0
  343. /package/server/dist/{run-duration-stats.js → modules/execution/runtime/run-duration-stats.js} +0 -0
  344. /package/server/dist/{verification-sentinel.js → modules/execution/runtime/verification-sentinel.js} +0 -0
  345. /package/server/dist/{loop-constants.js → modules/loops/runtime/loop-constants.js} +0 -0
  346. /package/server/dist/{loop-decider.js → modules/loops/runtime/loop-decider.js} +0 -0
  347. /package/server/dist/{loop-effect.js → modules/loops/runtime/loop-effect.js} +0 -0
  348. /package/server/dist/{loop-preview.js → modules/loops/runtime/loop-preview.js} +0 -0
  349. /package/server/dist/{loop-templates-ported.js → modules/loops/runtime/loop-templates-ported.js} +0 -0
  350. /package/server/dist/{loops-store.js → modules/loops/runtime/loops-store.js} +0 -0
  351. /package/server/dist/{agent-chat-registry.js → modules/missions/runtime/agent-chat-registry.js} +0 -0
  352. /package/server/dist/{agent-cwd-manager.js → modules/missions/runtime/agent-cwd-manager.js} +0 -0
  353. /package/server/dist/{agent-failure-briefing.js → modules/missions/runtime/agent-failure-briefing.js} +0 -0
  354. /package/server/dist/{agent-tier.js → modules/missions/runtime/agent-tier.js} +0 -0
  355. /package/server/dist/{spec-contract-prompt.js → modules/specs/runtime/spec-contract-prompt.js} +0 -0
  356. /package/server/dist/{spec-draft-parser.js → modules/specs/runtime/spec-draft-parser.js} +0 -0
  357. /package/server/dist/{ticket-store.js → modules/specs/runtime/ticket-store.js} +0 -0
  358. /package/server/dist/{terminal-marks-store.js → modules/terminals/runtime/terminal-marks-store.js} +0 -0
  359. /package/server/dist/{terminal-osc-parser.js → modules/terminals/runtime/terminal-osc-parser.js} +0 -0
  360. /package/server/dist/{terminal-settings.js → modules/terminals/runtime/terminal-settings.js} +0 -0
@@ -0,0 +1,205 @@
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
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.COMMIT_SHA_RE = void 0;
37
+ exports.exactRefSha = exactRefSha;
38
+ exports.isFastForwardCandidate = isFastForwardCandidate;
39
+ exports.releaseDeliveredRecoveryLineage = releaseDeliveredRecoveryLineage;
40
+ exports.parseRegisteredGitWorktrees = parseRegisteredGitWorktrees;
41
+ exports.authenticateRecoveryWorktree = authenticateRecoveryWorktree;
42
+ exports.commitObjectExists = commitObjectExists;
43
+ exports.captureBranchSha = captureBranchSha;
44
+ const path = __importStar(require("path"));
45
+ const fs = __importStar(require("fs"));
46
+ const rail_pr_store_1 = require("../../runtime/rail-pr-store");
47
+ const rail_pr_recovery_git_1 = require("../../runtime/rail-pr-recovery-git");
48
+ exports.COMMIT_SHA_RE = /^[0-9a-f]{40,64}$/i;
49
+ async function exactRefSha(deps, cwd, ref) {
50
+ try {
51
+ const result = await deps.git.run(['rev-parse', '--verify', ref], cwd);
52
+ const sha = result.code === 0 ? result.stdout.trim() : '';
53
+ return exports.COMMIT_SHA_RE.test(sha) ? sha : null;
54
+ }
55
+ catch {
56
+ return null;
57
+ }
58
+ }
59
+ async function isFastForwardCandidate(deps, baselineSha, candidateSha) {
60
+ if (baselineSha === candidateSha)
61
+ return true;
62
+ try {
63
+ return (await deps.git.run(['merge-base', '--is-ancestor', baselineSha, candidateSha], deps.project.path)).code === 0;
64
+ }
65
+ catch {
66
+ return false;
67
+ }
68
+ }
69
+ async function releaseDeliveredRecoveryLineage(deps, row, deliveredSha) {
70
+ if (!deliveredSha || !exports.COMMIT_SHA_RE.test(deliveredSha))
71
+ return;
72
+ const currentProtection = await (0, rail_pr_recovery_git_1.inspectRecoveryCommitProtection)(deps.git, deps.project.path, row.id);
73
+ if (currentProtection.kind === 'present' &&
74
+ currentProtection.sha.toLowerCase() === deliveredSha.toLowerCase()) {
75
+ await (0, rail_pr_recovery_git_1.releaseRecoveryCommit)(deps.git, deps.project.path, row.id, deliveredSha);
76
+ }
77
+ const visited = new Set([row.id]);
78
+ let predecessorId = row.supersedes_delivery_id;
79
+ for (let depth = 0; predecessorId && depth < 32 && !visited.has(predecessorId); depth++) {
80
+ visited.add(predecessorId);
81
+ const predecessor = (0, rail_pr_store_1.getPrDelivery)(deps.db, predecessorId);
82
+ if (!predecessor)
83
+ break;
84
+ if (predecessor.decision !== 'discarded' && predecessor.decision !== 'superseded')
85
+ break;
86
+ const protection = await (0, rail_pr_recovery_git_1.inspectRecoveryCommitProtection)(deps.git, deps.project.path, predecessor.id);
87
+ if (protection.kind === 'present' && await isFastForwardCandidate(deps, protection.sha, deliveredSha)) {
88
+ await (0, rail_pr_recovery_git_1.releaseRecoveryCommit)(deps.git, deps.project.path, predecessor.id, protection.sha);
89
+ }
90
+ predecessorId = predecessor.supersedes_delivery_id;
91
+ }
92
+ }
93
+ function parseRegisteredGitWorktrees(stdout) {
94
+ const worktrees = [];
95
+ let current = null;
96
+ const finish = () => {
97
+ if (current)
98
+ worktrees.push(current);
99
+ current = null;
100
+ };
101
+ for (const field of stdout.split('\0')) {
102
+ if (field === '') {
103
+ finish();
104
+ continue;
105
+ }
106
+ if (field.startsWith('worktree ')) {
107
+ finish();
108
+ current = { worktreePath: field.slice('worktree '.length), head: null, branch: null };
109
+ continue;
110
+ }
111
+ if (!current)
112
+ continue;
113
+ if (field.startsWith('HEAD '))
114
+ current.head = field.slice('HEAD '.length);
115
+ if (field.startsWith('branch '))
116
+ current.branch = field.slice('branch '.length);
117
+ }
118
+ finish();
119
+ return worktrees;
120
+ }
121
+ /** Authenticate a ledger path as a live, non-symlink worktree registered by
122
+ * this exact repository. The main checkout and ordinary directories fail
123
+ * closed. Callers repeat this immediately before staging to close the useful
124
+ * path-replacement window between inspection and mutation. */
125
+ async function authenticateRecoveryWorktree(deps, ledgerPath, expectedBranch, expectedHead) {
126
+ if (!path.isAbsolute(ledgerPath)) {
127
+ return { ok: false, detail: 'the recorded worktree path is not absolute' };
128
+ }
129
+ let realPath;
130
+ let projectRealPath;
131
+ try {
132
+ const ledgerStat = fs.lstatSync(ledgerPath);
133
+ if (ledgerStat.isSymbolicLink()) {
134
+ return { ok: false, detail: 'the recorded worktree path is a symbolic link' };
135
+ }
136
+ if (!ledgerStat.isDirectory()) {
137
+ return { ok: false, detail: 'the recorded worktree path is not a directory' };
138
+ }
139
+ realPath = fs.realpathSync(ledgerPath);
140
+ projectRealPath = fs.realpathSync(deps.project.path);
141
+ if (!fs.statSync(realPath).isDirectory()) {
142
+ return { ok: false, detail: 'the canonical worktree path is not a directory' };
143
+ }
144
+ }
145
+ catch {
146
+ return { ok: false, detail: 'the recorded worktree path could not be resolved safely' };
147
+ }
148
+ if (realPath === projectRealPath) {
149
+ return { ok: false, detail: 'the recorded worktree path resolves to the main project checkout' };
150
+ }
151
+ let listed;
152
+ try {
153
+ listed = await deps.git.run(['worktree', 'list', '--porcelain', '-z'], deps.project.path);
154
+ }
155
+ catch {
156
+ return { ok: false, detail: 'Git worktree registration could not be verified' };
157
+ }
158
+ if (listed.code !== 0) {
159
+ return { ok: false, detail: 'Git worktree registration could not be verified' };
160
+ }
161
+ const matches = parseRegisteredGitWorktrees(listed.stdout).filter((registered) => {
162
+ try {
163
+ return fs.realpathSync(registered.worktreePath) === realPath;
164
+ }
165
+ catch {
166
+ return false;
167
+ }
168
+ });
169
+ if (matches.length !== 1) {
170
+ return { ok: false, detail: 'the recorded path is not uniquely registered as a Git worktree of this project' };
171
+ }
172
+ const registered = matches[0];
173
+ if (registered.branch !== `refs/heads/${expectedBranch}`) {
174
+ return { ok: false, detail: 'the registered Git worktree is not on the recorded delivery branch' };
175
+ }
176
+ if (!registered.head || !exports.COMMIT_SHA_RE.test(registered.head)) {
177
+ return { ok: false, detail: 'the registered Git worktree has no verifiable commit identity' };
178
+ }
179
+ if (expectedHead && registered.head.toLowerCase() !== expectedHead.toLowerCase()) {
180
+ return { ok: false, detail: 'the registered Git worktree changed commits before staging' };
181
+ }
182
+ return { ok: true, realPath, head: registered.head };
183
+ }
184
+ async function commitObjectExists(deps, sha) {
185
+ if (!exports.COMMIT_SHA_RE.test(sha))
186
+ return false;
187
+ try {
188
+ return (await deps.git.run(['cat-file', '-e', `${sha}^{commit}`], deps.project.path)).code === 0;
189
+ }
190
+ catch {
191
+ return false;
192
+ }
193
+ }
194
+ /** Resolve a legacy mutable ref once into an immutable object. New settlement
195
+ * rows already carry finalSha and never take this compatibility path. */
196
+ async function captureBranchSha(deps, branch) {
197
+ try {
198
+ const result = await deps.git.run(['rev-parse', '--verify', `refs/heads/${branch}`], deps.project.path);
199
+ const sha = result.code === 0 ? result.stdout.trim() : '';
200
+ return exports.COMMIT_SHA_RE.test(sha) ? sha : null;
201
+ }
202
+ catch {
203
+ return null;
204
+ }
205
+ }
@@ -0,0 +1,338 @@
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
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.runMergeLocal = runMergeLocal;
37
+ exports.runMergeLocalLocked = runMergeLocalLocked;
38
+ exports.runMergeLocalIntoCheckout = runMergeLocalIntoCheckout;
39
+ const path = __importStar(require("path"));
40
+ const rail_worktree_release_1 = require("../../runtime/rail-worktree-release");
41
+ const rail_pr_store_1 = require("../../runtime/rail-pr-store");
42
+ const ids_1 = require("../../../../ids");
43
+ const repo_lock_1 = require("../../../../repo-lock");
44
+ const integration_branch_1 = require("../../../../integration-branch");
45
+ const metadata_1 = require("./metadata");
46
+ const transitions_1 = require("./transitions");
47
+ const evidence_1 = require("./evidence");
48
+ const ownership_1 = require("./ownership");
49
+ const chains_1 = require("./chains");
50
+ async function runMergeLocal(deps, row) {
51
+ return (0, repo_lock_1.withRepoLock)(deps.project.path, () => runMergeLocalLocked(deps, row));
52
+ }
53
+ async function runMergeLocalLocked(deps, row) {
54
+ // A stacked milestone delivery targets the chain integration branch, not
55
+ // the previous feature branch recorded as its PR base. Freeze that target
56
+ // for the whole locked operation and every pre/post-advance check.
57
+ const integrationTarget = (0, metadata_1.mergeLocalTargetBranch)(deps, row);
58
+ deps.assertAdmission?.();
59
+ if (!(0, integration_branch_1.isValidBranchName)(integrationTarget) || integrationTarget === 'HEAD' || integrationTarget.startsWith('refs/')) {
60
+ return {
61
+ status: 409,
62
+ body: { error: 'merge_local_blocked', reason: 'unresolved_head', base: integrationTarget,
63
+ detail: 'Configure a local integration branch before accepting this delivery.' },
64
+ };
65
+ }
66
+ const head = await deps.git.run(['symbolic-ref', '--quiet', 'HEAD'], deps.project.path);
67
+ if (head.code !== 0 && head.code !== 1) {
68
+ return { status: 409, body: { error: 'merge_local_blocked', reason: 'unresolved_head', base: integrationTarget } };
69
+ }
70
+ if (head.stdout.trim() === `refs/heads/${integrationTarget}`)
71
+ return runMergeLocalIntoCheckout(deps, row, deps.project.path, integrationTarget);
72
+ // Claim the designated base in an ordinary linked checkout. Git refuses if
73
+ // another worktree already holds it; never update-ref a checked-out branch
74
+ // behind its owner's back or switch/stash the user's current work.
75
+ const safeId = row.id.replace(/[^A-Za-z0-9-]/g, '').slice(0, 64) || 'delivery';
76
+ const target = path.join(deps.assemblyRoot ?? (0, metadata_1.batchWorktreeRoot)(deps.project.slug), `local-base-${safeId}-${(0, ids_1.newId)()}`);
77
+ const added = await deps.git.run(['worktree', 'add', target, integrationTarget], deps.project.path);
78
+ if (added.code !== 0) {
79
+ return {
80
+ status: 409,
81
+ body: {
82
+ error: 'merge_local_blocked', reason: 'integration_branch_busy', base: integrationTarget,
83
+ detail: added.stderr.trim() || added.stdout.trim() || 'The integration branch could not be opened safely.',
84
+ },
85
+ };
86
+ }
87
+ let result;
88
+ try {
89
+ result = await runMergeLocalIntoCheckout(deps, row, target, integrationTarget);
90
+ return result;
91
+ }
92
+ finally {
93
+ // Even failed assembly must release the temporary base checkout. Non-force
94
+ // removal preserves files if an external process wrote there during merge.
95
+ let warning = null;
96
+ try {
97
+ const removed = await deps.git.run(['worktree', 'remove', target], deps.project.path);
98
+ if (removed.code !== 0)
99
+ warning = `integration worktree ${target}: ${removed.stderr.trim() || removed.stdout.trim() || `exit ${removed.code}`}`;
100
+ }
101
+ catch (err) {
102
+ warning = `integration worktree ${target}: ${err instanceof Error ? err.message : String(err)}`;
103
+ }
104
+ if (warning) {
105
+ (0, transitions_1.safetyArchiveRecorder)(deps, row)(target);
106
+ const current = (0, rail_pr_store_1.getPrDelivery)(deps.db, row.id);
107
+ if (current?.operation_token === row.operation_token) {
108
+ const warnings = [...(0, rail_pr_store_1.toPrDeliverySnapshot)(current).cleanupWarnings, warning];
109
+ (0, transitions_1.casTransition)(deps, current, current.decision, { cleanupWarnings: warnings, statusCode: 'cleanup_incomplete' });
110
+ (0, transitions_1.finalizeTransition)(deps, row.id);
111
+ if (result)
112
+ result.body.cleanupWarnings = warnings;
113
+ }
114
+ }
115
+ }
116
+ }
117
+ async function runMergeLocalIntoCheckout(deps, row, targetRepo, integrationTarget) {
118
+ const snap = (0, rail_pr_store_1.toPrDeliverySnapshot)(row);
119
+ const cleanupWarnings = [];
120
+ // Snapshot branch/HEAD before assembly. Local edits are allowed: the final
121
+ // non-forced fast-forward leaves unrelated work intact and Git atomically
122
+ // refuses any overwrite, including ignored files.
123
+ const head = await deps.git.run(['symbolic-ref', '--quiet', 'HEAD'], targetRepo);
124
+ const currentBranch = head.code === 0 ? head.stdout.trim().replace(/^refs\/heads\//, '') : '';
125
+ if (currentBranch !== integrationTarget) {
126
+ return {
127
+ status: 409,
128
+ body: { error: 'merge_local_blocked', reason: 'wrong_branch', current: currentBranch || null, base: integrationTarget },
129
+ };
130
+ }
131
+ const status = await deps.git.run(['status', '--porcelain'], targetRepo);
132
+ if (status.code !== 0) {
133
+ return { status: 409, body: { error: 'merge_local_blocked', reason: 'status_unavailable', base: integrationTarget } };
134
+ }
135
+ const startingHead = await deps.git.run(['rev-parse', '--verify', 'HEAD'], targetRepo);
136
+ const startingSha = startingHead.code === 0 ? startingHead.stdout.trim() : '';
137
+ if (!/^[0-9a-f]{40,64}$/i.test(startingSha)) {
138
+ return { status: 409, body: { error: 'merge_local_blocked', reason: 'unresolved_head', base: integrationTarget } };
139
+ }
140
+ // What to merge: immutable object ids only. The assembled head carries every
141
+ // unit already; without one, merge each settled unit's exact final SHA.
142
+ let toMerge;
143
+ let deliveryHeadSha = null;
144
+ if (row.delivery_sha) {
145
+ if (!evidence_1.COMMIT_SHA_RE.test(row.delivery_sha) || !(await (0, evidence_1.commitObjectExists)(deps, row.delivery_sha))) {
146
+ return { status: 502, body: { error: 'merge_failed', detail: 'The verified delivery commit is unavailable; no branch fallback was merged.' } };
147
+ }
148
+ deliveryHeadSha = row.delivery_sha;
149
+ }
150
+ if (deliveryHeadSha) {
151
+ toMerge = [deliveryHeadSha];
152
+ }
153
+ else {
154
+ toMerge = [];
155
+ for (const unit of snap.branches.filter((b) => b.succeeded)) {
156
+ let sourceSha = unit.finalSha && evidence_1.COMMIT_SHA_RE.test(unit.finalSha) ? unit.finalSha : null;
157
+ if (sourceSha) {
158
+ if (!(await (0, evidence_1.commitObjectExists)(deps, sourceSha)))
159
+ sourceSha = null;
160
+ }
161
+ if (!sourceSha) {
162
+ return {
163
+ status: 502,
164
+ body: { error: 'merge_failed', detail: `verified commit for '${unit.branch}' (ticket #${unit.ticketId}) is unavailable` },
165
+ };
166
+ }
167
+ toMerge.push(sourceSha);
168
+ }
169
+ }
170
+ if (toMerge.length === 0) {
171
+ return { status: 502, body: { error: 'merge_failed', detail: 'no succeeded branch to merge' } };
172
+ }
173
+ // Assemble every merge away from the user's checkout. A conflict can only
174
+ // dirty this disposable detached worktree, never the integration branch.
175
+ const safeId = row.id.replace(/[^A-Za-z0-9-]/g, '').slice(0, 64) || 'delivery';
176
+ const assemblyPath = path.join(deps.assemblyRoot ?? (0, metadata_1.batchWorktreeRoot)(deps.project.slug), `local-merge-${safeId}-${(0, ids_1.newId)()}`);
177
+ const added = await deps.git.run(['worktree', 'add', '--detach', assemblyPath, startingSha], deps.project.path);
178
+ if (added.code !== 0) {
179
+ const detail = (added.stderr.trim() || added.stdout.trim()).split('\n')[0] || `exit ${added.code}`;
180
+ return { status: 502, body: { error: 'merge_failed', detail: `creating isolated assembly: ${detail}` } };
181
+ }
182
+ let assemblyRemovalAttempted = false;
183
+ const removeAssembly = async () => {
184
+ if (assemblyRemovalAttempted)
185
+ return;
186
+ assemblyRemovalAttempted = true;
187
+ try {
188
+ const removed = await deps.git.run(['worktree', 'remove', assemblyPath], deps.project.path);
189
+ if (removed.code !== 0) {
190
+ cleanupWarnings.push(`assembly worktree ${assemblyPath}: ${(removed.stderr.trim() || removed.stdout.trim()).split('\n')[0] || `exit ${removed.code}`}`);
191
+ (0, transitions_1.safetyArchiveRecorder)(deps, row)(assemblyPath);
192
+ }
193
+ }
194
+ catch (err) {
195
+ cleanupWarnings.push(`assembly worktree ${assemblyPath}: ${err instanceof Error ? err.message : String(err)}`);
196
+ (0, transitions_1.safetyArchiveRecorder)(deps, row)(assemblyPath);
197
+ }
198
+ };
199
+ const persistAssemblyFailure = (detail) => {
200
+ const conflict = (0, transitions_1.casTransition)(deps, row, row.decision, {
201
+ deliveryOutcome: 'blocked', statusCode: 'delivery_failed', statusDetail: detail, cleanupWarnings,
202
+ });
203
+ if (conflict)
204
+ return conflict;
205
+ (0, transitions_1.finalizeTransition)(deps, row.id);
206
+ return null;
207
+ };
208
+ try {
209
+ for (const branch of toMerge) {
210
+ const r = await deps.git.run(['merge', '--no-ff', '--no-edit', branch], assemblyPath);
211
+ if (r.code !== 0) {
212
+ try {
213
+ const aborted = await deps.git.run(['merge', '--abort'], assemblyPath);
214
+ if (aborted.code !== 0)
215
+ cleanupWarnings.push(`assembly abort ${branch}: exit ${aborted.code}`);
216
+ }
217
+ catch (err) {
218
+ cleanupWarnings.push(`assembly abort ${branch}: ${err instanceof Error ? err.message : String(err)}`);
219
+ }
220
+ await removeAssembly();
221
+ const detail = (r.stderr.trim() || r.stdout.trim()).split('\n')[0] || `exit ${r.code}`;
222
+ const conflict = persistAssemblyFailure(`merging '${branch}': ${detail}`);
223
+ if (conflict)
224
+ return conflict;
225
+ return { status: 502, body: { error: 'merge_failed', detail: `merging '${branch}': ${detail}` } };
226
+ }
227
+ }
228
+ const assembled = await deps.git.run(['rev-parse', '--verify', 'HEAD'], assemblyPath);
229
+ const assembledSha = assembled.code === 0 ? assembled.stdout.trim() : '';
230
+ if (!/^[0-9a-f]{40,64}$/i.test(assembledSha)) {
231
+ await removeAssembly();
232
+ const detail = 'isolated assembly produced no verifiable HEAD';
233
+ const conflict = persistAssemblyFailure(detail);
234
+ if (conflict)
235
+ return conflict;
236
+ return { status: 502, body: { error: 'merge_failed', detail } };
237
+ }
238
+ const [finalBranch, finalStatus, finalHead] = await Promise.all([
239
+ deps.git.run(['symbolic-ref', '--quiet', 'HEAD'], targetRepo),
240
+ deps.git.run(['status', '--porcelain'], targetRepo),
241
+ deps.git.run(['rev-parse', '--verify', 'HEAD'], targetRepo),
242
+ ]);
243
+ const changedReason = finalBranch.code !== 0 || finalBranch.stdout.trim() !== `refs/heads/${integrationTarget}`
244
+ ? 'wrong_branch'
245
+ : finalStatus.code !== 0
246
+ ? 'status_unavailable'
247
+ : finalHead.code !== 0 || finalHead.stdout.trim() !== startingSha
248
+ ? 'head_changed'
249
+ : null;
250
+ if (changedReason) {
251
+ await removeAssembly();
252
+ if (cleanupWarnings.length > 0) {
253
+ const conflict = (0, transitions_1.casTransition)(deps, row, row.decision, { cleanupWarnings });
254
+ if (conflict)
255
+ return conflict;
256
+ (0, transitions_1.finalizeTransition)(deps, row.id);
257
+ }
258
+ return { status: 409, body: { error: 'merge_local_blocked', reason: changedReason, base: integrationTarget } };
259
+ }
260
+ const advanced = await deps.git.run(['merge', '--ff-only', '--no-overwrite-ignore', assembledSha], targetRepo);
261
+ if (advanced.code !== 0) {
262
+ await removeAssembly();
263
+ if (/would be overwritten|local changes|untracked working tree/i.test(`${advanced.stderr}\n${advanced.stdout}`)) {
264
+ return {
265
+ status: 409,
266
+ body: {
267
+ error: 'merge_local_blocked', reason: 'dirty', base: integrationTarget,
268
+ detail: (advanced.stderr.trim() || advanced.stdout.trim()).slice(0, 1200),
269
+ },
270
+ };
271
+ }
272
+ const detail = (advanced.stderr.trim() || advanced.stdout.trim()).split('\n')[0] || `exit ${advanced.code}`;
273
+ const conflict = persistAssemblyFailure(`advancing '${integrationTarget}': ${detail}`);
274
+ if (conflict)
275
+ return conflict;
276
+ return { status: 502, body: { error: 'merge_failed', detail: `advancing '${integrationTarget}': ${detail}` } };
277
+ }
278
+ const [acceptedBranch, acceptedHead, acceptedBase] = await Promise.all([
279
+ deps.git.run(['symbolic-ref', '--quiet', 'HEAD'], targetRepo),
280
+ deps.git.run(['rev-parse', '--verify', 'HEAD'], targetRepo),
281
+ deps.git.run(['rev-parse', '--verify', `refs/heads/${integrationTarget}`], deps.project.path),
282
+ ]);
283
+ if (acceptedBranch.code !== 0 || acceptedBranch.stdout.trim() !== `refs/heads/${integrationTarget}` ||
284
+ acceptedHead.code !== 0 || acceptedHead.stdout.trim().toLowerCase() !== assembledSha.toLowerCase() ||
285
+ acceptedBase.code !== 0 || acceptedBase.stdout.trim().toLowerCase() !== assembledSha.toLowerCase()) {
286
+ // An external checkout/ref edit can race the final preflight. A successful
287
+ // Git exit is insufficient evidence that the authorized base was updated.
288
+ // Preserve the assembled object and all source worktrees/branches for a
289
+ // retry; never roll back the external edit or mark tickets done.
290
+ assemblyRemovalAttempted = true;
291
+ (0, transitions_1.safetyArchiveRecorder)(deps, row)(assemblyPath);
292
+ const detail = `The integration checkout changed during the final advance. The assembled result is preserved at ${assemblyPath}.`;
293
+ cleanupWarnings.push(detail);
294
+ const conflict = (0, transitions_1.casTransition)(deps, row, row.decision, { cleanupWarnings, statusCode: 'delivery_failed', statusDetail: detail });
295
+ if (conflict)
296
+ return conflict;
297
+ (0, transitions_1.finalizeTransition)(deps, row.id);
298
+ return { status: 409, body: { error: 'merge_local_blocked', reason: 'head_changed', base: integrationTarget, detail } };
299
+ }
300
+ await removeAssembly();
301
+ // Post-advance sweep: the work now lives on
302
+ // the integration branch, so the launch's worktrees + branches are spent.
303
+ cleanupWarnings.push(...await (0, rail_worktree_release_1.releaseRailWorktrees)({
304
+ db: deps.db,
305
+ git: deps.git,
306
+ repoDir: deps.project.path,
307
+ worktreeIds: (0, ownership_1.releasableWorktreeIds)(deps, snap),
308
+ state: 'merged',
309
+ expectedHeadByBranch: (0, rail_worktree_release_1.durableBranchHeads)(snap.branches),
310
+ overlayEvidenceByBranch: (0, rail_worktree_release_1.durableOverlayCleanupEvidence)(snap.branches),
311
+ settlementIgnoredByBranch: (0, rail_worktree_release_1.durableSettlementIgnoredPaths)(snap.branches),
312
+ onSafetyArchive: (0, transitions_1.safetyArchiveRecorder)(deps, row),
313
+ }));
314
+ await (0, ownership_1.deleteOwnedBranchesIfUnchanged)(deps, row, snap, cleanupWarnings);
315
+ const conflict = (0, transitions_1.casTransitionWithTicketEffect)(deps, row, 'merged', {
316
+ deliveryOutcome: 'delivered',
317
+ statusCode: cleanupWarnings.length > 0 ? 'cleanup_incomplete' : 'merged',
318
+ cleanupWarnings,
319
+ }, {
320
+ deliveryId: row.id,
321
+ ticketIds: snap.ticketIds,
322
+ targetStatus: 'done',
323
+ jiraAction: 'merged',
324
+ prUrl: null,
325
+ });
326
+ if (conflict)
327
+ return conflict;
328
+ (0, transitions_1.applyTerminalTicketEffect)(deps, row, 'merged', cleanupWarnings);
329
+ (0, transitions_1.finalizeTransition)(deps, row.id);
330
+ await (0, chains_1.sweepMergedChainAncestors)(deps, row);
331
+ return { status: 200, body: { ok: true, decision: 'merged', merged: true, local: true } };
332
+ }
333
+ finally {
334
+ // Runner exceptions (spawn failures/timeouts) must release the temporary
335
+ // assembly as well. A failed non-force removal leaves a recorded archive.
336
+ await removeAssembly();
337
+ }
338
+ }
@@ -0,0 +1,109 @@
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
+ })();
35
+ Object.defineProperty(exports, "__esModule", { value: true });
36
+ exports.parsePrNumber = parsePrNumber;
37
+ exports.batchWorktreeRoot = batchWorktreeRoot;
38
+ exports.loadPrTicketData = loadPrTicketData;
39
+ exports.resolveTicketFile = resolveTicketFile;
40
+ exports.mergeLocalTargetBranch = mergeLocalTargetBranch;
41
+ const path = __importStar(require("path"));
42
+ const artifact_registry_1 = require("../../../../artifact-registry");
43
+ const jira_db_1 = require("../../../../jira/jira-db");
44
+ const ticket_store_1 = require("../../../specs/runtime/ticket-store");
45
+ const workspace_resolution_1 = require("../../../../workspace-resolution");
46
+ const milestone_chain_store_1 = require("../../../builder/runtime/milestone-chain-store");
47
+ function parsePrNumber(prUrl) {
48
+ const m = /\/pull\/(\d+)/.exec(prUrl);
49
+ return m ? parseInt(m[1], 10) : null;
50
+ }
51
+ function batchWorktreeRoot(slug) {
52
+ // Mirrors rail-isolated-launch's worktreesRoot — derivable, never stored.
53
+ return path.join((0, artifact_registry_1.resolveHome)(), '.specrails', 'projects', slug, 'worktrees');
54
+ }
55
+ /**
56
+ * Load the PR's ticket data (title/labels/description) from the ticket store,
57
+ * with the Jira key resolved PER TICKET: the authoritative `jira_links` row
58
+ * prevails over the ticket's `jira_key` field (JIRA ALWAYS PREVAILS), no HTTP.
59
+ * Tolerant of a missing/corrupt store or link table — degrades to bare local
60
+ * ids, never throws, never blocks PR creation.
61
+ */
62
+ function loadPrTicketData(deps, ticketIds) {
63
+ let tickets = {};
64
+ try {
65
+ tickets = (0, ticket_store_1.readStore)(resolveTicketFile(deps)).tickets;
66
+ }
67
+ catch {
68
+ /* tolerated — the PR falls back to bare ticket refs */
69
+ }
70
+ return ticketIds.map((id) => {
71
+ const t = tickets[String(id)];
72
+ let jiraKey = t?.jira_key ?? null;
73
+ try {
74
+ const link = (0, jira_db_1.getLinkByLocalId)(deps.db, id);
75
+ if (link && !link.tombstoned && link.jiraKey)
76
+ jiraKey = link.jiraKey;
77
+ }
78
+ catch {
79
+ /* tolerated — fall back to the ticket field */
80
+ }
81
+ return {
82
+ ticketId: id,
83
+ title: t?.title ?? null,
84
+ labels: t?.labels ?? null,
85
+ description: t?.description ?? null,
86
+ jiraKey,
87
+ };
88
+ });
89
+ }
90
+ function resolveTicketFile(deps) {
91
+ if (deps.ticketFile)
92
+ return deps.ticketFile;
93
+ const exec = (0, workspace_resolution_1.resolveProjectExecution)({ slug: deps.project.slug, path: deps.project.path });
94
+ return exec.relocated ? exec.ticketsPath : (0, ticket_store_1.resolveTicketStoragePath)(deps.project.path);
95
+ }
96
+ /** Local-integration target: a chain-launched (stacked) delivery integrates
97
+ * into the chain's integration branch, never into its feature base. */
98
+ function mergeLocalTargetBranch(deps, row) {
99
+ if (deps.repositoryChildOf)
100
+ return deps.repositoryIntegrationBranch ?? row.base_branch;
101
+ try {
102
+ for (const chain of (0, milestone_chain_store_1.listChainsTouchingDelivery)(deps.db, row.id)) {
103
+ if (chain.integration_branch)
104
+ return chain.integration_branch;
105
+ }
106
+ }
107
+ catch { /* fall through */ }
108
+ return row.base_branch;
109
+ }