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,888 @@
1
+ "use strict";
2
+ // Real Playwright/CDP implementation of the browser-capture abstractions.
3
+ //
4
+ // This is the ONLY module that imports `playwright`. It is excluded from coverage
5
+ // (see vitest.config.ts) because every branch requires a live Chromium — the unit
6
+ // tests drive `BrowserCaptureManager` through a fake `ContextLauncher` instead.
7
+ //
8
+ // Screencast uses CDP (`Page.startScreencast`) since Playwright exposes no
9
+ // screencast API; input + screenshot + DOM use Playwright's high-level page API.
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.createPlaywrightLauncher = createPlaywrightLauncher;
12
+ const chromium_resolver_1 = require("./chromium-resolver");
13
+ const browser_network_1 = require("./browser-network");
14
+ function normalizeUrl(raw) {
15
+ const trimmed = raw.trim();
16
+ if (!trimmed)
17
+ return 'about:blank';
18
+ if (/^[a-z][a-z0-9+.-]*:\/\//i.test(trimmed) || trimmed.startsWith('about:'))
19
+ return trimmed;
20
+ return `https://${trimmed}`;
21
+ }
22
+ class PlaywrightPageHandle {
23
+ page;
24
+ // `page` and `cdp` are deliberately `any` — we don't want a hard type-level
25
+ // dependency on playwright's exported types leaking through the abstraction.
26
+ cdp = null;
27
+ screencastHandler = null;
28
+ // A dedicated, long-lived CDP session for the Network domain — kept SEPARATE
29
+ // from `cdp` (which is attached/detached around screencast) so request capture
30
+ // survives screencast toggles.
31
+ netCdp = null;
32
+ netEnabled = false;
33
+ netBuffer = new browser_network_1.NetworkRingBuffer();
34
+ constructor(page) {
35
+ this.page = page;
36
+ }
37
+ async navResult() {
38
+ let title = '';
39
+ try {
40
+ title = await this.page.title();
41
+ }
42
+ catch { /* about:blank etc */ }
43
+ return { url: this.page.url(), title };
44
+ }
45
+ async goto(url) {
46
+ try {
47
+ await this.page.goto(normalizeUrl(url), { waitUntil: 'domcontentloaded', timeout: 30_000 });
48
+ }
49
+ catch {
50
+ // A failed navigation (bad host, timeout) should not crash the session — the
51
+ // user just sees whatever the page settled on.
52
+ }
53
+ return this.navResult();
54
+ }
55
+ async goBack() {
56
+ try {
57
+ await this.page.goBack({ waitUntil: 'domcontentloaded', timeout: 30_000 });
58
+ }
59
+ catch { /* no history */ }
60
+ return this.navResult();
61
+ }
62
+ async goForward() {
63
+ try {
64
+ await this.page.goForward({ waitUntil: 'domcontentloaded', timeout: 30_000 });
65
+ }
66
+ catch { /* no history */ }
67
+ return this.navResult();
68
+ }
69
+ async reload() {
70
+ try {
71
+ await this.page.reload({ waitUntil: 'domcontentloaded', timeout: 30_000 });
72
+ }
73
+ catch { /* ignore */ }
74
+ return this.navResult();
75
+ }
76
+ currentUrl() {
77
+ return this.page.url();
78
+ }
79
+ async currentTitle() {
80
+ try {
81
+ return await this.page.title();
82
+ }
83
+ catch {
84
+ return '';
85
+ }
86
+ }
87
+ async setViewport(width, height) {
88
+ try {
89
+ await this.page.setViewportSize({ width: Math.max(1, Math.round(width)), height: Math.max(1, Math.round(height)) });
90
+ }
91
+ catch { /* ignore */ }
92
+ }
93
+ async dispatchInput(event) {
94
+ try {
95
+ if (event.type === 'mouse') {
96
+ if (event.action === 'move')
97
+ await this.page.mouse.move(event.x, event.y);
98
+ else if (event.action === 'down')
99
+ await this.page.mouse.down({ button: event.button ?? 'left', clickCount: event.clickCount ?? 1 });
100
+ else
101
+ await this.page.mouse.up({ button: event.button ?? 'left', clickCount: event.clickCount ?? 1 });
102
+ }
103
+ else if (event.type === 'wheel') {
104
+ await this.page.mouse.move(event.x, event.y);
105
+ await this.page.mouse.wheel(event.deltaX, event.deltaY);
106
+ }
107
+ else if (event.type === 'key') {
108
+ if (event.action === 'down') {
109
+ if (event.text && event.text.length >= 1 && [...event.text].length === 1) {
110
+ await this.page.keyboard.insertText(event.text);
111
+ }
112
+ else {
113
+ await this.page.keyboard.down(event.key);
114
+ }
115
+ }
116
+ else {
117
+ // Only release named (non-text) keys — text was inserted on down.
118
+ if (!event.text)
119
+ await this.page.keyboard.up(event.key);
120
+ }
121
+ }
122
+ else if (event.type === 'resize') {
123
+ await this.setViewport(event.width, event.height);
124
+ }
125
+ }
126
+ catch {
127
+ // Input on a navigating/closed page can throw; never let it bubble.
128
+ }
129
+ }
130
+ async startScreencast(onFrame) {
131
+ if (this.screencastHandler)
132
+ return;
133
+ this.screencastHandler = onFrame;
134
+ const ctx = this.page.context();
135
+ this.cdp = await ctx.newCDPSession(this.page);
136
+ this.cdp.on('Page.screencastFrame', async (evt) => {
137
+ try {
138
+ this.screencastHandler?.({
139
+ data: Buffer.from(evt.data, 'base64'),
140
+ width: evt.metadata?.deviceWidth ?? 0,
141
+ height: evt.metadata?.deviceHeight ?? 0,
142
+ });
143
+ }
144
+ finally {
145
+ try {
146
+ await this.cdp.send('Page.screencastFrameAck', { sessionId: evt.sessionId });
147
+ }
148
+ catch { /* ignore */ }
149
+ }
150
+ });
151
+ await this.cdp.send('Page.startScreencast', { format: 'jpeg', quality: 70, everyNthFrame: 1 });
152
+ }
153
+ async stopScreencast() {
154
+ this.screencastHandler = null;
155
+ if (this.cdp) {
156
+ try {
157
+ await this.cdp.send('Page.stopScreencast');
158
+ }
159
+ catch { /* ignore */ }
160
+ try {
161
+ await this.cdp.detach();
162
+ }
163
+ catch { /* ignore */ }
164
+ this.cdp = null;
165
+ }
166
+ }
167
+ async screenshotClip(rect) {
168
+ const clip = {
169
+ x: Math.max(0, Math.round(rect.x)),
170
+ y: Math.max(0, Math.round(rect.y)),
171
+ width: Math.max(1, Math.round(rect.width)),
172
+ height: Math.max(1, Math.round(rect.height)),
173
+ };
174
+ return this.page.screenshot({ clip, type: 'png' });
175
+ }
176
+ async extractDom(rect, htmlByteCap) {
177
+ // We can't pass `domExtractScript` directly to page.evaluate: under tsx/esbuild
178
+ // `keepNames` the compiled function body references a module-local `__name`
179
+ // helper that doesn't exist in the page context (→ "ReferenceError: __name is
180
+ // not defined"). Serialise the function to source and run it inside a wrapper
181
+ // that defines a no-op `__name`, so it works under both tsx (dev) and the
182
+ // esbuild sidecar bundle. Args are JSON-inlined (no external refs needed).
183
+ const arg = { rect, htmlByteCap };
184
+ const src = `(() => { const __name = (f) => f; return (${domExtractScript.toString()})(${JSON.stringify(arg)}); })()`;
185
+ const raw = (await this.page.evaluate(src));
186
+ return {
187
+ url: this.page.url(),
188
+ title: await this.currentTitle(),
189
+ viewport: raw.viewport,
190
+ rect,
191
+ html: raw.html,
192
+ htmlTruncated: raw.htmlTruncated,
193
+ css: raw.css,
194
+ cssTruncated: raw.cssTruncated,
195
+ nodes: raw.nodes,
196
+ designTokens: raw.designTokens,
197
+ capturedAt: new Date().toISOString(),
198
+ };
199
+ }
200
+ async probeElementAt(point) {
201
+ return this.runProbe({ point });
202
+ }
203
+ async navigateElement(selector, direction) {
204
+ return this.runProbe({ selector, direction });
205
+ }
206
+ async runProbe(arg) {
207
+ try {
208
+ // Serialise with the `__name` shim (same pattern as extractDom) so the inner
209
+ // const-arrow helpers survive esbuild keepNames in the page context.
210
+ const src = `(() => { const __name = (f) => f; return (${probeScript.toString()})(${JSON.stringify(arg)}); })()`;
211
+ return (await this.page.evaluate(src));
212
+ }
213
+ catch {
214
+ return null;
215
+ }
216
+ }
217
+ async enableNetwork() {
218
+ if (this.netEnabled)
219
+ return;
220
+ this.netEnabled = true;
221
+ try {
222
+ const ctx = this.page.context();
223
+ this.netCdp = await ctx.newCDPSession(this.page);
224
+ await this.netCdp.send('Network.enable', { maxResourceBufferSize: 5_000_000, maxTotalBufferSize: 10_000_000 });
225
+ this.netCdp.on('Network.requestWillBeSent', (e) => {
226
+ try {
227
+ this.netBuffer.start(e.requestId, {
228
+ method: e.request?.method ?? 'GET',
229
+ url: e.request?.url ?? '',
230
+ resourceType: e.type ?? 'Other',
231
+ startedAt: Date.now(),
232
+ requestBodyShape: e.request?.postData ? (0, browser_network_1.sketchJsonShape)(e.request.postData) : null,
233
+ });
234
+ }
235
+ catch { /* never let a network event bubble */ }
236
+ });
237
+ this.netCdp.on('Network.responseReceived', (e) => {
238
+ try {
239
+ this.netBuffer.response(e.requestId, { status: e.response?.status ?? 0, mimeType: e.response?.mimeType ?? null });
240
+ }
241
+ catch { /* ignore */ }
242
+ });
243
+ this.netCdp.on('Network.loadingFinished', (e) => {
244
+ try {
245
+ this.netBuffer.finish(e.requestId, { finishedAt: Date.now() });
246
+ // Sketch JSON response shapes only, body under a cap, fully guarded.
247
+ if (this.netBuffer.wantsBodySketch(e.requestId))
248
+ void this.sketchResponseBody(e.requestId);
249
+ }
250
+ catch { /* ignore */ }
251
+ });
252
+ this.netCdp.on('Network.loadingFailed', (e) => {
253
+ try {
254
+ this.netBuffer.fail(e.requestId, { finishedAt: Date.now(), errorText: e.errorText });
255
+ }
256
+ catch { /* ignore */ }
257
+ });
258
+ }
259
+ catch {
260
+ // Network capture is best-effort — a failure here never breaks the session.
261
+ this.netEnabled = false;
262
+ }
263
+ }
264
+ async sketchResponseBody(requestId) {
265
+ if (!this.netCdp)
266
+ return;
267
+ try {
268
+ const res = await this.netCdp.send('Network.getResponseBody', { requestId });
269
+ if (!res || res.base64Encoded)
270
+ return; // binary — skip
271
+ const body = typeof res.body === 'string' ? res.body : '';
272
+ const shape = (0, browser_network_1.sketchJsonShape)(body);
273
+ if (shape)
274
+ this.netBuffer.setResponseShape(requestId, shape);
275
+ }
276
+ catch {
277
+ // The body may already be evicted / unavailable — degrade to no shape.
278
+ }
279
+ }
280
+ recentNetwork(sinceMs) {
281
+ return this.netBuffer.recent(sinceMs);
282
+ }
283
+ async resolveAnchorSelector(point) {
284
+ try {
285
+ return await this.page.evaluate((p) => {
286
+ const el = document.elementFromPoint(p.x, p.y);
287
+ if (!el)
288
+ return null;
289
+ const esc = (s) => (window.CSS && CSS.escape ? CSS.escape(s) : s.replace(/[^a-zA-Z0-9_-]/g, '\\$&'));
290
+ const target = el;
291
+ if (target.id)
292
+ return '#' + esc(target.id);
293
+ const testid = target.getAttribute('data-testid');
294
+ if (testid)
295
+ return `[data-testid="${testid.replace(/"/g, '\\"')}"]`;
296
+ const parts = [];
297
+ let node = el;
298
+ let depth = 0;
299
+ while (node && node.nodeType === 1 && node !== document.body && depth < 6) {
300
+ const tag = node.tagName.toLowerCase();
301
+ const parent = node.parentElement;
302
+ if (!parent) {
303
+ parts.unshift(tag);
304
+ break;
305
+ }
306
+ const sameTag = Array.from(parent.children).filter((c) => c.tagName === node.tagName);
307
+ const idx = sameTag.indexOf(node) + 1;
308
+ parts.unshift(sameTag.length > 1 ? `${tag}:nth-of-type(${idx})` : tag);
309
+ node = parent;
310
+ depth++;
311
+ }
312
+ return parts.length ? parts.join(' > ') : null;
313
+ }, point);
314
+ }
315
+ catch {
316
+ return null;
317
+ }
318
+ }
319
+ async resolveAnchorRect(selector) {
320
+ try {
321
+ return await this.page.evaluate((sel) => {
322
+ const el = document.querySelector(sel);
323
+ if (!el)
324
+ return null;
325
+ // Bring it into view so a below-the-fold element at this breakpoint yields
326
+ // an on-screen rect (instant scroll → getBoundingClientRect reflects it).
327
+ try {
328
+ el.scrollIntoView({ block: 'center', inline: 'center' });
329
+ }
330
+ catch { /* ignore */ }
331
+ const b = el.getBoundingClientRect();
332
+ if (b.width <= 0 || b.height <= 0)
333
+ return null;
334
+ return { x: b.x, y: b.y, width: b.width, height: b.height };
335
+ }, selector);
336
+ }
337
+ catch {
338
+ return null;
339
+ }
340
+ }
341
+ async waitForStable() {
342
+ try {
343
+ await this.page.evaluate(() => new Promise((r) => requestAnimationFrame(() => requestAnimationFrame(() => r()))));
344
+ }
345
+ catch { /* ignore */ }
346
+ // A small extra settle for late reflow / lazy-loaded images / web fonts.
347
+ try {
348
+ await this.page.waitForTimeout?.(120);
349
+ }
350
+ catch { /* ignore */ }
351
+ }
352
+ async getSelectionText() {
353
+ try {
354
+ return await this.page.evaluate(() => window.getSelection()?.toString() ?? '');
355
+ }
356
+ catch {
357
+ return '';
358
+ }
359
+ }
360
+ async insertText(text) {
361
+ try {
362
+ await this.page.keyboard.insertText(text);
363
+ }
364
+ catch { /* ignore */ }
365
+ }
366
+ async deleteSelection() {
367
+ try {
368
+ await this.page.keyboard.press('Delete');
369
+ }
370
+ catch { /* ignore */ }
371
+ }
372
+ async close() {
373
+ await this.stopScreencast();
374
+ if (this.netCdp) {
375
+ try {
376
+ await this.netCdp.send('Network.disable');
377
+ }
378
+ catch { /* ignore */ }
379
+ try {
380
+ await this.netCdp.detach();
381
+ }
382
+ catch { /* ignore */ }
383
+ this.netCdp = null;
384
+ }
385
+ try {
386
+ await this.page.close();
387
+ }
388
+ catch { /* ignore */ }
389
+ }
390
+ }
391
+ // Serialised into the page via page.evaluate. Self-contained: no closures over
392
+ // Node scope. Returns the html + nodes; the Node side stamps url/title/time.
393
+ function domExtractScript(arg) {
394
+ const { rect, htmlByteCap } = arg;
395
+ const NODE_CAP = 60;
396
+ const CSS_CAP = 60_000;
397
+ const TEXT_CAP = 240;
398
+ const implicitRole = (el) => {
399
+ const tag = el.tagName.toLowerCase();
400
+ const map = {
401
+ a: el.getAttribute('href') ? 'link' : 'generic',
402
+ button: 'button',
403
+ nav: 'navigation',
404
+ header: 'banner',
405
+ footer: 'contentinfo',
406
+ main: 'main',
407
+ h1: 'heading', h2: 'heading', h3: 'heading', h4: 'heading', h5: 'heading', h6: 'heading',
408
+ img: 'img',
409
+ ul: 'list', ol: 'list', li: 'listitem',
410
+ table: 'table', tr: 'row', td: 'cell', th: 'columnheader',
411
+ select: 'combobox', textarea: 'textbox',
412
+ form: 'form', label: 'label', section: 'region', article: 'article',
413
+ };
414
+ if (tag === 'input') {
415
+ const t = el.type;
416
+ if (t === 'checkbox')
417
+ return 'checkbox';
418
+ if (t === 'radio')
419
+ return 'radio';
420
+ if (t === 'button' || t === 'submit')
421
+ return 'button';
422
+ return 'textbox';
423
+ }
424
+ return el.getAttribute('role') || map[tag] || null;
425
+ };
426
+ const collectAttrs = (el) => {
427
+ const out = {};
428
+ const keep = new Set(['id', 'class', 'name', 'href', 'src', 'type', 'placeholder', 'alt', 'title', 'value', 'aria-label']);
429
+ for (const a of Array.from(el.attributes)) {
430
+ if (keep.has(a.name) || a.name.startsWith('aria-') || a.name.startsWith('data-')) {
431
+ out[a.name] = a.value.slice(0, 200);
432
+ }
433
+ }
434
+ return out;
435
+ };
436
+ const STYLE_KEYS = ['display', 'position', 'color', 'backgroundColor', 'fontSize', 'fontWeight', 'fontFamily', 'padding', 'margin', 'border', 'borderRadius', 'textAlign'];
437
+ const collectStyles = (el) => {
438
+ const cs = window.getComputedStyle(el);
439
+ const out = {};
440
+ for (const k of STYLE_KEYS) {
441
+ const v = cs.getPropertyValue(k.replace(/[A-Z]/g, (m) => '-' + m.toLowerCase())) || cs[k];
442
+ if (v)
443
+ out[k] = String(v).slice(0, 120);
444
+ }
445
+ return out;
446
+ };
447
+ // ─── Design tokens: exact computed values for "clone this UI" specs ───────────
448
+ // getComputedStyle does not reliably populate the `border`/`borderRadius`/
449
+ // `padding`/`margin` shorthands, so we read the longhands and recompose. All
450
+ // helpers are `const` arrows (no inner named functions) so esbuild/tsx don't
451
+ // inject the `__name` helper that breaks page.evaluate (see extractDom).
452
+ const SIDES = ['top', 'right', 'bottom', 'left'];
453
+ const collapse4 = (vals) => {
454
+ const [t, r, b, l] = vals;
455
+ if (t === r && r === b && b === l)
456
+ return t;
457
+ if (t === b && r === l)
458
+ return `${t} ${r}`;
459
+ return vals.join(' ');
460
+ };
461
+ const tokenSetFor = (el) => {
462
+ const cs = window.getComputedStyle(el);
463
+ const g = (p) => cs.getPropertyValue(p) || '';
464
+ const out = {};
465
+ const setIf = (k, v, drop) => {
466
+ const t = String(v).trim();
467
+ if (t && !drop.includes(t))
468
+ out[k] = t.slice(0, 240);
469
+ };
470
+ setIf('color', g('color'), ['rgba(0, 0, 0, 0)']);
471
+ setIf('backgroundColor', g('background-color'), ['rgba(0, 0, 0, 0)', 'transparent']);
472
+ setIf('fontFamily', g('font-family'), []);
473
+ setIf('fontSize', g('font-size'), []);
474
+ setIf('fontWeight', g('font-weight'), []);
475
+ setIf('lineHeight', g('line-height'), ['normal']);
476
+ setIf('letterSpacing', g('letter-spacing'), ['normal']);
477
+ setIf('padding', collapse4(SIDES.map((s) => g('padding-' + s))), ['0px']);
478
+ setIf('margin', collapse4(SIDES.map((s) => g('margin-' + s))), ['0px']);
479
+ const bw = g('border-top-width');
480
+ const bsStyle = g('border-top-style');
481
+ const widthsUniform = SIDES.every((s) => g('border-' + s + '-width') === bw);
482
+ const stylesUniform = SIDES.every((s) => g('border-' + s + '-style') === bsStyle);
483
+ if (bsStyle && bsStyle !== 'none' && bw && bw !== '0px' && widthsUniform && stylesUniform) {
484
+ setIf('border', `${bw} ${bsStyle} ${g('border-top-color')}`, []);
485
+ }
486
+ const radii = ['top-left', 'top-right', 'bottom-right', 'bottom-left'].map((c) => g('border-' + c + '-radius'));
487
+ setIf('borderRadius', collapse4(radii), ['0px']);
488
+ setIf('boxShadow', g('box-shadow'), ['none']);
489
+ return out;
490
+ };
491
+ const deriveDesignTokens = (anchorEl, els) => {
492
+ const anchor = tokenSetFor(anchorEl);
493
+ const tagCount = {};
494
+ for (const el of els) {
495
+ const t = el.tagName.toLowerCase();
496
+ tagCount[t] = (tagCount[t] || 0) + 1;
497
+ }
498
+ const topTags = Object.keys(tagCount).sort((a, b) => tagCount[b] - tagCount[a]).slice(0, 8);
499
+ const byTag = {};
500
+ for (const t of topTags) {
501
+ const el = els.find((e) => e.tagName.toLowerCase() === t);
502
+ if (el)
503
+ byTag[t] = tokenSetFor(el);
504
+ }
505
+ const palette = [];
506
+ const fonts = [];
507
+ const consider = (ts) => {
508
+ for (const v of [ts.color, ts.backgroundColor]) {
509
+ if (v && !palette.includes(v) && palette.length < 12)
510
+ palette.push(v);
511
+ }
512
+ if (ts.fontFamily && !fonts.includes(ts.fontFamily) && fonts.length < 6)
513
+ fonts.push(ts.fontFamily);
514
+ };
515
+ consider(anchor);
516
+ for (const t of Object.keys(byTag))
517
+ consider(byTag[t]);
518
+ return { contractVersion: 1, anchor, byTag, palette, fonts };
519
+ };
520
+ // Sample a grid of points across the selection to discover candidate elements.
521
+ const candidates = new Set();
522
+ const cols = 5, rows = 5;
523
+ for (let i = 0; i <= cols; i++) {
524
+ for (let j = 0; j <= rows; j++) {
525
+ const px = rect.x + (rect.width * i) / cols;
526
+ const py = rect.y + (rect.height * j) / rows;
527
+ const stack = document.elementsFromPoint(px, py);
528
+ if (stack && stack.length > 0)
529
+ candidates.add(stack[0]);
530
+ }
531
+ }
532
+ // Container = smallest element whose box contains the whole selection rect.
533
+ const rectRight = rect.x + rect.width;
534
+ const rectBottom = rect.y + rect.height;
535
+ let container = document.body;
536
+ let containerArea = Infinity;
537
+ const seedSet = candidates.size > 0 ? candidates : new Set([document.body]);
538
+ for (const seed of seedSet) {
539
+ let el = seed;
540
+ while (el) {
541
+ const b = el.getBoundingClientRect();
542
+ if (b.left <= rect.x + 1 && b.top <= rect.y + 1 && b.right >= rectRight - 1 && b.bottom >= rectBottom - 1) {
543
+ const area = b.width * b.height;
544
+ if (area < containerArea) {
545
+ containerArea = area;
546
+ container = el;
547
+ }
548
+ break;
549
+ }
550
+ el = el.parentElement;
551
+ }
552
+ }
553
+ // Build node list: container + intersecting candidates (capped).
554
+ const nodeEls = [];
555
+ const pushUnique = (el) => { if (!nodeEls.includes(el) && nodeEls.length < NODE_CAP)
556
+ nodeEls.push(el); };
557
+ pushUnique(container);
558
+ for (const c of candidates)
559
+ pushUnique(c);
560
+ const nodes = nodeEls.map((el) => {
561
+ const b = el.getBoundingClientRect();
562
+ const text = (el.textContent || '').replace(/\s+/g, ' ').trim();
563
+ return {
564
+ tag: el.tagName.toLowerCase(),
565
+ role: implicitRole(el),
566
+ text: text ? text.slice(0, TEXT_CAP) : null,
567
+ rect: { x: Math.round(b.x), y: Math.round(b.y), width: Math.round(b.width), height: Math.round(b.height) },
568
+ attributes: collectAttrs(el),
569
+ styles: collectStyles(el),
570
+ };
571
+ });
572
+ // Pretty-print the container subtree (scripts/styles/svg dropped) with one
573
+ // element per line, indented by depth — readable in the panel AND clearer for
574
+ // the AI than a single-line outerHTML. Element-with-only-text collapses to one
575
+ // line; long attribute values (data: URIs etc.) are truncated.
576
+ let html = '';
577
+ let htmlTruncated = false;
578
+ try {
579
+ const VOID = new Set(['area', 'base', 'br', 'col', 'embed', 'hr', 'img', 'input', 'link', 'meta', 'param', 'source', 'track', 'wbr']);
580
+ const SKIP = new Set(['script', 'style', 'noscript', 'svg']);
581
+ const ATTR_CAP = 200;
582
+ const escText = (s) => s.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
583
+ // Escape < and > inside attribute values too so the client HTML tokenizer can
584
+ // reliably split tags on '>' (a raw '>' in an attr value would break it).
585
+ const escAttr = (s) => s.replace(/&/g, '&amp;').replace(/"/g, '&quot;').replace(/</g, '&lt;').replace(/>/g, '&gt;');
586
+ const lines = [];
587
+ const openTag = (el) => {
588
+ const attrs = Array.from(el.attributes).map((a) => {
589
+ let v = a.value;
590
+ if (v.length > ATTR_CAP)
591
+ v = v.slice(0, ATTR_CAP) + '…';
592
+ return ` ${a.name}="${escAttr(v)}"`;
593
+ }).join('');
594
+ return `<${el.tagName.toLowerCase()}${attrs}>`;
595
+ };
596
+ const serialize = (node, depth) => {
597
+ const pad = ' '.repeat(depth);
598
+ if (node.nodeType === 3) {
599
+ const t = (node.textContent || '').replace(/\s+/g, ' ').trim();
600
+ if (t)
601
+ lines.push(pad + escText(t));
602
+ return;
603
+ }
604
+ if (node.nodeType !== 1)
605
+ return;
606
+ const el = node;
607
+ const tag = el.tagName.toLowerCase();
608
+ if (SKIP.has(tag))
609
+ return;
610
+ if (VOID.has(tag)) {
611
+ lines.push(pad + openTag(el));
612
+ return;
613
+ }
614
+ const kids = Array.from(el.childNodes).filter((c) => c.nodeType === 1 || (c.nodeType === 3 && !!(c.textContent || '').trim()));
615
+ if (kids.length === 0) {
616
+ lines.push(`${pad}${openTag(el)}</${tag}>`);
617
+ return;
618
+ }
619
+ if (kids.length === 1 && kids[0].nodeType === 3) {
620
+ const t = escText((el.textContent || '').replace(/\s+/g, ' ').trim());
621
+ lines.push(`${pad}${openTag(el)}${t}</${tag}>`);
622
+ return;
623
+ }
624
+ lines.push(pad + openTag(el));
625
+ for (const c of kids)
626
+ serialize(c, depth + 1);
627
+ lines.push(`${pad}</${tag}>`);
628
+ };
629
+ serialize(container, 0);
630
+ html = lines.join('\n');
631
+ if (html.length > htmlByteCap) {
632
+ html = html.slice(0, htmlByteCap);
633
+ // Trim back to the last complete tag so we never emit a half-written tag.
634
+ const lastGt = html.lastIndexOf('>');
635
+ if (lastGt > 0)
636
+ html = html.slice(0, lastGt + 1);
637
+ htmlTruncated = true;
638
+ }
639
+ }
640
+ catch {
641
+ html = '';
642
+ }
643
+ // Collect the CSS rules that actually apply to the captured elements (plus
644
+ // :root / html custom-property declarations for design tokens), so the AI can
645
+ // replicate the styling instead of guessing. Same-origin stylesheets only —
646
+ // cross-origin .cssRules access throws and is skipped. @media rules whose inner
647
+ // rules match are kept whole. Capped.
648
+ let css = '';
649
+ let cssTruncated = false;
650
+ try {
651
+ const targets = [container, ...nodeEls];
652
+ const seen = new Set();
653
+ const out = [];
654
+ // Bound work on rule-heavy sites (matches() per target per rule).
655
+ let budget = 12000;
656
+ const selCache = new Map();
657
+ const matchesAny = (selector) => {
658
+ for (const el of targets) {
659
+ try {
660
+ if (el.matches(selector))
661
+ return true;
662
+ }
663
+ catch { /* invalid selector */ }
664
+ }
665
+ return false;
666
+ };
667
+ // Memoise by selector text so repeated selectors don't re-run matches().
668
+ const considerStyleRule = (r) => {
669
+ const sel = r.selectorText;
670
+ if (!sel)
671
+ return null;
672
+ let ok = selCache.get(sel);
673
+ if (ok === undefined) {
674
+ if (budget <= 0)
675
+ return null;
676
+ budget--;
677
+ const isToken = /:root|(^|,)\s*html\b|(^|,)\s*\*(\s|,|$)/.test(sel);
678
+ ok = isToken || matchesAny(sel);
679
+ selCache.set(sel, ok);
680
+ }
681
+ return ok ? r.cssText : null;
682
+ };
683
+ // The @-prefix for a conditional grouping rule (media/supports/container/layer),
684
+ // feature-detected so we don't hard-reference constructors missing from older
685
+ // lib typings or runtimes.
686
+ const groupingPrefix = (rule) => {
687
+ const r = rule;
688
+ const ctorName = rule.constructor?.name;
689
+ if (ctorName === 'CSSMediaRule')
690
+ return `@media ${r.conditionText ?? ''}`;
691
+ if (ctorName === 'CSSSupportsRule')
692
+ return `@supports ${r.conditionText ?? ''}`;
693
+ if (ctorName === 'CSSContainerRule')
694
+ return `@container ${r.conditionText ?? ''}`;
695
+ if (ctorName === 'CSSLayerBlockRule')
696
+ return `@layer ${r.name ?? ''}`;
697
+ return null;
698
+ };
699
+ const walk = (rules) => {
700
+ for (const rule of Array.from(rules)) {
701
+ if (rule instanceof CSSStyleRule) {
702
+ const t = considerStyleRule(rule);
703
+ if (t && !seen.has(t)) {
704
+ seen.add(t);
705
+ out.push(t);
706
+ }
707
+ continue;
708
+ }
709
+ const inner = rule.cssRules;
710
+ const prefix = groupingPrefix(rule);
711
+ if (prefix && inner) {
712
+ const innerMatched = [];
713
+ for (const sub of Array.from(inner)) {
714
+ if (sub instanceof CSSStyleRule) {
715
+ const t = considerStyleRule(sub);
716
+ if (t)
717
+ innerMatched.push(t);
718
+ }
719
+ }
720
+ if (innerMatched.length > 0) {
721
+ const block = `${prefix.trim()} {\n ${innerMatched.join('\n ')}\n}`;
722
+ if (!seen.has(block)) {
723
+ seen.add(block);
724
+ out.push(block);
725
+ }
726
+ }
727
+ }
728
+ }
729
+ };
730
+ for (const sheet of Array.from(document.styleSheets)) {
731
+ let rules = null;
732
+ try {
733
+ rules = sheet.cssRules;
734
+ }
735
+ catch {
736
+ rules = null;
737
+ } // cross-origin — skipped
738
+ if (rules)
739
+ walk(rules);
740
+ }
741
+ css = out.join('\n');
742
+ if (css.length > CSS_CAP) {
743
+ css = css.slice(0, CSS_CAP);
744
+ cssTruncated = true;
745
+ }
746
+ }
747
+ catch {
748
+ css = '';
749
+ }
750
+ let designTokens;
751
+ try {
752
+ designTokens = deriveDesignTokens(container, nodeEls);
753
+ }
754
+ catch {
755
+ designTokens = undefined;
756
+ }
757
+ return {
758
+ viewport: { width: window.innerWidth, height: window.innerHeight },
759
+ html,
760
+ htmlTruncated,
761
+ css,
762
+ cssTruncated,
763
+ nodes,
764
+ designTokens,
765
+ };
766
+ }
767
+ // Serialised into the page via page.evaluate (with a `__name` shim). Resolves an
768
+ // element by point or by selector (+optional parent/child step) and returns its
769
+ // rect, a stable-ish selector, and the ancestor breadcrumb root→element.
770
+ function probeScript(arg) {
771
+ const { point, selector, direction } = arg;
772
+ const SKIP = new Set(['SCRIPT', 'STYLE', 'NOSCRIPT']);
773
+ let el = null;
774
+ if (point) {
775
+ el = document.elementFromPoint(point.x, point.y);
776
+ }
777
+ else if (selector) {
778
+ const base = document.querySelector(selector);
779
+ if (base) {
780
+ if (direction === 'parent')
781
+ el = base.parentElement;
782
+ else if (direction === 'child')
783
+ el = Array.from(base.children).find((c) => !SKIP.has(c.tagName)) ?? null;
784
+ else
785
+ el = base;
786
+ }
787
+ }
788
+ if (el === document.documentElement)
789
+ el = document.body;
790
+ if (!el || el.nodeType !== 1)
791
+ return null;
792
+ const cssEsc = (s) => (window.CSS && CSS.escape ? CSS.escape(s) : s.replace(/[^a-zA-Z0-9_-]/g, '\\$&'));
793
+ const partFor = (node) => {
794
+ const tag = node.tagName.toLowerCase();
795
+ const id = node.id;
796
+ if (id)
797
+ return '#' + cssEsc(id);
798
+ const parent = node.parentElement;
799
+ if (!parent)
800
+ return tag;
801
+ const sameTag = Array.from(parent.children).filter((c) => c.tagName === node.tagName);
802
+ return sameTag.length > 1 ? `${tag}:nth-of-type(${sameTag.indexOf(node) + 1})` : tag;
803
+ };
804
+ const labelFor = (node) => {
805
+ const tag = node.tagName.toLowerCase();
806
+ const id = node.id;
807
+ if (id)
808
+ return `${tag}#${id}`;
809
+ const cn = node.getAttribute('class');
810
+ const first = cn ? cn.trim().split(/\s+/)[0] : '';
811
+ return first ? `${tag}.${first}` : tag;
812
+ };
813
+ const chain = [];
814
+ let node = el;
815
+ while (node && node.nodeType === 1 && node !== document.documentElement) {
816
+ chain.unshift(node);
817
+ node = node.parentElement;
818
+ }
819
+ const capped = new Set(chain.slice(Math.max(0, chain.length - 8)));
820
+ const path = [];
821
+ let sel = '';
822
+ for (const n of chain) {
823
+ const part = partFor(n);
824
+ sel = part.charAt(0) === '#' ? part : sel ? `${sel} > ${part}` : part;
825
+ if (capped.has(n))
826
+ path.push({ label: labelFor(n), selector: sel });
827
+ }
828
+ const b = el.getBoundingClientRect();
829
+ return {
830
+ rect: { x: b.x, y: b.y, width: b.width, height: b.height },
831
+ tag: el.tagName.toLowerCase(),
832
+ selector: sel,
833
+ path,
834
+ };
835
+ }
836
+ class PlaywrightContextHandle {
837
+ context;
838
+ // A persistent context opens with one blank page. Consume it for the FIRST
839
+ // session only; every later session gets its own fresh page. Reusing pages[0]
840
+ // for every session made concurrent sessions (e.g. React StrictMode's
841
+ // mount→unmount→mount double-create) share one page — killing the throwaway
842
+ // first session then closed the page out from under the live second session.
843
+ usedInitial = false;
844
+ constructor(context) {
845
+ this.context = context;
846
+ }
847
+ async newPage() {
848
+ let page;
849
+ if (!this.usedInitial) {
850
+ this.usedInitial = true;
851
+ const pages = this.context.pages();
852
+ page = pages.length > 0 ? pages[0] : await this.context.newPage();
853
+ }
854
+ else {
855
+ page = await this.context.newPage();
856
+ }
857
+ return new PlaywrightPageHandle(page);
858
+ }
859
+ async close() {
860
+ try {
861
+ await this.context.close();
862
+ }
863
+ catch { /* ignore */ }
864
+ }
865
+ }
866
+ /**
867
+ * Build the real Playwright-backed launcher. Lazy-imports playwright so the
868
+ * dependency is only loaded when the feature is actually used.
869
+ */
870
+ function createPlaywrightLauncher() {
871
+ return async (opts) => {
872
+ // Use CommonJS require (NOT dynamic import()): in the packaged pkg sidecar the
873
+ // native-addon banner redirects require('playwright') to the externally-copied
874
+ // package via _Module._load. A dynamic import() goes through Node's ESM resolver
875
+ // instead, which can't find 'playwright' inside the /snapshot pkg vfs
876
+ // ("Cannot find package 'playwright'"). require keeps it on the patched path.
877
+ // eslint-disable-next-line @typescript-eslint/no-require-imports
878
+ const { chromium } = require('playwright');
879
+ const executablePath = opts.executablePath ?? (await (0, chromium_resolver_1.resolveBundledChromiumExecutable)()) ?? undefined;
880
+ const context = await chromium.launchPersistentContext(opts.userDataDir, {
881
+ headless: true,
882
+ executablePath,
883
+ viewport: opts.viewport,
884
+ args: ['--no-sandbox', '--disable-dev-shm-usage', '--disable-gpu'],
885
+ });
886
+ return new PlaywrightContextHandle(context);
887
+ };
888
+ }