specrails-desktop 2.36.0 → 2.42.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (510) hide show
  1. package/README.md +94 -247
  2. package/client/dist/assets/ActivityFeedPage-DoEMumQS.js +1 -0
  3. package/client/dist/assets/AgentBrowserCapture-DIh4K0gh.js +1 -0
  4. package/client/dist/assets/AgentModeAnalyticsPane-mbq4WEoO.js +2 -0
  5. package/client/dist/assets/AgentModeCodePane-CKh7zuA4.js +2 -0
  6. package/client/dist/assets/AgentModeJobsPane-BDokPiLJ.js +1 -0
  7. package/client/dist/assets/AgentsPage-BFVAZbBj.js +87 -0
  8. package/client/dist/assets/AnalyticsPage-3Y9LuWwz.js +1 -0
  9. package/client/dist/assets/CodePage-C9KyuV_C.js +3 -0
  10. package/client/dist/assets/DesktopAnalyticsPage-Bhi54bXQ.js +1 -0
  11. package/client/dist/assets/{DocsDialog-C76VdBJC.js → DocsDialog-Dj6mt4ga.js} +2 -2
  12. package/client/dist/assets/{DocsPage-ziMlj6B6.js → DocsPage-24yWglNI.js} +1 -1
  13. package/client/dist/assets/ExportDropdown-ophapHrT.js +1 -0
  14. package/client/dist/assets/InteractiveJobComposer-C1ucmxQh.js +19 -0
  15. package/client/dist/assets/JobDetailModal-DNWmgVHD.js +1 -0
  16. package/client/dist/assets/JobDetailPage-BcajZyuu.js +1 -0
  17. package/client/dist/assets/JobsPage-B9nTZw6e.js +1 -0
  18. package/client/dist/assets/LoopBuilderPage-Oc48iOFW.js +7 -0
  19. package/client/dist/assets/LoopPreviewModal-ae0Fr6SU.js +1 -0
  20. package/client/dist/assets/LoopsPage-CUEqzUBI.js +1 -0
  21. package/client/dist/assets/MinimizedChatsContext-Deg39peL.js +1 -0
  22. package/client/dist/assets/PluginsPage-C1xtARIx.js +2 -0
  23. package/client/dist/assets/ProjectSettingsDialog-JZzrXFBN.js +1 -0
  24. package/client/dist/assets/RepositoryDeliveries-CSDsiVUz.js +5 -0
  25. package/client/dist/assets/RepositoryScopeSelector-D-RCaknl.js +1 -0
  26. package/client/dist/assets/ReviewPacketPage-x5EfGTiL.js +1 -0
  27. package/client/dist/assets/TemplatePreviewModal-BSyuZxGq.js +1 -0
  28. package/client/dist/assets/TicketDetailModalContext-DqyF0so-.js +14 -0
  29. package/client/dist/assets/Trans-SnMX4MhW.js +1 -0
  30. package/client/dist/assets/agent-BdT0SB1D.js +1 -0
  31. package/client/dist/assets/agent-Bh9K7iEt.js +1 -0
  32. package/client/dist/assets/agent-C4ibdFk9.js +1 -0
  33. package/client/dist/assets/agent-CSFY22Zo.js +1 -0
  34. package/client/dist/assets/agent-DAnqxUn8.js +1 -0
  35. package/client/dist/assets/agent-DTQiu0Mi.js +1 -0
  36. package/client/dist/assets/agent-T54WuR_Y.js +1 -0
  37. package/client/dist/assets/agent-i75WDZOA.js +1 -0
  38. package/client/dist/assets/browser-05vRDg_y.js +1 -0
  39. package/client/dist/assets/browser-Bulb-cB1.js +1 -0
  40. package/client/dist/assets/browser-C7f-Jsg1.js +1 -0
  41. package/client/dist/assets/browser-CG0PE1j_.js +1 -0
  42. package/client/dist/assets/browser-CMzaqAjo.js +1 -0
  43. package/client/dist/assets/browser-DMajYdNX.js +1 -0
  44. package/client/dist/assets/browser-DxcOHrdP.js +1 -0
  45. package/client/dist/assets/browser-ObE7xVo3.js +1 -0
  46. package/client/dist/assets/builder-765NeYTp.js +1 -0
  47. package/client/dist/assets/builder-8MG3V6ea.js +1 -0
  48. package/client/dist/assets/builder-B-1UBs5K.js +1 -0
  49. package/client/dist/assets/builder-BTiGnPT0.js +1 -0
  50. package/client/dist/assets/builder-Cx9Rz-7u.js +1 -0
  51. package/client/dist/assets/builder-DKFMELBl.js +1 -0
  52. package/client/dist/assets/builder-OcmKrC0h.js +1 -0
  53. package/client/dist/assets/builder-P9qVBXFZ.js +1 -0
  54. package/client/dist/assets/{button-CJqFnUOL.js → button-DCBqEaZl.js} +1 -1
  55. package/client/dist/assets/{code-CkUuW4m9.js → code-B37GRg9C.js} +1 -1
  56. package/client/dist/assets/{code-B0O8-p8k.js → code-BBOEZbf9.js} +1 -1
  57. package/client/dist/assets/{code-B1VLZDhS.js → code-BRm-jcyx.js} +1 -1
  58. package/client/dist/assets/{code-Bpj4Ddml.js → code-CF7w62CR.js} +1 -1
  59. package/client/dist/assets/{code-BykBZ5-e.js → code-CLuvJt2r.js} +1 -1
  60. package/client/dist/assets/{code-B86IMAfz.js → code-D0RCm59f.js} +1 -1
  61. package/client/dist/assets/code-DaZ-ZwCT.js +1 -0
  62. package/client/dist/assets/{code-cAqaqMTx.js → code-iIHkGaCL.js} +1 -1
  63. package/client/dist/assets/commands-0XjAftla.js +1 -0
  64. package/client/dist/assets/commands-BAWSYHjQ.js +1 -0
  65. package/client/dist/assets/commands-BBwowgiE.js +1 -0
  66. package/client/dist/assets/commands-BacjIZLN.js +1 -0
  67. package/client/dist/assets/commands-Bs62IAZ3.js +1 -0
  68. package/client/dist/assets/commands-CLPdh-Hh.js +1 -0
  69. package/client/dist/assets/commands-DlbFzgrp.js +1 -0
  70. package/client/dist/assets/commands-LjPSsi5F.js +1 -0
  71. package/client/dist/assets/common-B5AZNYMH.js +1 -0
  72. package/client/dist/assets/common-BFZ0c_vN.js +1 -0
  73. package/client/dist/assets/common-BrlwEnL7.js +1 -0
  74. package/client/dist/assets/common-BttQx3z4.js +1 -0
  75. package/client/dist/assets/common-CM65k_-e.js +1 -0
  76. package/client/dist/assets/common-D4mvFFlu.js +1 -0
  77. package/client/dist/assets/common-TZ9Ny96S.js +1 -0
  78. package/client/dist/assets/common-nFpSF4GC.js +1 -0
  79. package/client/dist/assets/dashboard-B14uYXkG.js +1 -0
  80. package/client/dist/assets/dashboard-BK_mez-z.js +1 -0
  81. package/client/dist/assets/dashboard-BfBir_6o.js +1 -0
  82. package/client/dist/assets/dashboard-Bt0cCzeG.js +1 -0
  83. package/client/dist/assets/dashboard-BwkjxI6H.js +1 -0
  84. package/client/dist/assets/{dashboard-C8WOEiPu.js → dashboard-C3bDKf7s.js} +1 -1
  85. package/client/dist/assets/dashboard-CdvjGfog.js +1 -0
  86. package/client/dist/assets/dashboard-fRrP0Kv0.js +1 -0
  87. package/client/dist/assets/dialog-SRw01_QU.js +45 -0
  88. package/client/dist/assets/dist-js-CJ_2XX1Y.js +1 -0
  89. package/client/dist/assets/formatDistanceToNow-DSj5DprF.js +1 -0
  90. package/client/dist/assets/getTimezoneOffsetInMilliseconds-YhD8rIEs.js +1 -0
  91. package/client/dist/assets/index-DwAmL7m5.css +2 -0
  92. package/client/dist/assets/index-EzrkUb8B.js +76 -0
  93. package/client/dist/assets/{jira-api-B1-MUehg.js → jira-api-CSCqGr-Q.js} +1 -1
  94. package/client/dist/assets/{jobs-CN_zv4Gr.js → jobs-B8rrzfyZ.js} +1 -1
  95. package/client/dist/assets/{jobs-DUlWSYq2.js → jobs-BS6RTurf.js} +1 -1
  96. package/client/dist/assets/{jobs-Bpks6doU.js → jobs-BTT0Bsks.js} +1 -1
  97. package/client/dist/assets/{jobs-Bgq-PZkC.js → jobs-CezU69AE.js} +1 -1
  98. package/client/dist/assets/{jobs-SwYS2M-B.js → jobs-ClFJae0s.js} +1 -1
  99. package/client/dist/assets/{jobs-BAls3bWq.js → jobs-DJSFIFVy.js} +1 -1
  100. package/client/dist/assets/{jobs-DhxKgWFq.js → jobs-DhgGr8vm.js} +1 -1
  101. package/client/dist/assets/{jobs-B_TeSQxb.js → jobs-DzMjUcaN.js} +1 -1
  102. package/client/dist/assets/mcp-6rMoZfEO.js +1 -0
  103. package/client/dist/assets/mcp-BD8sL5mP.js +1 -0
  104. package/client/dist/assets/mcp-BkcA3I5s.js +1 -0
  105. package/client/dist/assets/mcp-CCpSelOh.js +1 -0
  106. package/client/dist/assets/mcp-CUAN6ORK.js +1 -0
  107. package/client/dist/assets/mcp-CqbRxRTE.js +1 -0
  108. package/client/dist/assets/mcp-DP2YfVhO.js +1 -0
  109. package/client/dist/assets/mcp-DUVQamDz.js +1 -0
  110. package/client/dist/assets/narration-B-ynWTpn.js +1 -0
  111. package/client/dist/assets/narration-Bj_laZwg.js +1 -0
  112. package/client/dist/assets/narration-BxHpmMv_.js +1 -0
  113. package/client/dist/assets/narration-C1Px0-0j.js +1 -0
  114. package/client/dist/assets/narration-CAXhGbzM.js +1 -0
  115. package/client/dist/assets/narration-DQ1l_Kq6.js +1 -0
  116. package/client/dist/assets/narration-XISXwqZd.js +1 -0
  117. package/client/dist/assets/narration-kwzfglQo.js +1 -0
  118. package/client/dist/assets/nav-1-Hh2kOz.js +1 -0
  119. package/client/dist/assets/nav-B34QkESm.js +1 -0
  120. package/client/dist/assets/nav-Bap_UXAq.js +1 -0
  121. package/client/dist/assets/{nav-pYuXq7sf.js → nav-BwxXIB24.js} +1 -1
  122. package/client/dist/assets/nav-Ch-zHBG5.js +1 -0
  123. package/client/dist/assets/nav-CygC_WN-.js +1 -0
  124. package/client/dist/assets/{nav-iwjCg5FR.js → nav-KnnLQtOQ.js} +1 -1
  125. package/client/dist/assets/nav-m00uxYUG.js +1 -0
  126. package/client/dist/assets/packet-BQ2tXfJI.js +1 -0
  127. package/client/dist/assets/packet-BdpOJ1Cy.js +1 -0
  128. package/client/dist/assets/packet-C3Ievb9R.js +1 -0
  129. package/client/dist/assets/packet-C4zJIG0Y.js +1 -0
  130. package/client/dist/assets/packet-Cx-zRuWn.js +1 -0
  131. package/client/dist/assets/packet-DUTGX52M.js +1 -0
  132. package/client/dist/assets/packet-DhsKtUPB.js +1 -0
  133. package/client/dist/assets/packet-z3LJ8Zyy.js +1 -0
  134. package/client/dist/assets/project-repositories-DYhTvwQ1.js +1 -0
  135. package/client/dist/assets/provider-capabilities-B-wOHfLP.js +1 -0
  136. package/client/dist/assets/settings-BBt2xtDQ.js +1 -0
  137. package/client/dist/assets/settings-BJB9RKJj.js +1 -0
  138. package/client/dist/assets/settings-CHwQR2rB.js +1 -0
  139. package/client/dist/assets/settings-CrMi3kSi.js +1 -0
  140. package/client/dist/assets/settings-DKyhDGD1.js +1 -0
  141. package/client/dist/assets/settings-Deupji9c.js +1 -0
  142. package/client/dist/assets/settings-DqRMmwAM.js +1 -0
  143. package/client/dist/assets/settings-J4rj6vo-.js +1 -0
  144. package/client/dist/assets/setup-2xGgu4Sk.js +1 -0
  145. package/client/dist/assets/setup-Ba11l2JA.js +1 -0
  146. package/client/dist/assets/setup-BzW4kMok.js +1 -0
  147. package/client/dist/assets/setup-COzwYhkJ.js +1 -0
  148. package/client/dist/assets/setup-CRVULhtF.js +1 -0
  149. package/client/dist/assets/setup-DgvlxwpE.js +1 -0
  150. package/client/dist/assets/setup-Dw_wYeEY.js +1 -0
  151. package/client/dist/assets/setup-ZPtEeJPW.js +1 -0
  152. package/client/dist/assets/spending-BqbdPm_4.js +1 -0
  153. package/client/dist/assets/square-Ci-PFcFe.js +1 -0
  154. package/client/dist/assets/{terminal-BFRZnMPP.js → terminal-BAzpHtpY.js} +1 -1
  155. package/client/dist/assets/{terminal-IahE4LW9.js → terminal-C7dHeR3x.js} +1 -1
  156. package/client/dist/assets/{terminal-tITa81iz.js → terminal-CMla5Qsz.js} +1 -1
  157. package/client/dist/assets/{terminal-BZiIu3rf.js → terminal-CdNXH-n9.js} +1 -1
  158. package/client/dist/assets/{terminal-ScjyXNxQ.js → terminal-Cw5bZsmV.js} +1 -1
  159. package/client/dist/assets/{terminal-C2NAd7BW.js → terminal-DFUP4eNv.js} +1 -1
  160. package/client/dist/assets/{terminal-d7GadXbN.js → terminal-DGqljeK_.js} +1 -1
  161. package/client/dist/assets/{terminal-QpXZU2Bn.js → terminal-cU70NodO.js} +1 -1
  162. package/client/dist/assets/useDesktop-RSMTyy7V.js +1 -0
  163. package/client/dist/assets/useSharedWebSocket-BOdS5_Iz.js +2 -0
  164. package/client/dist/index.html +34 -35
  165. package/docs/README.md +3 -0
  166. package/docs/agent-live-steering.md +57 -0
  167. package/docs/ci-cd.md +57 -0
  168. package/docs/code-explorer.md +48 -0
  169. package/docs/codex.md +12 -1
  170. package/docs/features/detachable-mission-windows.md +59 -0
  171. package/docs/guide/de/integrations/5-mcp-server.md +13 -9
  172. package/docs/guide/de/integrations/6-agent-chat.md +1 -0
  173. package/docs/guide/en/integrations/5-mcp-server.md +13 -9
  174. package/docs/guide/en/integrations/6-agent-chat.md +1 -0
  175. package/docs/guide/es/integrations/5-mcp-server.md +13 -9
  176. package/docs/guide/es/integrations/6-agent-chat.md +1 -0
  177. package/docs/guide/fr/integrations/5-mcp-server.md +13 -9
  178. package/docs/guide/fr/integrations/6-agent-chat.md +1 -0
  179. package/docs/guide/it/integrations/5-mcp-server.md +13 -9
  180. package/docs/guide/it/integrations/6-agent-chat.md +1 -0
  181. package/docs/guide/ja/integrations/5-mcp-server.md +13 -9
  182. package/docs/guide/ja/integrations/6-agent-chat.md +1 -0
  183. package/docs/guide/pt/integrations/5-mcp-server.md +13 -9
  184. package/docs/guide/pt/integrations/6-agent-chat.md +1 -0
  185. package/docs/guide/zh/integrations/5-mcp-server.md +13 -9
  186. package/docs/guide/zh/integrations/6-agent-chat.md +1 -0
  187. package/docs/internals/README.md +1 -0
  188. package/docs/internals/browser-capture-performance.md +55 -3
  189. package/docs/internals/browser-login-popups.md +45 -0
  190. package/docs/internals/browser-native-retina-audit.md +39 -0
  191. package/docs/internals/ci-cd-audit.md +39 -0
  192. package/docs/internals/core-runtime-updates.md +68 -0
  193. package/docs/internals/embedded-browser-native-webview-evaluation.md +2 -0
  194. package/docs/internals/implementation-reliability-audit.md +93 -0
  195. package/docs/internals/interactive-jobs.md +110 -6
  196. package/docs/internals/mcp-mission-audit.md +76 -0
  197. package/docs/internals/project-builder.md +404 -42
  198. package/docs/internals/safe-pr-review-flow.md +52 -10
  199. package/docs/internals/startup-recovery-audit.md +58 -0
  200. package/docs/mcp.md +74 -41
  201. package/docs/mission-processes.md +59 -0
  202. package/docs/multi-repo-projects.md +51 -0
  203. package/docs/platforms/windows-parity.md +70 -0
  204. package/docs/platforms/windows.md +13 -11
  205. package/docs/running-pipelines.md +14 -0
  206. package/mcp-bridge/dist/specrails-mcp.js +7186 -0
  207. package/package.json +9 -4
  208. package/server/dist/agent-chat-manager.js +537 -68
  209. package/server/dist/agent-chat-router.js +87 -6
  210. package/server/dist/agent-context-resolver.js +129 -25
  211. package/server/dist/agent-defaults.js +19 -11
  212. package/server/dist/agent-input-store.js +206 -0
  213. package/server/dist/agent-mcp-config.js +54 -15
  214. package/server/dist/agent-operator-prompt.js +255 -65
  215. package/server/dist/agent-spec-framing.js +202 -0
  216. package/server/dist/agent-steering.js +218 -0
  217. package/server/dist/agent-store.js +153 -0
  218. package/server/dist/api-not-found.js +8 -0
  219. package/server/dist/background-process-control.js +164 -0
  220. package/server/dist/background-process-service.js +61 -0
  221. package/server/dist/background-process-store.js +242 -0
  222. package/server/dist/background-windows-bootstrap.js +238 -0
  223. package/server/dist/blueprint-chat-manager.js +476 -62
  224. package/server/dist/blueprint-commit.js +21 -1
  225. package/server/dist/blueprint-draft-parser.js +122 -17
  226. package/server/dist/blueprint-generation.js +238 -0
  227. package/server/dist/blueprint-operator-prompt.js +91 -63
  228. package/server/dist/blueprint-router.js +55 -3
  229. package/server/dist/blueprint-spec-fixtures.js +85 -0
  230. package/server/dist/blueprint-spec-quality.js +57 -16
  231. package/server/dist/blueprint-store.js +92 -1
  232. package/server/dist/browser-capture-manager.js +86 -30
  233. package/server/dist/browser-playwright.js +168 -45
  234. package/server/dist/browser-viewport.js +26 -0
  235. package/server/dist/chat-manager.js +23 -15
  236. package/server/dist/chromium-archive.cjs +83 -0
  237. package/server/dist/chromium-resolver.js +72 -64
  238. package/server/dist/code-activity.js +145 -0
  239. package/server/dist/code-explorer-router.js +714 -114
  240. package/server/dist/core-compat.js +28 -1
  241. package/server/dist/core-execution.js +111 -0
  242. package/server/dist/core-package.js +4 -16
  243. package/server/dist/core-runtime.js +202 -0
  244. package/server/dist/core-update-manager.js +161 -60
  245. package/server/dist/core-update-state.js +29 -0
  246. package/server/dist/db.js +66 -35
  247. package/server/dist/delivery-evidence.js +142 -39
  248. package/server/dist/desktop-db.js +239 -43
  249. package/server/dist/desktop-router.js +109 -9
  250. package/server/dist/dev-ports.js +8 -3
  251. package/server/dist/file-provenance.js +34 -22
  252. package/server/dist/file-story-manager.js +62 -64
  253. package/server/dist/file-story.js +118 -35
  254. package/server/dist/file-summary-generator.js +46 -5
  255. package/server/dist/file-summary-manager.js +355 -106
  256. package/server/dist/framework-manager.js +98 -110
  257. package/server/dist/framework-reseed.js +76 -10
  258. package/server/dist/git-diagnostics.js +2 -2
  259. package/server/dist/headroom-manager.js +38 -3
  260. package/server/dist/host-control.js +52 -0
  261. package/server/dist/index.js +43 -2
  262. package/server/dist/interactive-job-session.js +149 -16
  263. package/server/dist/internal-api.js +48 -0
  264. package/server/dist/jira/jira-materializer.js +1 -0
  265. package/server/dist/json-tolerant.js +174 -0
  266. package/server/dist/legacy-migration.js +4 -2
  267. package/server/dist/loop-command-catalog.js +83 -21
  268. package/server/dist/loop-constants.js +6 -1
  269. package/server/dist/loop-decider.js +11 -1
  270. package/server/dist/loop-executors.js +194 -45
  271. package/server/dist/loop-factory.js +11 -4
  272. package/server/dist/loop-graph.js +90 -4
  273. package/server/dist/loop-run-manager.js +301 -69
  274. package/server/dist/loop-shell-invocation.js +21 -0
  275. package/server/dist/loop-step-idle.js +55 -0
  276. package/server/dist/loop-templates.js +31 -7
  277. package/server/dist/mcp/agent-capability.js +37 -4
  278. package/server/dist/mcp/guide.js +149 -36
  279. package/server/dist/mcp/mcp-admin-router.js +20 -4
  280. package/server/dist/mcp/mcp-server.js +89 -43
  281. package/server/dist/mcp/mcp-tiers.js +6 -5
  282. package/server/dist/mcp/mcp-token.js +3 -1
  283. package/server/dist/mcp/resources.js +5 -4
  284. package/server/dist/mcp/tools/catalog.js +4 -0
  285. package/server/dist/mcp/tools/code.js +125 -14
  286. package/server/dist/mcp/tools/context.js +153 -0
  287. package/server/dist/mcp/tools/git.js +15 -5
  288. package/server/dist/mcp/tools/jobs.js +84 -71
  289. package/server/dist/mcp/tools/loops.js +17 -6
  290. package/server/dist/mcp/tools/meta.js +74 -27
  291. package/server/dist/mcp/tools/mission.js +29 -0
  292. package/server/dist/mcp/tools/projects.js +22 -6
  293. package/server/dist/mcp/tools/rails.js +48 -11
  294. package/server/dist/mcp/tools/specs.js +86 -14
  295. package/server/dist/mcp/tools/support.js +1 -1
  296. package/server/dist/mcp/tools/types.js +117 -43
  297. package/server/dist/mcp/tools/watch.js +144 -51
  298. package/server/dist/milestone-chain-store.js +164 -0
  299. package/server/dist/milestone-chain.js +487 -0
  300. package/server/dist/milestone-progress.js +348 -0
  301. package/server/dist/mobile/mobile-devices.js +10 -7
  302. package/server/dist/mobile/mobile-gateway.js +2 -0
  303. package/server/dist/mobile/mobile-missions.js +214 -0
  304. package/server/dist/mobile/mobile-redact.js +17 -3
  305. package/server/dist/mobile/mobile-router.js +46 -4
  306. package/server/dist/mobile/mobile-ws.js +49 -4
  307. package/server/dist/multi-repo-bases.js +56 -0
  308. package/server/dist/multi-repo-checkout.js +101 -0
  309. package/server/dist/multi-repo-delivery.js +100 -0
  310. package/server/dist/multi-repo-execution-store.js +65 -0
  311. package/server/dist/multi-repo-execution.js +453 -0
  312. package/server/dist/offline-assemble.js +10 -8
  313. package/server/dist/openspec-runtime-plugin-commands.json +18 -0
  314. package/server/dist/openspec-runtime-plugin.js +120 -0
  315. package/server/dist/plugins/codex-spawn.js +49 -0
  316. package/server/dist/plugins/serena/manifest.js +2 -2
  317. package/server/dist/plugins/serena/templates/instructions.md +16 -0
  318. package/server/dist/pr-publisher.js +1 -1
  319. package/server/dist/profiles-router.js +3 -18
  320. package/server/dist/project-code-discovery.js +142 -0
  321. package/server/dist/project-git.js +19 -21
  322. package/server/dist/project-registry.js +272 -20
  323. package/server/dist/project-repositories.js +157 -0
  324. package/server/dist/project-repository-provenance.js +31 -0
  325. package/server/dist/project-router-background-processes.js +105 -0
  326. package/server/dist/project-router-git.js +75 -16
  327. package/server/dist/project-router-jobs.js +2 -126
  328. package/server/dist/project-router-loop-runs.js +72 -2
  329. package/server/dist/project-router-tickets.js +53 -8
  330. package/server/dist/project-router.js +239 -38
  331. package/server/dist/provider-detection.js +18 -6
  332. package/server/dist/provider-limit.js +64 -0
  333. package/server/dist/providers/claude-adapter.js +26 -1
  334. package/server/dist/providers/claude-background-tasks.js +18 -0
  335. package/server/dist/providers/claude-live-session.js +383 -0
  336. package/server/dist/providers/codex-adapter.js +19 -0
  337. package/server/dist/providers/codex-live-session.js +545 -0
  338. package/server/dist/providers/gemini-adapter.js +1 -0
  339. package/server/dist/providers/live-session-types.js +12 -0
  340. package/server/dist/providers/live-session.js +13 -0
  341. package/server/dist/providers/terminal-result.js +24 -0
  342. package/server/dist/queue-manager.js +2 -0
  343. package/server/dist/rail-isolated-launch.js +141 -16
  344. package/server/dist/rail-pr-decision.js +364 -99
  345. package/server/dist/rail-pr-store.js +24 -10
  346. package/server/dist/rail-worktree-release.js +34 -2
  347. package/server/dist/rail-worktrees-store.js +4 -4
  348. package/server/dist/rails-router.js +249 -55
  349. package/server/dist/repo-lock.js +92 -17
  350. package/server/dist/review-packet.js +23 -13
  351. package/server/dist/schemas/file-summary.v1.json +59 -59
  352. package/server/dist/schemas/profile.v1.json +137 -137
  353. package/server/dist/setup-manager.js +52 -8
  354. package/server/dist/shell-integration/bash-shim.bash +45 -0
  355. package/server/dist/shell-integration/fish-shim.fish +36 -0
  356. package/server/dist/shell-integration/powershell-shim.ps1 +48 -0
  357. package/server/dist/shell-integration/zsh-shim.zsh +47 -0
  358. package/server/dist/smash-runner.js +1 -0
  359. package/server/dist/spawn-lifecycle.js +44 -27
  360. package/server/dist/spec-contract-prompt.js +143 -0
  361. package/server/dist/spec-draft-parser.js +6 -1
  362. package/server/dist/spec-models.js +1 -0
  363. package/server/dist/stuck-run-detector.js +1 -0
  364. package/server/dist/terminal-manager.js +21 -1
  365. package/server/dist/terminal-shell-integration.js +4 -1
  366. package/server/dist/transient-children.js +619 -230
  367. package/server/dist/util/cli-prompt.js +78 -5
  368. package/server/dist/util/sqlite-migrations.js +20 -0
  369. package/server/dist/util/win-spawn.js +18 -3
  370. package/server/dist/util/windows-provider-shell.js +29 -0
  371. package/server/dist/verification-sentinel.js +14 -0
  372. package/server/dist/vitest-setup.js +2 -0
  373. package/server/dist/windows-job-supervisor.js +133 -0
  374. package/server/dist/workspace-manager.js +9 -30
  375. package/server/dist/worktree-manager.js +17 -2
  376. package/server/dist/worktree-overlay.js +3 -1
  377. package/client/dist/assets/ActivityFeedPage-tAQcWs1R.js +0 -1
  378. package/client/dist/assets/AgentBrowserCapture-BX8BNae5.js +0 -1
  379. package/client/dist/assets/AgentModeAnalyticsPane-BVAqCL0K.js +0 -2
  380. package/client/dist/assets/AgentModeCodePane-9XfqQc9c.js +0 -2
  381. package/client/dist/assets/AgentModeJobsPane-BCjLsPhc.js +0 -1
  382. package/client/dist/assets/AgentsPage-C8J_42sm.js +0 -87
  383. package/client/dist/assets/AnalyticsPage-BtQuyfJm.js +0 -1
  384. package/client/dist/assets/CodePage-BZ2MwdCu.js +0 -2
  385. package/client/dist/assets/DesktopAnalyticsPage-Bh_29V4g.js +0 -1
  386. package/client/dist/assets/ExportDropdown-BrtfWzEG.js +0 -1
  387. package/client/dist/assets/InteractiveJobComposer-BCZiSfzc.js +0 -19
  388. package/client/dist/assets/JobDetailModal-NAJmuYIT.js +0 -1
  389. package/client/dist/assets/JobDetailPage-fE0ZycUX.js +0 -1
  390. package/client/dist/assets/JobsPage-z5M_HVJG.js +0 -1
  391. package/client/dist/assets/LoopBuilderPage-j1FQS47c.js +0 -7
  392. package/client/dist/assets/LoopPreviewModal-DhDJjdCe.js +0 -1
  393. package/client/dist/assets/LoopsPage-Ll7zORZb.js +0 -1
  394. package/client/dist/assets/MinimizedChatsContext-Bd3OqR_S.js +0 -1
  395. package/client/dist/assets/PluginsPage-DN4kGvJt.js +0 -2
  396. package/client/dist/assets/ProjectSettingsDialog-OgsgxjzF.js +0 -1
  397. package/client/dist/assets/ReviewPacketPage-DFog4sXn.js +0 -1
  398. package/client/dist/assets/TemplatePreviewModal-L2XxqiOD.js +0 -1
  399. package/client/dist/assets/TicketDetailModal-CsF-AWZX.js +0 -14
  400. package/client/dist/assets/Trans-Bsz9_gyq.js +0 -1
  401. package/client/dist/assets/agent-BQgKv_2F.js +0 -1
  402. package/client/dist/assets/agent-C1NRDJqL.js +0 -1
  403. package/client/dist/assets/agent-CLNleiy6.js +0 -1
  404. package/client/dist/assets/agent-CmceArkQ.js +0 -1
  405. package/client/dist/assets/agent-D3UxQ3SR.js +0 -1
  406. package/client/dist/assets/agent-DB1JeE64.js +0 -1
  407. package/client/dist/assets/agent-DXkHcQ-D.js +0 -1
  408. package/client/dist/assets/agent-DjJJJ2M8.js +0 -1
  409. package/client/dist/assets/auth-D_5bQv5W.js +0 -1
  410. package/client/dist/assets/ban-E4EaZe3a.js +0 -1
  411. package/client/dist/assets/bot-DzuuuC5R.js +0 -1
  412. package/client/dist/assets/browser-BgqHDMXP.js +0 -1
  413. package/client/dist/assets/browser-CsKJtrpv.js +0 -1
  414. package/client/dist/assets/browser-Cu58EpZU.js +0 -1
  415. package/client/dist/assets/browser-CvXOJm-j.js +0 -1
  416. package/client/dist/assets/browser-DOrFh1c7.js +0 -1
  417. package/client/dist/assets/browser-DQv_Jo7x.js +0 -1
  418. package/client/dist/assets/browser-LPgxvJu2.js +0 -1
  419. package/client/dist/assets/browser-eL-3MIEI.js +0 -1
  420. package/client/dist/assets/builder-0IWtosUm.js +0 -1
  421. package/client/dist/assets/builder-Bf2N6XWn.js +0 -1
  422. package/client/dist/assets/builder-BnqaaBkT.js +0 -1
  423. package/client/dist/assets/builder-BxxfGgAO.js +0 -1
  424. package/client/dist/assets/builder-C5IIgWsq.js +0 -1
  425. package/client/dist/assets/builder-CHuahItu.js +0 -1
  426. package/client/dist/assets/builder-CjWosXL_.js +0 -1
  427. package/client/dist/assets/builder-CpCIOoKj.js +0 -1
  428. package/client/dist/assets/code-CHPkOkDS.js +0 -1
  429. package/client/dist/assets/commands-6tYQih5m.js +0 -1
  430. package/client/dist/assets/commands-BK2QinXN.js +0 -1
  431. package/client/dist/assets/commands-C2Nca76h.js +0 -1
  432. package/client/dist/assets/commands-CKdLihNX.js +0 -1
  433. package/client/dist/assets/commands-CYIBTAlc.js +0 -1
  434. package/client/dist/assets/commands-CjUtYJIM.js +0 -1
  435. package/client/dist/assets/commands-Cq_u_8y9.js +0 -1
  436. package/client/dist/assets/commands-D_ZHYQug.js +0 -1
  437. package/client/dist/assets/common-6MLbD-jM.js +0 -1
  438. package/client/dist/assets/common-BKGEu4rm.js +0 -1
  439. package/client/dist/assets/common-BNbnv8cE.js +0 -1
  440. package/client/dist/assets/common-BqGWtDbt.js +0 -1
  441. package/client/dist/assets/common-DBtTzeYm.js +0 -1
  442. package/client/dist/assets/common-DEW3Nr8n.js +0 -1
  443. package/client/dist/assets/common-DHsv9N5d.js +0 -1
  444. package/client/dist/assets/common-mkrEcW-Y.js +0 -1
  445. package/client/dist/assets/dashboard-B9GhC5ku.js +0 -1
  446. package/client/dist/assets/dashboard-CBnv6zOI.js +0 -1
  447. package/client/dist/assets/dashboard-CaP0fU87.js +0 -1
  448. package/client/dist/assets/dashboard-D4ZZ4x84.js +0 -1
  449. package/client/dist/assets/dashboard-DmuTQBX8.js +0 -1
  450. package/client/dist/assets/dashboard-DynLYj3d.js +0 -1
  451. package/client/dist/assets/dashboard-zj4gGFJ1.js +0 -1
  452. package/client/dist/assets/dialog-CdWCb02j.js +0 -45
  453. package/client/dist/assets/dist-bVqfYmby.js +0 -1
  454. package/client/dist/assets/dist-js-CWeUdf5Z.js +0 -1
  455. package/client/dist/assets/formatDistanceToNow-DQCvMgUc.js +0 -1
  456. package/client/dist/assets/getTimezoneOffsetInMilliseconds-C16cxSe1.js +0 -1
  457. package/client/dist/assets/git-refresh-wTW0rO0Z.js +0 -1
  458. package/client/dist/assets/i18n-hnX2DPmo.js +0 -2
  459. package/client/dist/assets/index-DIhMEAVw.js +0 -66
  460. package/client/dist/assets/index-DwygcU7s.css +0 -2
  461. package/client/dist/assets/mcp-B8X8wBLu.js +0 -1
  462. package/client/dist/assets/mcp-C2AojZZN.js +0 -1
  463. package/client/dist/assets/mcp-D8BT78_L.js +0 -1
  464. package/client/dist/assets/mcp-Df5RWBNk.js +0 -1
  465. package/client/dist/assets/mcp-Dj7BgMQW.js +0 -1
  466. package/client/dist/assets/mcp-Q7iT7rcz.js +0 -1
  467. package/client/dist/assets/mcp-YlvNvJbW.js +0 -1
  468. package/client/dist/assets/mcp-mKFpTSRb.js +0 -1
  469. package/client/dist/assets/narration-4Z2VUhZw.js +0 -1
  470. package/client/dist/assets/narration-BGuiEDj3.js +0 -1
  471. package/client/dist/assets/narration-BuSoqRmv.js +0 -1
  472. package/client/dist/assets/narration-CB9t29fy.js +0 -1
  473. package/client/dist/assets/narration-CU3x8FHD.js +0 -1
  474. package/client/dist/assets/narration-CWeXhfP5.js +0 -1
  475. package/client/dist/assets/narration-DRaDnhT5.js +0 -1
  476. package/client/dist/assets/narration-DtEbQgCw.js +0 -1
  477. package/client/dist/assets/nav-ApJVg3xu.js +0 -1
  478. package/client/dist/assets/nav-BKNky1Bg.js +0 -1
  479. package/client/dist/assets/nav-C6vWWKYx.js +0 -1
  480. package/client/dist/assets/nav-CXJ6Aw89.js +0 -1
  481. package/client/dist/assets/nav-CsmFBIDf.js +0 -1
  482. package/client/dist/assets/nav-DjkmQJjd.js +0 -1
  483. package/client/dist/assets/packet-B1IxaL5f.js +0 -1
  484. package/client/dist/assets/packet-Bh5kkbiB.js +0 -1
  485. package/client/dist/assets/packet-By8fqYxW.js +0 -1
  486. package/client/dist/assets/packet-CZdvA44E.js +0 -1
  487. package/client/dist/assets/packet-CrjHRQCP.js +0 -1
  488. package/client/dist/assets/packet-Dwi2pTtx.js +0 -1
  489. package/client/dist/assets/packet-_-ZIa0IR.js +0 -1
  490. package/client/dist/assets/packet-n0W6E1Hn.js +0 -1
  491. package/client/dist/assets/play-DNlrawbS.js +0 -1
  492. package/client/dist/assets/provider-capabilities-Doej9lfa.js +0 -1
  493. package/client/dist/assets/settings-Bd0x4TBa.js +0 -1
  494. package/client/dist/assets/settings-C1-7cXzC.js +0 -1
  495. package/client/dist/assets/settings-CAFaT38b.js +0 -1
  496. package/client/dist/assets/settings-Ct3v1nW2.js +0 -1
  497. package/client/dist/assets/settings-DHh7_IF5.js +0 -1
  498. package/client/dist/assets/settings-DQXAmdcv.js +0 -1
  499. package/client/dist/assets/settings-guzlhpup.js +0 -1
  500. package/client/dist/assets/settings-sZfTPMEH.js +0 -1
  501. package/client/dist/assets/setup-3jWaoVUO.js +0 -1
  502. package/client/dist/assets/setup-BjgRneb2.js +0 -1
  503. package/client/dist/assets/setup-BzFIjv-f.js +0 -1
  504. package/client/dist/assets/setup-C4VfQsxE.js +0 -1
  505. package/client/dist/assets/setup-DfUkpDbN.js +0 -1
  506. package/client/dist/assets/setup-ECe90Pmu.js +0 -1
  507. package/client/dist/assets/setup-dlqC4Jmm.js +0 -1
  508. package/client/dist/assets/setup-jwfLMiM2.js +0 -1
  509. package/client/dist/assets/spending-EC9xqio-.js +0 -1
  510. package/client/dist/assets/useDesktop-BQVt8lFd.js +0 -1
@@ -0,0 +1,545 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.runCodexLiveSession = runCodexLiveSession;
4
+ const node_string_decoder_1 = require("node:string_decoder");
5
+ const cli_prompt_1 = require("../util/cli-prompt");
6
+ const win_spawn_1 = require("../util/win-spawn");
7
+ const runtime_1 = require("./runtime");
8
+ const live_session_types_1 = require("./live-session-types");
9
+ // Verified against codex-cli 0.153.4's generated app-server v2 protocol and
10
+ // https://learn.chatgpt.com/docs/app-server. No SDK or paid probe is required.
11
+ const RPC_TIMEOUT_MS = 60_000;
12
+ const STEER_TIMEOUT_MS = 30_000;
13
+ const MAX_FRAME_BYTES = 16 * 1024 * 1024;
14
+ const STDERR_CAP = 64 * 1024;
15
+ class RpcFailure extends Error {
16
+ code;
17
+ constructor(message, code) {
18
+ super(message);
19
+ this.code = code;
20
+ }
21
+ }
22
+ const object = (value) => value !== null && typeof value === 'object' && !Array.isArray(value) ? value : {};
23
+ const string = (value) => typeof value === 'string' ? value : '';
24
+ const preview = (value, limit = 4000) => (typeof value === 'string' ? value : JSON.stringify(value ?? '')).slice(0, limit);
25
+ const count = (value) => typeof value === 'number' && Number.isFinite(value) && value >= 0 ? value : 0;
26
+ const userInput = (text, imagePaths) => [
27
+ { type: 'text', text, text_elements: [] },
28
+ ...(imagePaths ?? []).map(path => ({ type: 'localImage', path })),
29
+ ];
30
+ /** One native Codex turn, retaining a full-duplex app-server connection until
31
+ * completion. Steering never interrupts, restarts, or replays an active action. */
32
+ function runCodexLiveSession(hooks) {
33
+ const opts = hooks.buildOpts;
34
+ const events = [];
35
+ let child = null;
36
+ let sessionId = null;
37
+ let lastResultEvent = null;
38
+ let stderrTail = '';
39
+ let activeTurnId = null;
40
+ let terminal = null;
41
+ let settled = false;
42
+ let transportFailed = false;
43
+ let closing = false;
44
+ let childClosed = false;
45
+ let turnRequested = false;
46
+ let nextId = 0;
47
+ let inputReady = false;
48
+ let lineBuffer = '';
49
+ const decoder = new node_string_decoder_1.StringDecoder('utf8');
50
+ const pending = new Map();
51
+ const messages = new Map();
52
+ const completedItems = new Set();
53
+ const startedTools = new Set();
54
+ const submissions = new Map();
55
+ let sendChain = Promise.resolve();
56
+ let inactivityTimer;
57
+ let wallTimer;
58
+ let shutdownTimer;
59
+ let killTimer;
60
+ let baselineUsage = null;
61
+ let lastTotal = null;
62
+ let usageSeen = false;
63
+ const usage = { inputTokens: 0, cachedInputTokens: 0, outputTokens: 0, reasoningOutputTokens: 0 };
64
+ return new Promise(resolve => {
65
+ const emit = (event) => {
66
+ if (settled)
67
+ return;
68
+ events.push(event);
69
+ if (event.kind === 'result')
70
+ lastResultEvent = event;
71
+ try {
72
+ hooks.onEvent?.(event);
73
+ }
74
+ catch { /* renderer failure must not replay provider actions */ }
75
+ };
76
+ const finish = (code, timedOut = false, spawnFailed = false) => {
77
+ if (settled)
78
+ return;
79
+ activeTurnId = null;
80
+ if (terminal || usageSeen) {
81
+ // Usage arrives before the terminal notification. Preserve observed
82
+ // billable work even after Stop, timeout, or an app-server disconnect.
83
+ // Without a terminal response, a normal exit is still not success.
84
+ const status = terminal?.status ?? (transportFailed || timedOut || spawnFailed || code !== null ? 'failed' : 'interrupted');
85
+ emit({ kind: 'result', payload: {
86
+ session_id: sessionId,
87
+ ...(usageSeen ? { usage: {
88
+ input_tokens: usage.inputTokens,
89
+ cached_input_tokens: usage.cachedInputTokens,
90
+ // The existing adapter adds reasoning_output_tokens to output.
91
+ // App-server outputTokens already includes them: avoid double billing.
92
+ output_tokens: Math.max(0, usage.outputTokens - usage.reasoningOutputTokens),
93
+ reasoning_output_tokens: usage.reasoningOutputTokens,
94
+ } } : {}),
95
+ status,
96
+ ...(typeof terminal?.durationMs === 'number' ? { duration_ms: terminal.durationMs } : {}),
97
+ }, ...(status === 'failed' ? { isError: true } : {}) });
98
+ }
99
+ settled = true;
100
+ clearTimeout(inactivityTimer);
101
+ clearTimeout(wallTimer);
102
+ clearTimeout(shutdownTimer);
103
+ if (childClosed)
104
+ clearTimeout(killTimer);
105
+ for (const request of pending.values()) {
106
+ clearTimeout(request.timer);
107
+ request.reject(request.method === 'turn/steer'
108
+ ? new live_session_types_1.LiveInputDeliveryError('Codex disconnected before acknowledging the input. Its delivery is unknown; do not resend it automatically.', true)
109
+ : new Error('Codex app-server closed before responding.'));
110
+ }
111
+ pending.clear();
112
+ child?.stdout?.removeListener('data', onStdout);
113
+ child?.stderr?.removeListener('data', onStderr);
114
+ // Keep error listeners on the dying pipes: a late EPIPE must not crash Desktop.
115
+ // Settlement no longer consumes output, so release all pipe handles even
116
+ // when a failed child needs the bounded SIGKILL fallback to finally exit.
117
+ try {
118
+ child?.stdin?.destroy();
119
+ }
120
+ catch { /* best effort */ }
121
+ try {
122
+ child?.stdout?.destroy();
123
+ }
124
+ catch { /* best effort */ }
125
+ try {
126
+ child?.stderr?.destroy();
127
+ }
128
+ catch { /* best effort */ }
129
+ resolve({ code, timedOut, spawnFailed, events, lastResultEvent, sessionId, stderrTail, child });
130
+ };
131
+ const terminate = () => {
132
+ if (!child || childClosed)
133
+ return;
134
+ const signal = (value) => {
135
+ try {
136
+ if (child?.pid)
137
+ (0, win_spawn_1.treeKillSafe)(child.pid, value, () => { });
138
+ else
139
+ child?.kill(value);
140
+ }
141
+ catch { /* exit/close remain authoritative */ }
142
+ };
143
+ signal('SIGTERM');
144
+ if (!childClosed && !killTimer) {
145
+ killTimer = setTimeout(() => { signal('SIGKILL'); finish(terminal?.status === 'completed' ? 0 : null); }, 2000);
146
+ killTimer.unref?.();
147
+ }
148
+ };
149
+ const fail = (message, timedOut = false) => {
150
+ if (settled)
151
+ return;
152
+ transportFailed = true;
153
+ emit({ kind: 'error', message });
154
+ finish(null, timedOut);
155
+ terminate();
156
+ };
157
+ const armIdle = () => {
158
+ if (settled || closing || !hooks.inactivityTimeoutMs || hooks.inactivityTimeoutMs <= 0)
159
+ return;
160
+ clearTimeout(inactivityTimer);
161
+ inactivityTimer = setTimeout(() => {
162
+ hooks.onInactivityTimeout?.();
163
+ fail('Codex stopped reporting progress before the turn completed.', true);
164
+ }, hooks.inactivityTimeoutMs);
165
+ inactivityTimer.unref?.();
166
+ };
167
+ const maybeClose = () => {
168
+ // A completion notification can precede a steering acknowledgement in
169
+ // the same stream. Drain those replies before closing stdin.
170
+ if (!terminal || settled || closing || pending.size > 0)
171
+ return;
172
+ closing = true;
173
+ activeTurnId = null;
174
+ clearTimeout(inactivityTimer);
175
+ shutdownTimer = setTimeout(terminate, 1500);
176
+ shutdownTimer.unref?.();
177
+ try {
178
+ child?.stdin?.end();
179
+ }
180
+ catch {
181
+ terminate();
182
+ }
183
+ };
184
+ const write = (frame) => {
185
+ if (settled || closing || childClosed || !child?.stdin || child.stdin.destroyed)
186
+ throw new Error('Codex app-server input is closed.');
187
+ child.stdin.write(JSON.stringify(frame) + '\n', error => {
188
+ if (error && !settled)
189
+ fail('Codex app-server input transport failed. Pending input delivery is unknown.');
190
+ });
191
+ };
192
+ const rpc = (method, params, onAccepted) => {
193
+ if (settled || closing || childClosed)
194
+ return Promise.reject(new live_session_types_1.LiveInputDeliveryError('Codex turn is closed.', false));
195
+ return new Promise((accept, reject) => {
196
+ const id = ++nextId;
197
+ const timer = setTimeout(() => {
198
+ if (!pending.delete(id))
199
+ return;
200
+ if (method === 'turn/steer')
201
+ reject(new live_session_types_1.LiveInputDeliveryError('Codex did not acknowledge the input in time. Delivery is unknown; do not resend it automatically.', true));
202
+ else
203
+ reject(new Error(`Codex app-server timed out during ${method}.`));
204
+ maybeClose();
205
+ }, method === 'turn/steer' ? STEER_TIMEOUT_MS : RPC_TIMEOUT_MS);
206
+ timer.unref?.();
207
+ pending.set(id, { method, resolve: accept, reject, timer, onAccepted });
208
+ try {
209
+ write({ id, method, params });
210
+ }
211
+ catch (error) {
212
+ clearTimeout(timer);
213
+ pending.delete(id);
214
+ reject(method === 'turn/steer'
215
+ ? new live_session_types_1.LiveInputDeliveryError('Codex could not confirm writing the input. Delivery is unknown; do not resend it automatically.', true)
216
+ : error);
217
+ }
218
+ });
219
+ };
220
+ const sink = {
221
+ // Core acknowledges submission before updating model context or sampling.
222
+ // A matching userMessage item also does not prove model consumption.
223
+ acceptedReceipt: 'received',
224
+ send(input, onAccepted) {
225
+ if (!input.id || typeof input.text !== 'string' || (input.imagePaths?.some(path => typeof path !== 'string'))) {
226
+ return Promise.reject(new live_session_types_1.LiveInputDeliveryError('Invalid Codex live input.', false));
227
+ }
228
+ const fingerprint = JSON.stringify([input.text, input.imagePaths ?? []]);
229
+ const existing = submissions.get(input.id);
230
+ if (existing)
231
+ return existing.fingerprint === fingerprint ? existing.promise
232
+ : Promise.reject(new live_session_types_1.LiveInputDeliveryError('The same live input ID was used for different content.', false));
233
+ const promise = sendChain.then(async () => {
234
+ const expectedTurnId = activeTurnId;
235
+ if (!expectedTurnId || terminal || settled || closing || child?.killed)
236
+ return false;
237
+ try {
238
+ await rpc('turn/steer', {
239
+ threadId: sessionId, expectedTurnId,
240
+ clientUserMessageId: input.id, input: userInput(input.text, input.imagePaths),
241
+ }, value => {
242
+ if (value.turnId !== expectedTurnId)
243
+ throw new live_session_types_1.LiveInputDeliveryError('Codex acknowledged an unexpected turn. Input delivery is unknown.', true);
244
+ // Commit before parsing the next stdout line, including when ACK
245
+ // and assistant text arrived in one OS pipe chunk.
246
+ try {
247
+ onAccepted?.();
248
+ }
249
+ catch {
250
+ throw new live_session_types_1.LiveInputDeliveryError('Codex accepted the input but local confirmation could not be saved. Do not resend it.', true);
251
+ }
252
+ });
253
+ return true;
254
+ }
255
+ catch (error) {
256
+ if (error instanceof RpcFailure) {
257
+ if (/no active turn|no turn (?:is )?(?:active|running)|(?:expected|active) turn.*(?:mismatch|does not match)|turn.*(?:already (?:completed|finished)|not found)/i.test(error.message))
258
+ return false;
259
+ throw new live_session_types_1.LiveInputDeliveryError(`Codex rejected the input: ${error.message}`, false);
260
+ }
261
+ throw error;
262
+ }
263
+ });
264
+ submissions.set(input.id, { fingerprint, promise });
265
+ sendChain = promise.catch(() => { });
266
+ return promise;
267
+ },
268
+ };
269
+ const item = (value, completed) => {
270
+ const entry = object(value), id = string(entry.id), type = string(entry.type);
271
+ if (!id || completedItems.has(id))
272
+ return;
273
+ if (type === 'agentMessage') {
274
+ if (completed) {
275
+ const text = string(entry.text), previous = messages.get(id) ?? '';
276
+ if (text.startsWith(previous) && text.length > previous.length)
277
+ emit({ kind: 'text-delta', text: text.slice(previous.length) });
278
+ messages.set(id, text);
279
+ }
280
+ }
281
+ else if (['commandExecution', 'mcpToolCall', 'fileChange', 'dynamicToolCall', 'collabAgentToolCall', 'webSearch'].includes(type)) {
282
+ if (!startedTools.has(id)) {
283
+ startedTools.add(id);
284
+ emit({ kind: 'tool-use', toolUseId: id,
285
+ name: type === 'mcpToolCall' ? `${string(entry.server)}.${string(entry.tool)}` : type,
286
+ inputPreview: preview(entry.command ?? entry.arguments ?? entry.changes ?? entry.prompt ?? entry.query ?? '', 1000) });
287
+ }
288
+ if (completed)
289
+ emit({ kind: 'tool-result', toolUseId: id,
290
+ outputPreview: preview(entry.aggregatedOutput ?? entry.result ?? entry.error ?? entry.changes ?? entry.contentItems ?? { status: entry.status }),
291
+ ...(['failed', 'declined'].includes(string(entry.status)) || entry.success === false || (typeof entry.exitCode === 'number' && entry.exitCode !== 0) || entry.error ? { isError: true } : {}) });
292
+ }
293
+ if (completed)
294
+ completedItems.add(id);
295
+ };
296
+ const notification = (method, params) => {
297
+ if (settled)
298
+ return;
299
+ if (method === 'thread/started')
300
+ return; // only the requested thread's response establishes identity
301
+ if (params.threadId !== sessionId || !sessionId)
302
+ return;
303
+ if (method === 'thread/tokenUsage/updated') {
304
+ const snapshot = object(params.tokenUsage), total = object(snapshot.total), last = object(snapshot.last);
305
+ if (!activeTurnId || params.turnId !== activeTurnId) {
306
+ if (!turnRequested)
307
+ baselineUsage = total;
308
+ return;
309
+ }
310
+ if (terminal)
311
+ return;
312
+ const previous = lastTotal ?? baselineUsage;
313
+ for (const key of Object.keys(usage))
314
+ usage[key] += previous
315
+ ? Math.max(0, count(total[key]) - count(previous[key])) : count(last[key]);
316
+ lastTotal = total;
317
+ usageSeen = true;
318
+ return;
319
+ }
320
+ if (method === 'turn/started') {
321
+ const turn = object(params.turn), id = string(turn.id);
322
+ if (turnRequested && !terminal && !activeTurnId && id)
323
+ activeTurnId = id;
324
+ return;
325
+ }
326
+ const turn = object(params.turn);
327
+ const turnId = string(params.turnId) || string(turn.id);
328
+ if (!turnRequested || !turnId || (activeTurnId && turnId !== activeTurnId))
329
+ return;
330
+ // The initial turn may complete before its start response is flushed.
331
+ if (!activeTurnId && !terminal)
332
+ activeTurnId = turnId;
333
+ if (terminal)
334
+ return;
335
+ if (method === 'item/agentMessage/delta') {
336
+ const id = string(params.itemId), delta = string(params.delta);
337
+ if (id && delta && !completedItems.has(id)) {
338
+ messages.set(id, (messages.get(id) ?? '') + delta);
339
+ emit({ kind: 'text-delta', text: delta });
340
+ }
341
+ }
342
+ else if (method === 'item/started' || method === 'item/completed')
343
+ item(params.item, method === 'item/completed');
344
+ else if (method === 'error') {
345
+ const error = string(object(params.error).message) || 'Codex reported an error.';
346
+ if (params.willRetry === true)
347
+ emit({ kind: 'other', type: 'codex.retrying', raw: { message: error } });
348
+ else
349
+ emit({ kind: 'error', message: error });
350
+ }
351
+ else if (method === 'turn/completed') {
352
+ if (!['completed', 'failed', 'interrupted'].includes(string(turn.status))) {
353
+ fail('Codex returned an invalid terminal turn status.');
354
+ return;
355
+ }
356
+ if (Array.isArray(turn.items))
357
+ turn.items.forEach(entry => item(entry, true));
358
+ terminal = turn;
359
+ activeTurnId = null;
360
+ if (turn.status === 'failed')
361
+ emit({ kind: 'error', message: string(object(turn.error).message) || 'Codex turn failed.' });
362
+ maybeClose();
363
+ }
364
+ };
365
+ const frame = (value) => {
366
+ const record = object(value), id = record.id;
367
+ if (typeof record.method === 'string') {
368
+ if (typeof id === 'string' || typeof id === 'number') {
369
+ // No approval is inferred from a server request. Native commands keep
370
+ // the requested sandbox; MCP permissions remain in the MCP server.
371
+ if (record.method === 'item/commandExecution/requestApproval' || record.method === 'item/fileChange/requestApproval')
372
+ write({ id, result: { decision: 'decline' } });
373
+ else if (record.method === 'item/tool/requestUserInput')
374
+ write({ id, result: { answers: {} } });
375
+ else
376
+ write({ id, error: { code: -32601, message: 'This client does not implement that request. Ask the user in the mission conversation when input is needed.' } });
377
+ }
378
+ else
379
+ notification(record.method, object(record.params));
380
+ return;
381
+ }
382
+ if (typeof id !== 'number' && typeof id !== 'string')
383
+ return;
384
+ const request = pending.get(id);
385
+ if (!request)
386
+ return;
387
+ pending.delete(id);
388
+ clearTimeout(request.timer);
389
+ if (record.error) {
390
+ const error = object(record.error);
391
+ request.reject(new RpcFailure(string(error.message) || 'Codex rejected the request.', typeof error.code === 'number' ? error.code : undefined));
392
+ }
393
+ else if ('result' in record) {
394
+ const result = object(record.result);
395
+ try {
396
+ request.onAccepted?.(result);
397
+ request.resolve(result);
398
+ }
399
+ catch (error) {
400
+ request.reject(error);
401
+ if (request.method === 'turn/steer' && error instanceof live_session_types_1.LiveInputDeliveryError && error.ambiguous)
402
+ fail(error.message);
403
+ }
404
+ }
405
+ else
406
+ request.reject(new live_session_types_1.LiveInputDeliveryError('Codex returned a malformed acknowledgement. Delivery is unknown.', request.method === 'turn/steer'));
407
+ maybeClose();
408
+ };
409
+ function onStdout(chunk) {
410
+ if (settled)
411
+ return;
412
+ armIdle();
413
+ hooks.onData?.('stdout');
414
+ lineBuffer += typeof chunk === 'string' ? chunk : decoder.write(chunk);
415
+ for (;;) {
416
+ const end = lineBuffer.indexOf('\n');
417
+ if (end < 0) {
418
+ if (Buffer.byteLength(lineBuffer) > MAX_FRAME_BYTES)
419
+ fail('Codex app-server exceeded the protocol frame limit.');
420
+ return;
421
+ }
422
+ const line = lineBuffer.slice(0, end).replace(/\r$/, '');
423
+ lineBuffer = lineBuffer.slice(end + 1);
424
+ if (!line.trim())
425
+ continue;
426
+ if (Buffer.byteLength(line) > MAX_FRAME_BYTES) {
427
+ fail('Codex app-server exceeded the protocol frame limit.');
428
+ return;
429
+ }
430
+ try {
431
+ hooks.onStdoutLine?.(line);
432
+ frame(JSON.parse(line));
433
+ }
434
+ catch {
435
+ fail('Codex app-server returned an invalid protocol frame.');
436
+ return;
437
+ }
438
+ if (settled)
439
+ return;
440
+ }
441
+ }
442
+ function onStderr(chunk) {
443
+ if (settled)
444
+ return;
445
+ armIdle();
446
+ hooks.onData?.('stderr');
447
+ const text = chunk.toString();
448
+ stderrTail = (stderrTail + text).slice(-STDERR_CAP);
449
+ if (hooks.onStderrLine)
450
+ for (const line of text.split(/\r?\n/).filter(Boolean))
451
+ hooks.onStderrLine(line);
452
+ }
453
+ if (!opts || hooks.adapter.id !== 'codex' || !['chat-turn', 'chat-resume'].includes(hooks.action ?? '')) {
454
+ emit({ kind: 'error', message: 'Codex live sessions require chat-turn/chat-resume build options.' });
455
+ finish(null, false, true);
456
+ return;
457
+ }
458
+ if (hooks.action === 'chat-resume' && !opts.sessionId) {
459
+ emit({ kind: 'error', message: 'Codex live resume requires a session id.' });
460
+ finish(null, false, true);
461
+ return;
462
+ }
463
+ if (opts.toolPolicy === 'none') {
464
+ emit({ kind: 'error', message: 'Codex cannot enforce a no-tools live session.' });
465
+ finish(null, false, true);
466
+ return;
467
+ }
468
+ try {
469
+ child = (hooks.spawn ?? cli_prompt_1.spawnAiCli)(hooks.binary ?? hooks.adapter.binary, ['app-server', '--listen', 'stdio://', ...(opts.extraArgs ?? [])], {
470
+ cwd: hooks.cwd, env: (0, runtime_1.buildProviderEnv)(hooks.adapter, opts, hooks.env ?? process.env), stdio: ['pipe', 'pipe', 'pipe'],
471
+ });
472
+ }
473
+ catch (error) {
474
+ hooks.onSpawnError?.(error);
475
+ emit({ kind: 'error', message: error instanceof Error ? error.message : 'Could not spawn Codex app-server.' });
476
+ finish(null, false, true);
477
+ return;
478
+ }
479
+ child.on('error', error => { hooks.onSpawnError?.(error); emit({ kind: 'error', message: error.message }); finish(null, false, true); });
480
+ child.on('close', code => {
481
+ childClosed = true;
482
+ clearTimeout(killTimer);
483
+ if (!settled && !terminal)
484
+ emit({ kind: 'error', message: 'Codex app-server closed before the turn completed.' });
485
+ finish(terminal?.status === 'completed' ? 0 : terminal?.status === 'failed' ? 1 : terminal?.status === 'interrupted' ? null : code);
486
+ });
487
+ child.stdout?.on('data', onStdout);
488
+ child.stderr?.on('data', onStderr);
489
+ child.stdin?.on('error', () => { if (!settled)
490
+ fail('Codex app-server input transport failed. Pending input delivery is unknown.'); });
491
+ hooks.onSpawn?.(child);
492
+ if (settled)
493
+ return;
494
+ if (!child.stdin || !child.stdout) {
495
+ fail('Codex app-server requires stdin/stdout pipes.');
496
+ return;
497
+ }
498
+ armIdle();
499
+ if (hooks.timeoutMs && hooks.timeoutMs > 0) {
500
+ wallTimer = setTimeout(() => { hooks.onTimeout?.(); fail('Codex live turn exceeded its time limit.', true); }, hooks.timeoutMs);
501
+ wallTimer.unref?.();
502
+ }
503
+ void (async () => {
504
+ try {
505
+ await rpc('initialize', { clientInfo: { name: 'specrails_desktop', title: 'Specrails Desktop', version: '1.0.0' }, capabilities: { experimentalApi: true } });
506
+ write({ method: 'initialized' });
507
+ const thread = await rpc(hooks.action === 'chat-resume' ? 'thread/resume' : 'thread/start', {
508
+ ...(hooks.action === 'chat-resume' ? { threadId: opts.sessionId } : {}),
509
+ model: opts.model, cwd: hooks.cwd, approvalPolicy: 'never', sandbox: opts.toolPolicy === 'read-only' ? 'read-only' : 'workspace-write',
510
+ });
511
+ sessionId = string(object(thread.thread).id) || null;
512
+ if (!sessionId)
513
+ throw new Error('Codex did not return a thread id.');
514
+ if (hooks.action === 'chat-resume' && sessionId !== opts.sessionId)
515
+ throw new Error('Codex resumed an unexpected thread.');
516
+ emit({ kind: 'session-started', sessionId });
517
+ turnRequested = true;
518
+ await rpc('turn/start', {
519
+ threadId: sessionId, input: userInput(opts.prompt, opts.imagePaths), model: opts.model,
520
+ ...(opts.reasoning_effort ? { effort: opts.reasoning_effort } : {}),
521
+ }, response => {
522
+ const turn = object(response.turn), id = string(turn.id);
523
+ if (!id || (activeTurnId && id !== activeTurnId))
524
+ throw new Error('Codex did not acknowledge the expected turn.');
525
+ if (!terminal)
526
+ activeTurnId = id;
527
+ hooks.onInitialInputAccepted?.();
528
+ // A fast turn can already be terminal in this response. Publish that
529
+ // state before exposing the sink so queued input remains unsent.
530
+ if (!terminal && ['completed', 'failed', 'interrupted'].includes(string(turn.status))) {
531
+ notification('turn/completed', { threadId: sessionId, turn });
532
+ }
533
+ if (!inputReady) {
534
+ inputReady = true;
535
+ hooks.onInputReady?.(sink);
536
+ }
537
+ });
538
+ }
539
+ catch (error) {
540
+ if (!settled)
541
+ fail(error instanceof Error ? error.message : 'Codex live session failed to initialize.');
542
+ }
543
+ })();
544
+ });
545
+ }
@@ -261,6 +261,7 @@ exports.geminiAdapter = {
261
261
  modelCatalog: () => GEMINI_MODELS,
262
262
  defaultModel: () => 'gemini-3.5-flash',
263
263
  buildArgs: buildGeminiArgs,
264
+ buildRepoAccessArgs: (paths) => paths.flatMap((repoPath) => ['--include-directories', repoPath]),
264
265
  parseStreamLine: parseGeminiStreamLine,
265
266
  extractResult: extractGeminiResult,
266
267
  projectMcpPath: (root) => path_1.default.join(root, '.gemini', 'settings.json'),
@@ -0,0 +1,12 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.LiveInputDeliveryError = void 0;
4
+ class LiveInputDeliveryError extends Error {
5
+ ambiguous;
6
+ constructor(message, ambiguous) {
7
+ super(message);
8
+ this.ambiguous = ambiguous;
9
+ this.name = 'LiveInputDeliveryError';
10
+ }
11
+ }
12
+ exports.LiveInputDeliveryError = LiveInputDeliveryError;
@@ -0,0 +1,13 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.nativeLiveSessionRunner = nativeLiveSessionRunner;
4
+ const claude_live_session_1 = require("./claude-live-session");
5
+ const codex_live_session_1 = require("./codex-live-session");
6
+ /** A capability decision, kept out of conversation management. */
7
+ function nativeLiveSessionRunner(adapter) {
8
+ switch (adapter.capabilities.liveInputTransport) {
9
+ case 'claude-stream-json': return claude_live_session_1.runClaudeLiveSession;
10
+ case 'codex-app-server': return codex_live_session_1.runCodexLiveSession;
11
+ default: return undefined;
12
+ }
13
+ }
@@ -0,0 +1,24 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.terminalResultError = terminalResultError;
4
+ /** Failure carried by a terminal provider result, independently of exit code.
5
+ * Keep the result event intact so its usage remains available for accounting.
6
+ * This deliberately does not inspect nested tool_result errors: a tool can
7
+ * fail and the model can recover within an otherwise successful turn. */
8
+ function terminalResultError(payload) {
9
+ if (!payload || typeof payload !== 'object')
10
+ return null;
11
+ const result = payload;
12
+ if (result.type !== undefined && result.type !== 'result')
13
+ return null;
14
+ const subtype = typeof result.subtype === 'string' ? result.subtype : '';
15
+ if (result.is_error !== true && !/^error(?:_|$)/.test(subtype))
16
+ return null;
17
+ const errors = Array.isArray(result.errors)
18
+ ? result.errors.filter((error) => typeof error === 'string' && Boolean(error.trim()))
19
+ : [];
20
+ const detail = errors.length > 0
21
+ ? errors.join('; ')
22
+ : typeof result.result === 'string' ? result.result.trim() : '';
23
+ return [/^error(?:_|$)/.test(subtype) ? subtype : 'terminal result error', detail].filter(Boolean).join(': ').slice(0, 2000);
24
+ }
@@ -24,6 +24,7 @@ const feature_flags_1 = require("./feature-flags");
24
24
  const file_provenance_1 = require("./file-provenance");
25
25
  const result_event_1 = require("./result-event");
26
26
  const crypto_1 = require("crypto");
27
+ const codex_spawn_1 = require("./plugins/codex-spawn");
27
28
  const providers_1 = require("./providers");
28
29
  const runtime_1 = require("./providers/runtime");
29
30
  const agent_defaults_1 = require("./agent-defaults");
@@ -2297,6 +2298,7 @@ class QueueManager {
2297
2298
  const railExtraArgs = execution.relocated
2298
2299
  ? (0, runtime_1.buildProviderRepoAccessArgs)(adapter, [execution.repoDir])
2299
2300
  : [];
2301
+ railExtraArgs.push(...(0, codex_spawn_1.buildCodexPluginArgs)({ providerId: adapter.id, stateRoot: execution.cwd, repositoryPath: execution.repoDir, legacyProviderId: this._adapter.id }));
2300
2302
  // Resolve agent profile (if any) and snapshot per-job before spawn.
2301
2303
  // Super mode only (projectId + projectSlug + cwd all present).
2302
2304
  // Skipped when the adapter does not honour `SPECRAILS_PROFILE_PATH` AND