specrails-desktop 2.0.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 (455) hide show
  1. package/.claude/commands/specrails/batch-implement.md +287 -0
  2. package/.claude/commands/specrails/compat-check.md +271 -0
  3. package/.claude/commands/specrails/doctor.md +62 -0
  4. package/.claude/commands/specrails/enrich.md +1635 -0
  5. package/.claude/commands/specrails/explore-spec.md +173 -0
  6. package/.claude/commands/specrails/health-check.md +527 -0
  7. package/.claude/commands/specrails/implement.md +1457 -0
  8. package/.claude/commands/specrails/memory-inspect.md +259 -0
  9. package/.claude/commands/specrails/opsx-diff.md +419 -0
  10. package/.claude/commands/specrails/propose-spec.md +102 -0
  11. package/.claude/commands/specrails/reconfig.md +89 -0
  12. package/.claude/commands/specrails/refactor-recommender.md +212 -0
  13. package/.claude/commands/specrails/retry.md +363 -0
  14. package/.claude/commands/specrails/telemetry.md +552 -0
  15. package/.claude/commands/specrails/why.md +96 -0
  16. package/LICENSE +21 -0
  17. package/README.md +290 -0
  18. package/cli/dist/specrails-desktop.js +1098 -0
  19. package/client/dist/assets/ActivityFeedPage-Gy4x8dBt.js +1 -0
  20. package/client/dist/assets/AgentsPage-CPgu--Fb.js +86 -0
  21. package/client/dist/assets/AnalyticsPage-B5sJEee2.js +1 -0
  22. package/client/dist/assets/BarChart-7IMQ8HY1.js +33 -0
  23. package/client/dist/assets/CodePage-CBdFvbwe.js +2 -0
  24. package/client/dist/assets/DesktopAnalyticsPage-w0rdTq4w.js +1 -0
  25. package/client/dist/assets/DocsDialog-BZUYM7wm.js +11 -0
  26. package/client/dist/assets/DocsPage-9QglWl46.js +11 -0
  27. package/client/dist/assets/ExportDropdown-BLZFXtNi.js +1 -0
  28. package/client/dist/assets/IntegrationsPage-BxBE4y99.js +3 -0
  29. package/client/dist/assets/JobDetailPage-DydWx_5S.js +16 -0
  30. package/client/dist/assets/JobsPage-20ibw0IO.js +1 -0
  31. package/client/dist/assets/abap-Bw6f2wDG.js +1 -0
  32. package/client/dist/assets/activity-BEIp_Y1A.js +1 -0
  33. package/client/dist/assets/activity-BdrPln96.js +1 -0
  34. package/client/dist/assets/activity-CpkRS8Sx.js +1 -0
  35. package/client/dist/assets/activity-DKCpESPt.js +1 -0
  36. package/client/dist/assets/activity-DOUVEjJi.js +1 -0
  37. package/client/dist/assets/activity-DRwkql_y.js +1 -0
  38. package/client/dist/assets/activity-DcDQ7tjw.js +1 -0
  39. package/client/dist/assets/activity-Dv6H7wEr.js +1 -0
  40. package/client/dist/assets/addon-image-3WCl5Vhd.js +1 -0
  41. package/client/dist/assets/addon-ligatures-C5OdliKs.js +2 -0
  42. package/client/dist/assets/addon-webgl-BbX6pSjl.js +44 -0
  43. package/client/dist/assets/addspec-B5yl4Loj.js +1 -0
  44. package/client/dist/assets/addspec-BEeF5-zc.js +1 -0
  45. package/client/dist/assets/addspec-D33ocMxf.js +1 -0
  46. package/client/dist/assets/addspec-DFswZ0jK.js +1 -0
  47. package/client/dist/assets/addspec-DRE-jZv7.js +1 -0
  48. package/client/dist/assets/addspec-DVZ15Jp8.js +1 -0
  49. package/client/dist/assets/addspec-Fkv91Opc.js +1 -0
  50. package/client/dist/assets/addspec-GWm4ffKl.js +1 -0
  51. package/client/dist/assets/agents-1nCDWRmP.js +1 -0
  52. package/client/dist/assets/agents-Bm9rPqnt.js +1 -0
  53. package/client/dist/assets/agents-CMxtJMLD.js +1 -0
  54. package/client/dist/assets/agents-DK-Dlc0i.js +1 -0
  55. package/client/dist/assets/agents-Q6Ldfpxx.js +1 -0
  56. package/client/dist/assets/agents-TeOSy-ax.js +1 -0
  57. package/client/dist/assets/agents-iTqjRajS.js +1 -0
  58. package/client/dist/assets/agents-s87sMGzL.js +1 -0
  59. package/client/dist/assets/agentstudio-B6Wb59E7.js +1 -0
  60. package/client/dist/assets/agentstudio-BADhZ41e.js +1 -0
  61. package/client/dist/assets/agentstudio-BSnWLR63.js +1 -0
  62. package/client/dist/assets/agentstudio-BdidyBzZ.js +1 -0
  63. package/client/dist/assets/agentstudio-CxlUllqI.js +1 -0
  64. package/client/dist/assets/agentstudio-D3I62TLJ.js +1 -0
  65. package/client/dist/assets/agentstudio-DuH9TogZ.js +1 -0
  66. package/client/dist/assets/agentstudio-Kw88_dUF.js +1 -0
  67. package/client/dist/assets/aiedit-BWxHGsYA.js +1 -0
  68. package/client/dist/assets/aiedit-D2ji6Qy0.js +1 -0
  69. package/client/dist/assets/aiedit-DAhZTvtk.js +1 -0
  70. package/client/dist/assets/aiedit-DJMny-D5.js +1 -0
  71. package/client/dist/assets/aiedit-DOcxERkU.js +1 -0
  72. package/client/dist/assets/aiedit-DvrcbwGv.js +1 -0
  73. package/client/dist/assets/aiedit-TTwzL1TS.js +1 -0
  74. package/client/dist/assets/aiedit-WBSjT_C1.js +1 -0
  75. package/client/dist/assets/analytics-BIdr0YfL.js +1 -0
  76. package/client/dist/assets/analytics-C6EzgtdE.js +1 -0
  77. package/client/dist/assets/analytics-C9Zc-rkM.js +1 -0
  78. package/client/dist/assets/analytics-CVx3YOc0.js +1 -0
  79. package/client/dist/assets/analytics-CYj0tfj7.js +1 -0
  80. package/client/dist/assets/analytics-CnY4kNG3.js +1 -0
  81. package/client/dist/assets/analytics-CrPCZRJ-.js +1 -0
  82. package/client/dist/assets/analytics-DMCto-TF.js +1 -0
  83. package/client/dist/assets/apex-Cw8_REBo.js +1 -0
  84. package/client/dist/assets/atom-one-dark-B-oHczHB.css +1 -0
  85. package/client/dist/assets/attachments-BIsSSnHJ.js +1 -0
  86. package/client/dist/assets/attachments-BW4L3l2L.js +1 -0
  87. package/client/dist/assets/attachments-Bcf6BG6V.js +1 -0
  88. package/client/dist/assets/attachments-Bke8sCU4.js +1 -0
  89. package/client/dist/assets/attachments-COcrGRFz.js +1 -0
  90. package/client/dist/assets/attachments-DYHGA2Dj.js +1 -0
  91. package/client/dist/assets/attachments-Dd92KpUH.js +1 -0
  92. package/client/dist/assets/attachments-DzdU6DV6.js +1 -0
  93. package/client/dist/assets/azcli-Cz6HAoOw.js +1 -0
  94. package/client/dist/assets/bat-CcJ-xyqL.js +1 -0
  95. package/client/dist/assets/bicep-z1WDCKYz.js +2 -0
  96. package/client/dist/assets/browser-5ErDlJoR.js +1 -0
  97. package/client/dist/assets/browser-Bc-YdlVg.js +1 -0
  98. package/client/dist/assets/browser-BlYF4OOq.js +1 -0
  99. package/client/dist/assets/browser-CT-ReZGt.js +1 -0
  100. package/client/dist/assets/browser-DGITz3fC.js +1 -0
  101. package/client/dist/assets/browser-JsAIGCEW.js +1 -0
  102. package/client/dist/assets/browser-M5-rbPlw.js +1 -0
  103. package/client/dist/assets/browser-Qya9cARy.js +1 -0
  104. package/client/dist/assets/cameligo-BRewOpfa.js +1 -0
  105. package/client/dist/assets/chat-BEGuC03z.js +1 -0
  106. package/client/dist/assets/chat-BEW60P_u.js +1 -0
  107. package/client/dist/assets/chat-BQNMD0PL.js +1 -0
  108. package/client/dist/assets/chat-BsbNGPW9.js +1 -0
  109. package/client/dist/assets/chat-CboQguCi.js +1 -0
  110. package/client/dist/assets/chat-DRCa9pOt.js +1 -0
  111. package/client/dist/assets/chat-DwUm6W9z.js +1 -0
  112. package/client/dist/assets/chat-yoXwguQu.js +1 -0
  113. package/client/dist/assets/chunk-CilyBKbf.js +1 -0
  114. package/client/dist/assets/clojure-DBjRWN6g.js +1 -0
  115. package/client/dist/assets/clsx-DnqN-uhr.js +1 -0
  116. package/client/dist/assets/code-AL1rVIMb.js +1 -0
  117. package/client/dist/assets/code-C0BKpkht.js +1 -0
  118. package/client/dist/assets/code-C0FTS3ew.js +1 -0
  119. package/client/dist/assets/code-CPcHxzxw.js +1 -0
  120. package/client/dist/assets/code-D3ryDniw.js +1 -0
  121. package/client/dist/assets/code-D3zVVQTj.js +1 -0
  122. package/client/dist/assets/code-PCmfS3dn.js +1 -0
  123. package/client/dist/assets/code-exI0G5Wd.js +1 -0
  124. package/client/dist/assets/codicon-ngg6Pgfi.ttf +0 -0
  125. package/client/dist/assets/coffee-Cfk_XHGR.js +1 -0
  126. package/client/dist/assets/commands-B772IyDa.js +1 -0
  127. package/client/dist/assets/commands-BDDp6xFG.js +1 -0
  128. package/client/dist/assets/commands-CJxCry-o.js +1 -0
  129. package/client/dist/assets/commands-CfgY-_of.js +1 -0
  130. package/client/dist/assets/commands-DLrvnPNg.js +1 -0
  131. package/client/dist/assets/commands-IXMOKBYt.js +1 -0
  132. package/client/dist/assets/commands-UD1NzmwX.js +1 -0
  133. package/client/dist/assets/commands-sqrqsxyE.js +1 -0
  134. package/client/dist/assets/common-DCr6VzJ7.js +1 -0
  135. package/client/dist/assets/common-Dard9UNH.js +1 -0
  136. package/client/dist/assets/common-DeDELLZJ.js +1 -0
  137. package/client/dist/assets/common-DltqHaAe.js +1 -0
  138. package/client/dist/assets/common-Dmm1GhdD.js +1 -0
  139. package/client/dist/assets/common-DnjcgkPH.js +1 -0
  140. package/client/dist/assets/common-GbpxfPG8.js +1 -0
  141. package/client/dist/assets/common-wA36jmj1.js +1 -0
  142. package/client/dist/assets/cpp-BVob6BaP.js +1 -0
  143. package/client/dist/assets/csharp-C4fbRuOu.js +1 -0
  144. package/client/dist/assets/csp-DthFP_vT.js +1 -0
  145. package/client/dist/assets/css-CGMH0hcW.js +3 -0
  146. package/client/dist/assets/css.worker-Wv5dxAWO.js +89 -0
  147. package/client/dist/assets/cssMode-Cc6ozl-J.js +1 -0
  148. package/client/dist/assets/cypher-Pnf68BRV.js +1 -0
  149. package/client/dist/assets/dart-PMMOtxZX.js +1 -0
  150. package/client/dist/assets/dashboard-B4ixDVk8.js +1 -0
  151. package/client/dist/assets/dashboard-BZBADHSj.js +1 -0
  152. package/client/dist/assets/dashboard-C1MfeUHs.js +1 -0
  153. package/client/dist/assets/dashboard-C7SK6xu5.js +1 -0
  154. package/client/dist/assets/dashboard-CB6Le1yN.js +1 -0
  155. package/client/dist/assets/dashboard-CoTpMOBM.js +1 -0
  156. package/client/dist/assets/dashboard-Duo4DDCW.js +1 -0
  157. package/client/dist/assets/dashboard-I19DXBxw.js +1 -0
  158. package/client/dist/assets/dist-js-BY-Fv_fg.js +1 -0
  159. package/client/dist/assets/dist-js-Bakc4uxT.js +1 -0
  160. package/client/dist/assets/dockerfile-di1nsJCc.js +1 -0
  161. package/client/dist/assets/ecl-D_WVcB5M.js +1 -0
  162. package/client/dist/assets/editor-Br_kD0ds.css +1 -0
  163. package/client/dist/assets/editor.api2-XLGzZfbc.js +872 -0
  164. package/client/dist/assets/editor.main-CfXxHimg.js +6 -0
  165. package/client/dist/assets/editor.worker-Bd9IXS8d.js +26 -0
  166. package/client/dist/assets/elixir-OAdJEMOn.js +1 -0
  167. package/client/dist/assets/explore-4mFpnrKU.js +1 -0
  168. package/client/dist/assets/explore-A8Ltoblq.js +1 -0
  169. package/client/dist/assets/explore-B9A3iN2W.js +1 -0
  170. package/client/dist/assets/explore-BV5Xxlsn.js +1 -0
  171. package/client/dist/assets/explore-BrBJvfjP.js +1 -0
  172. package/client/dist/assets/explore-C3FSE42C.js +1 -0
  173. package/client/dist/assets/explore-D2EFgt8J.js +1 -0
  174. package/client/dist/assets/explore-hFc3HFcp.js +1 -0
  175. package/client/dist/assets/flow9-D3QEZjgn.js +1 -0
  176. package/client/dist/assets/format-command-CwGuwzGA.js +1 -0
  177. package/client/dist/assets/freemarker2-DP7J1gG3.js +3 -0
  178. package/client/dist/assets/fsharp-BF0k_8N8.js +1 -0
  179. package/client/dist/assets/go-BAQO5Jsz.js +1 -0
  180. package/client/dist/assets/graphql-hdFVFkiV.js +1 -0
  181. package/client/dist/assets/handlebars-BjRlucw6.js +1 -0
  182. package/client/dist/assets/hcl-DWnl1o-X.js +1 -0
  183. package/client/dist/assets/html-OumBQJ-U.js +1 -0
  184. package/client/dist/assets/html.worker-CQP8QQsS.js +502 -0
  185. package/client/dist/assets/htmlMode-CStc3zXM.js +1 -0
  186. package/client/dist/assets/index-CimDRRi7.css +2 -0
  187. package/client/dist/assets/index-XGZaKl_u.js +142 -0
  188. package/client/dist/assets/ini-CB-6OVu3.js +1 -0
  189. package/client/dist/assets/integrations-C3p12Ms6.js +1 -0
  190. package/client/dist/assets/integrations-Cr6hH7XR.js +1 -0
  191. package/client/dist/assets/integrations-Cublz3m6.js +1 -0
  192. package/client/dist/assets/integrations-D28q1kF6.js +1 -0
  193. package/client/dist/assets/integrations-DRdbki5W.js +1 -0
  194. package/client/dist/assets/integrations-DaC4SzzL.js +1 -0
  195. package/client/dist/assets/integrations-DmQYCUvN.js +1 -0
  196. package/client/dist/assets/integrations-HIlUxXVs.js +1 -0
  197. package/client/dist/assets/java-d1CmfiHX.js +1 -0
  198. package/client/dist/assets/javascript-CMk--e7g.js +1 -0
  199. package/client/dist/assets/jobs-BE1siB0M.js +1 -0
  200. package/client/dist/assets/jobs-BHcQ_Faf.js +1 -0
  201. package/client/dist/assets/jobs-CFfc2dNX.js +1 -0
  202. package/client/dist/assets/jobs-CSi5n8X_.js +1 -0
  203. package/client/dist/assets/jobs-Dc3X86PY.js +1 -0
  204. package/client/dist/assets/jobs-De5tASex.js +1 -0
  205. package/client/dist/assets/jobs-DsoXEdo7.js +1 -0
  206. package/client/dist/assets/jobs-Wl-ApPMb.js +1 -0
  207. package/client/dist/assets/json.worker-DzV-CpCQ.js +58 -0
  208. package/client/dist/assets/jsonMode-C2h3ZcjZ.js +7 -0
  209. package/client/dist/assets/julia-Bgv08lKa.js +1 -0
  210. package/client/dist/assets/kotlin-u98kaVTf.js +1 -0
  211. package/client/dist/assets/less-CjYwpgg5.js +2 -0
  212. package/client/dist/assets/lexon-YTjaAFBB.js +1 -0
  213. package/client/dist/assets/lib-CPxTMOAq.js +7 -0
  214. package/client/dist/assets/liquid-mI3KJrBE.js +1 -0
  215. package/client/dist/assets/lspLanguageFeatures-DU09ggWi.js +4 -0
  216. package/client/dist/assets/lua-BzmkWv27.js +1 -0
  217. package/client/dist/assets/m3-CFwk9fw0.js +1 -0
  218. package/client/dist/assets/markdown-CR5iMpSZ.js +1 -0
  219. package/client/dist/assets/mdx-C41VDTR_.js +1 -0
  220. package/client/dist/assets/mips-CcEalc17.js +1 -0
  221. package/client/dist/assets/monaco.contribution-CPObAXMC.js +2 -0
  222. package/client/dist/assets/msdax-BQbkawnr.js +1 -0
  223. package/client/dist/assets/mysql-GTlaaW_P.js +1 -0
  224. package/client/dist/assets/nav-0fwkrgHt.js +1 -0
  225. package/client/dist/assets/nav-BEL3MTwK.js +1 -0
  226. package/client/dist/assets/nav-B_G-TJDW.js +1 -0
  227. package/client/dist/assets/nav-C2YXcbZS.js +1 -0
  228. package/client/dist/assets/nav-ClzOE4mA.js +1 -0
  229. package/client/dist/assets/nav-CtYwmMgu.js +1 -0
  230. package/client/dist/assets/nav-D2bOGSEg.js +1 -0
  231. package/client/dist/assets/nav-iH1V5j6o.js +1 -0
  232. package/client/dist/assets/objective-c-Byu1T5if.js +1 -0
  233. package/client/dist/assets/pascal-BrfzBfRm.js +1 -0
  234. package/client/dist/assets/pascaligo-BXXKFUeo.js +1 -0
  235. package/client/dist/assets/perl-B3OikKq-.js +1 -0
  236. package/client/dist/assets/pgsql-CTsa0Acc.js +1 -0
  237. package/client/dist/assets/php-DiQh3FUW.js +1 -0
  238. package/client/dist/assets/pla-92uH8Fzm.js +1 -0
  239. package/client/dist/assets/postiats-BbeWkKUr.js +1 -0
  240. package/client/dist/assets/powerquery-DgDMzpsm.js +1 -0
  241. package/client/dist/assets/powershell-BfdUUzaG.js +1 -0
  242. package/client/dist/assets/preload-helper-DSXbuxSR.js +1 -0
  243. package/client/dist/assets/protobuf-BojW2ftW.js +2 -0
  244. package/client/dist/assets/pug-BxqTg3IU.js +1 -0
  245. package/client/dist/assets/python-Y27rKQtk.js +1 -0
  246. package/client/dist/assets/qsharp-BX_A-MW9.js +1 -0
  247. package/client/dist/assets/r-D9BMnxvJ.js +1 -0
  248. package/client/dist/assets/razor-Cd5-q9Bp.js +1 -0
  249. package/client/dist/assets/redis-5cJqEQJJ.js +1 -0
  250. package/client/dist/assets/redshift-d8BBqiwb.js +1 -0
  251. package/client/dist/assets/restructuredtext-C8a6yIcZ.js +1 -0
  252. package/client/dist/assets/ruby-egeh-6KX.js +1 -0
  253. package/client/dist/assets/rust-a3r9IInB.js +1 -0
  254. package/client/dist/assets/sb-y8iRIDei.js +1 -0
  255. package/client/dist/assets/scala-BPDK2AmK.js +1 -0
  256. package/client/dist/assets/scheme-BIWUEoOs.js +1 -0
  257. package/client/dist/assets/scss-CA-PSzwg.js +3 -0
  258. package/client/dist/assets/settings-55oDcbSh.js +1 -0
  259. package/client/dist/assets/settings-Bd4Tq1RB.js +1 -0
  260. package/client/dist/assets/settings-CCSM-Fhn.js +1 -0
  261. package/client/dist/assets/settings-D3e_bDoW.js +1 -0
  262. package/client/dist/assets/settings-DKbTkbn7.js +1 -0
  263. package/client/dist/assets/settings-Dxpo6_w7.js +1 -0
  264. package/client/dist/assets/settings-bt84e3Aa.js +1 -0
  265. package/client/dist/assets/settings-nu68QukM.js +1 -0
  266. package/client/dist/assets/setup-BMqwfbW9.js +1 -0
  267. package/client/dist/assets/setup-Bb5LcG28.js +1 -0
  268. package/client/dist/assets/setup-BeEx2_da.js +1 -0
  269. package/client/dist/assets/setup-CCCrB53Q.js +1 -0
  270. package/client/dist/assets/setup-CJA0ATmd.js +1 -0
  271. package/client/dist/assets/setup-CeiDbZcb.js +1 -0
  272. package/client/dist/assets/setup-Cus7TApA.js +1 -0
  273. package/client/dist/assets/setup-D9qOs2Xo.js +1 -0
  274. package/client/dist/assets/shell--LiT1Bja.js +1 -0
  275. package/client/dist/assets/solidity-DdqZccZg.js +1 -0
  276. package/client/dist/assets/sophia-S6-YxNG_.js +1 -0
  277. package/client/dist/assets/sparql-BSf5kMp2.js +1 -0
  278. package/client/dist/assets/specs-BFfu3u-a.js +1 -0
  279. package/client/dist/assets/specs-B__C8-8a.js +1 -0
  280. package/client/dist/assets/specs-CZ1PsXsC.js +1 -0
  281. package/client/dist/assets/specs-D2FzlLn9.js +1 -0
  282. package/client/dist/assets/specs-DaUTrNF9.js +1 -0
  283. package/client/dist/assets/specs-Dyc5hYeE.js +1 -0
  284. package/client/dist/assets/specs-cKEh2LXt.js +1 -0
  285. package/client/dist/assets/specs-k0PyLDVt.js +1 -0
  286. package/client/dist/assets/sql-D7KgjR8G.js +1 -0
  287. package/client/dist/assets/st-BnoDa-Ml.js +1 -0
  288. package/client/dist/assets/swift-DEUHTkUX.js +1 -0
  289. package/client/dist/assets/systemverilog-Tqb_KPnW.js +1 -0
  290. package/client/dist/assets/tcl-BmBFS2qq.js +1 -0
  291. package/client/dist/assets/terminal-80yDMgMF.js +1 -0
  292. package/client/dist/assets/terminal-Bje4ziIa.js +1 -0
  293. package/client/dist/assets/terminal-C2WYcFHF.js +1 -0
  294. package/client/dist/assets/terminal-CSONJOex.js +1 -0
  295. package/client/dist/assets/terminal-DEqzGtcr.js +1 -0
  296. package/client/dist/assets/terminal-DeWzh6ys.js +1 -0
  297. package/client/dist/assets/terminal-YOlsJCQj.js +1 -0
  298. package/client/dist/assets/terminal-lkZYR4wJ.js +1 -0
  299. package/client/dist/assets/tickets-CB7N30gm.js +1 -0
  300. package/client/dist/assets/tickets-CF2PYelu.js +1 -0
  301. package/client/dist/assets/tickets-DNOANUXr.js +1 -0
  302. package/client/dist/assets/tickets-DU1aqsbr.js +1 -0
  303. package/client/dist/assets/tickets-DYvafSaY.js +1 -0
  304. package/client/dist/assets/tickets-DlpC_iTg.js +1 -0
  305. package/client/dist/assets/tickets-DucYgtdl.js +1 -0
  306. package/client/dist/assets/tickets-clefmXLv.js +1 -0
  307. package/client/dist/assets/ts.worker-METxwbDZ.js +67719 -0
  308. package/client/dist/assets/tsMode-B0y_xEci.js +11 -0
  309. package/client/dist/assets/twig-BQV8igWC.js +1 -0
  310. package/client/dist/assets/typescript-BzK0OgwW.js +1 -0
  311. package/client/dist/assets/typespec-DlFroUGY.js +1 -0
  312. package/client/dist/assets/useProjectCache-DSaiGFjV.js +1 -0
  313. package/client/dist/assets/vb-BlrJpIMX.js +1 -0
  314. package/client/dist/assets/wgsl-BWgIc6FZ.js +298 -0
  315. package/client/dist/assets/workers-rt--R2Qy.js +1 -0
  316. package/client/dist/assets/xml-eX9QXAmI.js +1 -0
  317. package/client/dist/assets/yaml-fcsNkpOt.js +1 -0
  318. package/client/dist/index.html +246 -0
  319. package/docs/README.md +54 -0
  320. package/docs/cli.md +198 -0
  321. package/docs/codex.md +210 -0
  322. package/docs/creating-specs.md +197 -0
  323. package/docs/customizing.md +197 -0
  324. package/docs/getting-started.md +140 -0
  325. package/docs/internals/README.md +25 -0
  326. package/docs/internals/adding-a-provider.md +238 -0
  327. package/docs/internals/api-reference.md +634 -0
  328. package/docs/internals/architecture.md +332 -0
  329. package/docs/internals/configuration.md +172 -0
  330. package/docs/internals/openspec-workflow.md +282 -0
  331. package/docs/internals/operations-runbook.md +198 -0
  332. package/docs/internals/profiles.md +152 -0
  333. package/docs/platforms/macos.md +130 -0
  334. package/docs/platforms/windows.md +81 -0
  335. package/docs/running-pipelines.md +240 -0
  336. package/docs/terminal.md +138 -0
  337. package/docs/tracking-cost.md +155 -0
  338. package/package.json +82 -0
  339. package/server/dist/agent-generator.js +232 -0
  340. package/server/dist/agent-refine-db.js +124 -0
  341. package/server/dist/agent-refine-manager.js +526 -0
  342. package/server/dist/ai-invocations.js +111 -0
  343. package/server/dist/attachment-manager.js +299 -0
  344. package/server/dist/auth.js +207 -0
  345. package/server/dist/binary-probe.js +35 -0
  346. package/server/dist/browser-capture-manager.js +576 -0
  347. package/server/dist/browser-capture-types.js +28 -0
  348. package/server/dist/browser-network.js +149 -0
  349. package/server/dist/browser-playwright.js +888 -0
  350. package/server/dist/build-dirs.js +44 -0
  351. package/server/dist/changes-reader.js +120 -0
  352. package/server/dist/chat-manager.js +1060 -0
  353. package/server/dist/chromium-resolver.js +311 -0
  354. package/server/dist/code-explorer-router.js +788 -0
  355. package/server/dist/codex-otel-bridge.js +235 -0
  356. package/server/dist/command-resolver.js +102 -0
  357. package/server/dist/config.js +306 -0
  358. package/server/dist/context-budget.js +113 -0
  359. package/server/dist/context-scope.js +279 -0
  360. package/server/dist/contract-refine-runner.js +521 -0
  361. package/server/dist/core-compat.js +207 -0
  362. package/server/dist/core-package.js +14 -0
  363. package/server/dist/db.js +1034 -0
  364. package/server/dist/desktop-analytics.js +156 -0
  365. package/server/dist/desktop-db.js +456 -0
  366. package/server/dist/desktop-router.js +735 -0
  367. package/server/dist/docs-router.js +207 -0
  368. package/server/dist/explore-contract-refine.js +421 -0
  369. package/server/dist/explore-cwd-manager.js +242 -0
  370. package/server/dist/explore-draft-title.js +47 -0
  371. package/server/dist/explore-smash.js +450 -0
  372. package/server/dist/feature-flags.js +17 -0
  373. package/server/dist/file-provenance.js +382 -0
  374. package/server/dist/file-summary-generator.js +221 -0
  375. package/server/dist/file-summary-manager.js +689 -0
  376. package/server/dist/hooks.js +102 -0
  377. package/server/dist/ids.js +7 -0
  378. package/server/dist/index.js +586 -0
  379. package/server/dist/metrics.js +136 -0
  380. package/server/dist/mobile/index.js +16 -0
  381. package/server/dist/mobile/mobile-admin-router.js +84 -0
  382. package/server/dist/mobile/mobile-auth.js +67 -0
  383. package/server/dist/mobile/mobile-devices.js +80 -0
  384. package/server/dist/mobile/mobile-event-bus.js +39 -0
  385. package/server/dist/mobile/mobile-gateway.js +285 -0
  386. package/server/dist/mobile/mobile-mdns.js +81 -0
  387. package/server/dist/mobile/mobile-pairing.js +179 -0
  388. package/server/dist/mobile/mobile-redact.js +53 -0
  389. package/server/dist/mobile/mobile-router.js +411 -0
  390. package/server/dist/mobile/mobile-tls.js +86 -0
  391. package/server/dist/mobile/mobile-types.js +9 -0
  392. package/server/dist/mobile/mobile-ws.js +275 -0
  393. package/server/dist/path-resolver.js +298 -0
  394. package/server/dist/plugin-manager.js +617 -0
  395. package/server/dist/plugins/claude-approval.js +179 -0
  396. package/server/dist/plugins/claude-md-mutation.js +146 -0
  397. package/server/dist/plugins/codex-mcp.js +108 -0
  398. package/server/dist/plugins/contributors.js +72 -0
  399. package/server/dist/plugins/drift.js +58 -0
  400. package/server/dist/plugins/index.js +14 -0
  401. package/server/dist/plugins/json-mutation.js +120 -0
  402. package/server/dist/plugins/manager.js +32 -0
  403. package/server/dist/plugins/ownership.js +86 -0
  404. package/server/dist/plugins/paths.js +37 -0
  405. package/server/dist/plugins/prereq-installer.js +104 -0
  406. package/server/dist/plugins/rail-integration.js +79 -0
  407. package/server/dist/plugins/serena/index.js +13 -0
  408. package/server/dist/plugins/serena/install.js +91 -0
  409. package/server/dist/plugins/serena/instructions-content.js +21 -0
  410. package/server/dist/plugins/serena/manifest.js +111 -0
  411. package/server/dist/plugins/serena/verify.js +78 -0
  412. package/server/dist/plugins-router.js +215 -0
  413. package/server/dist/pricing.js +89 -0
  414. package/server/dist/profile-manager.js +310 -0
  415. package/server/dist/profiles-router.js +759 -0
  416. package/server/dist/project-registry.js +443 -0
  417. package/server/dist/project-router.js +4016 -0
  418. package/server/dist/proposal-manager.js +291 -0
  419. package/server/dist/provider-selection.js +69 -0
  420. package/server/dist/providers/claude-adapter.js +281 -0
  421. package/server/dist/providers/codex-adapter.js +264 -0
  422. package/server/dist/providers/index.js +23 -0
  423. package/server/dist/providers/registry.js +37 -0
  424. package/server/dist/providers/types.js +22 -0
  425. package/server/dist/queue-manager.js +1511 -0
  426. package/server/dist/rails-router.js +362 -0
  427. package/server/dist/rails-store.js +116 -0
  428. package/server/dist/result-event.js +106 -0
  429. package/server/dist/schemas/profile.v1.json +151 -0
  430. package/server/dist/setup-manager.js +1165 -0
  431. package/server/dist/setup-prerequisites.js +372 -0
  432. package/server/dist/smash-runner.js +663 -0
  433. package/server/dist/spec-draft-parser.js +133 -0
  434. package/server/dist/spec-launcher-manager.js +174 -0
  435. package/server/dist/spec-models.js +32 -0
  436. package/server/dist/specrails-tech-client.js +82 -0
  437. package/server/dist/spending.js +448 -0
  438. package/server/dist/telemetry-compactor.js +180 -0
  439. package/server/dist/telemetry-export.js +317 -0
  440. package/server/dist/telemetry-receiver.js +224 -0
  441. package/server/dist/terminal-manager.js +633 -0
  442. package/server/dist/terminal-marks-store.js +117 -0
  443. package/server/dist/terminal-osc-parser.js +159 -0
  444. package/server/dist/terminal-settings.js +282 -0
  445. package/server/dist/terminal-shell-integration.js +196 -0
  446. package/server/dist/ticket-broadcast.js +47 -0
  447. package/server/dist/ticket-store.js +397 -0
  448. package/server/dist/ticket-watcher.js +117 -0
  449. package/server/dist/types.js +10 -0
  450. package/server/dist/user-mcp-config.js +117 -0
  451. package/server/dist/util/cli-prompt.js +181 -0
  452. package/server/dist/util/secure-fs.js +50 -0
  453. package/server/dist/util/win-spawn.js +43 -0
  454. package/server/dist/webhook-manager.js +89 -0
  455. package/server/dist/ws-routing.js +47 -0
@@ -0,0 +1,275 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MobileWsBridge = void 0;
4
+ const mobile_event_bus_1 = require("./mobile-event-bus");
5
+ const mobile_redact_1 = require("./mobile-redact");
6
+ // The gateway's WS fan-out. Subscribes ONCE to the in-process event bus and
7
+ // pushes a mobile-shaped, redacted, per-subscription-filtered stream to each
8
+ // attached socket. The raw /ws firehose (stream-json payloads, 256 KB
9
+ // scrollbacks) is never forwarded verbatim.
10
+ const OPEN = 1;
11
+ const INBOUND_MAX_BYTES = 4096;
12
+ const INBOUND_MAX_PER_MIN = 30;
13
+ const HEARTBEAT_MS = 30_000;
14
+ const LOG_FLUSH_MS = 250;
15
+ const LOG_LINE_MAX = 2048;
16
+ const LOG_BATCH_MAX = 60;
17
+ function topicFor(type) {
18
+ switch (type) {
19
+ case 'queue': return 'queue';
20
+ case 'phase': return 'phase';
21
+ case 'ticket_created':
22
+ case 'ticket_updated':
23
+ case 'ticket_deleted':
24
+ case 'spec_gen_stream':
25
+ case 'spec_gen_done':
26
+ case 'spec_gen_error': return 'tickets';
27
+ case 'rail.job_started':
28
+ case 'rail.job_stopped':
29
+ case 'rail.job_completed':
30
+ case 'rail.updated': return 'rails';
31
+ case 'spending.invalidated': return 'spending';
32
+ case 'chat_stream':
33
+ case 'chat_done':
34
+ case 'chat_error':
35
+ case 'chat_title_update':
36
+ case 'chat_command_proposal':
37
+ case 'spec_draft.update': return 'chat';
38
+ case 'cost_alert':
39
+ case 'daily_budget_exceeded':
40
+ case 'desktop_daily_budget_exceeded': return 'alerts';
41
+ case 'log':
42
+ case 'event': return 'jobtail';
43
+ case 'desktop.projects':
44
+ case 'desktop.project_added':
45
+ case 'desktop.project_removed': return 'hub'; // mobile-app v1 wire compat — topic name frozen
46
+ default: return null;
47
+ }
48
+ }
49
+ // ─── Mobile wire compat ───────────────────────────────────────────────────────
50
+ // mobile-app v1 wire compat — do not rename: the phone app (v1.0.0, in App
51
+ // Review) matches these exact legacy `type` strings (and the legacy budget
52
+ // payload field names). The internal broadcast types were renamed `desktop.*`
53
+ // in the Specrails Desktop rebrand; this outbound boundary translates them
54
+ // back before anything reaches a mobile socket.
55
+ const LEGACY_WIRE_TYPES = {
56
+ 'desktop.projects': 'hub.projects',
57
+ 'desktop.project_added': 'hub.project_added',
58
+ 'desktop.project_removed': 'hub.project_removed',
59
+ desktop_daily_budget_exceeded: 'hub_daily_budget_exceeded',
60
+ };
61
+ function toMobileWire(msg) {
62
+ const legacyType = LEGACY_WIRE_TYPES[msg.type];
63
+ if (!legacyType)
64
+ return msg;
65
+ const out = { ...msg, type: legacyType };
66
+ if (msg.type === 'desktop_daily_budget_exceeded') {
67
+ // mobile-app v1 wire compat — restore the legacy payload field names.
68
+ if ('desktopDailySpend' in out) {
69
+ out.hubDailySpend = out.desktopDailySpend;
70
+ delete out.desktopDailySpend;
71
+ }
72
+ if ('desktopBudget' in out) {
73
+ out.hubBudget = out.desktopBudget;
74
+ delete out.desktopBudget;
75
+ }
76
+ }
77
+ return out;
78
+ }
79
+ class MobileWsBridge {
80
+ _socks = new Set();
81
+ _unsub = null;
82
+ _flush = null;
83
+ _hb = null;
84
+ _clock;
85
+ constructor(opts = {}) {
86
+ this._clock = opts.clock ?? (() => Date.now());
87
+ }
88
+ start() {
89
+ if (this._unsub)
90
+ return;
91
+ this._unsub = (0, mobile_event_bus_1.getMobileEventBus)().onMessage((msg) => this.dispatch(msg));
92
+ this._flush = setInterval(() => this.flushLogs(), LOG_FLUSH_MS);
93
+ this._hb = setInterval(() => this.heartbeat(), HEARTBEAT_MS);
94
+ // Don't keep the event loop alive purely for these timers.
95
+ this._flush.unref?.();
96
+ this._hb.unref?.();
97
+ }
98
+ stop() {
99
+ if (this._unsub) {
100
+ this._unsub();
101
+ this._unsub = null;
102
+ }
103
+ if (this._flush) {
104
+ clearInterval(this._flush);
105
+ this._flush = null;
106
+ }
107
+ if (this._hb) {
108
+ clearInterval(this._hb);
109
+ this._hb = null;
110
+ }
111
+ for (const s of this._socks) {
112
+ try {
113
+ s.ws.close(1001, 'gateway stopping');
114
+ }
115
+ catch { /* ignore */ }
116
+ }
117
+ this._socks.clear();
118
+ }
119
+ get socketCount() {
120
+ return this._socks.size;
121
+ }
122
+ /** Register a freshly-upgraded socket for an authenticated device. */
123
+ attach(ws, deviceId) {
124
+ const state = {
125
+ ws, deviceId,
126
+ projects: new Set(), topics: new Set(), watchedJob: null,
127
+ inbound: [], alive: true,
128
+ logBuf: new Map(), logDropped: new Map(),
129
+ };
130
+ this._socks.add(state);
131
+ ws.on('message', (...args) => this.onInbound(state, args[0]));
132
+ ws.on('pong', () => { state.alive = true; });
133
+ ws.on('close', () => { this._socks.delete(state); });
134
+ ws.on('error', () => { this._socks.delete(state); });
135
+ }
136
+ /** Close every socket belonging to a (just-revoked) device. */
137
+ closeForDevice(deviceId) {
138
+ for (const s of this._socks) {
139
+ if (s.deviceId === deviceId) {
140
+ try {
141
+ s.ws.close(4401, 'revoked');
142
+ }
143
+ catch { /* ignore */ }
144
+ this._socks.delete(s);
145
+ }
146
+ }
147
+ }
148
+ onInbound(state, raw) {
149
+ const text = typeof raw === 'string' ? raw : Buffer.isBuffer(raw) ? raw.toString('utf8') : '';
150
+ if (Buffer.byteLength(text) > INBOUND_MAX_BYTES) {
151
+ try {
152
+ state.ws.close(1009, 'message too large');
153
+ }
154
+ catch { /* ignore */ }
155
+ return;
156
+ }
157
+ const now = this._clock();
158
+ state.inbound = state.inbound.filter((t) => now - t < 60_000);
159
+ state.inbound.push(now);
160
+ if (state.inbound.length > INBOUND_MAX_PER_MIN) {
161
+ try {
162
+ state.ws.close(1008, 'rate limit');
163
+ }
164
+ catch { /* ignore */ }
165
+ return;
166
+ }
167
+ let msg;
168
+ try {
169
+ msg = JSON.parse(text);
170
+ }
171
+ catch {
172
+ return;
173
+ }
174
+ switch (msg.type) {
175
+ case 'subscribe': {
176
+ const projects = Array.isArray(msg.projects) ? msg.projects.filter((x) => typeof x === 'string') : [];
177
+ const topics = Array.isArray(msg.topics) ? msg.topics.filter((x) => typeof x === 'string') : [];
178
+ state.projects = new Set(projects);
179
+ state.topics = new Set(topics);
180
+ break;
181
+ }
182
+ case 'watch_job': {
183
+ if (typeof msg.projectId === 'string' && typeof msg.jobId === 'string') {
184
+ state.watchedJob = { projectId: msg.projectId, jobId: msg.jobId };
185
+ }
186
+ break;
187
+ }
188
+ case 'unwatch_job':
189
+ state.watchedJob = null;
190
+ break;
191
+ }
192
+ }
193
+ /** Fan a single bus message out to matching sockets. */
194
+ dispatch(msg) {
195
+ const topic = topicFor(msg.type);
196
+ if (!topic)
197
+ return;
198
+ for (const s of this._socks) {
199
+ if (topic === 'hub') {
200
+ // App-level (project registry): always forward, but translate to the
201
+ // legacy mobile wire types and redact (the projects payload carries `path`).
202
+ this.send(s, (0, mobile_redact_1.redact)(toMobileWire(msg)));
203
+ continue;
204
+ }
205
+ const projectId = msg.projectId;
206
+ if (!projectId || !s.projects.has(projectId))
207
+ continue;
208
+ if (topic === 'jobtail') {
209
+ if (!s.watchedJob || s.watchedJob.projectId !== projectId)
210
+ continue;
211
+ const jobId = msg.jobId
212
+ ?? msg.processId;
213
+ if (jobId !== s.watchedJob.jobId)
214
+ continue;
215
+ if (msg.type === 'log') {
216
+ this.bufferLog(s, s.watchedJob.jobId, msg.line);
217
+ }
218
+ else if (msg.type === 'event') {
219
+ this.send(s, { type: 'job_event', projectId, jobId, eventType: msg.event_type });
220
+ }
221
+ continue;
222
+ }
223
+ if (s.topics.has(topic)) {
224
+ this.send(s, (0, mobile_redact_1.redact)(toMobileWire(msg)));
225
+ }
226
+ }
227
+ }
228
+ bufferLog(s, jobId, line) {
229
+ const buf = s.logBuf.get(jobId) ?? [];
230
+ if (buf.length >= LOG_BATCH_MAX) {
231
+ s.logDropped.set(jobId, (s.logDropped.get(jobId) ?? 0) + 1);
232
+ return;
233
+ }
234
+ buf.push(line.length > LOG_LINE_MAX ? line.slice(0, LOG_LINE_MAX) + '…' : line);
235
+ s.logBuf.set(jobId, buf);
236
+ }
237
+ flushLogs() {
238
+ for (const s of this._socks) {
239
+ for (const [jobId, lines] of s.logBuf) {
240
+ if (lines.length === 0)
241
+ continue;
242
+ const dropped = s.logDropped.get(jobId) ?? 0;
243
+ this.send(s, { type: 'log_batch', jobId, lines, dropped });
244
+ }
245
+ s.logBuf.clear();
246
+ s.logDropped.clear();
247
+ }
248
+ }
249
+ heartbeat() {
250
+ for (const s of this._socks) {
251
+ if (!s.alive) {
252
+ try {
253
+ s.ws.terminate();
254
+ }
255
+ catch { /* ignore */ }
256
+ this._socks.delete(s);
257
+ continue;
258
+ }
259
+ s.alive = false;
260
+ try {
261
+ s.ws.ping();
262
+ }
263
+ catch { /* ignore */ }
264
+ }
265
+ }
266
+ send(s, obj) {
267
+ if (s.ws.readyState !== OPEN)
268
+ return;
269
+ try {
270
+ s.ws.send(JSON.stringify(obj));
271
+ }
272
+ catch { /* ignore */ }
273
+ }
274
+ }
275
+ exports.MobileWsBridge = MobileWsBridge;
@@ -0,0 +1,298 @@
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.resolveBundledRuntimePath = resolveBundledRuntimePath;
7
+ exports.resolveStartupPath = resolveStartupPath;
8
+ exports.parseLoginShellOutput = parseLoginShellOutput;
9
+ exports.augmentPathFromLoginShell = augmentPathFromLoginShell;
10
+ exports.getPathDiagnostic = getPathDiagnostic;
11
+ exports.__resetPathResolverForTest = __resetPathResolverForTest;
12
+ const child_process_1 = require("child_process");
13
+ const fs_1 = __importDefault(require("fs"));
14
+ const os_1 = __importDefault(require("os"));
15
+ const path_1 = __importDefault(require("path"));
16
+ const PATH_BEGIN = '__SRH_PATH_BEGIN__';
17
+ const PATH_END = '__SRH_PATH_END__';
18
+ const LOGIN_SHELL_TIMEOUT_MS = 1500;
19
+ let diagnostic = {
20
+ pathSegments: [],
21
+ pathSources: [],
22
+ loginShellStatus: 'skipped',
23
+ };
24
+ let warnedLoginShell = false;
25
+ /**
26
+ * True once `resolveStartupPath()` has actually prepended at least one bundled
27
+ * runtime dir that exists on disk. Gates the login-shell no-op: when a desktop
28
+ * build ships no runtimes (e.g. Windows ARM64, or a partial CI extraction) the
29
+ * bundle is NOT active, so we fall back to system discovery + login-shell
30
+ * augmentation instead of going dark.
31
+ */
32
+ let bundledRuntimesActive = false;
33
+ function fileExists(p) {
34
+ try {
35
+ return fs_1.default.existsSync(p);
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ }
41
+ /**
42
+ * Resolve the bin directory for each bundled tool family from the actual binary
43
+ * FILE (not just the directory), returning the dir to prepend or `null`. Keeping
44
+ * this file-level and symmetric with setup-prerequisites means "bundle active"
45
+ * means the same thing in both modules.
46
+ */
47
+ function resolveBundledBinDirs(runtimesPath) {
48
+ const isWin = process.platform === 'win32';
49
+ const nodeBinDir = isWin
50
+ ? (fileExists(path_1.default.join(runtimesPath, 'node', 'node.exe')) ? path_1.default.join(runtimesPath, 'node') : null)
51
+ : (fileExists(path_1.default.join(runtimesPath, 'node', 'bin', 'node')) ? path_1.default.join(runtimesPath, 'node', 'bin') : null);
52
+ let gitBinDir = null;
53
+ if (isWin) {
54
+ // PortableGit ships the real binary at git/cmd/git.exe with a redirector at git/bin/git.exe.
55
+ if (fileExists(path_1.default.join(runtimesPath, 'git', 'cmd', 'git.exe')))
56
+ gitBinDir = path_1.default.join(runtimesPath, 'git', 'cmd');
57
+ else if (fileExists(path_1.default.join(runtimesPath, 'git', 'bin', 'git.exe')))
58
+ gitBinDir = path_1.default.join(runtimesPath, 'git', 'bin');
59
+ }
60
+ else if (fileExists(path_1.default.join(runtimesPath, 'git', 'bin', 'git'))) {
61
+ gitBinDir = path_1.default.join(runtimesPath, 'git', 'bin');
62
+ }
63
+ return { nodeBinDir, gitBinDir };
64
+ }
65
+ function getDelimiter() {
66
+ return process.platform === 'win32' ? ';' : ':';
67
+ }
68
+ function splitPath(value) {
69
+ if (!value)
70
+ return [];
71
+ return value.split(getDelimiter()).filter((s) => s.length > 0);
72
+ }
73
+ function joinPath(segments) {
74
+ return segments.join(getDelimiter());
75
+ }
76
+ function fastPathDirectories() {
77
+ if (process.platform === 'darwin') {
78
+ return ['/opt/homebrew/bin', '/opt/homebrew/sbin', '/usr/local/bin', '/usr/local/sbin'];
79
+ }
80
+ if (process.platform === 'linux') {
81
+ return ['/usr/local/bin', '/usr/local/sbin', path_1.default.join(os_1.default.homedir(), '.local/bin')];
82
+ }
83
+ return [];
84
+ }
85
+ /**
86
+ * Returns the absolute path to the bundled runtimes directory.
87
+ * Only valid when SPECRAILS_IS_DESKTOP=1 and SPECRAILS_BUNDLED_RUNTIMES_PATH is set.
88
+ * Throws if the env var is missing.
89
+ */
90
+ function resolveBundledRuntimePath() {
91
+ const p = process.env.SPECRAILS_BUNDLED_RUNTIMES_PATH;
92
+ if (!p) {
93
+ throw new Error('[path-resolver] resolveBundledRuntimePath() called but SPECRAILS_BUNDLED_RUNTIMES_PATH is not set');
94
+ }
95
+ return p;
96
+ }
97
+ /**
98
+ * Synchronously prepend well-known package-manager bin directories to
99
+ * `process.env.PATH` if they are missing. No-op on Windows.
100
+ *
101
+ * Records the resulting segments and their sources for diagnostic reporting.
102
+ */
103
+ function resolveStartupPath() {
104
+ // Desktop mode: bundled runtimes win when present. We existence-gate every
105
+ // candidate dir so a runtimes-less or partially-extracted build degrades to
106
+ // normal system PATH discovery instead of prepending dead dirs and disabling
107
+ // all fallback (which would dead-end Add Project with "corrupted-bundle").
108
+ if (process.env.SPECRAILS_IS_DESKTOP === '1') {
109
+ const runtimesPath = process.env.SPECRAILS_BUNDLED_RUNTIMES_PATH;
110
+ if (runtimesPath) {
111
+ const { nodeBinDir, gitBinDir } = resolveBundledBinDirs(runtimesPath);
112
+ // Activate the bundle only when BOTH node and git are present. A partial
113
+ // bundle (one tool present, the other missing — a botched extraction) is
114
+ // treated as NOT active so the full system fallback (fast-path + login-shell)
115
+ // runs for every tool. Otherwise the missing tool would fall through to a
116
+ // system probe against an un-augmented PATH and be wrongly reported missing.
117
+ if (nodeBinDir && gitBinDir) {
118
+ const inherited = splitPath(process.env.PATH);
119
+ const inheritedSet = new Set(inherited);
120
+ const toAdd = [nodeBinDir, gitBinDir].filter((d) => !inheritedSet.has(d));
121
+ const merged = [...toAdd, ...inherited];
122
+ process.env.PATH = joinPath(merged);
123
+ bundledRuntimesActive = true;
124
+ diagnostic = {
125
+ pathSegments: merged,
126
+ pathSources: [
127
+ ...toAdd.map(() => 'bundled'),
128
+ ...inherited.map(() => 'inherited'),
129
+ ],
130
+ loginShellStatus: 'skipped',
131
+ };
132
+ return;
133
+ }
134
+ // Bundle absent or incomplete → fall through to system PATH discovery below
135
+ // so system node/git still resolve (graceful fallback).
136
+ }
137
+ // No runtimes path, or no/partial bundle present: fall through (do NOT return).
138
+ }
139
+ const inherited = splitPath(process.env.PATH);
140
+ const inheritedSet = new Set(inherited);
141
+ if (process.platform === 'win32') {
142
+ diagnostic = {
143
+ pathSegments: inherited,
144
+ pathSources: inherited.map(() => 'inherited'),
145
+ loginShellStatus: 'skipped',
146
+ };
147
+ return;
148
+ }
149
+ const toPrepend = [];
150
+ for (const dir of fastPathDirectories()) {
151
+ if (!inheritedSet.has(dir)) {
152
+ toPrepend.push(dir);
153
+ inheritedSet.add(dir);
154
+ }
155
+ }
156
+ const merged = [...toPrepend, ...inherited];
157
+ process.env.PATH = joinPath(merged);
158
+ diagnostic = {
159
+ pathSegments: merged,
160
+ pathSources: [
161
+ ...toPrepend.map(() => 'fast-path'),
162
+ ...inherited.map(() => 'inherited'),
163
+ ],
164
+ loginShellStatus: 'skipped',
165
+ };
166
+ }
167
+ /**
168
+ * Parse stdout from the login-shell probe. Returns the PATH between sentinel
169
+ * markers, or `null` if the markers are not present.
170
+ */
171
+ function parseLoginShellOutput(stdout) {
172
+ const begin = stdout.indexOf(PATH_BEGIN);
173
+ if (begin === -1)
174
+ return null;
175
+ const start = begin + PATH_BEGIN.length;
176
+ const end = stdout.indexOf(PATH_END, start);
177
+ if (end === -1)
178
+ return null;
179
+ return stdout.slice(start, end);
180
+ }
181
+ /**
182
+ * Spawn the user's login shell once and merge any additional PATH segments
183
+ * it exposes (Volta/nvm/fnm/asdf shims) into `process.env.PATH`. Async,
184
+ * fire-and-forget — must not block startup.
185
+ *
186
+ * No-op on Windows and in test environments.
187
+ */
188
+ async function augmentPathFromLoginShell(opts = {}) {
189
+ if (process.platform === 'win32') {
190
+ diagnostic.loginShellStatus = 'skipped';
191
+ return;
192
+ }
193
+ if (process.env.NODE_ENV === 'test' || process.env.VITEST === 'true') {
194
+ diagnostic.loginShellStatus = 'skipped';
195
+ return;
196
+ }
197
+ // Desktop mode WITH an active bundle: login-shell augmentation must never run
198
+ // — it could prepend system node/git dirs ahead of bundled ones. But when the
199
+ // bundle is absent (runtimes-less build → system fallback), we DO want
200
+ // login-shell augmentation so nvm/volta/fnm shims are discovered.
201
+ if (process.env.SPECRAILS_IS_DESKTOP === '1' && bundledRuntimesActive) {
202
+ diagnostic.loginShellStatus = 'skipped';
203
+ return;
204
+ }
205
+ const spawnFn = opts.spawnFn ?? child_process_1.spawn;
206
+ const timeoutMs = opts.timeoutMs ?? LOGIN_SHELL_TIMEOUT_MS;
207
+ const shell = process.env.SHELL || '/bin/sh';
208
+ const command = `printf "${PATH_BEGIN}%s${PATH_END}" "$PATH"`;
209
+ const status = await new Promise((resolve) => {
210
+ let child;
211
+ try {
212
+ child = spawnFn(shell, ['-l', '-i', '-c', command], { stdio: ['ignore', 'pipe', 'pipe'] });
213
+ }
214
+ catch {
215
+ resolve('error');
216
+ return;
217
+ }
218
+ let stdout = '';
219
+ let timedOut = false;
220
+ let settled = false;
221
+ const timer = setTimeout(() => {
222
+ timedOut = true;
223
+ try {
224
+ child.kill('SIGKILL');
225
+ }
226
+ catch { /* ignore */ }
227
+ }, timeoutMs);
228
+ child.stdout?.on('data', (chunk) => { stdout += chunk.toString('utf-8'); });
229
+ child.stderr?.on('data', () => { });
230
+ const finish = (s) => {
231
+ if (settled)
232
+ return;
233
+ settled = true;
234
+ clearTimeout(timer);
235
+ resolve(s);
236
+ };
237
+ child.on('error', () => finish('error'));
238
+ child.on('close', (code) => {
239
+ if (timedOut) {
240
+ finish('timeout');
241
+ return;
242
+ }
243
+ if (code !== 0) {
244
+ finish('error');
245
+ return;
246
+ }
247
+ const parsed = parseLoginShellOutput(stdout);
248
+ if (parsed === null) {
249
+ finish('error');
250
+ return;
251
+ }
252
+ mergeLoginShellPath(parsed);
253
+ finish('ok');
254
+ });
255
+ });
256
+ diagnostic.loginShellStatus = status;
257
+ if (status !== 'ok' && !warnedLoginShell) {
258
+ warnedLoginShell = true;
259
+ console.warn(`[path-resolver] login-shell merge ${status}; using fast-path PATH only`);
260
+ }
261
+ }
262
+ function mergeLoginShellPath(rawPath) {
263
+ const current = splitPath(process.env.PATH);
264
+ const currentSet = new Set(current);
265
+ const incoming = splitPath(rawPath);
266
+ const additions = [];
267
+ for (const dir of incoming) {
268
+ if (!currentSet.has(dir)) {
269
+ additions.push(dir);
270
+ currentSet.add(dir);
271
+ }
272
+ }
273
+ if (additions.length === 0)
274
+ return;
275
+ const merged = [...additions, ...current];
276
+ process.env.PATH = joinPath(merged);
277
+ diagnostic = {
278
+ pathSegments: merged,
279
+ pathSources: [
280
+ ...additions.map(() => 'login-shell'),
281
+ ...diagnostic.pathSources,
282
+ ],
283
+ loginShellStatus: diagnostic.loginShellStatus,
284
+ };
285
+ }
286
+ function getPathDiagnostic() {
287
+ return {
288
+ pathSegments: [...diagnostic.pathSegments],
289
+ pathSources: [...diagnostic.pathSources],
290
+ loginShellStatus: diagnostic.loginShellStatus,
291
+ };
292
+ }
293
+ /** Test-only helper to reset module state. */
294
+ function __resetPathResolverForTest() {
295
+ diagnostic = { pathSegments: [], pathSources: [], loginShellStatus: 'skipped' };
296
+ warnedLoginShell = false;
297
+ bundledRuntimesActive = false;
298
+ }