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,179 @@
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.getClaudeApprovalState = getClaudeApprovalState;
7
+ exports.findEnabledMarketplaceKeys = findEnabledMarketplaceKeys;
8
+ exports.findInstalledMarketplaceKeys = findInstalledMarketplaceKeys;
9
+ exports.findInstalledButNotEnabledMarketplaceKeys = findInstalledButNotEnabledMarketplaceKeys;
10
+ exports.disableMarketplacePlugin = disableMarketplacePlugin;
11
+ const fs_1 = __importDefault(require("fs"));
12
+ const os_1 = __importDefault(require("os"));
13
+ const path_1 = __importDefault(require("path"));
14
+ /**
15
+ * Returns the approval state for `<projectPath>` × `<serverName>`. The state
16
+ * is sourced from EITHER:
17
+ *
18
+ * 1. `~/.claude.json` → projects[<path>].{enabled,disabled}McpjsonServers —
19
+ * the per-project approval set when the user accepts (or denies) the
20
+ * `.mcp.json` prompt the first time Claude opens the repo.
21
+ *
22
+ * 2. `~/.claude/settings.json` → enabledPlugins["<serverName>@*"] — Claude
23
+ * Code's plugin-marketplace mechanism. When a user installs an MCP via
24
+ * the marketplace, Serena (or similar) is available in EVERY project
25
+ * regardless of `.mcp.json`. The card should reflect that the tool is
26
+ * loaded, not that our app-managed `.mcp.json` entry is dormant.
27
+ *
28
+ * Resolution order:
29
+ * - explicit disable in (1) → `disabled`
30
+ * - explicit enable in (1) OR (2) → `enabled`
31
+ * - otherwise → `pending`
32
+ *
33
+ * Defensive: any I/O / parse error falls back to 'pending'. Never throws.
34
+ */
35
+ function getClaudeApprovalState(projectPath, serverName) {
36
+ // (1) Per-project mcpjson approval.
37
+ // Order:
38
+ // - explicit disabled list → disabled
39
+ // - explicit enabled list → enabled
40
+ // - trusted project → enabled (Claude auto-loads .mcp.json
41
+ // without prompting once trust is granted)
42
+ // - none of the above → pending (first prompt not yet shown)
43
+ let mcpjsonState = 'pending';
44
+ try {
45
+ const configPath = path_1.default.join(os_1.default.homedir(), '.claude.json');
46
+ if (fs_1.default.existsSync(configPath)) {
47
+ const parsed = JSON.parse(fs_1.default.readFileSync(configPath, 'utf8'));
48
+ const entry = parsed.projects?.[path_1.default.resolve(projectPath)];
49
+ if (entry) {
50
+ if (entry.disabledMcpjsonServers?.includes(serverName))
51
+ mcpjsonState = 'disabled';
52
+ else if (entry.enabledMcpjsonServers?.includes(serverName))
53
+ mcpjsonState = 'enabled';
54
+ else if (entry.hasTrustDialogAccepted === true)
55
+ mcpjsonState = 'enabled';
56
+ }
57
+ }
58
+ }
59
+ catch {
60
+ // ignore — falls through to marketplace check
61
+ }
62
+ // Explicit disabled wins over marketplace enable.
63
+ if (mcpjsonState === 'disabled')
64
+ return 'disabled';
65
+ // (2) Claude marketplace plugin (per-user, project-agnostic).
66
+ let marketplaceEnabled = false;
67
+ try {
68
+ const settingsPath = path_1.default.join(os_1.default.homedir(), '.claude', 'settings.json');
69
+ if (fs_1.default.existsSync(settingsPath)) {
70
+ const settings = JSON.parse(fs_1.default.readFileSync(settingsPath, 'utf8'));
71
+ const enabled = settings.enabledPlugins ?? {};
72
+ const prefix = `${serverName}@`;
73
+ for (const [key, value] of Object.entries(enabled)) {
74
+ if (value === true && key.startsWith(prefix)) {
75
+ marketplaceEnabled = true;
76
+ break;
77
+ }
78
+ }
79
+ }
80
+ }
81
+ catch {
82
+ // ignore
83
+ }
84
+ if (mcpjsonState === 'enabled' || marketplaceEnabled)
85
+ return 'enabled';
86
+ return 'pending';
87
+ }
88
+ /**
89
+ * Returns the keys (e.g., `serena@claude-plugins-official`) under
90
+ * `~/.claude/settings.json#enabledPlugins` that match `<serverName>@*` and
91
+ * are set to `true`. Empty array if none.
92
+ */
93
+ function findEnabledMarketplaceKeys(serverName) {
94
+ try {
95
+ const settingsPath = path_1.default.join(os_1.default.homedir(), '.claude', 'settings.json');
96
+ if (!fs_1.default.existsSync(settingsPath))
97
+ return [];
98
+ const settings = JSON.parse(fs_1.default.readFileSync(settingsPath, 'utf8'));
99
+ const enabled = settings.enabledPlugins ?? {};
100
+ const prefix = `${serverName}@`;
101
+ return Object.entries(enabled)
102
+ .filter(([k, v]) => v === true && k.startsWith(prefix))
103
+ .map(([k]) => k);
104
+ }
105
+ catch {
106
+ return [];
107
+ }
108
+ }
109
+ /**
110
+ * Returns the keys present in `~/.claude/plugins/installed_plugins.json`
111
+ * that match `<serverName>@*`, regardless of the `enabledPlugins` toggle.
112
+ * Used to detect plugins that are physically in Claude's cache and may be
113
+ * loaded by Claude even when `enabledPlugins[key]=false` (observed: Claude
114
+ * keeps them resolvable from the cache `.mcp.json`).
115
+ */
116
+ function findInstalledMarketplaceKeys(serverName) {
117
+ try {
118
+ const filePath = path_1.default.join(os_1.default.homedir(), '.claude', 'plugins', 'installed_plugins.json');
119
+ if (!fs_1.default.existsSync(filePath))
120
+ return [];
121
+ const parsed = JSON.parse(fs_1.default.readFileSync(filePath, 'utf8'));
122
+ const map = parsed.plugins ?? {};
123
+ const prefix = `${serverName}@`;
124
+ return Object.keys(map).filter((k) => k.startsWith(prefix));
125
+ }
126
+ catch {
127
+ return [];
128
+ }
129
+ }
130
+ /**
131
+ * Returns marketplace keys that are physically installed in Claude's plugin
132
+ * cache but NOT enabled (i.e., `enabledPlugins[key] !== true`). These are
133
+ * the ones likely to confuse users — the app disabled them but the binary +
134
+ * shipped `.mcp.json` are still on disk; Claude may still resolve the server.
135
+ */
136
+ function findInstalledButNotEnabledMarketplaceKeys(serverName) {
137
+ const installed = findInstalledMarketplaceKeys(serverName);
138
+ if (installed.length === 0)
139
+ return [];
140
+ let enabledMap = {};
141
+ try {
142
+ const settingsPath = path_1.default.join(os_1.default.homedir(), '.claude', 'settings.json');
143
+ if (fs_1.default.existsSync(settingsPath)) {
144
+ const settings = JSON.parse(fs_1.default.readFileSync(settingsPath, 'utf8'));
145
+ enabledMap = settings.enabledPlugins ?? {};
146
+ }
147
+ }
148
+ catch { /* fall through */ }
149
+ return installed.filter((k) => enabledMap[k] !== true);
150
+ }
151
+ /**
152
+ * Mutates `~/.claude/settings.json` so the named marketplace plugin is set
153
+ * to `false` (disabling it). Atomic temp+rename. Returns true on success.
154
+ *
155
+ * NOTE: this is the only place the app touches Claude's per-user config.
156
+ * Surface to the user via an explicit action (button/CLI), never silently.
157
+ */
158
+ function disableMarketplacePlugin(marketplaceKey) {
159
+ try {
160
+ const settingsPath = path_1.default.join(os_1.default.homedir(), '.claude', 'settings.json');
161
+ if (!fs_1.default.existsSync(settingsPath)) {
162
+ return { ok: false, reason: 'settings-not-found' };
163
+ }
164
+ const raw = fs_1.default.readFileSync(settingsPath, 'utf8');
165
+ const settings = JSON.parse(raw);
166
+ settings.enabledPlugins ??= {};
167
+ if (settings.enabledPlugins[marketplaceKey] === false) {
168
+ return { ok: true, reason: 'already-disabled' };
169
+ }
170
+ settings.enabledPlugins[marketplaceKey] = false;
171
+ const tmp = `${settingsPath}.${process.pid}.${Date.now()}.tmp`;
172
+ fs_1.default.writeFileSync(tmp, JSON.stringify(settings, null, 2) + '\n', 'utf8');
173
+ fs_1.default.renameSync(tmp, settingsPath);
174
+ return { ok: true };
175
+ }
176
+ catch (err) {
177
+ return { ok: false, reason: err.message };
178
+ }
179
+ }
@@ -0,0 +1,146 @@
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.getBlockContent = getBlockContent;
7
+ exports.upsertBlock = upsertBlock;
8
+ exports.removeBlock = removeBlock;
9
+ const fs_1 = __importDefault(require("fs"));
10
+ const path_1 = __importDefault(require("path"));
11
+ const json_mutation_1 = require("./json-mutation");
12
+ /**
13
+ * Plugins contribute named sections to the project's top-level instructions
14
+ * file (`CLAUDE.md` for claude projects, `AGENTS.md` for codex projects, and
15
+ * the adapter-declared filename for future providers) so the agent's global
16
+ * context includes per-plugin usage hints (e.g. "prefer Serena tools over
17
+ * raw Read/Grep when locating symbols"). Each plugin owns one named block
18
+ * delimited by HTML-comment markers; multiple plugins coexist without
19
+ * stomping each other.
20
+ *
21
+ * <!-- specrails-desktop-managed:<plugin>:start -->
22
+ * ...content...
23
+ * <!-- specrails-desktop-managed:<plugin>:end -->
24
+ *
25
+ * Operations are surgical, atomic (temp+rename), and serialized via the
26
+ * shared in-process file mutex.
27
+ *
28
+ * The `filename` parameter on every function defaults to `'CLAUDE.md'` so
29
+ * existing callsites compile unchanged during the multi-provider migration.
30
+ * Callers that know the resolved provider pass `adapter.instructionsFilename`
31
+ * explicitly.
32
+ */
33
+ function startMarker(pluginName) {
34
+ return `<!-- specrails-desktop-managed:${pluginName}:start -->`;
35
+ }
36
+ function endMarker(pluginName) {
37
+ return `<!-- specrails-desktop-managed:${pluginName}:end -->`;
38
+ }
39
+ // Legacy marker compat — blocks written by pre-rebrand "Specrails Hub"
40
+ // installs used the `specrails-hub-managed` namespace. We still locate (and
41
+ // therefore replace/remove) those blocks so existing user files never end up
42
+ // with orphaned managed sections. New writes always use the new markers.
43
+ function legacyStartMarker(pluginName) {
44
+ return `<!-- specrails-hub-managed:${pluginName}:start -->`;
45
+ }
46
+ function legacyEndMarker(pluginName) {
47
+ return `<!-- specrails-hub-managed:${pluginName}:end -->`;
48
+ }
49
+ function instructionsMdPath(projectPath, filename) {
50
+ return path_1.default.join(projectPath, filename);
51
+ }
52
+ /** Backwards-compat alias for callers that haven't been threaded the
53
+ * adapter-driven filename yet. */
54
+ function claudeMdPath(projectPath) {
55
+ return instructionsMdPath(projectPath, 'CLAUDE.md');
56
+ }
57
+ function locateBlockWithMarkers(text, start, end) {
58
+ const sIdx = text.indexOf(start);
59
+ if (sIdx < 0)
60
+ return null;
61
+ const eIdx = text.indexOf(end, sIdx + start.length);
62
+ if (eIdx < 0)
63
+ return null;
64
+ const innerStart = sIdx + start.length;
65
+ const innerEnd = eIdx;
66
+ return {
67
+ start: sIdx,
68
+ end: eIdx + end.length,
69
+ content: text.slice(innerStart, innerEnd).replace(/^\n+|\n+$/g, ''),
70
+ };
71
+ }
72
+ function locateBlock(text, pluginName) {
73
+ return (locateBlockWithMarkers(text, startMarker(pluginName), endMarker(pluginName)) ??
74
+ // Fall back to the legacy pre-rebrand markers (see legacyStartMarker).
75
+ locateBlockWithMarkers(text, legacyStartMarker(pluginName), legacyEndMarker(pluginName)));
76
+ }
77
+ /** Returns the current managed-block content for `pluginName`, or null if absent. */
78
+ function getBlockContent(projectPath, pluginName, filename = 'CLAUDE.md') {
79
+ const file = instructionsMdPath(projectPath, filename);
80
+ if (!fs_1.default.existsSync(file))
81
+ return null;
82
+ const text = fs_1.default.readFileSync(file, 'utf8');
83
+ const match = locateBlock(text, pluginName);
84
+ return match ? match.content : null;
85
+ }
86
+ /**
87
+ * Insert or replace the managed block for `pluginName`. If the instructions
88
+ * file does not exist, it is created with just the block. If it exists
89
+ * without our block, the block is appended at the end (separated by a blank
90
+ * line). The filename defaults to `CLAUDE.md` for backwards compatibility;
91
+ * codex projects pass `AGENTS.md`.
92
+ */
93
+ async function upsertBlock(projectPath, pluginName, content, filename = 'CLAUDE.md') {
94
+ const file = instructionsMdPath(projectPath, filename);
95
+ const block = `${startMarker(pluginName)}\n${content.trim()}\n${endMarker(pluginName)}`;
96
+ await (0, json_mutation_1.withFileLock)(file, async () => {
97
+ let next;
98
+ if (!fs_1.default.existsSync(file)) {
99
+ next = block + '\n';
100
+ }
101
+ else {
102
+ const cur = fs_1.default.readFileSync(file, 'utf8');
103
+ const match = locateBlock(cur, pluginName);
104
+ if (match) {
105
+ next = cur.slice(0, match.start) + block + cur.slice(match.end);
106
+ }
107
+ else {
108
+ const sep = cur.endsWith('\n\n') ? '' : cur.endsWith('\n') ? '\n' : '\n\n';
109
+ next = cur + sep + block + '\n';
110
+ }
111
+ }
112
+ (0, json_mutation_1.atomicWriteFileSync)(file, next);
113
+ });
114
+ }
115
+ /**
116
+ * Remove the managed block for `pluginName`. No-op when the instructions
117
+ * file is missing or the block is absent. Surrounding user content is
118
+ * preserved byte-identical.
119
+ *
120
+ * If removing the block leaves the file empty (the managed block was the
121
+ * only content), the file is deleted — this restores the pre-install state
122
+ * for projects that didn't have an instructions file before any plugin
123
+ * install. The filename defaults to `CLAUDE.md`.
124
+ */
125
+ async function removeBlock(projectPath, pluginName, filename = 'CLAUDE.md') {
126
+ const file = instructionsMdPath(projectPath, filename);
127
+ if (!fs_1.default.existsSync(file))
128
+ return;
129
+ await (0, json_mutation_1.withFileLock)(file, async () => {
130
+ const cur = fs_1.default.readFileSync(file, 'utf8');
131
+ const match = locateBlock(cur, pluginName);
132
+ if (!match)
133
+ return;
134
+ // Strip the block plus a single trailing newline if present, so we don't
135
+ // leave a stray blank line behind.
136
+ let next = cur.slice(0, match.start) + cur.slice(match.end);
137
+ next = next.replace(/\n{3,}$/, '\n').replace(/^\n+/, '');
138
+ if (next.trim() === '') {
139
+ fs_1.default.unlinkSync(file);
140
+ return;
141
+ }
142
+ (0, json_mutation_1.atomicWriteFileSync)(file, next);
143
+ });
144
+ }
145
+ // Suppress unused-warning for the legacy alias — kept for API ergonomics.
146
+ void claudeMdPath;
@@ -0,0 +1,108 @@
1
+ "use strict";
2
+ // Codex MCP registration helpers. Plugins on codex projects don't write
3
+ // `<project>/.mcp.json`; instead, the app invokes `codex mcp add` against
4
+ // a per-project `CODEX_HOME` so the resulting MCP registration is scoped
5
+ // to that project alone, never leaking into the user's terminal codex
6
+ // state or another managed project.
7
+ //
8
+ // Spec: openspec/changes/add-multi-provider-support/specs/plugin-system/spec.md
9
+ // - "Plugin install path is provider-aware" / "Per-provider home directory
10
+ // isolates plugin state"
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.codexHomeFor = codexHomeFor;
16
+ exports.ensureCodexHome = ensureCodexHome;
17
+ exports.codexMcpAdd = codexMcpAdd;
18
+ exports.codexMcpRemove = codexMcpRemove;
19
+ exports.codexMcpList = codexMcpList;
20
+ const child_process_1 = require("child_process");
21
+ const fs_1 = __importDefault(require("fs"));
22
+ const path_1 = __importDefault(require("path"));
23
+ const os_1 = __importDefault(require("os"));
24
+ /** Per-project CODEX_HOME root, sibling of the existing
25
+ * `~/.specrails/projects/<slug>/{telemetry,jobs,explore-cwd,...}` tree. */
26
+ function codexHomeFor(slug) {
27
+ return path_1.default.join(os_1.default.homedir(), '.specrails', 'projects', slug, 'codex-home');
28
+ }
29
+ /** Lazy-create the per-project codex home so `codex mcp add` writes its
30
+ * config there without touching the user's `~/.codex/`. */
31
+ function ensureCodexHome(slug) {
32
+ const dir = codexHomeFor(slug);
33
+ fs_1.default.mkdirSync(dir, { recursive: true });
34
+ return dir;
35
+ }
36
+ /** Run `codex mcp add <name> -- <command> <args...>` with the project's
37
+ * CODEX_HOME exported. Idempotent at the caller level — invokers should
38
+ * probe `codexMcpList` first when re-registration matters. */
39
+ function codexMcpAdd(slug, name, entry) {
40
+ const home = ensureCodexHome(slug);
41
+ const argv = ['mcp', 'add', name, '--', entry.command, ...entry.args];
42
+ const result = (0, child_process_1.spawnSync)('codex', argv, {
43
+ env: {
44
+ ...process.env,
45
+ ...(entry.env ?? {}),
46
+ CODEX_HOME: home,
47
+ },
48
+ encoding: 'utf-8',
49
+ timeout: 10_000,
50
+ });
51
+ if (result.error) {
52
+ return { ok: false, stdout: '', stderr: `${result.error.message}` };
53
+ }
54
+ return {
55
+ ok: (result.status ?? 1) === 0,
56
+ stdout: `${result.stdout ?? ''}`,
57
+ stderr: `${result.stderr ?? ''}`,
58
+ };
59
+ }
60
+ /** Run `codex mcp remove <name>` against the per-project CODEX_HOME. */
61
+ function codexMcpRemove(slug, name) {
62
+ const home = ensureCodexHome(slug);
63
+ const result = (0, child_process_1.spawnSync)('codex', ['mcp', 'remove', name], {
64
+ env: { ...process.env, CODEX_HOME: home },
65
+ encoding: 'utf-8',
66
+ timeout: 10_000,
67
+ });
68
+ if (result.error) {
69
+ return { ok: false, stdout: '', stderr: `${result.error.message}` };
70
+ }
71
+ return {
72
+ ok: (result.status ?? 1) === 0,
73
+ stdout: `${result.stdout ?? ''}`,
74
+ stderr: `${result.stderr ?? ''}`,
75
+ };
76
+ }
77
+ /** Run `codex mcp list` against the per-project CODEX_HOME and return the
78
+ * list of registered server names. Output format is `codex mcp list`'s
79
+ * plain text — best-effort line scan, since codex doesn't expose --json
80
+ * for this subcommand. */
81
+ function codexMcpList(slug) {
82
+ const home = ensureCodexHome(slug);
83
+ const result = (0, child_process_1.spawnSync)('codex', ['mcp', 'list'], {
84
+ env: { ...process.env, CODEX_HOME: home },
85
+ encoding: 'utf-8',
86
+ timeout: 10_000,
87
+ });
88
+ if (result.error || (result.status ?? 1) !== 0) {
89
+ return { ok: false, servers: [], raw: `${result.stderr ?? result.stdout ?? ''}` };
90
+ }
91
+ const raw = `${result.stdout ?? ''}`;
92
+ // Heuristic line scan: a server name appears at the start of a line, then
93
+ // whitespace, then the command. Lines starting with `#` or empty are
94
+ // ignored. Empty list also returns ok with []. We intentionally don't
95
+ // hard-fail when the format drifts — manifest-level checks downstream
96
+ // catch real misalignments.
97
+ const servers = [];
98
+ for (const line of raw.split(/\r?\n/)) {
99
+ const trimmed = line.trim();
100
+ if (!trimmed || trimmed.startsWith('#'))
101
+ continue;
102
+ const firstToken = trimmed.split(/\s+/)[0];
103
+ if (firstToken && /^[A-Za-z][A-Za-z0-9_-]*$/.test(firstToken)) {
104
+ servers.push(firstToken);
105
+ }
106
+ }
107
+ return { ok: true, servers, raw };
108
+ }
@@ -0,0 +1,72 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.SHARED_FILE_CONTRIBUTORS = void 0;
4
+ exports.applyContributors = applyContributors;
5
+ exports.revertContributors = revertContributors;
6
+ exports.contributorPaths = contributorPaths;
7
+ const claude_md_mutation_1 = require("./claude-md-mutation");
8
+ const providers_1 = require("../providers");
9
+ /** Resolve the instructions filename for a provider id, defaulting to
10
+ * `CLAUDE.md` when the id is unknown or absent. */
11
+ function instructionsFilenameFor(providerId) {
12
+ if (!providerId)
13
+ return 'CLAUDE.md';
14
+ try {
15
+ return (0, providers_1.getAdapter)(providerId).instructionsFilename;
16
+ }
17
+ catch {
18
+ return 'CLAUDE.md';
19
+ }
20
+ }
21
+ /** Provider-aware instructions-file contributor. Same block format
22
+ * (`<!-- specrails-desktop-managed:<plugin>:start/end -->`); destination
23
+ * filename is the adapter's `instructionsFilename`. */
24
+ const instructionsMdContributor = {
25
+ id: 'instructions-md',
26
+ appliesTo: (p) => typeof p.manifest.claudeMdInstructions === 'string' && p.manifest.claudeMdInstructions.trim().length > 0,
27
+ relativePaths: (_p, providerId) => [instructionsFilenameFor(providerId)],
28
+ apply: async (p, projectPath, providerId) => {
29
+ await (0, claude_md_mutation_1.upsertBlock)(projectPath, p.manifest.name, p.manifest.claudeMdInstructions, instructionsFilenameFor(providerId));
30
+ },
31
+ revert: async (p, projectPath, providerId) => {
32
+ await (0, claude_md_mutation_1.removeBlock)(projectPath, p.manifest.name, instructionsFilenameFor(providerId));
33
+ },
34
+ };
35
+ exports.SHARED_FILE_CONTRIBUTORS = [
36
+ instructionsMdContributor,
37
+ ];
38
+ /** Run `apply` for every contributor that applies to this plugin. */
39
+ async function applyContributors(plugin, projectPath, providerId) {
40
+ const touchedPaths = [];
41
+ for (const c of exports.SHARED_FILE_CONTRIBUTORS) {
42
+ if (!c.appliesTo(plugin))
43
+ continue;
44
+ await c.apply(plugin, projectPath, providerId);
45
+ for (const rel of c.relativePaths(plugin, providerId)) {
46
+ if (!touchedPaths.includes(rel))
47
+ touchedPaths.push(rel);
48
+ }
49
+ }
50
+ return touchedPaths;
51
+ }
52
+ /** Run `revert` for every contributor that applies to this plugin. */
53
+ async function revertContributors(plugin, projectPath, providerId) {
54
+ for (const c of exports.SHARED_FILE_CONTRIBUTORS) {
55
+ if (!c.appliesTo(plugin))
56
+ continue;
57
+ await c.revert(plugin, projectPath, providerId);
58
+ }
59
+ }
60
+ /** Project-relative paths every applicable contributor will touch. */
61
+ function contributorPaths(plugin, providerId) {
62
+ const out = [];
63
+ for (const c of exports.SHARED_FILE_CONTRIBUTORS) {
64
+ if (!c.appliesTo(plugin))
65
+ continue;
66
+ for (const rel of c.relativePaths(plugin, providerId)) {
67
+ if (!out.includes(rel))
68
+ out.push(rel);
69
+ }
70
+ }
71
+ return out;
72
+ }
@@ -0,0 +1,58 @@
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.detectMcpDrift = detectMcpDrift;
7
+ const fs_1 = __importDefault(require("fs"));
8
+ const paths_1 = require("./paths");
9
+ const claude_md_mutation_1 = require("./claude-md-mutation");
10
+ /**
11
+ * Returns true when the project's `.mcp.json` entry for any of the plugin's
12
+ * owned mcpServers no longer matches the bundled manifest. Used to surface
13
+ * an "Update available" affordance when upstream changes args (e.g.,
14
+ * Serena's `serena-mcp-server` → `serena start-mcp-server`).
15
+ *
16
+ * Only inspects entries the plugin owns; user-authored entries are ignored.
17
+ */
18
+ function detectMcpDrift(projectPath, plugin) {
19
+ const ownedKeys = plugin.manifest.owns.mcpServers ?? [];
20
+ if (ownedKeys.length === 0)
21
+ return false;
22
+ // The plugin tells us what its current canonical entry should look like
23
+ // via `previewInstall` is too heavy; we instead introspect via a marker:
24
+ // plugins that ship their canonical entry expose it via `expectedMcpEntry`.
25
+ // We accept Plugins without it (drift detection silently disabled).
26
+ const expected = plugin
27
+ .expectedMcpEntry?.();
28
+ if (!expected)
29
+ return false;
30
+ const file = (0, paths_1.mcpJsonPath)(projectPath);
31
+ if (!fs_1.default.existsSync(file))
32
+ return false;
33
+ let parsed;
34
+ try {
35
+ parsed = JSON.parse(fs_1.default.readFileSync(file, 'utf8'));
36
+ }
37
+ catch {
38
+ return false;
39
+ }
40
+ const servers = parsed.mcpServers ?? {};
41
+ for (const key of ownedKeys) {
42
+ const current = servers[key];
43
+ if (current === undefined)
44
+ continue;
45
+ if (JSON.stringify(current) !== JSON.stringify(expected))
46
+ return true;
47
+ }
48
+ // Shared-file contributor drift. Today only CLAUDE.md is contributed to;
49
+ // we hardcode the comparison here. If/when more shared-file contributors
50
+ // land we move this to a `compareDrift` hook on the contributor type.
51
+ if (plugin.manifest.claudeMdInstructions) {
52
+ const expectedMd = plugin.manifest.claudeMdInstructions.trim();
53
+ const actualMd = ((0, claude_md_mutation_1.getBlockContent)(projectPath, plugin.manifest.name) ?? '').trim();
54
+ if (actualMd !== expectedMd)
55
+ return true;
56
+ }
57
+ return false;
58
+ }
@@ -0,0 +1,14 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.BUNDLED_PLUGINS = void 0;
4
+ const serena_1 = require("./serena");
5
+ /**
6
+ * Bundled plugins available to every project on this app build. Adding a new
7
+ * plugin requires only:
8
+ * 1. Implementing the `Plugin` interface under `server/plugins/<name>/`.
9
+ * 2. Importing and appending it to this array.
10
+ *
11
+ * No other code in the app needs to change. PluginManager iterates this list
12
+ * dynamically; conflicts (overlapping ownership) fail fast at startup.
13
+ */
14
+ exports.BUNDLED_PLUGINS = [serena_1.serenaPlugin];