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,382 @@
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.resolveHeadSha = resolveHeadSha;
7
+ exports.listUntracked = listUntracked;
8
+ exports.snapshotWorkingTree = snapshotWorkingTree;
9
+ exports.diffAgainstSnapshot = diffAgainstSnapshot;
10
+ exports.collectDiffPatches = collectDiffPatches;
11
+ exports.recordProvenanceForJob = recordProvenanceForJob;
12
+ exports.getProvenanceDiff = getProvenanceDiff;
13
+ exports.listProvenanceByTicket = listProvenanceByTicket;
14
+ exports.listProvenanceByPath = listProvenanceByPath;
15
+ exports.broadcastProvenanceUpdated = broadcastProvenanceUpdated;
16
+ const child_process_1 = require("child_process");
17
+ const fs_1 = __importDefault(require("fs"));
18
+ const path_1 = __importDefault(require("path"));
19
+ const MAX_PATCH_BYTES = 512 * 1024;
20
+ // These git calls run synchronously on the main event loop (pre-spawn snapshot
21
+ // and post-exit diff). Bound every one: a timeout so a stuck index.lock /
22
+ // filesystem stall / credential prompt can't freeze the whole app, a maxBuffer
23
+ // cap, and an env that disables any interactive prompt. The existing try/catch
24
+ // in each function degrades a timeout to empty provenance. Mirrors metrics.ts.
25
+ const GIT_TIMEOUT_MS = 15_000;
26
+ const GIT_MAX_BUFFER = 16 * 1024 * 1024;
27
+ // Bound on how many per-file patches we collect after a job. Each is a synchronous
28
+ // git spawn on the event loop, so a job touching hundreds of files would otherwise
29
+ // block the whole app. Provenance ROWS are recorded for every path regardless; only
30
+ // the on-demand diff patches beyond this cap are skipped (the UI shows "diff
31
+ // unavailable" for them). Mirrors the existing large-job warn threshold (50).
32
+ const MAX_PATCH_FILES = 50;
33
+ const GIT_EXEC_ENV = (() => {
34
+ // Inherit the parent env but STRIP git-location vars. If the app process (or a
35
+ // parent) ever exports GIT_DIR / GIT_WORK_TREE / GIT_INDEX_FILE, every cwd-scoped
36
+ // git call below would silently operate on that repo instead of the project —
37
+ // corrupting provenance. Always pin git to the cwd we pass.
38
+ const env = { ...process.env };
39
+ delete env.GIT_DIR;
40
+ delete env.GIT_WORK_TREE;
41
+ delete env.GIT_INDEX_FILE;
42
+ delete env.GIT_COMMON_DIR;
43
+ delete env.GIT_OBJECT_DIRECTORY;
44
+ env.GIT_TERMINAL_PROMPT = '0';
45
+ env.GIT_ASKPASS = 'echo';
46
+ env.GCM_INTERACTIVE = 'never';
47
+ // M2: these git calls run INSIDE the project repo (cwd = project.path) for every
48
+ // queued job, and git honors the repo's own .git/config. A hostile repo added as
49
+ // a project can ship `[core] fsmonitor = <script>` (or a hook) that git executes
50
+ // during index refresh (stash create / diff / status) → RCE on job spawn. Strip
51
+ // system config and override the hook-bearing keys for ALL invocations via
52
+ // GIT_CONFIG_PARAMETERS (same precedence as `-c`, so it wins over the repo's
53
+ // local config). Disabling fsmonitor only costs a perf hint; provenance reads
54
+ // never need hooks.
55
+ env.GIT_CONFIG_NOSYSTEM = '1';
56
+ env.GIT_CONFIG_PARAMETERS = "'core.fsmonitor=false' 'core.hooksPath=/dev/null' 'protocol.ext.allow=user'";
57
+ return env;
58
+ })();
59
+ /** Resolve the current HEAD commit SHA. Best-effort: '' on any git failure
60
+ * (no repo, unborn HEAD, no git, timeout). */
61
+ function resolveHeadSha(cwd) {
62
+ try {
63
+ const out = (0, child_process_1.execSync)('git rev-parse HEAD', {
64
+ cwd,
65
+ encoding: 'utf8',
66
+ stdio: ['ignore', 'pipe', 'pipe'],
67
+ timeout: GIT_TIMEOUT_MS,
68
+ maxBuffer: GIT_MAX_BUFFER,
69
+ env: GIT_EXEC_ENV,
70
+ });
71
+ return out.trim();
72
+ }
73
+ catch {
74
+ return '';
75
+ }
76
+ }
77
+ /** List untracked, non-ignored paths in the working tree. Best-effort: any git
78
+ * failure (no git, no repo, timeout) degrades to []. */
79
+ function listUntracked(cwd) {
80
+ try {
81
+ const out = (0, child_process_1.execSync)('git ls-files --others --exclude-standard -z', {
82
+ cwd,
83
+ encoding: 'utf8',
84
+ stdio: ['ignore', 'pipe', 'pipe'],
85
+ timeout: GIT_TIMEOUT_MS,
86
+ maxBuffer: GIT_MAX_BUFFER,
87
+ env: GIT_EXEC_ENV,
88
+ });
89
+ return out.split('\0').filter((p) => p.length > 0);
90
+ }
91
+ catch {
92
+ return [];
93
+ }
94
+ }
95
+ function snapshotWorkingTree(cwd) {
96
+ let ref = '';
97
+ try {
98
+ const out = (0, child_process_1.execSync)('git stash create --include-untracked', {
99
+ cwd,
100
+ encoding: 'utf8',
101
+ stdio: ['ignore', 'pipe', 'pipe'],
102
+ timeout: GIT_TIMEOUT_MS,
103
+ maxBuffer: GIT_MAX_BUFFER,
104
+ env: GIT_EXEC_ENV,
105
+ });
106
+ ref = out.trim();
107
+ }
108
+ catch (err) {
109
+ const msg = err.message ?? '';
110
+ if (/ENOENT|not found|command not found/i.test(msg)) {
111
+ throw err;
112
+ }
113
+ ref = '';
114
+ }
115
+ // Capture the untracked set NOW so the post-job diff can tell rail-created
116
+ // files apart from files that were already untracked before the job ran. Also
117
+ // freeze the HEAD SHA so a job that commits from a clean tree is still diffed
118
+ // against its true starting point (not the post-commit HEAD).
119
+ return { ref, untracked: listUntracked(cwd), headSha: resolveHeadSha(cwd) };
120
+ }
121
+ function diffAgainstSnapshot(cwd, snapshotRef, untrackedBefore, baseSha) {
122
+ const hasSnap = snapshotRef && snapshotRef.length > 0;
123
+ // When there is no stash ref (clean tree at snapshot time), prefer the frozen
124
+ // pre-job HEAD SHA over the literal 'HEAD'. A job that commits its output
125
+ // advances HEAD, so `git diff HEAD` at exit would report nothing — the frozen
126
+ // base recovers the real created/modified/deleted set.
127
+ const ref = hasSnap ? snapshotRef : (baseSha && baseSha.length > 0 ? baseSha : 'HEAD');
128
+ let out = '';
129
+ try {
130
+ // --find-renames so rename detection is deterministic regardless of the
131
+ // user's global `diff.renames` config (matches collectDiffPatches).
132
+ out = (0, child_process_1.execSync)(`git diff --name-status --find-renames -z ${ref} --`, {
133
+ cwd,
134
+ encoding: 'utf8',
135
+ stdio: ['ignore', 'pipe', 'pipe'],
136
+ timeout: GIT_TIMEOUT_MS,
137
+ maxBuffer: GIT_MAX_BUFFER,
138
+ env: GIT_EXEC_ENV,
139
+ });
140
+ }
141
+ catch {
142
+ out = '';
143
+ }
144
+ const entries = [];
145
+ const seen = new Set();
146
+ if (out) {
147
+ const tokens = out.split('\0').filter((t) => t.length > 0);
148
+ let i = 0;
149
+ while (i < tokens.length) {
150
+ const raw = tokens[i];
151
+ const code = raw[0];
152
+ if (code === 'R' || code === 'C') {
153
+ // Rename/copy: `<status>\0<old>\0<new>\0`.
154
+ const oldPath = tokens[i + 1];
155
+ const newPath = tokens[i + 2];
156
+ if (oldPath !== undefined && newPath !== undefined && !seen.has(newPath)) {
157
+ entries.push(code === 'R'
158
+ ? { path: newPath, status: 'R', renamedFrom: oldPath }
159
+ : { path: newPath, status: 'A' });
160
+ seen.add(newPath);
161
+ }
162
+ i += 3;
163
+ continue;
164
+ }
165
+ if (code === 'A' || code === 'M' || code === 'D') {
166
+ const p = tokens[i + 1];
167
+ if (p !== undefined && !seen.has(p)) {
168
+ entries.push({ path: p, status: code });
169
+ seen.add(p);
170
+ }
171
+ i += 2;
172
+ continue;
173
+ }
174
+ if (code === 'T') {
175
+ // Typechange (file⇄symlink, regular⇄submodule). Record as modified.
176
+ const p = tokens[i + 1];
177
+ if (p !== undefined && !seen.has(p)) {
178
+ entries.push({ path: p, status: 'M' });
179
+ seen.add(p);
180
+ }
181
+ i += 2;
182
+ continue;
183
+ }
184
+ // Unknown single-letter status: `<status>\0<path>\0`. Consume the pair so
185
+ // the path token is never re-read as a status (which would corrupt the
186
+ // rest of the stream).
187
+ i += 2;
188
+ }
189
+ }
190
+ // `git diff <ref>` only reports TRACKED-file deltas — it never lists untracked
191
+ // files. New files a rail creates are untracked, so without this pass they are
192
+ // silently lost whenever the tree was dirty at snapshot time (the common case).
193
+ // Always surface currently-untracked paths, minus those already untracked at
194
+ // snapshot time (which the rail did not create), as 'A' (created).
195
+ const before = new Set(untrackedBefore ?? []);
196
+ for (const p of listUntracked(cwd)) {
197
+ if (!seen.has(p) && !before.has(p)) {
198
+ entries.push({ path: p, status: 'A' });
199
+ seen.add(p);
200
+ }
201
+ }
202
+ return entries;
203
+ }
204
+ function truncatePatch(patch) {
205
+ const bytes = Buffer.byteLength(patch, 'utf8');
206
+ if (bytes <= MAX_PATCH_BYTES)
207
+ return { patch, truncated: false };
208
+ return {
209
+ patch: `${patch.slice(0, MAX_PATCH_BYTES)}\n[specrails-desktop] diff truncated at ${MAX_PATCH_BYTES} bytes\n`,
210
+ truncated: true,
211
+ };
212
+ }
213
+ function addedFilePatch(cwd, relPath) {
214
+ const abs = path_1.default.resolve(cwd, relPath);
215
+ const root = cwd.endsWith(path_1.default.sep) ? cwd : `${cwd}${path_1.default.sep}`;
216
+ if (abs !== cwd && !abs.startsWith(root))
217
+ return '';
218
+ let content = '';
219
+ try {
220
+ const stat = fs_1.default.statSync(abs);
221
+ if (!stat.isFile() || stat.size > MAX_PATCH_BYTES)
222
+ return '';
223
+ content = fs_1.default.readFileSync(abs, 'utf8');
224
+ }
225
+ catch {
226
+ return '';
227
+ }
228
+ const noTrailingNewline = content.length > 0 && !content.endsWith('\n');
229
+ const lines = content.split('\n');
230
+ if (lines.length > 0 && lines[lines.length - 1] === '')
231
+ lines.pop();
232
+ const body = lines.map((line) => `+${line}`);
233
+ // Mirror git's own unified-diff output for a file with no terminating newline.
234
+ if (noTrailingNewline)
235
+ body.push('\');
236
+ return [
237
+ `diff --git a/${relPath} b/${relPath}`,
238
+ 'new file mode 100644',
239
+ 'index 0000000..0000000',
240
+ '--- /dev/null',
241
+ `+++ b/${relPath}`,
242
+ `@@ -0,0 +1,${lines.length} @@`,
243
+ ...body,
244
+ '',
245
+ ].join('\n');
246
+ }
247
+ function collectDiffPatches(cwd, snapshotRef, diff, baseSha) {
248
+ const patches = new Map();
249
+ if (diff.length === 0)
250
+ return patches;
251
+ // Same frozen-base fallback as diffAgainstSnapshot: a clean-tree snapshot has
252
+ // no stash ref, so use the pre-job HEAD SHA to capture patches for committed
253
+ // work instead of diffing against the (advanced) live HEAD.
254
+ const ref = snapshotRef && snapshotRef.length > 0
255
+ ? snapshotRef
256
+ : (baseSha && baseSha.length > 0 ? baseSha : 'HEAD');
257
+ // Cap the number of per-file git spawns: each runs synchronously on the event
258
+ // loop. Beyond the cap, provenance rows are still recorded (by the caller) but
259
+ // patches are skipped — the UI renders "diff unavailable" for them.
260
+ const capped = diff.slice(0, MAX_PATCH_FILES);
261
+ for (const entry of capped) {
262
+ // For a rename, scope the diff to BOTH paths so git can pair them and emit a
263
+ // proper `rename from`/`rename to` patch instead of a delete + 100%-add.
264
+ const pathspec = entry.status === 'R' && entry.renamedFrom !== undefined
265
+ ? [entry.renamedFrom, entry.path]
266
+ : [entry.path];
267
+ let patch = '';
268
+ try {
269
+ patch = (0, child_process_1.execFileSync)('git', ['diff', '--no-ext-diff', '--find-renames', '--unified=80', ref, '--', ...pathspec], {
270
+ cwd,
271
+ encoding: 'utf8',
272
+ stdio: ['ignore', 'pipe', 'pipe'],
273
+ maxBuffer: MAX_PATCH_BYTES + 64 * 1024,
274
+ timeout: GIT_TIMEOUT_MS,
275
+ env: GIT_EXEC_ENV,
276
+ });
277
+ }
278
+ catch (err) {
279
+ patch = (err.stdout ?? '').toString();
280
+ }
281
+ if (!patch && entry.status === 'A')
282
+ patch = addedFilePatch(cwd, entry.path);
283
+ if (patch)
284
+ patches.set(entry.path, truncatePatch(patch));
285
+ }
286
+ return patches;
287
+ }
288
+ function recordProvenanceForJob(db, projectId, jobId, ticketId, diff, atMs = Date.now(), patches) {
289
+ void projectId;
290
+ if (diff.length === 0)
291
+ return [];
292
+ const pending = [];
293
+ for (const entry of diff) {
294
+ if (entry.status === 'A') {
295
+ pending.push({ file_path: entry.path, kind: 'created' });
296
+ }
297
+ else if (entry.status === 'M') {
298
+ pending.push({ file_path: entry.path, kind: 'modified' });
299
+ }
300
+ else if (entry.status === 'D') {
301
+ pending.push({ file_path: entry.path, kind: 'deleted' });
302
+ }
303
+ else if (entry.status === 'R') {
304
+ // rename = two rows because tree row tracking needs both the new path (modified) and old path (deleted)
305
+ pending.push({ file_path: entry.path, kind: 'modified' });
306
+ if (entry.renamedFrom !== undefined) {
307
+ pending.push({ file_path: entry.renamedFrom, kind: 'deleted' });
308
+ }
309
+ }
310
+ }
311
+ const insert = db.prepare(`
312
+ INSERT INTO file_provenance (file_path, ticket_id, job_id, kind, at)
313
+ VALUES (?, ?, ?, ?, ?)
314
+ `);
315
+ let insertPatch = null;
316
+ try {
317
+ insertPatch = db.prepare(`
318
+ INSERT OR REPLACE INTO file_provenance_diffs (provenance_id, patch, truncated)
319
+ VALUES (?, ?, ?)
320
+ `);
321
+ }
322
+ catch {
323
+ insertPatch = null;
324
+ }
325
+ const inserted = [];
326
+ const tx = db.transaction((rows) => {
327
+ for (const r of rows) {
328
+ const result = insert.run(r.file_path, ticketId, jobId, r.kind, atMs);
329
+ inserted.push({
330
+ id: Number(result.lastInsertRowid),
331
+ file_path: r.file_path,
332
+ ticket_id: ticketId,
333
+ job_id: jobId,
334
+ kind: r.kind,
335
+ at: atMs,
336
+ });
337
+ const storedPatch = patches?.get(r.file_path);
338
+ if (insertPatch && storedPatch) {
339
+ insertPatch.run(Number(result.lastInsertRowid), storedPatch.patch, storedPatch.truncated ? 1 : 0);
340
+ }
341
+ }
342
+ });
343
+ tx(pending);
344
+ return inserted;
345
+ }
346
+ function getProvenanceDiff(db, projectId, jobId, filePath) {
347
+ void projectId;
348
+ try {
349
+ const row = db.prepare(`SELECT d.patch, d.truncated
350
+ FROM file_provenance p
351
+ JOIN file_provenance_diffs d ON d.provenance_id = p.id
352
+ WHERE p.job_id = ? AND p.file_path = ?
353
+ ORDER BY p.at DESC, p.id DESC
354
+ LIMIT 1`).get(jobId, filePath);
355
+ return row ? { patch: row.patch, truncated: row.truncated === 1 } : null;
356
+ }
357
+ catch {
358
+ return null;
359
+ }
360
+ }
361
+ function listProvenanceByTicket(db, projectId, ticketId) {
362
+ void projectId;
363
+ return db.prepare(`SELECT id, file_path, ticket_id, job_id, kind, at
364
+ FROM file_provenance WHERE ticket_id = ? ORDER BY at DESC`).all(ticketId);
365
+ }
366
+ function listProvenanceByPath(db, projectId, filePath) {
367
+ void projectId;
368
+ return db.prepare(`SELECT id, file_path, ticket_id, job_id, kind, at
369
+ FROM file_provenance WHERE file_path = ? ORDER BY at DESC`).all(filePath);
370
+ }
371
+ function broadcastProvenanceUpdated(broadcast, projectId, row) {
372
+ const msg = {
373
+ type: 'file.provenance_updated',
374
+ projectId,
375
+ path: row.file_path,
376
+ kind: row.kind,
377
+ ticketId: row.ticket_id,
378
+ jobId: row.job_id,
379
+ at: row.at,
380
+ };
381
+ broadcast(msg);
382
+ }
@@ -0,0 +1,221 @@
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.buildSystemPrompt = buildSystemPrompt;
7
+ exports.createFileSummaryGenerator = createFileSummaryGenerator;
8
+ const readline_1 = require("readline");
9
+ const tree_kill_1 = __importDefault(require("tree-kill"));
10
+ const cli_prompt_1 = require("./util/cli-prompt");
11
+ const result_event_1 = require("./result-event");
12
+ const GENERATE_TIMEOUT_MS = 60_000;
13
+ const SYSTEM_PROMPT_EN = 'You are explaining code to a non-developer. Output 2 to 4 sentences in plain language about what the file does. ' +
14
+ 'No code, no jargon, no bullet lists. Output only the explanation, nothing else.';
15
+ const SYSTEM_PROMPT_ES = 'Estás explicando código a una persona no desarrolladora. Escribe entre 2 y 4 frases en lenguaje llano sobre qué hace el archivo. ' +
16
+ 'Sin código, sin jerga, sin listas. Devuelve solo la explicación, nada más.';
17
+ function buildSystemPrompt(language) {
18
+ return language === 'es' ? SYSTEM_PROMPT_ES : SYSTEM_PROMPT_EN;
19
+ }
20
+ /** Compose the single user-message body that goes to the model. The provider
21
+ * adapter decides whether the system prompt rides along via a flag or gets
22
+ * folded into this string (see `adapter.capabilities.systemPromptArg`). */
23
+ function buildUserPrompt(input, adapter) {
24
+ const body = `${input.relPath}\n${input.contents}`;
25
+ if (adapter.capabilities.systemPromptArg)
26
+ return body;
27
+ // Provider does not accept a system-prompt flag; fold the instruction inline.
28
+ return `${buildSystemPrompt(input.language)}\n\n${body}`;
29
+ }
30
+ /** Cheapest model per provider for summary generation. Codex MUST run
31
+ * `gpt-5.4-mini` (product decision: file summaries are non-critical and the
32
+ * mini tier is the right cost target). Claude uses `haiku`. The per-provider
33
+ * env overrides exist for ops escape hatches; the generic
34
+ * `SPECRAILS_FILE_SUMMARY_MODEL` is honoured only when no provider-specific
35
+ * override is set. */
36
+ function defaultModelFor(adapter) {
37
+ if (adapter.id === 'claude') {
38
+ return process.env.SPECRAILS_FILE_SUMMARY_MODEL_CLAUDE
39
+ ?? process.env.SPECRAILS_FILE_SUMMARY_MODEL
40
+ ?? 'haiku';
41
+ }
42
+ if (adapter.id === 'codex') {
43
+ return process.env.SPECRAILS_FILE_SUMMARY_MODEL_CODEX ?? 'gpt-5.4-mini';
44
+ }
45
+ return process.env.SPECRAILS_FILE_SUMMARY_MODEL ?? adapter.defaultModel();
46
+ }
47
+ function createFileSummaryGenerator(opts) {
48
+ const adapter = opts.adapter;
49
+ const model = opts.model ?? defaultModelFor(adapter);
50
+ const timeoutMs = opts.timeoutMs ?? GENERATE_TIMEOUT_MS;
51
+ const spawn = opts.spawn ?? cli_prompt_1.spawnAiCli;
52
+ return async function generate(input, signal) {
53
+ const startedAt = Date.now();
54
+ if (signal?.aborted)
55
+ throw new Error('file-summary generator aborted before start');
56
+ const args = adapter.buildArgs('spec-gen', {
57
+ prompt: buildUserPrompt(input, adapter),
58
+ systemPrompt: adapter.capabilities.systemPromptArg ? buildSystemPrompt(input.language) : undefined,
59
+ model,
60
+ maxTurns: 1,
61
+ });
62
+ const child = spawn(adapter.binary, args, {
63
+ env: process.env,
64
+ stdio: ['ignore', 'pipe', 'pipe'],
65
+ cwd: opts.cwd,
66
+ });
67
+ return await new Promise((resolve, reject) => {
68
+ const events = [];
69
+ let fullText = '';
70
+ let stderrBuf = '';
71
+ let settled = false;
72
+ // Best-effort partial usage so a timeout/abort that killed the child AFTER
73
+ // the provider billed tokens still reports real spend (the manager stamps
74
+ // it onto the failed ai_invocations row instead of $0).
75
+ const buildPartial = () => {
76
+ if (events.length === 0)
77
+ return undefined;
78
+ try {
79
+ const { result, estimated } = (0, result_event_1.finaliseInvocationResult)(adapter, events, { fallbackModel: model });
80
+ return {
81
+ model: result.model ?? model,
82
+ provider: adapter.id,
83
+ costUsd: result.total_cost_usd ?? 0,
84
+ costEstimated: estimated,
85
+ tokensIn: result.tokens_in ?? 0,
86
+ tokensOut: result.tokens_out ?? 0,
87
+ tokensCacheRead: result.tokens_cache_read,
88
+ tokensCacheCreate: result.tokens_cache_create,
89
+ durationMs: result.duration_ms ?? (Date.now() - startedAt),
90
+ };
91
+ }
92
+ catch {
93
+ return undefined;
94
+ }
95
+ };
96
+ const rejectWithPartial = (message) => {
97
+ const err = new Error(message);
98
+ const partial = buildPartial();
99
+ if (partial)
100
+ err.partial = partial;
101
+ reject(err);
102
+ };
103
+ let killGrace = null;
104
+ const killTree = () => {
105
+ const pid = child.pid;
106
+ if (pid) {
107
+ try {
108
+ (0, tree_kill_1.default)(pid, 'SIGTERM');
109
+ }
110
+ catch { /* best effort */ }
111
+ killGrace = setTimeout(() => {
112
+ try {
113
+ (0, tree_kill_1.default)(pid, 'SIGKILL', () => { });
114
+ }
115
+ catch { /* best effort */ }
116
+ }, 2000);
117
+ if (typeof killGrace.unref === 'function')
118
+ killGrace.unref();
119
+ }
120
+ else {
121
+ try {
122
+ child.kill('SIGTERM');
123
+ }
124
+ catch { /* best effort */ }
125
+ }
126
+ };
127
+ const onAbort = () => {
128
+ if (settled)
129
+ return;
130
+ settled = true;
131
+ // treeKill (not child.kill) so the whole process tree dies — on Windows
132
+ // the CLI is wrapped in cmd.exe; on POSIX the CLI may have grandchildren.
133
+ killTree();
134
+ rejectWithPartial('file-summary generator aborted');
135
+ };
136
+ if (signal)
137
+ signal.addEventListener('abort', onAbort, { once: true });
138
+ const timer = setTimeout(() => {
139
+ if (settled)
140
+ return;
141
+ settled = true;
142
+ killTree();
143
+ rejectWithPartial(`file-summary generator timeout after ${timeoutMs}ms`);
144
+ }, timeoutMs);
145
+ if (child.stderr) {
146
+ child.stderr.on('data', (chunk) => {
147
+ stderrBuf += typeof chunk === 'string' ? chunk : chunk.toString('utf-8');
148
+ if (stderrBuf.length > 8192)
149
+ stderrBuf = stderrBuf.slice(-8192);
150
+ });
151
+ }
152
+ if (!child.stdout) {
153
+ clearTimeout(timer);
154
+ if (signal)
155
+ signal.removeEventListener('abort', onAbort);
156
+ reject(new Error('file-summary generator: child has no stdout'));
157
+ return;
158
+ }
159
+ const reader = (0, readline_1.createInterface)({ input: child.stdout, crlfDelay: Infinity });
160
+ reader.on('line', (line) => {
161
+ const ev = adapter.parseStreamLine(line);
162
+ if (!ev)
163
+ return;
164
+ events.push(ev);
165
+ if (ev.kind === 'text-delta')
166
+ fullText += ev.text;
167
+ });
168
+ child.on('error', (err) => {
169
+ clearTimeout(timer);
170
+ if (signal)
171
+ signal.removeEventListener('abort', onAbort);
172
+ if (killGrace) {
173
+ clearTimeout(killGrace);
174
+ killGrace = null;
175
+ }
176
+ if (settled)
177
+ return;
178
+ settled = true;
179
+ reject(err);
180
+ });
181
+ child.on('close', (code) => {
182
+ clearTimeout(timer);
183
+ if (signal)
184
+ signal.removeEventListener('abort', onAbort);
185
+ // A child that exits after a timeout-triggered SIGTERM clears the
186
+ // escalation so no stray SIGKILL lands on a recycled pid.
187
+ if (killGrace) {
188
+ clearTimeout(killGrace);
189
+ killGrace = null;
190
+ }
191
+ if (settled)
192
+ return;
193
+ settled = true;
194
+ if (code !== 0) {
195
+ const tail = stderrBuf.slice(-500);
196
+ reject(new Error(`${adapter.binary} exit code=${code}; ${tail ? `stderr=${tail}` : 'no stderr'}`));
197
+ return;
198
+ }
199
+ const summary = fullText.trim();
200
+ if (!summary) {
201
+ reject(new Error(`${adapter.binary} returned empty summary text`));
202
+ return;
203
+ }
204
+ const { result, estimated } = (0, result_event_1.finaliseInvocationResult)(adapter, events, { fallbackModel: model });
205
+ const durationMs = result.duration_ms ?? (Date.now() - startedAt);
206
+ resolve({
207
+ summary,
208
+ model: result.model ?? model,
209
+ provider: adapter.id,
210
+ costUsd: result.total_cost_usd ?? 0,
211
+ costEstimated: estimated,
212
+ tokensIn: result.tokens_in ?? 0,
213
+ tokensOut: result.tokens_out ?? 0,
214
+ tokensCacheRead: result.tokens_cache_read,
215
+ tokensCacheCreate: result.tokens_cache_create,
216
+ durationMs,
217
+ });
218
+ });
219
+ });
220
+ };
221
+ }