specrails-desktop 2.55.0 → 2.56.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (368) 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-DdMNmVBk.js} +1 -1
  11. package/client/dist/assets/{AgentBrowserCapture-UcsupCy7.js → AgentBrowserCapture-CeerUf--.js} +1 -1
  12. package/client/dist/assets/{AgentModeAnalyticsPane-CQuxYh8B.js → AgentModeAnalyticsPane-BjGb-8rh.js} +2 -2
  13. package/client/dist/assets/{AgentModeCodePane-zPWbW7ei.js → AgentModeCodePane-8XRkQEo_.js} +2 -2
  14. package/client/dist/assets/{AgentModeJobsPane-CInByIdl.js → AgentModeJobsPane-BN3dgJOA.js} +1 -1
  15. package/client/dist/assets/{AgentsPage-BWvgxaBv.js → AgentsPage-DfHWgP_x.js} +1 -1
  16. package/client/dist/assets/{AnalyticsPage-DP3jakv-.js → AnalyticsPage-CyfhYiBn.js} +1 -1
  17. package/client/dist/assets/{CodePage-BKXiwE5a.js → CodePage-C2Nf-Q5W.js} +1 -1
  18. package/client/dist/assets/{DesktopAnalyticsPage-DryJOaMz.js → DesktopAnalyticsPage-tc0p4jJW.js} +1 -1
  19. package/client/dist/assets/{DocsDialog-BsCG9ksG.js → DocsDialog-Br3bczCp.js} +1 -1
  20. package/client/dist/assets/{DocsPage-Cc-GeKYl.js → DocsPage-BcDr2cBm.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-DFPpdg2D.js} +1 -1
  23. package/client/dist/assets/{JobDetailModal-DHeur9YK.js → JobDetailModal-BdOv-l-M.js} +1 -1
  24. package/client/dist/assets/{JobDetailPage-CraDKzeG.js → JobDetailPage-vBbNeRuz.js} +1 -1
  25. package/client/dist/assets/{JobsPage-CcbuSwj7.js → JobsPage-CJCtPhIz.js} +1 -1
  26. package/client/dist/assets/{LoopBuilderPage-BKtNp494.js → LoopBuilderPage-BemvUOxy.js} +1 -1
  27. package/client/dist/assets/{LoopPreviewModal-DbZd9isy.js → LoopPreviewModal-C6hNAeYN.js} +1 -1
  28. package/client/dist/assets/{LoopsPage-DEg6sIkG.js → LoopsPage-BZr0quvh.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-DOpTV75p.js} +1 -1
  31. package/client/dist/assets/{ProjectSettingsDialog-CAjLgJAZ.js → ProjectSettingsDialog-Dkwrn0z1.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-DcOq-UTA.js +4 -0
  35. package/client/dist/assets/{TemplatePreviewModal-Bqs-9fhn.js → TemplatePreviewModal-Cejcquah.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-C51x61Bz.css +2 -0
  49. package/client/dist/assets/{index-BfAZg5DG.js → index-Cxb288Rj.js} +29 -29
  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 +22 -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/core-runtime-updates.md +5 -0
  79. package/docs/internals/embedded-browser-native-webview-evaluation.md +5 -5
  80. package/docs/internals/gemini-mcp-registration.md +2 -2
  81. package/docs/internals/global-artifacts-alignment-contract.md +1 -1
  82. package/docs/internals/global-artifacts-relocation-evaluation.md +1 -1
  83. package/docs/internals/interactive-jobs.md +8 -8
  84. package/docs/internals/legacy-implementation-notes.md +722 -0
  85. package/docs/internals/loop-step-log-explorer.md +8 -8
  86. package/docs/internals/mission-rail-cards.md +14 -14
  87. package/docs/internals/modular-architecture.md +107 -0
  88. package/docs/internals/profiles.md +1 -1
  89. package/docs/internals/programmatic-agent-runtime.md +66 -0
  90. package/docs/internals/project-builder.md +18 -18
  91. package/docs/internals/review-packet.md +8 -8
  92. package/docs/internals/safe-pr-review-flow.md +11 -11
  93. package/docs/internals/source-architecture.md +131 -0
  94. package/docs/internals/source-map.md +1356 -0
  95. package/docs/internals/spec-addenda.md +65 -9
  96. package/docs/internals/switch-to-agent-mode-design.md +11 -11
  97. package/docs/tracking-cost.md +1 -1
  98. package/package.json +5 -2
  99. package/server/dist/agent-mcp-config.js +1 -1
  100. package/server/dist/attachment-manager.js +1 -1
  101. package/server/dist/build-dirs.js +2 -2
  102. package/server/dist/config.js +0 -3
  103. package/server/dist/core-completion.js +1 -1
  104. package/server/dist/core-execution.js +1 -1
  105. package/server/dist/db/activity.js +39 -0
  106. package/server/dist/db/connection.js +41 -0
  107. package/server/dist/db/conversations.js +48 -0
  108. package/server/dist/db/jobs.js +251 -0
  109. package/server/dist/db/migrations.js +1521 -0
  110. package/server/dist/db/proposals.js +50 -0
  111. package/server/dist/db/settings.js +15 -0
  112. package/server/dist/db/stats.js +61 -0
  113. package/server/dist/db/telemetry.js +56 -0
  114. package/server/dist/db/templates.js +37 -0
  115. package/server/dist/db/types.js +2 -0
  116. package/server/dist/db.js +66 -2224
  117. package/server/dist/desktop-db.js +3 -3
  118. package/server/dist/desktop-router.js +8 -8
  119. package/server/dist/git-diagnostics.js +1 -1
  120. package/server/dist/index.js +11 -11
  121. package/server/dist/integration-branch.js +3 -14
  122. package/server/dist/jira/jira-issue-fields.js +0 -1
  123. package/server/dist/jira/jira-materializer.js +1 -1
  124. package/server/dist/jira/jira-sync-manager.js +1 -1
  125. package/server/dist/mcp/guide.js +16 -2
  126. package/server/dist/mcp/mcp-admin-router.js +1 -1
  127. package/server/dist/mcp/mcp-server.js +1 -1
  128. package/server/dist/mcp/tools/catalog.js +2 -0
  129. package/server/dist/mcp/tools/jobs.js +23 -5
  130. package/server/dist/mcp/tools/rails.js +2 -2
  131. package/server/dist/mcp/tools/recovery.js +35 -0
  132. package/server/dist/mcp/tools/specs.js +2 -2
  133. package/server/dist/mcp/tools/support.js +4 -1
  134. package/server/dist/mcp/tools/types.js +3 -3
  135. package/server/dist/mobile/mobile-gateway.js +1 -1
  136. package/server/dist/mobile/mobile-missions.js +1 -1
  137. package/server/dist/{desktop-analytics.js → modules/accounting/runtime/desktop-analytics.js} +2 -2
  138. package/server/dist/{pricing.js → modules/accounting/runtime/pricing.js} +10 -3
  139. package/server/dist/{result-event.js → modules/accounting/runtime/result-event.js} +3 -3
  140. package/server/dist/{spending.js → modules/accounting/runtime/spending.js} +0 -3
  141. package/server/dist/{telemetry-compactor.js → modules/accounting/runtime/telemetry-compactor.js} +1 -1
  142. package/server/dist/{telemetry-receiver.js → modules/accounting/runtime/telemetry-receiver.js} +2 -2
  143. package/server/dist/{agent-runtime-bridge.js → modules/agent-runtime/runtime/agent-runtime-bridge.js} +2 -2
  144. package/server/dist/{agent-runtime-controls-router.js → modules/agent-runtime/runtime/agent-runtime-controls-router.js} +16 -0
  145. package/server/dist/{agent-runtime-controls.js → modules/agent-runtime/runtime/agent-runtime-controls.js} +100 -8
  146. package/server/dist/{agent-runtime-effective-config.js → modules/agent-runtime/runtime/agent-runtime-effective-config.js} +1 -1
  147. package/server/dist/{agent-runtime-loader.js → modules/agent-runtime/runtime/agent-runtime-loader.js} +3 -3
  148. package/server/dist/{agent-runtime-paths.js → modules/agent-runtime/runtime/agent-runtime-paths.js} +1 -1
  149. package/server/dist/modules/agent-runtime/runtime/agent-runtime-recovery.js +53 -0
  150. package/server/dist/{agent-runtime-settings-router.js → modules/agent-runtime/runtime/agent-runtime-settings-router.js} +2 -2
  151. package/server/dist/{agent-runtime-settings.js → modules/agent-runtime/runtime/agent-runtime-settings.js} +3 -3
  152. package/server/dist/{agent-runtime-settlement.js → modules/agent-runtime/runtime/agent-runtime-settlement.js} +6 -6
  153. package/server/dist/{agent-defaults.js → modules/agents/runtime/agent-defaults.js} +3 -3
  154. package/server/dist/{agent-generator.js → modules/agents/runtime/agent-generator.js} +7 -7
  155. package/server/dist/{agent-refine-manager.js → modules/agents/runtime/agent-refine-manager.js} +5 -5
  156. package/server/dist/{agent-store.js → modules/agents/runtime/agent-store.js} +1 -1
  157. package/server/dist/{profile-manager.js → modules/agents/runtime/profile-manager.js} +2 -2
  158. package/server/dist/{profiles-router.js → modules/agents/runtime/profiles-router.js} +5 -5
  159. package/server/dist/{browser-capture-manager.js → modules/browser/runtime/browser-capture-manager.js} +2 -4
  160. package/server/dist/{browser-playwright.js → modules/browser/runtime/browser-playwright.js} +1 -1
  161. package/server/dist/{blueprint-chat-manager.js → modules/builder/runtime/blueprint-chat-manager.js} +7 -7
  162. package/server/dist/{blueprint-commit.js → modules/builder/runtime/blueprint-commit.js} +8 -8
  163. package/server/dist/{blueprint-draft-parser.js → modules/builder/runtime/blueprint-draft-parser.js} +1 -1
  164. package/server/dist/{blueprint-generation.js → modules/builder/runtime/blueprint-generation.js} +1 -1
  165. package/server/dist/{blueprint-operator-prompt.js → modules/builder/runtime/blueprint-operator-prompt.js} +1 -1
  166. package/server/dist/{blueprint-router.js → modules/builder/runtime/blueprint-router.js} +3 -3
  167. package/server/dist/{blueprint-spec-quality.js → modules/builder/runtime/blueprint-spec-quality.js} +1 -1
  168. package/server/dist/{milestone-chain.js → modules/builder/runtime/milestone-chain.js} +1 -1
  169. package/server/dist/{milestone-progress.js → modules/builder/runtime/milestone-progress.js} +6 -6
  170. package/server/dist/{code-activity.js → modules/code/runtime/code-activity.js} +1 -1
  171. package/server/dist/{code-explorer-router.js → modules/code/runtime/code-explorer-router.js} +5 -5
  172. package/server/dist/{file-provenance.js → modules/code/runtime/file-provenance.js} +1 -1
  173. package/server/dist/{file-story-manager.js → modules/code/runtime/file-story-manager.js} +2 -2
  174. package/server/dist/{file-story.js → modules/code/runtime/file-story.js} +2 -2
  175. package/server/dist/{file-summary-generator.js → modules/code/runtime/file-summary-generator.js} +3 -3
  176. package/server/dist/{file-summary-manager.js → modules/code/runtime/file-summary-manager.js} +3 -3
  177. package/server/dist/{project-code-discovery.js → modules/code/runtime/project-code-discovery.js} +2 -2
  178. package/server/dist/modules/conversations/domain/draft-stream.js +91 -0
  179. package/server/dist/modules/conversations/domain/recovery-context.js +101 -0
  180. package/server/dist/modules/conversations/index.js +10 -0
  181. package/server/dist/{chat-manager.js → modules/conversations/runtime/chat-manager.js} +32 -216
  182. package/server/dist/{context-budget.js → modules/conversations/runtime/context-budget.js} +1 -1
  183. package/server/dist/{explore-cwd-manager.js → modules/conversations/runtime/explore-cwd-manager.js} +1 -1
  184. package/server/dist/{explore-smash.js → modules/conversations/runtime/explore-smash.js} +1 -1
  185. package/server/dist/{explore-stdin-session.js → modules/conversations/runtime/explore-stdin-session.js} +1 -1
  186. package/server/dist/modules/delivery/adapters/decisions/chains.js +138 -0
  187. package/server/dist/modules/delivery/adapters/decisions/contracts.js +2 -0
  188. package/server/dist/modules/delivery/adapters/decisions/create.js +234 -0
  189. package/server/dist/modules/delivery/adapters/decisions/discard.js +251 -0
  190. package/server/dist/modules/delivery/adapters/decisions/dispatch.js +107 -0
  191. package/server/dist/modules/delivery/adapters/decisions/evidence.js +205 -0
  192. package/server/dist/modules/delivery/adapters/decisions/merge-local.js +338 -0
  193. package/server/dist/modules/delivery/adapters/decisions/metadata.js +109 -0
  194. package/server/dist/modules/delivery/adapters/decisions/observations.js +260 -0
  195. package/server/dist/modules/delivery/adapters/decisions/ownership.js +83 -0
  196. package/server/dist/modules/delivery/adapters/decisions/publish.js +242 -0
  197. package/server/dist/modules/delivery/adapters/decisions/recovery.js +425 -0
  198. package/server/dist/modules/delivery/adapters/decisions/retry.js +112 -0
  199. package/server/dist/modules/delivery/adapters/decisions/transitions.js +94 -0
  200. package/server/dist/modules/delivery/domain/decision-policy.js +50 -0
  201. package/server/dist/modules/delivery/domain/state.js +2 -0
  202. package/server/dist/modules/delivery/index.js +7 -0
  203. package/server/dist/{active-pr-continuation.js → modules/delivery/runtime/active-pr-continuation.js} +2 -2
  204. package/server/dist/{delivery-evidence.js → modules/delivery/runtime/delivery-evidence.js} +3 -3
  205. package/server/dist/{multi-repo-bases.js → modules/delivery/runtime/multi-repo-bases.js} +1 -1
  206. package/server/dist/{multi-repo-checkout.js → modules/delivery/runtime/multi-repo-checkout.js} +4 -4
  207. package/server/dist/{multi-repo-delivery.js → modules/delivery/runtime/multi-repo-delivery.js} +4 -4
  208. package/server/dist/{multi-repo-execution.js → modules/delivery/runtime/multi-repo-execution.js} +8 -8
  209. package/server/dist/{pr-body.js → modules/delivery/runtime/pr-body.js} +1 -1
  210. package/server/dist/{pr-follow-up-scope.js → modules/delivery/runtime/pr-follow-up-scope.js} +2 -2
  211. package/server/dist/{pr-follow-up.js → modules/delivery/runtime/pr-follow-up.js} +1 -1
  212. package/server/dist/{pr-naming.js → modules/delivery/runtime/pr-naming.js} +1 -1
  213. package/server/dist/{pr-publisher.js → modules/delivery/runtime/pr-publisher.js} +2 -2
  214. package/server/dist/{rail-isolated-launch.js → modules/delivery/runtime/rail-isolated-launch.js} +29 -27
  215. package/server/dist/{rail-launch-parser.js → modules/delivery/runtime/rail-launch-parser.js} +2 -2
  216. package/server/dist/{rail-merge-orchestrator.js → modules/delivery/runtime/rail-merge-orchestrator.js} +5 -5
  217. package/server/dist/modules/delivery/runtime/rail-pr-decision.js +12 -0
  218. package/server/dist/{rail-pr-delivery.js → modules/delivery/runtime/rail-pr-delivery.js} +1 -1
  219. package/server/dist/{rail-pr-store.js → modules/delivery/runtime/rail-pr-store.js} +2 -2
  220. package/server/dist/{rail-pr-ticket-effects.js → modules/delivery/runtime/rail-pr-ticket-effects.js} +3 -3
  221. package/server/dist/{rail-worktree-release.js → modules/delivery/runtime/rail-worktree-release.js} +4 -4
  222. package/server/dist/{rails-router.js → modules/delivery/runtime/rails-router.js} +66 -67
  223. package/server/dist/{review-packet.js → modules/delivery/runtime/review-packet.js} +3 -3
  224. package/server/dist/modules/execution/adapters/budget-storage.js +21 -0
  225. package/server/dist/modules/execution/adapters/usage-reader.js +38 -0
  226. package/server/dist/modules/execution/application/enforce-budget.js +14 -0
  227. package/server/dist/modules/execution/application/record-job-invocations.js +64 -0
  228. package/server/dist/modules/execution/application/recover-job-usage.js +200 -0
  229. package/server/dist/modules/execution/domain/job-accounting.js +2 -0
  230. package/server/dist/modules/execution/domain/scheduling.js +24 -0
  231. package/server/dist/modules/execution/domain/usage.js +21 -0
  232. package/server/dist/modules/execution/index.js +14 -0
  233. package/server/dist/modules/execution/ports.js +2 -0
  234. package/server/dist/{accept-ladder.js → modules/execution/runtime/accept-ladder.js} +1 -1
  235. package/server/dist/{interactive-job-session.js → modules/execution/runtime/interactive-job-session.js} +11 -11
  236. package/server/dist/{job-phase-breakdown.js → modules/execution/runtime/job-phase-breakdown.js} +1 -1
  237. package/server/dist/{queue-manager.js → modules/execution/runtime/queue-manager.js} +74 -491
  238. package/server/dist/{revision-seed.js → modules/execution/runtime/revision-seed.js} +1 -1
  239. package/server/dist/{spawn-lifecycle.js → modules/execution/runtime/spawn-lifecycle.js} +3 -3
  240. package/server/dist/{stuck-run-detector.js → modules/execution/runtime/stuck-run-detector.js} +1 -1
  241. package/server/dist/{loop-command-catalog.js → modules/loops/runtime/loop-command-catalog.js} +1 -1
  242. package/server/dist/{loop-executors.js → modules/loops/runtime/loop-executors.js} +17 -17
  243. package/server/dist/{loop-factory.js → modules/loops/runtime/loop-factory.js} +2 -21
  244. package/server/dist/{loop-graph.js → modules/loops/runtime/loop-graph.js} +25 -0
  245. package/server/dist/{loop-role-engines.js → modules/loops/runtime/loop-role-engines.js} +4 -4
  246. package/server/dist/{loop-run-manager.js → modules/loops/runtime/loop-run-manager.js} +101 -26
  247. package/server/dist/{loop-runs-store.js → modules/loops/runtime/loop-runs-store.js} +1 -1
  248. package/server/dist/{loop-shell-invocation.js → modules/loops/runtime/loop-shell-invocation.js} +2 -2
  249. package/server/dist/{loop-step-idle.js → modules/loops/runtime/loop-step-idle.js} +1 -1
  250. package/server/dist/{loop-templates.js → modules/loops/runtime/loop-templates.js} +24 -29
  251. package/server/dist/{loops-router.js → modules/loops/runtime/loops-router.js} +2 -2
  252. package/server/dist/{agent-chat-manager.js → modules/missions/runtime/agent-chat-manager.js} +19 -19
  253. package/server/dist/{agent-chat-router.js → modules/missions/runtime/agent-chat-router.js} +6 -6
  254. package/server/dist/{agent-context-resolver.js → modules/missions/runtime/agent-context-resolver.js} +8 -8
  255. package/server/dist/{agent-failure-briefing.js → modules/missions/runtime/agent-failure-briefing.js} +4 -2
  256. package/server/dist/{agent-fence-promotion.js → modules/missions/runtime/agent-fence-promotion.js} +1 -1
  257. package/server/dist/{agent-input-store.js → modules/missions/runtime/agent-input-store.js} +1 -1
  258. package/server/dist/{agent-operator-prompt.js → modules/missions/runtime/agent-operator-prompt.js} +75 -12
  259. package/server/dist/{agent-spec-framing.js → modules/missions/runtime/agent-spec-framing.js} +4 -4
  260. package/server/dist/{agent-steering.js → modules/missions/runtime/agent-steering.js} +1 -1
  261. package/server/dist/{mission-run-notify.js → modules/missions/runtime/mission-run-notify.js} +5 -2
  262. package/server/dist/modules/project-settings/adapters/http.js +24 -0
  263. package/server/dist/modules/project-settings/adapters/sqlite.js +120 -0
  264. package/server/dist/modules/project-settings/application.js +11 -0
  265. package/server/dist/modules/project-settings/domain.js +95 -0
  266. package/server/dist/modules/project-settings/index.js +11 -0
  267. package/server/dist/modules/project-settings/ports.js +2 -0
  268. package/server/dist/{contract-refine-runner.js → modules/specs/runtime/contract-refine-runner.js} +12 -12
  269. package/server/dist/{proposal-manager.js → modules/specs/runtime/proposal-manager.js} +8 -8
  270. package/server/dist/{smash-runner.js → modules/specs/runtime/smash-runner.js} +26 -58
  271. package/server/dist/{spec-addenda-core.js → modules/specs/runtime/spec-addenda-core.js} +2 -2
  272. package/server/dist/{spec-addenda.js → modules/specs/runtime/spec-addenda.js} +3 -3
  273. package/server/dist/{spec-launcher-manager.js → modules/specs/runtime/spec-launcher-manager.js} +8 -8
  274. package/server/dist/{spec-models.js → modules/specs/runtime/spec-models.js} +1 -1
  275. package/server/dist/{ticket-watcher.js → modules/specs/runtime/ticket-watcher.js} +1 -1
  276. package/server/dist/{background-process-control.js → modules/terminals/runtime/background-process-control.js} +1 -1
  277. package/server/dist/{background-process-service.js → modules/terminals/runtime/background-process-service.js} +3 -3
  278. package/server/dist/{background-process-store.js → modules/terminals/runtime/background-process-store.js} +1 -1
  279. package/server/dist/{background-windows-bootstrap.js → modules/terminals/runtime/background-windows-bootstrap.js} +3 -3
  280. package/server/dist/{terminal-manager.js → modules/terminals/runtime/terminal-manager.js} +3 -3
  281. package/server/dist/project-git.js +1 -1
  282. package/server/dist/project-profile-support.js +32 -0
  283. package/server/dist/project-registry.js +34 -40
  284. package/server/dist/project-router-background-processes.js +1 -1
  285. package/server/dist/project-router-chat.js +6 -6
  286. package/server/dist/project-router-git.js +1 -1
  287. package/server/dist/project-router-helpers.js +2 -2
  288. package/server/dist/project-router-jobs.js +14 -12
  289. package/server/dist/project-router-loop-runs.js +12 -12
  290. package/server/dist/project-router-settings.js +15 -75
  291. package/server/dist/project-router-setup.js +2 -2
  292. package/server/dist/project-router-spending.js +4 -4
  293. package/server/dist/project-router-terminals.js +4 -4
  294. package/server/dist/project-router-tickets.js +14 -14
  295. package/server/dist/project-router.js +13 -13
  296. package/server/dist/providers/claude-adapter.js +3 -2
  297. package/server/dist/providers/codex-adapter.js +3 -3
  298. package/server/dist/providers/gemini-adapter.js +1 -1
  299. package/server/dist/providers/telemetry-env.js +55 -0
  300. package/server/dist/runtime-role-prompts-router.js +2 -2
  301. package/server/dist/setup-manager.js +2 -48
  302. package/server/dist/shared/git-branch-name.js +16 -0
  303. package/server/dist/transient-children.js +3 -3
  304. package/server/dist/util/distribute-int.js +33 -0
  305. package/client/dist/assets/ReviewPacketPage-D-UjTef3.js +0 -4
  306. package/client/dist/assets/index-BAtqmAZR.css +0 -2
  307. package/client/dist/assets/packet-CjS_478C.js +0 -1
  308. package/client/dist/assets/packet-D69dKsHN.js +0 -1
  309. package/client/dist/assets/packet-D9rU6Oxo.js +0 -1
  310. package/client/dist/assets/packet-DMDFoamg.js +0 -1
  311. package/client/dist/assets/packet-Dd2RMs1h.js +0 -1
  312. package/client/dist/assets/packet-DjC9OibC.js +0 -1
  313. package/client/dist/assets/packet-DwPtJoDz.js +0 -1
  314. package/client/dist/assets/packet-ceahDg8_.js +0 -1
  315. package/server/dist/rail-pr-decision.js +0 -2377
  316. package/server/dist/ticket-broadcast.js +0 -47
  317. /package/server/dist/{ai-invocations.js → modules/accounting/runtime/ai-invocations.js} +0 -0
  318. /package/server/dist/{codex-otel-bridge.js → modules/accounting/runtime/codex-otel-bridge.js} +0 -0
  319. /package/server/dist/{metrics.js → modules/accounting/runtime/metrics.js} +0 -0
  320. /package/server/dist/{telemetry-export.js → modules/accounting/runtime/telemetry-export.js} +0 -0
  321. /package/server/dist/{agent-runtime-accounting.js → modules/agent-runtime/runtime/agent-runtime-accounting.js} +0 -0
  322. /package/server/dist/{agent-runtime-events.js → modules/agent-runtime/runtime/agent-runtime-events.js} +0 -0
  323. /package/server/dist/{agent-runtime-history.js → modules/agent-runtime/runtime/agent-runtime-history.js} +0 -0
  324. /package/server/dist/{agent-runtime-metrics.js → modules/agent-runtime/runtime/agent-runtime-metrics.js} +0 -0
  325. /package/server/dist/{agent-runtime-package.js → modules/agent-runtime/runtime/agent-runtime-package.js} +0 -0
  326. /package/server/dist/{agent-runtime-repositories.js → modules/agent-runtime/runtime/agent-runtime-repositories.js} +0 -0
  327. /package/server/dist/{agent-runtime-verification-suggestions.js → modules/agent-runtime/runtime/agent-runtime-verification-suggestions.js} +0 -0
  328. /package/server/dist/{agent-refine-db.js → modules/agents/runtime/agent-refine-db.js} +0 -0
  329. /package/server/dist/{browser-capture-types.js → modules/browser/runtime/browser-capture-types.js} +0 -0
  330. /package/server/dist/{browser-context-pool.js → modules/browser/runtime/browser-context-pool.js} +0 -0
  331. /package/server/dist/{browser-network.js → modules/browser/runtime/browser-network.js} +0 -0
  332. /package/server/dist/{browser-viewport.js → modules/browser/runtime/browser-viewport.js} +0 -0
  333. /package/server/dist/{blueprint-render.js → modules/builder/runtime/blueprint-render.js} +0 -0
  334. /package/server/dist/{blueprint-spec-fixtures.js → modules/builder/runtime/blueprint-spec-fixtures.js} +0 -0
  335. /package/server/dist/{blueprint-store.js → modules/builder/runtime/blueprint-store.js} +0 -0
  336. /package/server/dist/{blueprint-types.js → modules/builder/runtime/blueprint-types.js} +0 -0
  337. /package/server/dist/{builder-cwd-manager.js → modules/builder/runtime/builder-cwd-manager.js} +0 -0
  338. /package/server/dist/{milestone-chain-store.js → modules/builder/runtime/milestone-chain-store.js} +0 -0
  339. /package/server/dist/{changes-reader.js → modules/code/runtime/changes-reader.js} +0 -0
  340. /package/server/dist/{context-scope.js → modules/conversations/runtime/context-scope.js} +0 -0
  341. /package/server/dist/{explore-contract-refine.js → modules/conversations/runtime/explore-contract-refine.js} +0 -0
  342. /package/server/dist/{explore-draft-title.js → modules/conversations/runtime/explore-draft-title.js} +0 -0
  343. /package/server/dist/{merge-manager.js → modules/delivery/runtime/merge-manager.js} +0 -0
  344. /package/server/dist/{multi-repo-execution-store.js → modules/delivery/runtime/multi-repo-execution-store.js} +0 -0
  345. /package/server/dist/{pr-lifecycle.js → modules/delivery/runtime/pr-lifecycle.js} +0 -0
  346. /package/server/dist/{rail-isolation.js → modules/delivery/runtime/rail-isolation.js} +0 -0
  347. /package/server/dist/{rail-pr-recovery-git.js → modules/delivery/runtime/rail-pr-recovery-git.js} +0 -0
  348. /package/server/dist/{rail-worktrees-store.js → modules/delivery/runtime/rail-worktrees-store.js} +0 -0
  349. /package/server/dist/{rails-store.js → modules/delivery/runtime/rails-store.js} +0 -0
  350. /package/server/dist/{job-listing.js → modules/execution/runtime/job-listing.js} +0 -0
  351. /package/server/dist/{job-spawn-idempotency.js → modules/execution/runtime/job-spawn-idempotency.js} +0 -0
  352. /package/server/dist/{run-duration-stats.js → modules/execution/runtime/run-duration-stats.js} +0 -0
  353. /package/server/dist/{verification-sentinel.js → modules/execution/runtime/verification-sentinel.js} +0 -0
  354. /package/server/dist/{loop-constants.js → modules/loops/runtime/loop-constants.js} +0 -0
  355. /package/server/dist/{loop-decider.js → modules/loops/runtime/loop-decider.js} +0 -0
  356. /package/server/dist/{loop-effect.js → modules/loops/runtime/loop-effect.js} +0 -0
  357. /package/server/dist/{loop-preview.js → modules/loops/runtime/loop-preview.js} +0 -0
  358. /package/server/dist/{loop-templates-ported.js → modules/loops/runtime/loop-templates-ported.js} +0 -0
  359. /package/server/dist/{loops-store.js → modules/loops/runtime/loops-store.js} +0 -0
  360. /package/server/dist/{agent-chat-registry.js → modules/missions/runtime/agent-chat-registry.js} +0 -0
  361. /package/server/dist/{agent-cwd-manager.js → modules/missions/runtime/agent-cwd-manager.js} +0 -0
  362. /package/server/dist/{agent-tier.js → modules/missions/runtime/agent-tier.js} +0 -0
  363. /package/server/dist/{spec-contract-prompt.js → modules/specs/runtime/spec-contract-prompt.js} +0 -0
  364. /package/server/dist/{spec-draft-parser.js → modules/specs/runtime/spec-draft-parser.js} +0 -0
  365. /package/server/dist/{ticket-store.js → modules/specs/runtime/ticket-store.js} +0 -0
  366. /package/server/dist/{terminal-marks-store.js → modules/terminals/runtime/terminal-marks-store.js} +0 -0
  367. /package/server/dist/{terminal-osc-parser.js → modules/terminals/runtime/terminal-osc-parser.js} +0 -0
  368. /package/server/dist/{terminal-settings.js → modules/terminals/runtime/terminal-settings.js} +0 -0
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ // ---------------------------------------------------------------------------
3
+ // Constants
4
+ // ---------------------------------------------------------------------------
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.KNOWN_VERBS = exports.DEFAULT_PORT = void 0;
7
+ exports.parseArgs = parseArgs;
8
+ exports.DEFAULT_PORT = 4200;
9
+ exports.KNOWN_VERBS = new Set([
10
+ 'implement',
11
+ 'batch-implement',
12
+ 'why',
13
+ 'get-backlog-specs',
14
+ 'auto-propose-backlog-specs',
15
+ 'propose-spec',
16
+ 'refactor-recommender',
17
+ 'health-check',
18
+ 'compat-check',
19
+ 'enrich',
20
+ ]);
21
+ function parseArgs(argv) {
22
+ // argv is process.argv.slice(2)
23
+ let port = exports.DEFAULT_PORT;
24
+ let projectOverride;
25
+ const args = [...argv];
26
+ // Extract --port <n> and --project <name|path> from any position
27
+ for (let i = 0; i < args.length; i++) {
28
+ if (args[i] === '--port' && i + 1 < args.length) {
29
+ const parsed = parseInt(args[i + 1], 10);
30
+ if (!isNaN(parsed)) {
31
+ port = parsed;
32
+ }
33
+ args.splice(i, 2);
34
+ i--;
35
+ }
36
+ else if (args[i] === '--project' && i + 1 < args.length) {
37
+ projectOverride = args[i + 1];
38
+ args.splice(i, 2);
39
+ i--;
40
+ }
41
+ }
42
+ if (args[0] === '--version' || args[0] === '-v') {
43
+ return { mode: 'version' };
44
+ }
45
+ if (args.length === 0 || args[0] === '--help' || args[0] === '-h') {
46
+ return { mode: 'help' };
47
+ }
48
+ if (args[0] === '--status') {
49
+ return { mode: 'status', port };
50
+ }
51
+ if (args[0] === '--jobs') {
52
+ return { mode: 'jobs', port };
53
+ }
54
+ if (args[0] === 'desktop') {
55
+ return { mode: 'desktop', subArgs: args.slice(1), port };
56
+ }
57
+ // Allow server-management subcommands directly without the 'desktop' prefix:
58
+ // specrails-desktop start → specrails-desktop desktop start
59
+ // specrails-desktop stop → specrails-desktop desktop stop
60
+ // specrails-desktop add → specrails-desktop desktop add
61
+ // etc.
62
+ const DESKTOP_SUBCOMMANDS = new Set(['start', 'stop', 'status', 'add', 'remove', 'list']);
63
+ if (DESKTOP_SUBCOMMANDS.has(args[0])) {
64
+ return { mode: 'desktop', subArgs: args, port };
65
+ }
66
+ const first = args[0];
67
+ // Slash-prefixed command: pass through unchanged
68
+ if (first.startsWith('/')) {
69
+ const resolved = args.join(' ');
70
+ return { mode: 'raw', resolved, port, projectOverride };
71
+ }
72
+ // Known verb: inject /specrails: prefix
73
+ if (exports.KNOWN_VERBS.has(first)) {
74
+ const resolved = `/specrails:${args.join(' ')}`;
75
+ return { mode: 'command', resolved, port, projectOverride };
76
+ }
77
+ // Unknown first token: treat as raw prompt
78
+ const resolved = args.join(' ');
79
+ return { mode: 'raw', resolved, port, projectOverride };
80
+ }
@@ -0,0 +1,125 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.HTTP_REQUEST_TIMEOUT_MS = exports.DETECTION_TIMEOUT_MS = void 0;
7
+ exports.detectWebManager = detectWebManager;
8
+ exports.loadDesktopToken = loadDesktopToken;
9
+ exports.requestTimeoutError = requestTimeoutError;
10
+ exports.httpGet = httpGet;
11
+ exports.httpPost = httpPost;
12
+ const http_1 = __importDefault(require("http"));
13
+ const path_1 = __importDefault(require("path"));
14
+ const os_1 = __importDefault(require("os"));
15
+ const fs_1 = __importDefault(require("fs"));
16
+ exports.DETECTION_TIMEOUT_MS = 500;
17
+ exports.HTTP_REQUEST_TIMEOUT_MS = 15_000;
18
+ function detectWebManager(port) {
19
+ const baseUrl = `http://127.0.0.1:${port}`;
20
+ return new Promise((resolve) => {
21
+ const timer = setTimeout(() => {
22
+ req.destroy();
23
+ resolve({ running: false, baseUrl });
24
+ }, exports.DETECTION_TIMEOUT_MS);
25
+ const req = http_1.default.get(`${baseUrl}/api/health`, { timeout: exports.DETECTION_TIMEOUT_MS }, (res) => {
26
+ clearTimeout(timer);
27
+ res.resume(); // drain the response
28
+ if (res.statusCode !== undefined && res.statusCode >= 200 && res.statusCode < 300) {
29
+ resolve({ running: true, baseUrl });
30
+ }
31
+ else {
32
+ resolve({ running: false, baseUrl });
33
+ }
34
+ });
35
+ req.on('error', () => {
36
+ clearTimeout(timer);
37
+ resolve({ running: false, baseUrl });
38
+ });
39
+ req.on('timeout', () => {
40
+ req.destroy();
41
+ clearTimeout(timer);
42
+ resolve({ running: false, baseUrl });
43
+ });
44
+ });
45
+ }
46
+ // ---------------------------------------------------------------------------
47
+ // HTTP helpers
48
+ // ---------------------------------------------------------------------------
49
+ function loadDesktopToken() {
50
+ const candidates = [
51
+ path_1.default.join(os_1.default.homedir(), '.specrails', 'desktop.token'),
52
+ // Legacy fallback: pre-rename installs keep the token at hub.token until the
53
+ // server migrates it on next startup. Compat only — do not extend.
54
+ path_1.default.join(os_1.default.homedir(), '.specrails', 'hub.token'),
55
+ ];
56
+ for (const tokenPath of candidates) {
57
+ try {
58
+ const t = fs_1.default.readFileSync(tokenPath, 'utf-8').trim();
59
+ if (t.length >= 32)
60
+ return t;
61
+ }
62
+ catch {
63
+ // try next candidate
64
+ }
65
+ }
66
+ return null;
67
+ }
68
+ function requestTimeoutError(url, timeoutMs) {
69
+ return new Error(`Request to ${url} timed out after ${timeoutMs}ms`);
70
+ }
71
+ function httpGet(url, timeoutMs = exports.HTTP_REQUEST_TIMEOUT_MS) {
72
+ return new Promise((resolve, reject) => {
73
+ const token = loadDesktopToken();
74
+ const parsed = new URL(url);
75
+ const headers = {};
76
+ if (token)
77
+ headers['Authorization'] = `Bearer ${token}`;
78
+ const options = {
79
+ hostname: parsed.hostname,
80
+ port: parsed.port,
81
+ path: parsed.pathname + parsed.search,
82
+ headers,
83
+ };
84
+ const req = http_1.default.get(options, (res) => {
85
+ let body = '';
86
+ res.on('data', (chunk) => { body += chunk; });
87
+ res.on('end', () => resolve({ status: res.statusCode ?? 0, body }));
88
+ });
89
+ req.setTimeout(timeoutMs, () => {
90
+ req.destroy(requestTimeoutError(url, timeoutMs));
91
+ });
92
+ req.on('error', reject);
93
+ });
94
+ }
95
+ function httpPost(url, payload, timeoutMs = exports.HTTP_REQUEST_TIMEOUT_MS) {
96
+ return new Promise((resolve, reject) => {
97
+ const data = JSON.stringify(payload);
98
+ const urlObj = new URL(url);
99
+ const token = loadDesktopToken();
100
+ const headers = {
101
+ 'Content-Type': 'application/json',
102
+ 'Content-Length': Buffer.byteLength(data),
103
+ };
104
+ if (token)
105
+ headers['Authorization'] = `Bearer ${token}`;
106
+ const options = {
107
+ hostname: urlObj.hostname,
108
+ port: urlObj.port,
109
+ path: urlObj.pathname,
110
+ method: 'POST',
111
+ headers,
112
+ };
113
+ const req = http_1.default.request(options, (res) => {
114
+ let body = '';
115
+ res.on('data', (chunk) => { body += chunk; });
116
+ res.on('end', () => resolve({ status: res.statusCode ?? 0, body }));
117
+ });
118
+ req.setTimeout(timeoutMs, () => {
119
+ req.destroy(requestTimeoutError(url, timeoutMs));
120
+ });
121
+ req.on('error', reject);
122
+ req.write(data);
123
+ req.end();
124
+ });
125
+ }
@@ -0,0 +1,339 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.DESKTOP_LOG_FILE = exports.DESKTOP_PID_FILE = void 0;
7
+ exports.isPortInUse = isPortInUse;
8
+ exports.readPid = readPid;
9
+ exports.isProcessRunning = isProcessRunning;
10
+ exports.desktopServerPath = desktopServerPath;
11
+ exports.desktopStart = desktopStart;
12
+ exports.desktopStop = desktopStop;
13
+ exports.desktopStatus = desktopStatus;
14
+ exports.desktopAdd = desktopAdd;
15
+ exports.desktopRemove = desktopRemove;
16
+ exports.desktopList = desktopList;
17
+ exports.handleDesktop = handleDesktop;
18
+ const http_1 = __importDefault(require("http"));
19
+ const net_1 = __importDefault(require("net"));
20
+ const path_1 = __importDefault(require("path"));
21
+ const os_1 = __importDefault(require("os"));
22
+ const win_spawn_1 = require("./win-spawn");
23
+ const fs_1 = __importDefault(require("fs"));
24
+ const output_1 = require("./output");
25
+ const desktop_client_1 = require("./desktop-client");
26
+ // ---------------------------------------------------------------------------
27
+ // Server-management subcommand group
28
+ // ---------------------------------------------------------------------------
29
+ exports.DESKTOP_PID_FILE = path_1.default.join(os_1.default.homedir(), '.specrails', 'manager.pid');
30
+ exports.DESKTOP_LOG_FILE = path_1.default.join(os_1.default.homedir(), '.specrails', 'desktop.log');
31
+ function isPortInUse(port) {
32
+ return new Promise((resolve) => {
33
+ const srv = net_1.default.createServer();
34
+ srv.once('error', (err) => {
35
+ resolve(err.code === 'EADDRINUSE');
36
+ });
37
+ srv.once('listening', () => {
38
+ srv.close();
39
+ resolve(false);
40
+ });
41
+ srv.listen(port, '127.0.0.1');
42
+ });
43
+ }
44
+ function readPid() {
45
+ try {
46
+ const raw = fs_1.default.readFileSync(exports.DESKTOP_PID_FILE, 'utf-8').trim();
47
+ const pid = parseInt(raw, 10);
48
+ return isNaN(pid) ? null : pid;
49
+ }
50
+ catch {
51
+ return null;
52
+ }
53
+ }
54
+ function isProcessRunning(pid) {
55
+ try {
56
+ process.kill(pid, 0);
57
+ return true;
58
+ }
59
+ catch {
60
+ return false;
61
+ }
62
+ }
63
+ function desktopServerPath() {
64
+ // __dirname differs by runtime:
65
+ // compiled (npm install): <root>/cli/dist/ → need ../../server/dist/index.js
66
+ // tsx dev: <root>/cli/ → need ../server/dist/index.js
67
+ // Try both, compiled path first.
68
+ const fromDist = path_1.default.resolve(__dirname, '..', '..', 'server', 'dist', 'index.js');
69
+ const fromSrc = path_1.default.resolve(__dirname, '..', 'server', 'dist', 'index.js');
70
+ const devTs = path_1.default.resolve(__dirname, '..', 'server', 'index.ts');
71
+ if (fs_1.default.existsSync(fromDist))
72
+ return fromDist;
73
+ if (fs_1.default.existsSync(fromSrc))
74
+ return fromSrc;
75
+ if (fs_1.default.existsSync(devTs))
76
+ return devTs;
77
+ return fromDist;
78
+ }
79
+ async function desktopStart(port) {
80
+ const pid = readPid();
81
+ if (pid !== null && isProcessRunning(pid)) {
82
+ (0, output_1.cliLog)(`server already running (pid ${pid}) on port ${port}`);
83
+ return 0;
84
+ }
85
+ // Check if port is already in use by another process
86
+ const portBusy = await isPortInUse(port);
87
+ if (portBusy) {
88
+ (0, output_1.cliError)(`port ${port} is already in use by another process`);
89
+ (0, output_1.cliError)(`if a previous server is stale, run: specrails-desktop stop`);
90
+ (0, output_1.cliError)(`or use a different port: specrails-desktop --port <port> start`);
91
+ return 1;
92
+ }
93
+ const serverPath = desktopServerPath();
94
+ const isTs = serverPath.endsWith('.ts');
95
+ const args = isTs
96
+ ? ['tsx', serverPath, '--port', String(port)]
97
+ : ['node', serverPath, '--port', String(port)];
98
+ // Ensure log dir exists and open log file for server output
99
+ try {
100
+ fs_1.default.mkdirSync(path_1.default.dirname(exports.DESKTOP_LOG_FILE), { recursive: true });
101
+ }
102
+ catch { /* ignore */ }
103
+ let logFd;
104
+ try {
105
+ logFd = fs_1.default.openSync(exports.DESKTOP_LOG_FILE, 'a');
106
+ }
107
+ catch { /* ignore — fall back to silent */ }
108
+ const stdio = [
109
+ 'ignore',
110
+ logFd ?? 'ignore',
111
+ logFd ?? 'ignore',
112
+ ];
113
+ // spawnCli so a dev `tsx`(.cmd) launcher resolves on Windows and the env is
114
+ // SystemRoot-backfilled; for the packaged `node` path cross-spawn spawns the
115
+ // .exe directly (no cmd.exe wrapper), keeping `detached` clean.
116
+ const child = (0, win_spawn_1.spawnCli)(args[0], args.slice(1), {
117
+ detached: true,
118
+ stdio,
119
+ env: { ...process.env },
120
+ });
121
+ if (logFd !== undefined) {
122
+ try {
123
+ fs_1.default.closeSync(logFd);
124
+ }
125
+ catch { /* ignore */ }
126
+ }
127
+ child.unref();
128
+ // Poll until the server is ready (up to 15 seconds, checking every 300ms)
129
+ const pollTimeoutMs = 15000;
130
+ const pollIntervalMs = 300;
131
+ const startPoll = Date.now();
132
+ while (Date.now() - startPoll < pollTimeoutMs) {
133
+ await new Promise((resolve) => setTimeout(resolve, pollIntervalMs));
134
+ const detection = await (0, desktop_client_1.detectWebManager)(port);
135
+ if (detection.running) {
136
+ (0, output_1.cliLog)(`server started on http://127.0.0.1:${port}`);
137
+ return 0;
138
+ }
139
+ }
140
+ (0, output_1.cliError)(`server failed to start — logs: ${exports.DESKTOP_LOG_FILE}`);
141
+ return 1;
142
+ }
143
+ async function desktopStop() {
144
+ const pid = readPid();
145
+ if (pid === null) {
146
+ (0, output_1.cliLog)('server is not running (no pid file)');
147
+ return 0;
148
+ }
149
+ if (!isProcessRunning(pid)) {
150
+ (0, output_1.cliLog)('server is not running (stale pid file)');
151
+ try {
152
+ fs_1.default.unlinkSync(exports.DESKTOP_PID_FILE);
153
+ }
154
+ catch { /* ignore */ }
155
+ return 0;
156
+ }
157
+ try {
158
+ process.kill(pid, 'SIGTERM');
159
+ (0, output_1.cliLog)(`server stopped (pid ${pid})`);
160
+ return 0;
161
+ }
162
+ catch (err) {
163
+ (0, output_1.cliError)(`failed to stop server: ${err.message}`);
164
+ return 1;
165
+ }
166
+ }
167
+ async function desktopStatus(port) {
168
+ const pid = readPid();
169
+ const detection = await (0, desktop_client_1.detectWebManager)(port);
170
+ if (!detection.running) {
171
+ process.stdout.write(`server: not running\n`);
172
+ return 1;
173
+ }
174
+ try {
175
+ const res = await (0, desktop_client_1.httpGet)(`${detection.baseUrl}/api/state`);
176
+ const state = JSON.parse(res.body);
177
+ process.stdout.write(`server: running (pid ${pid ?? '?'}) on ${detection.baseUrl}\n`);
178
+ process.stdout.write(`projects: ${state.projectCount ?? 0}\n`);
179
+ if (state.projects) {
180
+ for (const p of state.projects) {
181
+ process.stdout.write(` - ${p.name}\n`);
182
+ }
183
+ }
184
+ return 0;
185
+ }
186
+ catch {
187
+ process.stdout.write(`server: running on ${detection.baseUrl}\n`);
188
+ return 0;
189
+ }
190
+ }
191
+ async function desktopAdd(projectPath, port) {
192
+ const detection = await (0, desktop_client_1.detectWebManager)(port);
193
+ if (!detection.running) {
194
+ (0, output_1.cliError)('server is not running. Start it first with: specrails-desktop start');
195
+ return 1;
196
+ }
197
+ try {
198
+ const res = await (0, desktop_client_1.httpPost)(`${detection.baseUrl}/api/projects`, {
199
+ path: path_1.default.resolve(projectPath),
200
+ });
201
+ if (res.status === 201) {
202
+ const data = JSON.parse(res.body);
203
+ (0, output_1.cliLog)(`added project: ${data.project?.name ?? projectPath}`);
204
+ return 0;
205
+ }
206
+ else if (res.status === 409) {
207
+ (0, output_1.cliLog)('project already registered');
208
+ return 0;
209
+ }
210
+ else {
211
+ let errMsg = `HTTP ${res.status}`;
212
+ try {
213
+ errMsg = JSON.parse(res.body).error ?? errMsg;
214
+ }
215
+ catch { /* use default */ }
216
+ (0, output_1.cliError)(`failed to add project: ${errMsg}`);
217
+ return 1;
218
+ }
219
+ }
220
+ catch (err) {
221
+ (0, output_1.cliError)(`failed to connect to server: ${err.message}`);
222
+ return 1;
223
+ }
224
+ }
225
+ async function desktopRemove(projectId, port) {
226
+ const detection = await (0, desktop_client_1.detectWebManager)(port);
227
+ if (!detection.running) {
228
+ (0, output_1.cliError)('server is not running');
229
+ return 1;
230
+ }
231
+ try {
232
+ const deleteRes = await new Promise((resolve, reject) => {
233
+ const urlObj = new URL(`${detection.baseUrl}/api/projects/${projectId}`);
234
+ const token = (0, desktop_client_1.loadDesktopToken)();
235
+ const headers = {};
236
+ if (token)
237
+ headers['Authorization'] = `Bearer ${token}`;
238
+ const options = {
239
+ hostname: urlObj.hostname,
240
+ port: urlObj.port,
241
+ path: urlObj.pathname,
242
+ method: 'DELETE',
243
+ headers,
244
+ };
245
+ const req = http_1.default.request(options, (res) => {
246
+ let body = '';
247
+ res.on('data', (chunk) => { body += chunk; });
248
+ res.on('end', () => resolve({ status: res.statusCode ?? 0, body }));
249
+ });
250
+ req.on('error', reject);
251
+ req.end();
252
+ });
253
+ if (deleteRes.status === 200) {
254
+ (0, output_1.cliLog)(`project removed`);
255
+ return 0;
256
+ }
257
+ else {
258
+ (0, output_1.cliError)(`failed to remove project: HTTP ${deleteRes.status}`);
259
+ return 1;
260
+ }
261
+ }
262
+ catch (err) {
263
+ (0, output_1.cliError)(`failed to connect to server: ${err.message}`);
264
+ return 1;
265
+ }
266
+ }
267
+ async function desktopList(port) {
268
+ const detection = await (0, desktop_client_1.detectWebManager)(port);
269
+ if (!detection.running) {
270
+ (0, output_1.cliError)('server is not running');
271
+ return 1;
272
+ }
273
+ try {
274
+ const res = await (0, desktop_client_1.httpGet)(`${detection.baseUrl}/api/projects`);
275
+ const data = JSON.parse(res.body);
276
+ if (!data.projects || data.projects.length === 0) {
277
+ (0, output_1.cliLog)('no projects registered');
278
+ return 0;
279
+ }
280
+ const idW = 36;
281
+ const nameW = 24;
282
+ process.stdout.write(`${(0, output_1.bold)('ID'.padEnd(idW))} ${(0, output_1.bold)('NAME'.padEnd(nameW))} ${(0, output_1.bold)('PATH')}\n`);
283
+ for (const p of data.projects) {
284
+ process.stdout.write(`${p.id.padEnd(idW)} ${p.name.padEnd(nameW)} ${p.path}\n`);
285
+ }
286
+ return 0;
287
+ }
288
+ catch (err) {
289
+ (0, output_1.cliError)(`failed to fetch projects: ${err.message}`);
290
+ return 1;
291
+ }
292
+ }
293
+ async function handleDesktop(subArgs, port) {
294
+ const sub = subArgs[0];
295
+ if (!sub || sub === 'help' || sub === '--help' || sub === '-h') {
296
+ process.stdout.write(`
297
+ ${(0, output_1.bold)('specrails-desktop')} — server management
298
+
299
+ ${(0, output_1.bold)('Usage:')}
300
+ specrails-desktop start Start the Specrails server
301
+ specrails-desktop stop Stop the Specrails server
302
+ specrails-desktop status Show server status and registered projects
303
+ specrails-desktop add <path> Register a project by path
304
+ specrails-desktop remove <id> Unregister a project by ID
305
+ specrails-desktop list List all registered projects
306
+ `.trimStart());
307
+ return 0;
308
+ }
309
+ if (sub === 'start') {
310
+ return desktopStart(port);
311
+ }
312
+ if (sub === 'stop') {
313
+ return desktopStop();
314
+ }
315
+ if (sub === 'status') {
316
+ return desktopStatus(port);
317
+ }
318
+ if (sub === 'add') {
319
+ const projectPath = subArgs[1];
320
+ if (!projectPath) {
321
+ (0, output_1.cliError)('usage: specrails-desktop add <path>');
322
+ return 1;
323
+ }
324
+ return desktopAdd(projectPath, port);
325
+ }
326
+ if (sub === 'remove') {
327
+ const projectId = subArgs[1];
328
+ if (!projectId) {
329
+ (0, output_1.cliError)('usage: specrails-desktop remove <id>');
330
+ return 1;
331
+ }
332
+ return desktopRemove(projectId, port);
333
+ }
334
+ if (sub === 'list') {
335
+ return desktopList(port);
336
+ }
337
+ (0, output_1.cliError)(`unknown subcommand: ${sub}`);
338
+ return 1;
339
+ }
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ // ---------------------------------------------------------------------------
3
+ // Duration formatting
4
+ // ---------------------------------------------------------------------------
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.formatDuration = formatDuration;
7
+ exports.formatTokens = formatTokens;
8
+ exports.formatJobDuration = formatJobDuration;
9
+ exports.formatJobStarted = formatJobStarted;
10
+ function formatDuration(ms) {
11
+ const totalSeconds = Math.floor(ms / 1000);
12
+ if (totalSeconds < 60) {
13
+ return `${totalSeconds}s`;
14
+ }
15
+ const minutes = Math.floor(totalSeconds / 60);
16
+ const seconds = totalSeconds % 60;
17
+ return `${minutes}m ${seconds}s`;
18
+ }
19
+ // ---------------------------------------------------------------------------
20
+ // Token formatting
21
+ // ---------------------------------------------------------------------------
22
+ function formatTokens(n) {
23
+ return new Intl.NumberFormat('en-US', { useGrouping: true })
24
+ .format(n)
25
+ .replace(/,/g, ' ');
26
+ }
27
+ function formatJobDuration(ms) {
28
+ if (ms == null)
29
+ return '-';
30
+ return formatDuration(ms);
31
+ }
32
+ function formatJobStarted(isoStr) {
33
+ try {
34
+ const d = new Date(isoStr);
35
+ const year = d.getFullYear();
36
+ const month = String(d.getMonth() + 1).padStart(2, '0');
37
+ const day = String(d.getDate()).padStart(2, '0');
38
+ const hour = String(d.getHours()).padStart(2, '0');
39
+ const min = String(d.getMinutes()).padStart(2, '0');
40
+ return `${year}-${month}-${day} ${hour}:${min}`;
41
+ }
42
+ catch {
43
+ return isoStr.slice(0, 16);
44
+ }
45
+ }
@@ -0,0 +1,68 @@
1
+ "use strict";
2
+ var __importDefault = (this && this.__importDefault) || function (mod) {
3
+ return (mod && mod.__esModule) ? mod : { "default": mod };
4
+ };
5
+ Object.defineProperty(exports, "__esModule", { value: true });
6
+ exports.getVersion = getVersion;
7
+ exports.printVersion = printVersion;
8
+ exports.printHelp = printHelp;
9
+ const path_1 = __importDefault(require("path"));
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const output_1 = require("./output");
12
+ const args_1 = require("./args");
13
+ function getVersion() {
14
+ for (const rel of ['../package.json', '../../package.json']) {
15
+ try {
16
+ const pkgPath = path_1.default.join(__dirname, rel);
17
+ const pkg = JSON.parse(fs_1.default.readFileSync(pkgPath, 'utf8'));
18
+ if (typeof pkg.version === 'string')
19
+ return pkg.version;
20
+ }
21
+ catch {
22
+ // try next
23
+ }
24
+ }
25
+ return 'unknown';
26
+ }
27
+ function printVersion() {
28
+ process.stdout.write(`specrails-desktop v${getVersion()}\n`);
29
+ }
30
+ function printHelp() {
31
+ const version = getVersion();
32
+ process.stdout.write(`
33
+ ${(0, output_1.bold)(`specrails-desktop v${version}`)} — specrails CLI bridge
34
+
35
+ ${(0, output_1.bold)('Project Required:')}
36
+ Every command runs in the context of a project registered for the current
37
+ directory. Register your project once before running any commands:
38
+
39
+ ${(0, output_1.dim)('# Register your project (run once per project):')}
40
+ specrails-desktop add .
41
+
42
+ ${(0, output_1.dim)('# Then run commands from that directory:')}
43
+ specrails-desktop implement #42
44
+
45
+ ${(0, output_1.bold)('Usage:')}
46
+ specrails-desktop implement #42 Run a known specrails verb (prepends /specrails:)
47
+ specrails-desktop batch-implement #40 #41 Batch implementation across issues
48
+ specrails-desktop why Explain recent changes
49
+ specrails-desktop get-backlog-specs View prioritized spec backlog
50
+ specrails-desktop auto-propose-backlog-specs Generate new spec ideas
51
+ specrails-desktop propose-spec Explore an idea and produce a spec
52
+ specrails-desktop refactor-recommender Find refactoring opportunities
53
+ specrails-desktop health-check Run codebase health check
54
+ specrails-desktop compat-check Check for breaking API changes
55
+ specrails-desktop "any raw prompt" Pass a raw prompt directly to claude
56
+ specrails-desktop --status Print manager status and exit
57
+ specrails-desktop --jobs Print recent job history and exit
58
+ specrails-desktop start|stop|add|remove|list Manage the server
59
+ specrails-desktop --project <name|path> Override project (default: current directory)
60
+ specrails-desktop --port <n> Override default port (${args_1.DEFAULT_PORT})
61
+ specrails-desktop --version, -v Print version and exit
62
+ specrails-desktop --help, -h Show this help text
63
+
64
+ ${(0, output_1.bold)('Execution paths:')}
65
+ Manager running → POST /api/spawn + stream logs via WebSocket
66
+ Manager not running → spawn claude directly with stream-json output
67
+ `.trimStart());
68
+ }