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,117 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.MARKS_PER_SESSION_CAP = void 0;
4
+ exports.appendMark = appendMark;
5
+ exports.listMarks = listMarks;
6
+ exports.deleteForSession = deleteForSession;
7
+ exports.pruneSessionFifo = pruneSessionFifo;
8
+ exports.markOpenAsKilled = markOpenAsKilled;
9
+ exports.getOpenMark = getOpenMark;
10
+ exports.closeOpenMark = closeOpenMark;
11
+ exports.getMark = getMark;
12
+ exports.MARKS_PER_SESSION_CAP = 1000;
13
+ function appendMark(db, input) {
14
+ const insert = db.prepare(`
15
+ INSERT INTO terminal_command_marks (session_id, started_at, finished_at, exit_code, command, cwd)
16
+ VALUES (?, ?, ?, ?, ?, ?)
17
+ `);
18
+ const tx = db.transaction((row) => {
19
+ const result = insert.run(row.sessionId, row.startedAt, row.finishedAt ?? null, row.exitCode ?? null, row.command ?? null, row.cwd ?? null);
20
+ pruneSessionFifo(db, row.sessionId, exports.MARKS_PER_SESSION_CAP);
21
+ return result.lastInsertRowid;
22
+ });
23
+ const id = tx(input);
24
+ return {
25
+ id,
26
+ sessionId: input.sessionId,
27
+ startedAt: input.startedAt,
28
+ finishedAt: input.finishedAt ?? null,
29
+ exitCode: input.exitCode ?? null,
30
+ command: input.command ?? null,
31
+ cwd: input.cwd ?? null,
32
+ };
33
+ }
34
+ function rowToMark(r) {
35
+ return {
36
+ id: r.id,
37
+ sessionId: r.session_id,
38
+ startedAt: r.started_at,
39
+ finishedAt: r.finished_at,
40
+ exitCode: r.exit_code,
41
+ command: r.command,
42
+ cwd: r.cwd,
43
+ };
44
+ }
45
+ function listMarks(db, sessionId, opts = {}) {
46
+ const limit = Math.min(Math.max(opts.limit ?? 100, 1), 1000);
47
+ if (typeof opts.before === 'number') {
48
+ const rows = db.prepare(`
49
+ SELECT * FROM terminal_command_marks
50
+ WHERE session_id = ? AND started_at < ?
51
+ ORDER BY started_at DESC, id DESC LIMIT ?
52
+ `).all(sessionId, opts.before, limit);
53
+ return rows.map(rowToMark);
54
+ }
55
+ const rows = db.prepare(`
56
+ SELECT * FROM terminal_command_marks
57
+ WHERE session_id = ?
58
+ ORDER BY started_at DESC, id DESC LIMIT ?
59
+ `).all(sessionId, limit);
60
+ return rows.map(rowToMark);
61
+ }
62
+ function deleteForSession(db, sessionId) {
63
+ db.prepare('DELETE FROM terminal_command_marks WHERE session_id = ?').run(sessionId);
64
+ }
65
+ function pruneSessionFifo(db, sessionId, cap = exports.MARKS_PER_SESSION_CAP) {
66
+ const countRow = db.prepare('SELECT COUNT(*) AS c FROM terminal_command_marks WHERE session_id = ?').get(sessionId);
67
+ if (countRow.c <= cap)
68
+ return;
69
+ const excess = countRow.c - cap;
70
+ // Delete oldest excess rows for this session.
71
+ db.prepare(`
72
+ DELETE FROM terminal_command_marks
73
+ WHERE id IN (
74
+ SELECT id FROM terminal_command_marks
75
+ WHERE session_id = ?
76
+ ORDER BY started_at ASC, id ASC
77
+ LIMIT ?
78
+ )
79
+ `).run(sessionId, excess);
80
+ }
81
+ /**
82
+ * Mark all open (finished_at IS NULL) marks for a session as killed —
83
+ * called when the session exits without a clean post-exec.
84
+ */
85
+ function markOpenAsKilled(db, sessionId, killedAt) {
86
+ const result = db.prepare(`
87
+ UPDATE terminal_command_marks
88
+ SET finished_at = ?, exit_code = NULL
89
+ WHERE session_id = ? AND finished_at IS NULL
90
+ `).run(killedAt, sessionId);
91
+ return result.changes;
92
+ }
93
+ function getOpenMark(db, sessionId) {
94
+ const row = db.prepare(`
95
+ SELECT * FROM terminal_command_marks
96
+ WHERE session_id = ? AND finished_at IS NULL
97
+ ORDER BY started_at DESC, id DESC LIMIT 1
98
+ `).get(sessionId);
99
+ return row ? rowToMark(row) : null;
100
+ }
101
+ function closeOpenMark(db, sessionId, finishedAt, exitCode, command, cwd) {
102
+ const open = getOpenMark(db, sessionId);
103
+ if (!open)
104
+ return null;
105
+ db.prepare(`
106
+ UPDATE terminal_command_marks
107
+ SET finished_at = ?, exit_code = ?,
108
+ command = COALESCE(?, command),
109
+ cwd = COALESCE(?, cwd)
110
+ WHERE id = ?
111
+ `).run(finishedAt, exitCode, command ?? null, cwd ?? null, open.id);
112
+ return getMark(db, open.id);
113
+ }
114
+ function getMark(db, id) {
115
+ const row = db.prepare('SELECT * FROM terminal_command_marks WHERE id = ?').get(id);
116
+ return row ? rowToMark(row) : null;
117
+ }
@@ -0,0 +1,159 @@
1
+ "use strict";
2
+ /**
3
+ * Streaming OSC sequence parser for shell-integration marks.
4
+ *
5
+ * Recognises:
6
+ * ESC ] 133 ; A ST → prompt-start
7
+ * ESC ] 133 ; B ST → prompt-end (input start)
8
+ * ESC ] 133 ; C ST → pre-exec
9
+ * ESC ] 133 ; D [; <code>] ST → post-exec (with optional exit code)
10
+ * ESC ] 1337 ; CurrentDir=… ST → cwd
11
+ * ESC ] 1337 ; File=… ST → (observed but produces no mark; left for image addon)
12
+ *
13
+ * Where ESC = 0x1B, ST = either BEL (0x07) or ESC \ (0x1B 0x5C).
14
+ *
15
+ * Invariants:
16
+ * - The byte stream is never modified. The parser is observe-only.
17
+ * - Malformed or truncated sequences are tolerated; parser state is bounded.
18
+ * - Sequence body length is capped (8 KB) to bound memory under adversarial input.
19
+ */
20
+ Object.defineProperty(exports, "__esModule", { value: true });
21
+ exports.OscParser = void 0;
22
+ const ESC = 0x1b;
23
+ const BEL = 0x07;
24
+ const BACKSLASH = 0x5c;
25
+ const MAX_BODY_BYTES = 8 * 1024;
26
+ class OscParser {
27
+ state = 'normal';
28
+ body = [];
29
+ reset() {
30
+ this.state = 'normal';
31
+ this.body = [];
32
+ }
33
+ feed(chunk) {
34
+ const out = [];
35
+ for (let i = 0; i < chunk.length; i++) {
36
+ const b = chunk[i];
37
+ switch (this.state) {
38
+ case 'normal':
39
+ if (b === ESC)
40
+ this.state = 'esc';
41
+ break;
42
+ case 'esc':
43
+ if (b === 0x5d /* ']' */) {
44
+ this.state = 'osc-body';
45
+ this.body = [];
46
+ }
47
+ else {
48
+ this.state = 'normal';
49
+ }
50
+ break;
51
+ case 'osc-body':
52
+ if (b === BEL) {
53
+ this.flush(out);
54
+ this.state = 'normal';
55
+ }
56
+ else if (b === ESC) {
57
+ this.state = 'st-pending';
58
+ }
59
+ else {
60
+ if (this.body.length < MAX_BODY_BYTES) {
61
+ this.body.push(b);
62
+ }
63
+ else {
64
+ // Body too large — discard sequence and reset.
65
+ this.body = [];
66
+ this.state = 'normal';
67
+ }
68
+ }
69
+ break;
70
+ case 'st-pending':
71
+ if (b === BACKSLASH) {
72
+ this.flush(out);
73
+ this.state = 'normal';
74
+ }
75
+ else if (b === ESC) {
76
+ // Two ESCs in a row inside an OSC body — restart from this ESC.
77
+ this.body = [];
78
+ this.state = 'esc';
79
+ }
80
+ else {
81
+ // Not a real ST. Append the previous ESC and this byte to the body.
82
+ if (this.body.length + 2 <= MAX_BODY_BYTES) {
83
+ this.body.push(ESC);
84
+ this.body.push(b);
85
+ this.state = 'osc-body';
86
+ }
87
+ else {
88
+ this.body = [];
89
+ this.state = 'normal';
90
+ }
91
+ }
92
+ break;
93
+ }
94
+ }
95
+ return out;
96
+ }
97
+ flush(out) {
98
+ const ev = parseOscBody(this.body);
99
+ if (ev)
100
+ out.push(ev);
101
+ this.body = [];
102
+ }
103
+ }
104
+ exports.OscParser = OscParser;
105
+ function bytesToString(bytes) {
106
+ // Fast ASCII path; OSC payloads are ASCII or UTF-8. Use TextDecoder for safety.
107
+ return new TextDecoder('utf-8', { fatal: false }).decode(Uint8Array.from(bytes));
108
+ }
109
+ function parseOscBody(bytes) {
110
+ if (bytes.length === 0)
111
+ return null;
112
+ // Find the first ';' separator. The code prefix before ';' tells us 133 vs 1337.
113
+ const semicolon = bytes.indexOf(0x3b /* ';' */);
114
+ if (semicolon === -1)
115
+ return null;
116
+ const codeStr = bytesToString(bytes.slice(0, semicolon));
117
+ const rest = bytesToString(bytes.slice(semicolon + 1));
118
+ if (codeStr === '133')
119
+ return parse133(rest);
120
+ if (codeStr === '1337')
121
+ return parse1337(rest);
122
+ return null;
123
+ }
124
+ function parse133(rest) {
125
+ if (rest.length === 0)
126
+ return null;
127
+ const subcode = rest[0];
128
+ switch (subcode) {
129
+ case 'A': return { kind: 'prompt-start' };
130
+ case 'B': return { kind: 'prompt-end' };
131
+ case 'C': return { kind: 'pre-exec' };
132
+ case 'D': {
133
+ const tail = rest.slice(1); // "" or ";<code>" or ";<code>;..."
134
+ if (tail.length === 0)
135
+ return { kind: 'post-exec' };
136
+ if (tail[0] !== ';')
137
+ return null;
138
+ const codeStr = tail.slice(1).split(';')[0];
139
+ if (codeStr.length === 0)
140
+ return { kind: 'post-exec' };
141
+ const n = Number(codeStr);
142
+ if (!Number.isFinite(n) || !Number.isInteger(n))
143
+ return { kind: 'post-exec' };
144
+ return { kind: 'post-exec', exitCode: n };
145
+ }
146
+ default: return null;
147
+ }
148
+ }
149
+ function parse1337(rest) {
150
+ // Only CurrentDir=… surfaces a mark; File=… is left for the image addon.
151
+ const eq = rest.indexOf('=');
152
+ if (eq === -1)
153
+ return null;
154
+ const key = rest.slice(0, eq);
155
+ const value = rest.slice(eq + 1);
156
+ if (key === 'CurrentDir')
157
+ return { kind: 'cwd', payload: value };
158
+ return null;
159
+ }
@@ -0,0 +1,282 @@
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.TerminalSettingsValidationError = exports.TERMINAL_DEFAULTS = exports.TERMINAL_SETTINGS_KEYS = void 0;
7
+ exports.defaultQuickScript = defaultQuickScript;
8
+ exports.validateField = validateField;
9
+ exports.validatePartial = validatePartial;
10
+ exports.getDesktopTerminalSettings = getDesktopTerminalSettings;
11
+ exports.patchDesktopTerminalSettings = patchDesktopTerminalSettings;
12
+ exports.getProjectOverride = getProjectOverride;
13
+ exports.patchProjectOverride = patchProjectOverride;
14
+ exports.resolveTerminalSettings = resolveTerminalSettings;
15
+ const os_1 = __importDefault(require("os"));
16
+ function defaultUsername() {
17
+ try {
18
+ return os_1.default.userInfo().username || 'friend';
19
+ }
20
+ catch {
21
+ return 'friend';
22
+ }
23
+ }
24
+ function defaultQuickScript() {
25
+ return `echo "Wake up, ${defaultUsername()} (edit this snippet in settings to help your local development)"`;
26
+ }
27
+ exports.TERMINAL_SETTINGS_KEYS = [
28
+ 'fontFamily',
29
+ 'fontSize',
30
+ 'renderMode',
31
+ 'copyOnSelect',
32
+ 'shellIntegrationEnabled',
33
+ 'notifyOnCompletion',
34
+ 'imageRendering',
35
+ 'longCommandThresholdMs',
36
+ 'browserShortcutUrl',
37
+ 'quickScript',
38
+ ];
39
+ exports.TERMINAL_DEFAULTS = {
40
+ fontFamily: "'DM Mono', 'JetBrains Mono', ui-monospace, Menlo, monospace",
41
+ fontSize: 12,
42
+ renderMode: 'auto',
43
+ copyOnSelect: false,
44
+ shellIntegrationEnabled: true,
45
+ notifyOnCompletion: true,
46
+ imageRendering: true,
47
+ longCommandThresholdMs: 60_000,
48
+ browserShortcutUrl: 'https://specrails.dev',
49
+ quickScript: defaultQuickScript(),
50
+ };
51
+ const FONT_SIZE_MIN = 8;
52
+ const FONT_SIZE_MAX = 32;
53
+ const LONG_COMMAND_THRESHOLD_MIN_MS = 1_000;
54
+ class TerminalSettingsValidationError extends Error {
55
+ field;
56
+ constructor(field, message) {
57
+ super(message);
58
+ this.field = field;
59
+ this.name = 'TerminalSettingsValidationError';
60
+ }
61
+ }
62
+ exports.TerminalSettingsValidationError = TerminalSettingsValidationError;
63
+ // ─── Codec: TEXT row value ⇄ typed field ──────────────────────────────────────
64
+ function encode(field, value) {
65
+ switch (field) {
66
+ case 'fontFamily':
67
+ case 'renderMode':
68
+ case 'browserShortcutUrl':
69
+ case 'quickScript':
70
+ if (typeof value !== 'string')
71
+ throw new TerminalSettingsValidationError(field, `${field} must be a string`);
72
+ return value;
73
+ case 'fontSize':
74
+ case 'longCommandThresholdMs':
75
+ if (typeof value !== 'number' || !Number.isFinite(value) || !Number.isInteger(value)) {
76
+ throw new TerminalSettingsValidationError(field, `${field} must be an integer`);
77
+ }
78
+ return String(value);
79
+ case 'copyOnSelect':
80
+ case 'shellIntegrationEnabled':
81
+ case 'notifyOnCompletion':
82
+ case 'imageRendering':
83
+ if (typeof value !== 'boolean')
84
+ throw new TerminalSettingsValidationError(field, `${field} must be a boolean`);
85
+ return value ? 'true' : 'false';
86
+ }
87
+ }
88
+ function decode(field, raw) {
89
+ switch (field) {
90
+ case 'fontFamily':
91
+ case 'browserShortcutUrl':
92
+ case 'quickScript':
93
+ return raw;
94
+ case 'renderMode': {
95
+ if (raw !== 'auto' && raw !== 'canvas' && raw !== 'webgl') {
96
+ return exports.TERMINAL_DEFAULTS.renderMode;
97
+ }
98
+ return raw;
99
+ }
100
+ case 'fontSize':
101
+ case 'longCommandThresholdMs': {
102
+ const n = Number(raw);
103
+ return (Number.isFinite(n) && Number.isInteger(n)
104
+ ? n
105
+ : exports.TERMINAL_DEFAULTS[field]);
106
+ }
107
+ case 'copyOnSelect':
108
+ case 'shellIntegrationEnabled':
109
+ case 'notifyOnCompletion':
110
+ case 'imageRendering':
111
+ return (raw === 'true');
112
+ }
113
+ // Unreachable; satisfies TS.
114
+ return exports.TERMINAL_DEFAULTS[field];
115
+ }
116
+ // ─── Validation (apply BEFORE encode) ─────────────────────────────────────────
117
+ function validateField(field, value) {
118
+ switch (field) {
119
+ case 'fontFamily': {
120
+ const v = value;
121
+ if (typeof v !== 'string' || v.trim().length === 0) {
122
+ throw new TerminalSettingsValidationError(field, 'fontFamily must be a non-empty string');
123
+ }
124
+ return;
125
+ }
126
+ case 'fontSize': {
127
+ const n = value;
128
+ if (typeof n !== 'number' || !Number.isInteger(n) || n < FONT_SIZE_MIN || n > FONT_SIZE_MAX) {
129
+ throw new TerminalSettingsValidationError(field, `fontSize must be an integer in [${FONT_SIZE_MIN}, ${FONT_SIZE_MAX}]`);
130
+ }
131
+ return;
132
+ }
133
+ case 'renderMode': {
134
+ const v = value;
135
+ if (v !== 'auto' && v !== 'canvas' && v !== 'webgl') {
136
+ throw new TerminalSettingsValidationError(field, 'renderMode must be one of "auto", "canvas", "webgl"');
137
+ }
138
+ return;
139
+ }
140
+ case 'copyOnSelect':
141
+ case 'shellIntegrationEnabled':
142
+ case 'notifyOnCompletion':
143
+ case 'imageRendering': {
144
+ if (typeof value !== 'boolean') {
145
+ throw new TerminalSettingsValidationError(field, `${field} must be a boolean`);
146
+ }
147
+ return;
148
+ }
149
+ case 'longCommandThresholdMs': {
150
+ const n = value;
151
+ if (typeof n !== 'number' || !Number.isInteger(n) || n < LONG_COMMAND_THRESHOLD_MIN_MS) {
152
+ throw new TerminalSettingsValidationError(field, `longCommandThresholdMs must be an integer ≥ ${LONG_COMMAND_THRESHOLD_MIN_MS}`);
153
+ }
154
+ return;
155
+ }
156
+ case 'browserShortcutUrl': {
157
+ const v = value;
158
+ if (typeof v !== 'string' || v.trim().length === 0) {
159
+ throw new TerminalSettingsValidationError(field, 'browserShortcutUrl must be a non-empty string');
160
+ }
161
+ // Allow http(s) URLs only — no file://, no javascript:, etc.
162
+ if (!/^https?:\/\//i.test(v.trim())) {
163
+ throw new TerminalSettingsValidationError(field, 'browserShortcutUrl must start with http:// or https://');
164
+ }
165
+ return;
166
+ }
167
+ case 'quickScript': {
168
+ const v = value;
169
+ if (typeof v !== 'string') {
170
+ throw new TerminalSettingsValidationError(field, 'quickScript must be a string');
171
+ }
172
+ // Empty strings allowed (user disabling the shortcut). Cap to avoid abuse.
173
+ if (v.length > 8192) {
174
+ throw new TerminalSettingsValidationError(field, 'quickScript exceeds 8KB cap');
175
+ }
176
+ return;
177
+ }
178
+ }
179
+ }
180
+ function validatePartial(patch) {
181
+ const out = {};
182
+ for (const key of Object.keys(patch)) {
183
+ if (!exports.TERMINAL_SETTINGS_KEYS.includes(key)) {
184
+ throw new TerminalSettingsValidationError(key, `unknown setting: ${key}`);
185
+ }
186
+ const field = key;
187
+ const value = patch[key];
188
+ if (value === null)
189
+ continue; // null = clear (override layer); not validated here
190
+ validateField(field, value);
191
+ out[field] = value;
192
+ }
193
+ return out;
194
+ }
195
+ // ─── App-level access (desktop.sqlite, table: desktop_settings) ───────────────────────
196
+ const DESKTOP_KEY_PREFIX = 'terminal.';
197
+ function desktopKey(field) {
198
+ return `${DESKTOP_KEY_PREFIX}${field}`;
199
+ }
200
+ function getDesktopTerminalSettings(desktopDb) {
201
+ const rows = desktopDb
202
+ .prepare('SELECT key, value FROM desktop_settings WHERE key LIKE ?')
203
+ .all(`${DESKTOP_KEY_PREFIX}%`);
204
+ const map = new Map(rows.map((r) => [r.key, r.value]));
205
+ const out = {};
206
+ for (const field of exports.TERMINAL_SETTINGS_KEYS) {
207
+ const raw = map.get(desktopKey(field));
208
+ out[field] = (raw !== undefined ? decode(field, raw) : exports.TERMINAL_DEFAULTS[field]);
209
+ }
210
+ return out;
211
+ }
212
+ function patchDesktopTerminalSettings(desktopDb, patch) {
213
+ const valid = validatePartial(patch);
214
+ const upsert = desktopDb.prepare('INSERT OR REPLACE INTO desktop_settings (key, value) VALUES (?, ?)');
215
+ const tx = desktopDb.transaction((entries) => {
216
+ for (const [k, v] of entries)
217
+ upsert.run(k, v);
218
+ });
219
+ const entries = [];
220
+ for (const field of Object.keys(valid)) {
221
+ entries.push([desktopKey(field), encode(field, valid[field])]);
222
+ }
223
+ if (entries.length > 0)
224
+ tx(entries);
225
+ return getDesktopTerminalSettings(desktopDb);
226
+ }
227
+ // ─── Per-project override (jobs.sqlite, table: terminal_settings_override) ────
228
+ function getProjectOverride(projectDb) {
229
+ const rows = projectDb
230
+ .prepare('SELECT key, value FROM terminal_settings_override WHERE key LIKE ?')
231
+ .all(`${DESKTOP_KEY_PREFIX}%`);
232
+ const out = {};
233
+ for (const r of rows) {
234
+ const field = r.key.slice(DESKTOP_KEY_PREFIX.length);
235
+ if (!exports.TERMINAL_SETTINGS_KEYS.includes(field))
236
+ continue;
237
+ out[field] = decode(field, r.value);
238
+ }
239
+ return out;
240
+ }
241
+ function patchProjectOverride(projectDb, patch) {
242
+ // Validate non-null entries; null entries are deletes and don't go through validateField.
243
+ const setEntries = [];
244
+ const deleteKeys = [];
245
+ for (const key of Object.keys(patch)) {
246
+ if (!exports.TERMINAL_SETTINGS_KEYS.includes(key)) {
247
+ throw new TerminalSettingsValidationError(key, `unknown setting: ${key}`);
248
+ }
249
+ const field = key;
250
+ const value = patch[key];
251
+ if (value === null) {
252
+ deleteKeys.push(desktopKey(field));
253
+ continue;
254
+ }
255
+ validateField(field, value);
256
+ setEntries.push([desktopKey(field), encode(field, value)]);
257
+ }
258
+ const upsert = projectDb.prepare('INSERT OR REPLACE INTO terminal_settings_override (key, value) VALUES (?, ?)');
259
+ const del = projectDb.prepare('DELETE FROM terminal_settings_override WHERE key = ?');
260
+ const tx = projectDb.transaction(() => {
261
+ for (const [k, v] of setEntries)
262
+ upsert.run(k, v);
263
+ for (const k of deleteKeys)
264
+ del.run(k);
265
+ });
266
+ tx();
267
+ return getProjectOverride(projectDb);
268
+ }
269
+ // ─── Resolution: project override → app default → built-in ────────────────────
270
+ function resolveTerminalSettings(desktopDb, projectDb) {
271
+ const desktop = getDesktopTerminalSettings(desktopDb);
272
+ if (!projectDb)
273
+ return desktop;
274
+ const override = getProjectOverride(projectDb);
275
+ const out = { ...desktop };
276
+ for (const field of Object.keys(override)) {
277
+ const v = override[field];
278
+ if (v !== undefined)
279
+ out[field] = v;
280
+ }
281
+ return out;
282
+ }