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
@@ -3,151 +3,51 @@ var __importDefault = (this && this.__importDefault) || function (mod) {
3
3
  return (mod && mod.__esModule) ? mod : { "default": mod };
4
4
  };
5
5
  Object.defineProperty(exports, "__esModule", { value: true });
6
- exports.QueueManager = exports.FREESTYLE_COMMAND_RE = exports.InvalidJobDependencyError = exports.JobAlreadyTerminalError = exports.JobNotFoundError = exports.CodexNotFoundError = exports.ClaudeNotFoundError = exports.DEFAULT_ZOMBIE_TIMEOUT_MS = void 0;
7
- exports.buildTelemetryEnv = buildTelemetryEnv;
8
- exports.projectSupportsProfiles = projectSupportsProfiles;
9
- exports.distributeIntEvenly = distributeIntEvenly;
6
+ exports.QueueManager = exports.FREESTYLE_COMMAND_RE = exports.InvalidJobDependencyError = exports.JobAlreadyTerminalError = exports.JobNotFoundError = exports.CodexNotFoundError = exports.ClaudeNotFoundError = exports.DEFAULT_ZOMBIE_TIMEOUT_MS = exports.distributeIntEvenly = exports.projectSupportsProfiles = exports.buildTelemetryEnv = void 0;
7
+ const budget_storage_1 = require("../adapters/budget-storage");
8
+ const __1 = require("..");
9
+ const usage_reader_1 = require("../adapters/usage-reader");
10
+ const __2 = require("..");
10
11
  const fs_1 = __importDefault(require("fs"));
11
12
  const path_1 = __importDefault(require("path"));
12
13
  const readline_1 = require("readline");
13
- const ids_1 = require("./ids");
14
- const win_spawn_1 = require("./util/win-spawn");
15
- const types_1 = require("./types");
16
- const command_resolver_1 = require("./command-resolver");
17
- const rail_isolation_1 = require("./rail-isolation");
18
- const repo_map_1 = require("./repo-map");
19
- const cli_prompt_1 = require("./util/cli-prompt");
20
- const stream_display_1 = require("./util/stream-display");
21
- const hooks_1 = require("./hooks");
22
- const ai_invocations_1 = require("./ai-invocations");
23
- const feature_flags_1 = require("./feature-flags");
24
- const file_provenance_1 = require("./file-provenance");
25
- const result_event_1 = require("./result-event");
14
+ const ids_1 = require("../../../ids");
15
+ const win_spawn_1 = require("../../../util/win-spawn");
16
+ const types_1 = require("../../../types");
17
+ const rail_isolation_1 = require("../../delivery/runtime/rail-isolation");
18
+ const repo_map_1 = require("../../../repo-map");
19
+ const cli_prompt_1 = require("../../../util/cli-prompt");
20
+ const stream_display_1 = require("../../../util/stream-display");
21
+ const hooks_1 = require("../../../hooks");
22
+ const ai_invocations_1 = require("../../accounting/runtime/ai-invocations");
23
+ const feature_flags_1 = require("../../../feature-flags");
24
+ const file_provenance_1 = require("../../code/runtime/file-provenance");
25
+ const result_event_1 = require("../../accounting/runtime/result-event");
26
26
  const crypto_1 = require("crypto");
27
- const codex_spawn_1 = require("./plugins/codex-spawn");
28
- const providers_1 = require("./providers");
29
- const runtime_1 = require("./providers/runtime");
30
- const agent_defaults_1 = require("./agent-defaults");
31
- const codex_otel_bridge_1 = require("./codex-otel-bridge");
32
- const db_1 = require("./db");
27
+ const codex_spawn_1 = require("../../../plugins/codex-spawn");
28
+ const providers_1 = require("../../../providers");
29
+ const runtime_1 = require("../../../providers/runtime");
30
+ const agent_defaults_1 = require("../../agents/runtime/agent-defaults");
31
+ const codex_otel_bridge_1 = require("../../accounting/runtime/codex-otel-bridge");
32
+ const db_1 = require("../../../db");
33
33
  const interactive_job_session_1 = require("./interactive-job-session");
34
- const attachment_manager_1 = require("./attachment-manager");
35
- const ticket_store_1 = require("./ticket-store");
36
- const spec_addenda_1 = require("./spec-addenda");
37
- const binary_probe_1 = require("./binary-probe");
38
- const workspace_manager_1 = require("./workspace-manager");
39
- const claude_trust_1 = require("./claude-trust");
40
- const workspace_resolution_1 = require("./workspace-resolution");
41
- const project_env_1 = require("./project-env");
42
- const framework_manager_1 = require("./framework-manager");
43
- const openspec_shim_1 = require("./openspec-shim");
44
- const artifact_registry_1 = require("./artifact-registry");
45
- // ─── Telemetry env helpers ────────────────────────────────────────────────────
46
- /** Build the OTLP/telemetry environment variable block for a spawned AI-CLI
47
- * process. Extracted as a pure function so it is unit-testable without a full
48
- * spawn.
49
- *
50
- * Provider-aware: claude and codex honour the standard `OTEL_*` env-var
51
- * convention (plus claude's `CLAUDE_CODE_ENABLE_TELEMETRY=1` master switch),
52
- * but the Gemini CLI does NOT — it reads its own `GEMINI_TELEMETRY_*` prefixed
53
- * vars (verified against google-gemini/gemini-cli docs/cli/telemetry.md) and
54
- * defaults to gRPC, so gemini rails need `GEMINI_TELEMETRY_OTLP_PROTOCOL=http`
55
- * and the OTLP endpoint pointed at our loopback receiver. Resource attributes
56
- * still flow via the standard `OTEL_RESOURCE_ATTRIBUTES` (read by the OTel JS
57
- * SDK that the Gemini CLI uses), so the receiver can route by job/project id.
58
- *
59
- * The `providerId` argument defaults to `'claude'` so existing claude/codex
60
- * call paths stay byte-identical. */
61
- function buildTelemetryEnv(jobId, projectId, desktopPort, extraResourceAttributes = {}, providerId = 'claude') {
62
- const baseAttrs = [
63
- ['specrails.job_id', jobId],
64
- ['specrails.project_id', projectId],
65
- ];
66
- for (const [k, v] of Object.entries(extraResourceAttributes)) {
67
- baseAttrs.push([k, String(v)]);
68
- }
69
- const resourceAttributes = baseAttrs.map(([k, v]) => `${k}=${v}`).join(',');
70
- const endpoint = `http://127.0.0.1:${desktopPort}/otlp`;
71
- if (providerId === 'gemini') {
72
- // Gemini CLI uses its own env contract (not OTEL_*). Defaults to gRPC, so we
73
- // must force the http transport to reach our OTLP/HTTP JSON receiver, and
74
- // target the `local` backend (not gcp). OTEL_RESOURCE_ATTRIBUTES is still
75
- // honoured by the underlying OTel SDK for job/project routing.
76
- return {
77
- GEMINI_TELEMETRY_ENABLED: 'true',
78
- GEMINI_TELEMETRY_TARGET: 'local',
79
- GEMINI_TELEMETRY_OTLP_ENDPOINT: endpoint,
80
- GEMINI_TELEMETRY_OTLP_PROTOCOL: 'http',
81
- GEMINI_TELEMETRY_TRACES_ENABLED: 'true',
82
- OTEL_RESOURCE_ATTRIBUTES: resourceAttributes,
83
- };
84
- }
85
- // claude (master switch + OTEL_*) and codex (OTEL_* only) — byte-identical to
86
- // the pre-fix block for both.
87
- return {
88
- CLAUDE_CODE_ENABLE_TELEMETRY: '1',
89
- OTEL_EXPORTER_OTLP_ENDPOINT: endpoint,
90
- OTEL_EXPORTER_OTLP_PROTOCOL: 'http/json',
91
- OTEL_METRICS_EXPORTER: 'otlp',
92
- OTEL_LOGS_EXPORTER: 'otlp',
93
- OTEL_TRACES_EXPORTER: 'otlp',
94
- OTEL_RESOURCE_ATTRIBUTES: resourceAttributes,
95
- };
96
- }
97
- /** Detect whether a project's installed specrails-core version supports the
98
- * profile-aware pipeline (shipped in 4.1.0). Returns false when the version
99
- * file is missing or unparseable so we default to legacy (safer). */
100
- function projectSupportsProfiles(projectPath) {
101
- const candidates = [
102
- path_1.default.join(projectPath, '.specrails', 'specrails-version'),
103
- path_1.default.join(projectPath, '.specrails-version'),
104
- ];
105
- for (const p of candidates) {
106
- if (!fs_1.default.existsSync(p))
107
- continue;
108
- try {
109
- const raw = fs_1.default.readFileSync(p, 'utf8').trim();
110
- const [ma, mi, pa] = raw.split('.').map((n) => parseInt(n, 10));
111
- if (isNaN(ma) || isNaN(mi) || isNaN(pa))
112
- return false;
113
- return ma > 4 || (ma === 4 && mi > 1) || (ma === 4 && mi === 1 && pa >= 0);
114
- }
115
- catch {
116
- return false;
117
- }
118
- }
119
- return false;
120
- }
121
- /**
122
- * Distribute an integer `total` across `n` buckets via the largest-remainder
123
- * method so the per-bucket values sum EXACTLY back to `total` (no floor loss).
124
- * Mirrors smash-runner's `distributeInt` — used to split a multi-ticket job's
125
- * token / turn totals across one ai_invocations row per ticket
126
- * (COST-ACCOUNTING-AUDIT MED-7). Returns `undefined` per bucket when the input
127
- * is absent so the row carries NULL rather than a spurious 0.
128
- */
129
- function distributeIntEvenly(total, n) {
130
- if (total === null || total === undefined)
131
- return new Array(n).fill(undefined);
132
- const t = Math.trunc(total);
133
- const base = Math.floor(t / n);
134
- let remainder = t - base * n;
135
- const out = new Array(n);
136
- for (let i = 0; i < n; i++) {
137
- // Hand the leftover to the leading buckets; sign-safe for negative totals.
138
- if (remainder > 0) {
139
- out[i] = base + 1;
140
- remainder -= 1;
141
- }
142
- else if (remainder < 0) {
143
- out[i] = base - 1;
144
- remainder += 1;
145
- }
146
- else
147
- out[i] = base;
148
- }
149
- return out;
150
- }
34
+ const attachment_manager_1 = require("../../../attachment-manager");
35
+ const ticket_store_1 = require("../../specs/runtime/ticket-store");
36
+ const spec_addenda_1 = require("../../specs/runtime/spec-addenda");
37
+ const binary_probe_1 = require("../../../binary-probe");
38
+ const workspace_manager_1 = require("../../../workspace-manager");
39
+ const claude_trust_1 = require("../../../claude-trust");
40
+ const workspace_resolution_1 = require("../../../workspace-resolution");
41
+ const project_env_1 = require("../../../project-env");
42
+ const framework_manager_1 = require("../../../framework-manager");
43
+ const openspec_shim_1 = require("../../../openspec-shim");
44
+ const artifact_registry_1 = require("../../../artifact-registry");
45
+ const telemetry_env_1 = require("../../../providers/telemetry-env");
46
+ Object.defineProperty(exports, "buildTelemetryEnv", { enumerable: true, get: function () { return telemetry_env_1.buildTelemetryEnv; } });
47
+ const project_profile_support_1 = require("../../../project-profile-support");
48
+ Object.defineProperty(exports, "projectSupportsProfiles", { enumerable: true, get: function () { return project_profile_support_1.projectSupportsProfiles; } });
49
+ const distribute_int_1 = require("../../../util/distribute-int");
50
+ Object.defineProperty(exports, "distributeIntEvenly", { enumerable: true, get: function () { return distribute_int_1.distributeIntEvenly; } });
151
51
  function maxNullable(left, right) {
152
52
  const safeLeft = typeof left === 'number' && Number.isFinite(left) && left >= 0 ? left : null;
153
53
  const safeRight = typeof right === 'number' && Number.isFinite(right) && right >= 0 ? right : null;
@@ -157,24 +57,6 @@ function maxNullable(left, right) {
157
57
  return safeLeft;
158
58
  return Math.max(safeLeft, safeRight);
159
59
  }
160
- function sanitizeRecoveredResult(result) {
161
- const safe = { ...result };
162
- const numeric = [
163
- 'tokens_in', 'tokens_out', 'tokens_cache_read', 'tokens_cache_create',
164
- 'total_cost_usd', 'num_turns', 'duration_ms', 'duration_api_ms',
165
- ];
166
- for (const key of numeric) {
167
- const value = safe[key];
168
- if (value !== undefined && (typeof value !== 'number' || !Number.isFinite(value) || value < 0)) {
169
- delete safe[key];
170
- }
171
- }
172
- if (safe.model !== undefined && typeof safe.model !== 'string')
173
- delete safe.model;
174
- if (safe.session_id !== undefined && typeof safe.session_id !== 'string')
175
- delete safe.session_id;
176
- return safe;
177
- }
178
60
  const LOG_BUFFER_MAX = 5000;
179
61
  const LOG_BUFFER_DROP = 1000;
180
62
  exports.DEFAULT_ZOMBIE_TIMEOUT_MS = 1_800_000; // 30 minutes
@@ -1284,13 +1166,6 @@ class QueueManager {
1284
1166
  phasesForCommand(command) {
1285
1167
  return this._phasesForCommand(command);
1286
1168
  }
1287
- /**
1288
- * Resolve a slash command into a full prompt with $ARGUMENTS substituted.
1289
- * Delegates to the shared resolveCommand utility in command-resolver.ts.
1290
- */
1291
- _resolveCommand(command) {
1292
- return (0, command_resolver_1.resolveCommand)(command, this._cwd ?? process.cwd());
1293
- }
1294
1169
  _phasesForCommand(command) {
1295
1170
  // Extract slug from command strings like "/specrails:implement #5" or "implement"
1296
1171
  const firstToken = command.trim().split(/\s+/)[0];
@@ -1319,67 +1194,14 @@ class QueueManager {
1319
1194
  * locate/replace the rows later.
1320
1195
  */
1321
1196
  _recordJobInvocations(params) {
1322
- const { jobId, provider, status, startedAt, finishedAt, ticketIds, estimated, result } = params;
1323
1197
  const db = this._db;
1324
1198
  const projectId = this._projectId;
1325
1199
  if (!db || !projectId)
1326
1200
  return [];
1327
- // Single-ticket / no-ticket: one row, plain jobId (byte-compatible).
1328
- if (ticketIds.length <= 1) {
1329
- (0, ai_invocations_1.recordInvocation)(db, {
1330
- id: (0, crypto_1.randomUUID)(),
1331
- project_id: projectId,
1332
- provider,
1333
- surface: 'job',
1334
- surface_ref_id: jobId,
1335
- ticket_id: ticketIds[0] ?? null,
1336
- conversation_id: params.conversationId ?? null,
1337
- status,
1338
- started_at: startedAt,
1339
- finished_at: finishedAt,
1340
- total_cost_usd_estimated: estimated,
1341
- ...result,
1342
- });
1343
- return [jobId];
1344
- }
1345
- // Multi-ticket: split across one row per ticket. Cost & duration split evenly
1346
- // as floats; token & turn totals via largest-remainder (sum exactly to total).
1347
- const n = ticketIds.length;
1348
- const evenSplit = (v) => v === undefined ? undefined : v / n;
1349
- const tokensIn = distributeIntEvenly(result.tokens_in, n);
1350
- const tokensOut = distributeIntEvenly(result.tokens_out, n);
1351
- const cacheRead = distributeIntEvenly(result.tokens_cache_read, n);
1352
- const cacheCreate = distributeIntEvenly(result.tokens_cache_create, n);
1353
- const numTurns = distributeIntEvenly(result.num_turns, n);
1354
- const refIds = [];
1355
- ticketIds.forEach((ticketId, i) => {
1356
- const refId = `${jobId}#t${ticketId}`;
1357
- refIds.push(refId);
1358
- (0, ai_invocations_1.recordInvocation)(db, {
1359
- id: (0, crypto_1.randomUUID)(),
1360
- project_id: projectId,
1361
- provider,
1362
- surface: 'job',
1363
- surface_ref_id: refId,
1364
- ticket_id: ticketId,
1365
- conversation_id: params.conversationId ?? null,
1366
- status,
1367
- started_at: startedAt,
1368
- finished_at: finishedAt,
1369
- total_cost_usd_estimated: estimated,
1370
- tokens_in: tokensIn[i],
1371
- tokens_out: tokensOut[i],
1372
- tokens_cache_read: cacheRead[i],
1373
- tokens_cache_create: cacheCreate[i],
1374
- total_cost_usd: evenSplit(result.total_cost_usd),
1375
- num_turns: numTurns[i],
1376
- model: result.model,
1377
- session_id: result.session_id,
1378
- duration_ms: evenSplit(result.duration_ms),
1379
- duration_api_ms: evenSplit(result.duration_api_ms),
1380
- });
1201
+ return (0, __2.recordJobInvocations)(projectId, params, {
1202
+ newId: crypto_1.randomUUID,
1203
+ write: invocation => (0, ai_invocations_1.recordInvocation)(db, invocation),
1381
1204
  });
1382
- return refIds;
1383
1205
  }
1384
1206
  /**
1385
1207
  * Local calendar-day start, expressed as a UTC-ISO instant so it compares
@@ -1402,46 +1224,31 @@ class QueueManager {
1402
1224
  if (!db)
1403
1225
  return;
1404
1226
  try {
1405
- // Per-project daily budget: sum the ai_invocations ledger for the LOCAL day
1406
- // across ALL statuses + surfaces (failed/aborted runs cost real money).
1407
- const dailyBudgetRow = db.prepare(`SELECT value FROM queue_state WHERE key = 'config.daily_budget_usd'`).get();
1408
- if (dailyBudgetRow && this._projectId) {
1409
- const dailyBudget = parseFloat(dailyBudgetRow.value);
1410
- if (dailyBudget > 0) {
1411
- const fromIso = this._localDayStartIso();
1412
- const spendRow = db.prepare(`SELECT COALESCE(SUM(total_cost_usd), 0) as total FROM ai_invocations
1413
- WHERE project_id = ? AND total_cost_usd IS NOT NULL AND started_at >= ?`).get(this._projectId, fromIso);
1414
- const dailySpend = spendRow.total;
1415
- if (dailySpend >= dailyBudget) {
1416
- const wasPaused = this._paused;
1417
- this._paused = true;
1418
- if (!wasPaused) {
1419
- db.prepare(`INSERT OR REPLACE INTO queue_state (key, value) VALUES ('paused', 'true')`).run();
1420
- }
1421
- this._broadcast({ type: 'daily_budget_exceeded', projectId: '', dailySpend, budget: dailyBudget, queuePaused: true });
1227
+ const storage = (0, budget_storage_1.createQueueBudgetStorage)(db);
1228
+ (0, __1.enforceDailyBudgets)({
1229
+ project: () => storage.project(this._projectId, () => this._localDayStartIso()),
1230
+ desktop: this._getDesktopDailyBudget ? () => this._getDesktopDailyBudget() : undefined,
1231
+ exceeded: (scope, { budget, totalSpend }) => {
1232
+ const wasPaused = this._paused;
1233
+ this._paused = true;
1234
+ if (!wasPaused)
1235
+ storage.pause();
1236
+ if (scope === 'project') {
1237
+ this._broadcast({ type: 'daily_budget_exceeded', projectId: '', dailySpend: totalSpend, budget, queuePaused: true });
1422
1238
  try {
1423
- this._onBudgetExceeded?.('daily_budget_exceeded', { dailySpend, budget: dailyBudget, queuePaused: true });
1239
+ this._onBudgetExceeded?.('daily_budget_exceeded', { dailySpend: totalSpend, budget, queuePaused: true });
1424
1240
  }
1425
1241
  catch { /* webhook delivery is best-effort */ }
1426
1242
  }
1427
- }
1428
- }
1429
- // App-level daily budget enforcement (totalSpend computed by the caller).
1430
- if (this._getDesktopDailyBudget) {
1431
- const { budget: desktopBudget, totalSpend: desktopTotalSpend } = this._getDesktopDailyBudget();
1432
- if (desktopBudget != null && desktopBudget > 0 && desktopTotalSpend >= desktopBudget) {
1433
- const wasPaused = this._paused;
1434
- this._paused = true;
1435
- if (!wasPaused) {
1436
- db.prepare(`INSERT OR REPLACE INTO queue_state (key, value) VALUES ('paused', 'true')`).run();
1437
- }
1438
- this._broadcast({ type: 'desktop_daily_budget_exceeded', projectId: '', desktopDailySpend: desktopTotalSpend, desktopBudget, queuePaused: true });
1439
- try {
1440
- this._onBudgetExceeded?.('desktop_daily_budget_exceeded', { desktopDailySpend: desktopTotalSpend, desktopBudget, queuePaused: true });
1243
+ else {
1244
+ this._broadcast({ type: 'desktop_daily_budget_exceeded', projectId: '', desktopDailySpend: totalSpend, desktopBudget: budget, queuePaused: true });
1245
+ try {
1246
+ this._onBudgetExceeded?.('desktop_daily_budget_exceeded', { desktopDailySpend: totalSpend, desktopBudget: budget, queuePaused: true });
1247
+ }
1248
+ catch { /* webhook delivery is best-effort */ }
1441
1249
  }
1442
- catch { /* webhook delivery is best-effort */ }
1443
- }
1444
- }
1250
+ },
1251
+ });
1445
1252
  }
1446
1253
  catch (err) {
1447
1254
  console.error('[queue-manager] daily-budget enforcement failed (db unavailable?):', err);
@@ -1549,19 +1356,7 @@ class QueueManager {
1549
1356
  // an invalid caller: only unique, presently-queued jobs may reach start.
1550
1357
  // In particular, a duplicated id must not relaunch after its first run
1551
1358
  // becomes terminal.
1552
- const seen = new Set();
1553
- const normalizedQueue = [];
1554
- const removedJobIds = [];
1555
- for (const id of this._queue) {
1556
- if (seen.has(id))
1557
- continue;
1558
- seen.add(id);
1559
- const candidate = this._jobs.get(id);
1560
- if (candidate?.status === 'queued')
1561
- normalizedQueue.push(id);
1562
- else
1563
- removedJobIds.push(id);
1564
- }
1359
+ const { normalizedQueue, removedJobIds } = (0, __2.normalizePendingQueue)(this._queue, this._jobs);
1565
1360
  if (normalizedQueue.length !== this._queue.length) {
1566
1361
  this._queue = normalizedQueue;
1567
1362
  this._recomputePositions();
@@ -2348,10 +2143,10 @@ class QueueManager {
2348
2143
  const selection = this._jobProfileSelection.get(jobId); // undefined|null|string
2349
2144
  // When relocated, core + `.specrails/profiles` live in the workspace
2350
2145
  // (execution.cwd); legacy reads from the repo (execution.cwd === repo).
2351
- const coreSupports = projectSupportsProfiles(execution.cwd);
2146
+ const coreSupports = (0, project_profile_support_1.projectSupportsProfiles)(execution.cwd);
2352
2147
  if (selection !== null && coreSupports) {
2353
2148
  // selection is string (explicit) or undefined (default resolution)
2354
- const { resolveProfile, snapshotForJob, persistJobProfile, } = require('./profile-manager');
2149
+ const { resolveProfile, snapshotForJob, persistJobProfile, } = require('../../agents/runtime/profile-manager');
2355
2150
  let resolved = resolveProfile(execution.cwd, selection ?? undefined, adapter.id);
2356
2151
  // Global agent defaults: fill per-agent model gaps in the resolved
2357
2152
  // profile, or synthesize a baseline profile when the project has
@@ -2438,7 +2233,7 @@ class QueueManager {
2438
2233
  extra['specrails.framework_version'] = frameworkVersion;
2439
2234
  spawnEnv = {
2440
2235
  ...spawnEnv,
2441
- ...buildTelemetryEnv(jobId, this._projectId, this._desktopPort, extra, adapter.id),
2236
+ ...(0, telemetry_env_1.buildTelemetryEnv)(jobId, this._projectId, this._desktopPort, extra, adapter.id),
2442
2237
  };
2443
2238
  }
2444
2239
  // Inject the profile path whenever the adapter honours it (was: claude-
@@ -2465,7 +2260,7 @@ class QueueManager {
2465
2260
  let resolver = this._resolvePluginsForSpawn;
2466
2261
  let snapshotter = null;
2467
2262
  if (!resolver) {
2468
- const pluginIntegration = require('./plugins/rail-integration');
2263
+ const pluginIntegration = require('../../../plugins/rail-integration');
2469
2264
  resolver = pluginIntegration.resolvePluginsForSpawn;
2470
2265
  snapshotter = pluginIntegration.snapshotPluginsForJob;
2471
2266
  }
@@ -2481,7 +2276,7 @@ class QueueManager {
2481
2276
  if (pluginActive.length > 0 || pluginDegraded.length > 0) {
2482
2277
  // The injected resolver normally returns an empty test fixture. Load
2483
2278
  // the snapshotter lazily only if its result actually needs one.
2484
- snapshotter ??= require('./plugins/rail-integration').snapshotPluginsForJob;
2279
+ snapshotter ??= require('../../../plugins/rail-integration').snapshotPluginsForJob;
2485
2280
  pluginSnapshotPath = snapshotter(this._projectSlug, jobId, this._projectId, pluginActive, pluginDegraded);
2486
2281
  }
2487
2282
  for (const d of pluginDegraded) {
@@ -2534,7 +2329,7 @@ class QueueManager {
2534
2329
  }
2535
2330
  spawnEnv = {
2536
2331
  ...spawnEnv,
2537
- ...buildTelemetryEnv(jobId, this._projectId, this._desktopPort, extra),
2332
+ ...(0, telemetry_env_1.buildTelemetryEnv)(jobId, this._projectId, this._desktopPort, extra),
2538
2333
  };
2539
2334
  }
2540
2335
  }
@@ -3388,7 +3183,7 @@ class QueueManager {
3388
3183
  });
3389
3184
  try {
3390
3185
  const finalised = (0, result_event_1.finaliseInvocationResult)(adapter, adapterEvents, { fallbackModel: spawnedModel });
3391
- const normalised = sanitizeRecoveredResult(finalised.result);
3186
+ const normalised = (0, __2.sanitizeRecoveredResult)(finalised.result);
3392
3187
  const estimated = finalised.estimated;
3393
3188
  const hasRealSpend = (normalised.total_cost_usd ?? 0) > 0 ||
3394
3189
  (normalised.tokens_in ?? 0) > 0 ||
@@ -3706,7 +3501,7 @@ class QueueManager {
3706
3501
  if (!job.dependsOnJobId)
3707
3502
  return true;
3708
3503
  const parentStatus = this._getDependencyStatus(job.dependsOnJobId);
3709
- return parentStatus === null || parentStatus === 'completed';
3504
+ return (0, __2.isDependencySatisfied)(parentStatus);
3710
3505
  }
3711
3506
  _skipDependents(parentJobId, reason) {
3712
3507
  const toSkip = [];
@@ -3857,8 +3652,7 @@ class QueueManager {
3857
3652
  * cumulative cost/turn snapshot, so segments must be folded exactly like the
3858
3653
  * live session; assistant-only tail frames are one estimated in-flight turn. */
3859
3654
  _recoverPersistedJobUsage(jobId, providerId, fallbackModel, interactive) {
3860
- const db = this._db;
3861
- if (!db)
3655
+ if (!this._db)
3862
3656
  return { result: {}, estimated: false, authoritative: false };
3863
3657
  let adapter;
3864
3658
  try {
@@ -3867,218 +3661,7 @@ class QueueManager {
3867
3661
  catch {
3868
3662
  adapter = this._adapter;
3869
3663
  }
3870
- const parse = (row) => {
3871
- try {
3872
- return (0, runtime_1.parseStreamEvents)(adapter, row.payload);
3873
- }
3874
- catch (err) {
3875
- console.warn(`[queue-manager] ignored malformed durable event for ${jobId}:`, err);
3876
- return [];
3877
- }
3878
- };
3879
- const makeUsageAccumulator = () => {
3880
- const totals = {
3881
- tokens_in: 0,
3882
- tokens_out: 0,
3883
- tokens_cache_read: 0,
3884
- tokens_cache_create: 0,
3885
- total_cost_usd: 0,
3886
- num_turns: 0,
3887
- duration_ms: 0,
3888
- duration_api_ms: 0,
3889
- };
3890
- let model = fallbackModel ?? undefined;
3891
- let sessionId;
3892
- let estimated = false;
3893
- const snapshots = new Map();
3894
- const MAX_SNAPSHOT_KEYS = 4_096;
3895
- const add = (event, seq) => {
3896
- const finalised = (0, result_event_1.finaliseInvocationResult)(adapter, [event], { fallbackModel: model });
3897
- const result = sanitizeRecoveredResult(finalised.result);
3898
- const raw = event.kind === 'other' ? event.raw : null;
3899
- const message = raw && typeof raw.message === 'object' && raw.message
3900
- ? raw.message
3901
- : null;
3902
- const directMessageId = event.messageId;
3903
- const messageId = directMessageId ?? (message && typeof message.id === 'string' ? message.id : undefined);
3904
- const stableId = messageId ? `message:${messageId}` : `${event.kind}:${seq}`;
3905
- const previous = snapshots.get(stableId) ?? {};
3906
- const addDelta = (key) => {
3907
- const current = result[key];
3908
- if (typeof current !== 'number')
3909
- return;
3910
- const prior = previous[key];
3911
- totals[key] += Math.max(0, current - (typeof prior === 'number' ? prior : 0));
3912
- };
3913
- addDelta('tokens_in');
3914
- addDelta('tokens_out');
3915
- addDelta('tokens_cache_read');
3916
- addDelta('tokens_cache_create');
3917
- addDelta('total_cost_usd');
3918
- addDelta('num_turns');
3919
- addDelta('duration_ms');
3920
- addDelta('duration_api_ms');
3921
- model = result.model ?? model;
3922
- sessionId = result.session_id ?? sessionId;
3923
- estimated = estimated || finalised.estimated;
3924
- if (!snapshots.has(stableId) && snapshots.size >= MAX_SNAPSHOT_KEYS) {
3925
- snapshots.delete(snapshots.keys().next().value);
3926
- }
3927
- // Frames for one provider message are contiguous; retain a bounded LRU
3928
- // of recent snapshots for retransmission/delta dedupe without letting a
3929
- // malicious transcript allocate one map entry per event forever.
3930
- snapshots.delete(stableId);
3931
- snapshots.set(stableId, { ...previous, ...result });
3932
- };
3933
- const result = () => {
3934
- const hasUsage = Object.values(totals).some((value) => value > 0);
3935
- return {
3936
- result: hasUsage ? { ...totals, model, session_id: sessionId } : {},
3937
- estimated,
3938
- };
3939
- };
3940
- return { add, result };
3941
- };
3942
- if (!interactive) {
3943
- const accumulator = makeUsageAccumulator();
3944
- let lastValidResult = null;
3945
- const events = db.prepare(`
3946
- SELECT seq, event_type, payload FROM events
3947
- WHERE job_id = ? AND source = 'stdout' AND event_type != 'log'
3948
- ORDER BY seq, id
3949
- `).iterate(jobId);
3950
- for (const row of events) {
3951
- for (const event of parse(row)) {
3952
- if (event.kind === 'result') {
3953
- const finalised = (0, result_event_1.finaliseInvocationResult)(adapter, [event], {
3954
- fallbackModel: fallbackModel ?? undefined,
3955
- });
3956
- lastValidResult = {
3957
- ...finalised,
3958
- result: sanitizeRecoveredResult(finalised.result),
3959
- };
3960
- }
3961
- else {
3962
- accumulator.add(event, row.seq);
3963
- }
3964
- }
3965
- }
3966
- const fallback = accumulator.result();
3967
- if (lastValidResult) {
3968
- const result = { ...fallback.result };
3969
- for (const [key, value] of Object.entries(lastValidResult.result)) {
3970
- // Provider normalisers intentionally retain optional keys with an
3971
- // undefined value. Only concrete terminal fields are authoritative;
3972
- // an omitted field must not erase recoverable assistant evidence.
3973
- if (value !== undefined) {
3974
- result[key] = value;
3975
- }
3976
- }
3977
- return {
3978
- result,
3979
- // A native terminal cost is authoritative. When the terminal frame
3980
- // omits cost, preserve whether the assistant-frame backfill was an
3981
- // estimate instead of silently relabelling it as exact.
3982
- estimated: result.total_cost_usd === lastValidResult.result.total_cost_usd &&
3983
- lastValidResult.result.total_cost_usd !== undefined
3984
- ? lastValidResult.estimated
3985
- : (lastValidResult.estimated || fallback.estimated),
3986
- authoritative: true,
3987
- };
3988
- }
3989
- return { ...fallback, authoritative: false };
3990
- }
3991
- const totals = {
3992
- tokens_in: 0,
3993
- tokens_out: 0,
3994
- tokens_cache_read: 0,
3995
- tokens_cache_create: 0,
3996
- total_cost_usd: 0,
3997
- num_turns: 0,
3998
- duration_ms: 0,
3999
- duration_api_ms: 0,
4000
- };
4001
- let model = fallbackModel ?? undefined;
4002
- let sessionId;
4003
- let baselineCost = 0;
4004
- let baselineTurns = 0;
4005
- let estimated = false;
4006
- let lastResultSeq = -1;
4007
- const resultRows = db.prepare(`
4008
- SELECT seq, event_type, payload FROM events
4009
- WHERE job_id = ? AND source = 'stdout' AND event_type = 'result'
4010
- ORDER BY seq, id
4011
- `).iterate(jobId);
4012
- for (const row of resultRows) {
4013
- for (const event of parse(row)) {
4014
- if (event.kind !== 'result')
4015
- continue;
4016
- const finalised = (0, result_event_1.finaliseInvocationResult)(adapter, [event], { fallbackModel: model });
4017
- const result = sanitizeRecoveredResult(finalised.result);
4018
- totals.tokens_in += result.tokens_in ?? 0;
4019
- totals.tokens_out += result.tokens_out ?? 0;
4020
- totals.tokens_cache_read += result.tokens_cache_read ?? 0;
4021
- totals.tokens_cache_create += result.tokens_cache_create ?? 0;
4022
- const cumulativeCost = result.total_cost_usd ?? baselineCost;
4023
- totals.total_cost_usd += Math.max(0, cumulativeCost - baselineCost);
4024
- baselineCost = cumulativeCost;
4025
- const cumulativeTurns = result.num_turns ?? (baselineTurns + 1);
4026
- totals.num_turns += Math.max(0, cumulativeTurns - baselineTurns);
4027
- baselineTurns = cumulativeTurns;
4028
- totals.duration_ms += result.duration_ms ?? 0;
4029
- totals.duration_api_ms += result.duration_api_ms ?? 0;
4030
- model = result.model ?? model;
4031
- sessionId = result.session_id ?? sessionId;
4032
- estimated = estimated || finalised.estimated;
4033
- lastResultSeq = row.seq;
4034
- }
4035
- }
4036
- const tail = makeUsageAccumulator();
4037
- const tailRows = db.prepare(`
4038
- SELECT seq, event_type, payload FROM events
4039
- WHERE job_id = ? AND source = 'stdout' AND event_type != 'log' AND seq > ?
4040
- ORDER BY seq, id
4041
- `).iterate(jobId, lastResultSeq);
4042
- for (const row of tailRows) {
4043
- for (const event of parse(row)) {
4044
- if (event.kind !== 'result')
4045
- tail.add(event, row.seq);
4046
- }
4047
- }
4048
- const tailUsage = tail.result();
4049
- const tailResult = tailUsage.result;
4050
- const hasTailUsage = [
4051
- tailResult.tokens_in,
4052
- tailResult.tokens_out,
4053
- tailResult.tokens_cache_read,
4054
- tailResult.tokens_cache_create,
4055
- tailResult.total_cost_usd,
4056
- ].some((value) => typeof value === 'number' && value > 0);
4057
- if (hasTailUsage) {
4058
- totals.tokens_in += tailResult.tokens_in ?? 0;
4059
- totals.tokens_out += tailResult.tokens_out ?? 0;
4060
- totals.tokens_cache_read += tailResult.tokens_cache_read ?? 0;
4061
- totals.tokens_cache_create += tailResult.tokens_cache_create ?? 0;
4062
- totals.total_cost_usd += tailResult.total_cost_usd ?? 0;
4063
- totals.num_turns += tailResult.num_turns ?? 1;
4064
- totals.duration_ms += tailResult.duration_ms ?? 0;
4065
- totals.duration_api_ms += tailResult.duration_api_ms ?? 0;
4066
- model = tailResult.model ?? model;
4067
- sessionId = tailResult.session_id ?? sessionId;
4068
- estimated = estimated || tailUsage.estimated;
4069
- }
4070
- const hasRecoveredUsage = Object.values(totals).some((value) => value > 0);
4071
- return {
4072
- result: hasRecoveredUsage
4073
- ? {
4074
- ...totals,
4075
- model,
4076
- session_id: sessionId,
4077
- }
4078
- : {},
4079
- estimated,
4080
- authoritative: false,
4081
- };
3664
+ return (0, __2.recoverJobUsage)((0, usage_reader_1.createDurableUsageReader)(this._db, jobId, adapter), fallbackModel, interactive);
4082
3665
  }
4083
3666
  _decodeRecoveryPayload(jobId, encoded) {
4084
3667
  const payload = JSON.parse(encoded);