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,526 @@
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.AgentRefineManager = void 0;
7
+ exports.validateAgentBody = validateAgentBody;
8
+ exports.buildFirstTurnPrompt = buildFirstTurnPrompt;
9
+ exports.refineSessionToJson = refineSessionToJson;
10
+ const fs_1 = __importDefault(require("fs"));
11
+ const path_1 = __importDefault(require("path"));
12
+ const readline_1 = require("readline");
13
+ const crypto_1 = require("crypto");
14
+ const tree_kill_1 = __importDefault(require("tree-kill"));
15
+ const cli_prompt_1 = require("./util/cli-prompt");
16
+ const agent_generator_1 = require("./agent-generator");
17
+ const ai_invocations_1 = require("./ai-invocations");
18
+ const result_event_1 = require("./result-event");
19
+ const providers_1 = require("./providers");
20
+ const agent_refine_db_1 = require("./agent-refine-db");
21
+ const CUSTOM_PREFIX = /^custom-[a-z0-9][a-z0-9-]*$/;
22
+ const SMART_TEST_DEBOUNCE_MS = 5_000;
23
+ /**
24
+ * Manager for AI-driven iterative refinement of custom agent .md files.
25
+ *
26
+ * Mirrors ProposalManager: spawn `claude` with stream-json, capture session id
27
+ * on first turn, resume on follow-ups. Streams deltas + phase pills over WS.
28
+ */
29
+ class AgentRefineManager {
30
+ _broadcast;
31
+ _db;
32
+ _projectPath;
33
+ _projectId;
34
+ _adapter;
35
+ _activeProcesses = new Map();
36
+ _bodyBuffers = new Map();
37
+ _disposed = false;
38
+ constructor(broadcast, db, projectPath, projectId, provider) {
39
+ this._broadcast = broadcast;
40
+ this._db = db;
41
+ this._projectPath = projectPath;
42
+ this._projectId = projectId;
43
+ this._adapter = (0, providers_1.getAdapter)(provider ?? 'claude');
44
+ }
45
+ isActive(refineId) {
46
+ return this._activeProcesses.has(refineId);
47
+ }
48
+ /**
49
+ * Tear down before the project's DB is closed (M12). Marks the manager disposed
50
+ * so in-flight close/error handlers short-circuit instead of writing to a
51
+ * closed connection (which throws synchronously inside the EventEmitter and,
52
+ * with no uncaughtException handler, crashes the whole app), and SIGTERMs any
53
+ * orphaned refine child. Idempotent.
54
+ */
55
+ shutdown() {
56
+ this._disposed = true;
57
+ for (const child of this._activeProcesses.values()) {
58
+ if (child.pid) {
59
+ try {
60
+ (0, tree_kill_1.default)(child.pid, 'SIGTERM');
61
+ }
62
+ catch { /* ignore */ }
63
+ }
64
+ }
65
+ this._activeProcesses.clear();
66
+ this._bodyBuffers.clear();
67
+ }
68
+ /** Start a new refine session for the given custom agent. */
69
+ async startRefine(opts) {
70
+ if (!CUSTOM_PREFIX.test(opts.agentId)) {
71
+ throw new Error('not_a_custom_agent');
72
+ }
73
+ const file = this._agentFile(opts.agentId);
74
+ if (!fs_1.default.existsSync(file)) {
75
+ throw new Error('agent_not_found');
76
+ }
77
+ const body = fs_1.default.readFileSync(file, 'utf8');
78
+ const baseHash = sha256(body);
79
+ const baseVersion = this._currentVersion(opts.agentId);
80
+ const refineId = (0, crypto_1.randomUUID)();
81
+ (0, agent_refine_db_1.createRefineSession)(this._db, {
82
+ id: refineId,
83
+ agentId: opts.agentId,
84
+ baseVersion,
85
+ baseBodyHash: baseHash,
86
+ autoTest: opts.autoTest !== false,
87
+ });
88
+ // Seed history with the user's instruction so reconnects show full thread.
89
+ this._appendHistory(refineId, { role: 'user', content: opts.instruction, timestamp: Date.now() });
90
+ void this._runTurn(refineId, opts.instruction, /* isFirst */ true, body);
91
+ return { refineId };
92
+ }
93
+ /** Send a follow-up instruction on an existing session. */
94
+ async sendTurn(opts) {
95
+ const session = (0, agent_refine_db_1.getRefineSession)(this._db, opts.refineId);
96
+ if (!session)
97
+ throw new Error('session_not_found');
98
+ if (session.status === 'streaming')
99
+ throw new Error('turn_in_progress');
100
+ if (!session.session_id)
101
+ throw new Error('no_session_id');
102
+ this._appendHistory(opts.refineId, { role: 'user', content: opts.instruction, timestamp: Date.now() });
103
+ void this._runTurn(opts.refineId, opts.instruction, /* isFirst */ false, null);
104
+ }
105
+ /** Cancel an in-flight session. Idempotent. */
106
+ cancel(refineId) {
107
+ const child = this._activeProcesses.get(refineId);
108
+ if (child?.pid) {
109
+ try {
110
+ (0, tree_kill_1.default)(child.pid, 'SIGTERM');
111
+ }
112
+ catch { /* ignore */ }
113
+ }
114
+ const existing = (0, agent_refine_db_1.getRefineSession)(this._db, refineId);
115
+ if (existing) {
116
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { status: 'cancelled', phase: 'idle' });
117
+ }
118
+ this._broadcast({
119
+ type: 'agent_refine_cancelled',
120
+ projectId: '',
121
+ refineId,
122
+ timestamp: new Date().toISOString(),
123
+ });
124
+ }
125
+ /** Toggle auto-test for a session. */
126
+ toggleAutoTest(refineId, enabled) {
127
+ const session = (0, agent_refine_db_1.getRefineSession)(this._db, refineId);
128
+ if (!session)
129
+ throw new Error('session_not_found');
130
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { auto_test: enabled ? 1 : 0 });
131
+ }
132
+ /** Apply the current draft_body to disk through the standard write path. */
133
+ apply(opts) {
134
+ const session = (0, agent_refine_db_1.getRefineSession)(this._db, opts.refineId);
135
+ if (!session)
136
+ return { ok: false, reason: 'session_not_found' };
137
+ if (!session.draft_body)
138
+ return { ok: false, reason: 'invalid_state' };
139
+ const file = this._agentFile(session.agent_id);
140
+ if (!fs_1.default.existsSync(file))
141
+ return { ok: false, reason: 'agent_not_found' };
142
+ const currentBody = fs_1.default.readFileSync(file, 'utf8');
143
+ if (!opts.force && sha256(currentBody) !== session.base_body_hash) {
144
+ return { ok: false, reason: 'disk_changed' };
145
+ }
146
+ const draftName = extractFrontmatterName(session.draft_body);
147
+ const currentName = extractFrontmatterName(currentBody) ?? session.agent_id;
148
+ if (draftName && draftName !== currentName) {
149
+ return { ok: false, reason: 'name_changed' };
150
+ }
151
+ fs_1.default.writeFileSync(file, session.draft_body, 'utf8');
152
+ const maxVersion = this._db
153
+ .prepare(`SELECT COALESCE(MAX(version), 0) AS v FROM agent_versions WHERE agent_name = ?`)
154
+ .get(session.agent_id).v;
155
+ const nextVersion = maxVersion + 1;
156
+ this._db.prepare(`INSERT INTO agent_versions (agent_name, version, body, created_at) VALUES (?, ?, ?, ?)`).run(session.agent_id, nextVersion, session.draft_body, Date.now());
157
+ (0, agent_refine_db_1.updateRefineSession)(this._db, opts.refineId, { status: 'applied', phase: 'done' });
158
+ this._broadcast({
159
+ type: 'agent_refine_applied',
160
+ projectId: '',
161
+ refineId: opts.refineId,
162
+ agentId: session.agent_id,
163
+ version: nextVersion,
164
+ timestamp: new Date().toISOString(),
165
+ });
166
+ // Also broadcast the standard catalog change event so existing UI updates.
167
+ this._broadcast({ type: 'agent.changed', projectId: '', id: session.agent_id });
168
+ return { ok: true, version: nextVersion, body: session.draft_body };
169
+ }
170
+ /** Hard-delete a session (used by cleanup/admin paths). */
171
+ destroy(refineId) {
172
+ this.cancel(refineId);
173
+ (0, agent_refine_db_1.deleteRefineSession)(this._db, refineId);
174
+ }
175
+ // ─── Private ──────────────────────────────────────────────────────────────
176
+ _agentFile(agentId) {
177
+ // Per-provider on-disk layout:
178
+ // claude → <project>/.claude/agents/<agentId>.md
179
+ // codex → <project>/.codex/skills/<agentId>/SKILL.md
180
+ // Future providers add their own branch via the adapter; the projectDir
181
+ // is already provider-aware.
182
+ if (this._adapter.id === 'codex') {
183
+ return path_1.default.join(this._projectPath, this._adapter.projectDirName, 'skills', agentId, 'SKILL.md');
184
+ }
185
+ return path_1.default.join(this._projectPath, this._adapter.projectDirName, 'agents', `${agentId}.md`);
186
+ }
187
+ _currentVersion(agentId) {
188
+ const row = this._db
189
+ .prepare(`SELECT COALESCE(MAX(version), 0) AS v FROM agent_versions WHERE agent_name = ?`)
190
+ .get(agentId);
191
+ return row.v;
192
+ }
193
+ _appendHistory(refineId, turn) {
194
+ const session = (0, agent_refine_db_1.getRefineSession)(this._db, refineId);
195
+ if (!session)
196
+ return;
197
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { history: [...session.history, turn] });
198
+ }
199
+ async _runTurn(refineId, instruction, isFirst, bodyForFirstTurn) {
200
+ const session = (0, agent_refine_db_1.getRefineSession)(this._db, refineId);
201
+ if (!session)
202
+ return;
203
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { status: 'streaming', phase: 'reading' });
204
+ this._emitPhase(refineId, 'reading');
205
+ const prompt = isFirst
206
+ ? buildFirstTurnPrompt({
207
+ agentId: session.agent_id,
208
+ currentBody: bodyForFirstTurn ?? '',
209
+ userInstruction: instruction,
210
+ })
211
+ : instruction;
212
+ const action = !isFirst && session.session_id && this._adapter.capabilities.nativeResume
213
+ ? 'chat-resume'
214
+ : 'agent-refine';
215
+ const refineModel = this._adapter.defaultModel();
216
+ const args = this._adapter.buildArgs(action, {
217
+ prompt,
218
+ model: refineModel,
219
+ sessionId: session.session_id ?? undefined,
220
+ });
221
+ let drafted = false;
222
+ const child = (0, cli_prompt_1.spawnAiCli)(this._adapter.binary, args, {
223
+ env: process.env,
224
+ stdio: ['ignore', 'pipe', 'pipe'],
225
+ cwd: this._projectPath,
226
+ });
227
+ this._activeProcesses.set(refineId, child);
228
+ this._bodyBuffers.set(refineId, '');
229
+ let capturedSessionId = null;
230
+ const adapterEvents = [];
231
+ const turnStartedAt = new Date().toISOString();
232
+ const reader = (0, readline_1.createInterface)({ input: child.stdout, crlfDelay: Infinity });
233
+ reader.on('line', (line) => {
234
+ const ev = this._adapter.parseStreamLine(line);
235
+ if (!ev)
236
+ return;
237
+ adapterEvents.push(ev);
238
+ switch (ev.kind) {
239
+ case 'session-started':
240
+ if (!capturedSessionId)
241
+ capturedSessionId = ev.sessionId;
242
+ break;
243
+ case 'result': {
244
+ const sid = ev.payload.session_id;
245
+ if (sid && !capturedSessionId)
246
+ capturedSessionId = sid;
247
+ break;
248
+ }
249
+ case 'text-delta': {
250
+ if (!drafted) {
251
+ drafted = true;
252
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { phase: 'drafting' });
253
+ this._emitPhase(refineId, 'drafting');
254
+ }
255
+ const prev = this._bodyBuffers.get(refineId) ?? '';
256
+ const next = prev + ev.text;
257
+ this._bodyBuffers.set(refineId, next);
258
+ this._broadcast({
259
+ type: 'agent_refine_stream',
260
+ projectId: '',
261
+ refineId,
262
+ delta: ev.text,
263
+ timestamp: new Date().toISOString(),
264
+ });
265
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { draft_body: next });
266
+ break;
267
+ }
268
+ case 'tool-use':
269
+ this._broadcast({
270
+ type: 'agent_refine_stream',
271
+ projectId: '',
272
+ refineId,
273
+ delta: `<!--tool:${ev.name}-->`,
274
+ timestamp: new Date().toISOString(),
275
+ });
276
+ break;
277
+ case 'other':
278
+ break;
279
+ }
280
+ });
281
+ let stderr = '';
282
+ child.stderr.on('data', (chunk) => { stderr += chunk.toString(); });
283
+ return new Promise((resolve) => {
284
+ child.on('error', (err) => {
285
+ this._activeProcesses.delete(refineId);
286
+ this._bodyBuffers.delete(refineId);
287
+ if (this._disposed) {
288
+ resolve();
289
+ return;
290
+ } // M12: project removed mid-flight; DB closing
291
+ this._emitError(refineId, `Failed to launch claude: ${err.message}`);
292
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { status: 'error', phase: 'idle' });
293
+ resolve();
294
+ });
295
+ child.on('close', (code) => {
296
+ this._activeProcesses.delete(refineId);
297
+ const fullDraft = this._bodyBuffers.get(refineId) ?? '';
298
+ this._bodyBuffers.delete(refineId);
299
+ if (this._disposed) {
300
+ resolve();
301
+ return;
302
+ } // M12: project removed mid-flight; DB closing
303
+ // ai_invocations capture (surface='ai-edit'). One row per refine turn.
304
+ if (this._projectId) {
305
+ try {
306
+ const invStatus = code === 0 && fullDraft.trim() ? 'success' : 'failed';
307
+ const { result: normalised, estimated } = (0, result_event_1.finaliseInvocationResult)(this._adapter, adapterEvents, { fallbackModel: refineModel });
308
+ (0, ai_invocations_1.recordInvocation)(this._db, {
309
+ id: (0, crypto_1.randomUUID)(),
310
+ project_id: this._projectId,
311
+ provider: this._adapter.id,
312
+ surface: 'ai-edit',
313
+ surface_ref_id: refineId,
314
+ status: invStatus,
315
+ started_at: turnStartedAt,
316
+ finished_at: new Date().toISOString(),
317
+ total_cost_usd_estimated: estimated,
318
+ ...normalised,
319
+ });
320
+ this._broadcast({ type: 'spending.invalidated', projectId: this._projectId });
321
+ }
322
+ catch (err) {
323
+ console.error('[agent-refine-manager] recordInvocation failed:', err);
324
+ }
325
+ }
326
+ if (code !== 0 || !fullDraft.trim()) {
327
+ this._emitError(refineId, code !== 0
328
+ ? `claude exited with code ${code}${stderr ? `: ${stderr.slice(-300)}` : ''}`
329
+ : 'claude returned empty output');
330
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { status: 'error', phase: 'idle' });
331
+ resolve();
332
+ return;
333
+ }
334
+ // Validation phase.
335
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { phase: 'validating' });
336
+ this._emitPhase(refineId, 'validating');
337
+ const stripped = stripToolMarkers(fullDraft);
338
+ const validation = validateAgentBody(stripped, this._adapter.id);
339
+ if (!validation.ok) {
340
+ this._emitError(refineId, `Frontmatter invalid: ${validation.error}`);
341
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { status: 'error', phase: 'idle', draft_body: stripped });
342
+ resolve();
343
+ return;
344
+ }
345
+ // Append assistant turn to history (use stripped body — markers gone).
346
+ this._appendHistory(refineId, {
347
+ role: 'assistant',
348
+ content: stripped,
349
+ timestamp: Date.now(),
350
+ });
351
+ const patch = {
352
+ status: 'ready',
353
+ phase: 'done',
354
+ draft_body: stripped,
355
+ ...(capturedSessionId ? { session_id: capturedSessionId } : {}),
356
+ };
357
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, patch);
358
+ this._broadcast({
359
+ type: 'agent_refine_ready',
360
+ projectId: '',
361
+ refineId,
362
+ draftBody: stripped,
363
+ timestamp: new Date().toISOString(),
364
+ });
365
+ this._emitPhase(refineId, 'done');
366
+ // Smart-mode auto-test: only run if enabled, body changed since last
367
+ // test, and >5s elapsed. Best-effort; failures are non-fatal.
368
+ const session2 = (0, agent_refine_db_1.getRefineSession)(this._db, refineId);
369
+ if (session2 && session2.auto_test === 1) {
370
+ const draftHash = sha256(stripped);
371
+ const recent = session2.last_test_at !== null && Date.now() - session2.last_test_at < SMART_TEST_DEBOUNCE_MS;
372
+ const sameBody = session2.last_test_hash === draftHash;
373
+ if (!recent && !sameBody) {
374
+ void this._runAutoTest(refineId, session2.agent_id, stripped, draftHash);
375
+ }
376
+ }
377
+ resolve();
378
+ });
379
+ });
380
+ }
381
+ async _runAutoTest(refineId, agentId, draftBody, draftHash) {
382
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { phase: 'testing' });
383
+ this._emitPhase(refineId, 'testing');
384
+ const sampleTask = pickSampleTask(this._db, agentId);
385
+ try {
386
+ const result = await (0, agent_generator_1.testCustomAgent)(this._projectPath, { draftBody, sampleTask });
387
+ this._db.prepare(`INSERT INTO agent_tests (agent_name, draft_hash, sample_task_id, tokens, duration_ms, output, created_at)
388
+ VALUES (?, ?, ?, ?, ?, ?, ?)`).run(agentId, result.draftHash, null, result.tokens, result.durationMs, result.output, Date.now());
389
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, {
390
+ last_test_at: Date.now(),
391
+ last_test_hash: draftHash,
392
+ phase: 'done',
393
+ });
394
+ this._appendHistory(refineId, {
395
+ role: 'system',
396
+ kind: 'test_result',
397
+ content: result.output,
398
+ timestamp: Date.now(),
399
+ });
400
+ this._broadcast({
401
+ type: 'agent_refine_test',
402
+ projectId: '',
403
+ refineId,
404
+ result: { output: result.output, tokens: result.tokens, durationMs: result.durationMs },
405
+ timestamp: new Date().toISOString(),
406
+ });
407
+ }
408
+ catch (err) {
409
+ this._emitError(refineId, `Auto-test failed: ${err.message}`);
410
+ (0, agent_refine_db_1.updateRefineSession)(this._db, refineId, { phase: 'done' });
411
+ }
412
+ }
413
+ _emitPhase(refineId, phase) {
414
+ this._broadcast({
415
+ type: 'agent_refine_phase',
416
+ projectId: '',
417
+ refineId,
418
+ phase,
419
+ timestamp: new Date().toISOString(),
420
+ });
421
+ }
422
+ _emitError(refineId, error) {
423
+ this._broadcast({
424
+ type: 'agent_refine_error',
425
+ projectId: '',
426
+ refineId,
427
+ error,
428
+ timestamp: new Date().toISOString(),
429
+ });
430
+ }
431
+ }
432
+ exports.AgentRefineManager = AgentRefineManager;
433
+ // ─── Helpers ───────────────────────────────────────────────────────────────
434
+ function sha256(s) {
435
+ return (0, crypto_1.createHash)('sha256').update(s).digest('hex');
436
+ }
437
+ function stripToolMarkers(s) {
438
+ return s.replace(/<!--tool:[^>]+-->/g, '').trim();
439
+ }
440
+ function extractFrontmatterName(body) {
441
+ const fm = body.match(/^---\r?\n([\s\S]*?)\r?\n---/);
442
+ if (!fm)
443
+ return null;
444
+ const m = fm[1].match(/^name:\s*(\S+)/m);
445
+ return m ? m[1].trim() : null;
446
+ }
447
+ function validateAgentBody(body, providerId = 'claude') {
448
+ const trimmed = body.trim();
449
+ if (!trimmed.startsWith('---'))
450
+ return { ok: false, error: 'missing YAML frontmatter' };
451
+ const fm = trimmed.match(/^---\r?\n([\s\S]*?)\r?\n---/);
452
+ if (!fm)
453
+ return { ok: false, error: 'unterminated YAML frontmatter' };
454
+ const block = fm[1];
455
+ if (!/^name:\s*\S+/m.test(block))
456
+ return { ok: false, error: 'frontmatter must include `name:`' };
457
+ if (!/^description:/m.test(block))
458
+ return { ok: false, error: 'frontmatter must include `description:`' };
459
+ // Per-provider model field rules:
460
+ // - claude: `.claude/agents/sr-*.md` frontmatter requires `model:` from
461
+ // the short alias set (sonnet/opus/haiku) for the Task tool to resolve.
462
+ // - codex: SKILL.md format has no `model:` field — model is decided at
463
+ // spawn time via `--model`. Skip the model check entirely.
464
+ if (providerId === 'claude' && !/^model:\s*(sonnet|opus|haiku)/m.test(block)) {
465
+ return { ok: false, error: 'frontmatter `model:` must be sonnet|opus|haiku' };
466
+ }
467
+ return { ok: true };
468
+ }
469
+ function buildFirstTurnPrompt(opts) {
470
+ return [
471
+ 'You are refining an existing custom agent. The user wants to iterate on its',
472
+ 'definition. Output the COMPLETE refined `.md` file — full YAML frontmatter',
473
+ 'between `---` separators, then the body. Do not include code fences,',
474
+ 'commentary, or explanations. Start at `---`.',
475
+ '',
476
+ 'Hard rules:',
477
+ ' 1. Frontmatter MUST include `name`, `description`, and `model` (one of',
478
+ ' `sonnet`, `opus`, `haiku`).',
479
+ ` 2. The frontmatter \`name\` MUST remain exactly: ${opts.agentId}`,
480
+ ' 3. The id `name` is locked; renaming is a separate explicit action.',
481
+ '',
482
+ `Agent id: ${opts.agentId}`,
483
+ '',
484
+ 'Current agent file:',
485
+ '```markdown',
486
+ opts.currentBody,
487
+ '```',
488
+ '',
489
+ `User refinement request:`,
490
+ opts.userInstruction,
491
+ '',
492
+ 'Output only the new file content, starting with `---`.',
493
+ ].join('\n');
494
+ }
495
+ function pickSampleTask(db, agentId) {
496
+ try {
497
+ const row = db
498
+ .prepare(`SELECT output FROM agent_tests
499
+ WHERE agent_name = ? AND sample_task_id IS NOT NULL
500
+ ORDER BY created_at DESC LIMIT 1`)
501
+ .get(agentId);
502
+ if (row?.output)
503
+ return row.output;
504
+ }
505
+ catch { /* ignore */ }
506
+ return DEFAULT_SAMPLE_TASK;
507
+ }
508
+ const DEFAULT_SAMPLE_TASK = [
509
+ 'Demonstrate how you would handle a small representative task within your',
510
+ 'declared focus areas. Keep the answer under 150 words.',
511
+ ].join(' ');
512
+ /** Build a public, JSON-friendly view of a session for the GET /refine/:id endpoint. */
513
+ function refineSessionToJson(row) {
514
+ return {
515
+ id: row.id,
516
+ agentId: row.agent_id,
517
+ status: row.status,
518
+ phase: row.phase,
519
+ autoTest: row.auto_test === 1,
520
+ draftBody: row.draft_body,
521
+ history: row.history,
522
+ baseVersion: row.base_version,
523
+ createdAt: row.created_at,
524
+ updatedAt: row.updated_at,
525
+ };
526
+ }
@@ -0,0 +1,111 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.InvalidSurfaceError = void 0;
4
+ exports.recordInvocation = recordInvocation;
5
+ exports.updateTicketIdForConversation = updateTicketIdForConversation;
6
+ exports.listInvocationsForConversation = listInvocationsForConversation;
7
+ exports.getTicketSpendingSummary = getTicketSpendingSummary;
8
+ exports.getInvocationsByProvider = getInvocationsByProvider;
9
+ const ALLOWED_SURFACES = new Set([
10
+ 'job',
11
+ 'quick-spec',
12
+ 'explore-spec',
13
+ 'ai-edit',
14
+ 'smash',
15
+ 'file-summary',
16
+ ]);
17
+ class InvalidSurfaceError extends Error {
18
+ surface;
19
+ constructor(surface) {
20
+ super(`Invalid surface: ${surface}`);
21
+ this.surface = surface;
22
+ this.name = 'InvalidSurfaceError';
23
+ }
24
+ }
25
+ exports.InvalidSurfaceError = InvalidSurfaceError;
26
+ function recordInvocation(db, input) {
27
+ if (!ALLOWED_SURFACES.has(input.surface)) {
28
+ throw new InvalidSurfaceError(input.surface);
29
+ }
30
+ if (!input.provider) {
31
+ throw new Error('recordInvocation: provider is required');
32
+ }
33
+ db.prepare(`
34
+ INSERT INTO ai_invocations (
35
+ id, project_id, provider, surface, surface_ref_id, ticket_id, conversation_id,
36
+ model, status, started_at, finished_at, duration_ms, duration_api_ms,
37
+ tokens_in, tokens_out, tokens_cache_read, tokens_cache_create,
38
+ total_cost_usd, total_cost_usd_estimated, num_turns, session_id
39
+ ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)
40
+ `).run(input.id, input.project_id, input.provider, input.surface, input.surface_ref_id ?? null, input.ticket_id ?? null, input.conversation_id ?? null, input.model ?? null, input.status, input.started_at, input.finished_at ?? null, input.duration_ms ?? null, input.duration_api_ms ?? null, input.tokens_in ?? null, input.tokens_out ?? null, input.tokens_cache_read ?? null, input.tokens_cache_create ?? null, input.total_cost_usd ?? null, input.total_cost_usd_estimated ? 1 : 0, input.num_turns ?? null, input.session_id ?? null);
41
+ }
42
+ function updateTicketIdForConversation(db, conversationId, ticketId) {
43
+ const result = db.prepare(`UPDATE ai_invocations SET ticket_id = ? WHERE conversation_id = ? AND ticket_id IS NULL`).run(ticketId, conversationId);
44
+ return result.changes;
45
+ }
46
+ function listInvocationsForConversation(db, conversationId) {
47
+ return db.prepare(`SELECT * FROM ai_invocations WHERE conversation_id = ? ORDER BY started_at ASC`).all(conversationId);
48
+ }
49
+ function getTicketSpendingSummary(db, ticketId) {
50
+ const rows = db.prepare(`SELECT surface, status, total_cost_usd, num_turns, duration_ms,
51
+ tokens_in, tokens_out, tokens_cache_read, tokens_cache_create
52
+ FROM ai_invocations WHERE ticket_id = ?`).all(ticketId);
53
+ const bySurface = {
54
+ job: { count: 0, costUsd: 0 },
55
+ 'quick-spec': { count: 0, costUsd: 0 },
56
+ 'explore-spec': { count: 0, costUsd: 0 },
57
+ 'ai-edit': { count: 0, costUsd: 0 },
58
+ smash: { count: 0, costUsd: 0 },
59
+ 'file-summary': { count: 0, costUsd: 0 },
60
+ };
61
+ let totalCostUsd = 0;
62
+ let totalTokens = 0;
63
+ let totalTurns = 0;
64
+ let activeDurationMs = 0;
65
+ for (const r of rows) {
66
+ bySurface[r.surface].count += 1;
67
+ bySurface[r.surface].costUsd += r.total_cost_usd ?? 0;
68
+ totalCostUsd += r.total_cost_usd ?? 0;
69
+ // Real total tokens = fresh input + output + cache-read + cache-create.
70
+ totalTokens +=
71
+ (r.tokens_in ?? 0) +
72
+ (r.tokens_out ?? 0) +
73
+ (r.tokens_cache_read ?? 0) +
74
+ (r.tokens_cache_create ?? 0);
75
+ totalTurns += r.num_turns ?? 0;
76
+ activeDurationMs += r.duration_ms ?? 0;
77
+ }
78
+ return { totalCostUsd, totalTokens, totalTurns, activeDurationMs, bySurface, totalRuns: rows.length };
79
+ }
80
+ /**
81
+ * Per-provider aggregation for the Analytics dashboard. Returns counts +
82
+ * authoritative cost (rows with total_cost_usd_estimated=0) and estimated
83
+ * cost (rows with total_cost_usd_estimated=1) split, so the UI can render the
84
+ * ~ badge and the "Includes estimated costs" footnote accurately.
85
+ *
86
+ * Spec: openspec/.../specs/project-spending/spec.md ("byProvider analytics breakdown")
87
+ */
88
+ function getInvocationsByProvider(db, projectId, opts = {}) {
89
+ const params = [projectId];
90
+ let dateClause = '';
91
+ if (opts.fromIso) {
92
+ dateClause += ' AND started_at >= ?';
93
+ params.push(opts.fromIso);
94
+ }
95
+ if (opts.toIso) {
96
+ dateClause += ' AND started_at < ?';
97
+ params.push(opts.toIso);
98
+ }
99
+ const rows = db.prepare(`
100
+ SELECT
101
+ COALESCE(provider, 'claude') AS provider,
102
+ COUNT(*) AS count,
103
+ COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 0 THEN total_cost_usd ELSE 0 END), 0) AS costUsd,
104
+ COALESCE(SUM(CASE WHEN total_cost_usd_estimated = 1 THEN total_cost_usd ELSE 0 END), 0) AS estimatedCostUsd
105
+ FROM ai_invocations
106
+ WHERE project_id = ?${dateClause}
107
+ GROUP BY provider
108
+ ORDER BY (costUsd + estimatedCostUsd) DESC
109
+ `).all(...params);
110
+ return rows;
111
+ }