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,136 @@
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.getProjectMetrics = getProjectMetrics;
7
+ const child_process_1 = require("child_process");
8
+ const fs_1 = __importDefault(require("fs"));
9
+ const path_1 = __importDefault(require("path"));
10
+ function readCoverage(projectPath) {
11
+ const candidatePaths = [
12
+ path_1.default.join(projectPath, 'coverage', 'coverage-summary.json'),
13
+ path_1.default.join(projectPath, 'coverage', 'coverage-final.json'),
14
+ ];
15
+ for (const filePath of candidatePaths) {
16
+ if (!fs_1.default.existsSync(filePath))
17
+ continue;
18
+ try {
19
+ const raw = JSON.parse(fs_1.default.readFileSync(filePath, 'utf-8'));
20
+ const total = raw['total'];
21
+ if (total) {
22
+ return {
23
+ pct: total.lines?.pct ?? null,
24
+ lines: total.lines?.pct ?? null,
25
+ statements: total.statements?.pct ?? null,
26
+ functions: total.functions?.pct ?? null,
27
+ branches: total.branches?.pct ?? null,
28
+ source: path_1.default.relative(projectPath, filePath),
29
+ };
30
+ }
31
+ }
32
+ catch { /* malformed file — try next */ }
33
+ }
34
+ return { pct: null, lines: null, statements: null, functions: null, branches: null, source: null };
35
+ }
36
+ // ─── Git activity ─────────────────────────────────────────────────────────────
37
+ function getGitCommits(projectPath, limit = 10) {
38
+ try {
39
+ const out = (0, child_process_1.execSync)(`git log --pretty=format:"%H|%s|%an|%ai" -${limit}`, { cwd: projectPath, timeout: 5000, stdio: ['ignore', 'pipe', 'ignore'] }).toString().trim();
40
+ if (!out)
41
+ return [];
42
+ return out.split('\n').map((line) => {
43
+ const parts = line.split('|');
44
+ return {
45
+ hash: (parts[0] ?? '').slice(0, 7),
46
+ message: parts[1] ?? '',
47
+ author: parts[2] ?? '',
48
+ date: parts[3] ?? '',
49
+ };
50
+ });
51
+ }
52
+ catch {
53
+ return [];
54
+ }
55
+ }
56
+ // ─── Failure pattern detection ────────────────────────────────────────────────
57
+ const FAILURE_PATTERN_THRESHOLD = 3;
58
+ const FAILURE_PATTERN_WINDOW_DAYS = 7;
59
+ function getFailurePatterns(db) {
60
+ const rows = db.prepare(`
61
+ SELECT
62
+ CASE
63
+ WHEN instr(command, ' ') > 0 THEN substr(command, 1, instr(command, ' ') - 1)
64
+ ELSE command
65
+ END as command_key,
66
+ COUNT(*) as failure_count,
67
+ MAX(started_at) as last_failed_at
68
+ FROM jobs
69
+ WHERE status = 'failed'
70
+ AND started_at >= datetime('now', '-${FAILURE_PATTERN_WINDOW_DAYS} days')
71
+ GROUP BY command_key
72
+ HAVING COUNT(*) >= ${FAILURE_PATTERN_THRESHOLD}
73
+ ORDER BY failure_count DESC
74
+ LIMIT 10
75
+ `).all();
76
+ return rows.map((r) => ({
77
+ command: r.command_key,
78
+ count: r.failure_count,
79
+ lastFailedAt: r.last_failed_at,
80
+ }));
81
+ }
82
+ // ─── Pipeline status ──────────────────────────────────────────────────────────
83
+ function getPipelineStatus(db) {
84
+ const row = db.prepare(`SELECT id, status, command, finished_at
85
+ FROM jobs
86
+ WHERE status IN ('completed', 'failed', 'canceled', 'zombie_terminated')
87
+ ORDER BY finished_at DESC
88
+ LIMIT 1`).get();
89
+ if (!row) {
90
+ return { lastJobId: null, lastJobStatus: null, lastJobCommand: null, lastJobAt: null };
91
+ }
92
+ return {
93
+ lastJobId: row.id,
94
+ lastJobStatus: row.status,
95
+ lastJobCommand: row.command,
96
+ lastJobAt: row.finished_at,
97
+ };
98
+ }
99
+ // ─── Health score computation ─────────────────────────────────────────────────
100
+ function computeHealthScore(coverage, pipeline, commits) {
101
+ const hasCoverage = coverage.pct !== null;
102
+ const coverageGood = hasCoverage && (coverage.pct ?? 0) >= 70;
103
+ const pipelineHealthy = pipeline.lastJobStatus === 'completed';
104
+ const sevenDaysAgo = new Date(Date.now() - 7 * 24 * 60 * 60 * 1000);
105
+ const hasRecentActivity = commits.some((c) => new Date(c.date) > sevenDaysAgo);
106
+ // Weighted score: pipeline 35pts, coverage pass 25pts, recent activity 25pts, any coverage 15pts
107
+ let score = 0;
108
+ if (hasCoverage)
109
+ score += 15;
110
+ if (coverageGood)
111
+ score += 25;
112
+ if (pipelineHealthy)
113
+ score += 35;
114
+ if (hasRecentActivity)
115
+ score += 25;
116
+ return {
117
+ score: Math.min(100, score),
118
+ factors: { hasCoverage, coverageGood, pipelineHealthy, hasRecentActivity },
119
+ };
120
+ }
121
+ // ─── Public API ───────────────────────────────────────────────────────────────
122
+ function getProjectMetrics(projectPath, db) {
123
+ const coverage = readCoverage(projectPath);
124
+ const recentCommits = getGitCommits(projectPath, 10);
125
+ const pipeline = getPipelineStatus(db);
126
+ const { score, factors } = computeHealthScore(coverage, pipeline, recentCommits);
127
+ const failurePatterns = getFailurePatterns(db);
128
+ return {
129
+ coverage,
130
+ healthScore: score,
131
+ healthFactors: factors,
132
+ recentCommits,
133
+ pipeline,
134
+ failurePatterns,
135
+ };
136
+ }
@@ -0,0 +1,16 @@
1
+ "use strict";
2
+ // Mobile Gateway — public surface. The gateway is a second HTTPS+WSS listener in
3
+ // the same Node process (default :4202, OFF by default) that pairs phones by QR +
4
+ // desktop approval and exposes a redacted, deny-by-default allow-list of the
5
+ // desktop API over per-device tokens. The main server at 127.0.0.1:4200 is never
6
+ // exposed.
7
+ Object.defineProperty(exports, "__esModule", { value: true });
8
+ exports.MOBILE_ALLOWLIST = exports.getMobileEventBus = exports.createMobileAdminRouter = exports.MobileGateway = void 0;
9
+ var mobile_gateway_1 = require("./mobile-gateway");
10
+ Object.defineProperty(exports, "MobileGateway", { enumerable: true, get: function () { return mobile_gateway_1.MobileGateway; } });
11
+ var mobile_admin_router_1 = require("./mobile-admin-router");
12
+ Object.defineProperty(exports, "createMobileAdminRouter", { enumerable: true, get: function () { return mobile_admin_router_1.createMobileAdminRouter; } });
13
+ var mobile_event_bus_1 = require("./mobile-event-bus");
14
+ Object.defineProperty(exports, "getMobileEventBus", { enumerable: true, get: function () { return mobile_event_bus_1.getMobileEventBus; } });
15
+ var mobile_router_1 = require("./mobile-router");
16
+ Object.defineProperty(exports, "MOBILE_ALLOWLIST", { enumerable: true, get: function () { return mobile_router_1.MOBILE_ALLOWLIST; } });
@@ -0,0 +1,84 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.createMobileAdminRouter = createMobileAdminRouter;
4
+ const express_1 = require("express");
5
+ const mobile_devices_1 = require("./mobile-devices");
6
+ const DEVICE_ID_RE = /^[A-Za-z0-9-]{1,64}$/;
7
+ function createMobileAdminRouter(deps) {
8
+ const router = (0, express_1.Router)();
9
+ const { gateway, desktopDb } = deps;
10
+ router.get('/status', (_req, res) => {
11
+ res.json(gateway.status());
12
+ });
13
+ router.post('/enable', async (_req, res) => {
14
+ try {
15
+ const status = await gateway.setEnabled(true);
16
+ res.json(status);
17
+ }
18
+ catch (err) {
19
+ // EADDRINUSE etc — keep the flag off and report, never crash.
20
+ res.status(409).json({ error: err instanceof Error ? err.message : 'Failed to start gateway' });
21
+ }
22
+ });
23
+ router.post('/disable', async (_req, res) => {
24
+ await gateway.setEnabled(false);
25
+ res.json(gateway.status());
26
+ });
27
+ // —— Pairing session ——
28
+ router.post('/pairing-session', (_req, res) => {
29
+ if (!gateway.running || !gateway.pairing) {
30
+ res.status(409).json({ error: 'Enable mobile access first' });
31
+ return;
32
+ }
33
+ res.json({ qr: gateway.pairing.createSession() });
34
+ });
35
+ router.get('/pairing-session', (_req, res) => {
36
+ if (!gateway.pairing) {
37
+ res.json({ status: 'none' });
38
+ return;
39
+ }
40
+ res.json(gateway.pairing.getDesktopState() ?? { status: 'none' });
41
+ });
42
+ router.post('/pairing-session/approve', (_req, res) => {
43
+ if (!gateway.pairing) {
44
+ res.status(409).json({ error: 'No pairing session' });
45
+ return;
46
+ }
47
+ const result = gateway.pairing.approve();
48
+ if (!result.ok) {
49
+ res.status(409).json({ error: result.reason });
50
+ return;
51
+ }
52
+ res.json({ ok: true });
53
+ });
54
+ router.post('/pairing-session/deny', (_req, res) => {
55
+ gateway.pairing?.deny();
56
+ res.json({ ok: true });
57
+ });
58
+ router.delete('/pairing-session', (_req, res) => {
59
+ gateway.pairing?.cancel();
60
+ res.json({ ok: true });
61
+ });
62
+ // —— Devices ——
63
+ router.get('/devices', (_req, res) => {
64
+ res.json({ devices: (0, mobile_devices_1.listDevices)(desktopDb) });
65
+ });
66
+ router.delete('/devices/:id', (req, res) => {
67
+ const id = typeof req.params.id === 'string' ? req.params.id : '';
68
+ if (!DEVICE_ID_RE.test(id)) {
69
+ res.status(400).json({ error: 'Invalid device id' });
70
+ return;
71
+ }
72
+ const changed = (0, mobile_devices_1.revokeDevice)(desktopDb, id);
73
+ if (changed) {
74
+ gateway.bridge?.closeForDevice(id);
75
+ deps.broadcast({ type: 'mobile.device_revoked', deviceId: id, timestamp: new Date().toISOString() });
76
+ }
77
+ res.json({ ok: changed });
78
+ });
79
+ router.post('/cert/rotate', async (_req, res) => {
80
+ const status = await gateway.rotateCert();
81
+ res.json(status);
82
+ });
83
+ return router;
84
+ }
@@ -0,0 +1,67 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.extractBearer = extractBearer;
4
+ exports.resolveDevice = resolveDevice;
5
+ exports.createMobileAuthMiddleware = createMobileAuthMiddleware;
6
+ const mobile_devices_1 = require("./mobile-devices");
7
+ function extractBearer(req) {
8
+ const h = req.headers['authorization'];
9
+ if (typeof h === 'string' && h.startsWith('Bearer ')) {
10
+ const t = h.slice(7).trim();
11
+ return t.length > 0 ? t : null;
12
+ }
13
+ return null;
14
+ }
15
+ /** Resolve a device from a raw token against the current cert fingerprint, or
16
+ * null. Shared by the REST middleware and the WS upgrade check. */
17
+ function resolveDevice(db, token, currentFingerprint) {
18
+ if (!token)
19
+ return null;
20
+ const row = (0, mobile_devices_1.getActiveDeviceByTokenHash)(db, (0, mobile_devices_1.hashToken)(token));
21
+ if (!row)
22
+ return null;
23
+ if (row.cert_fingerprint !== currentFingerprint)
24
+ return null;
25
+ return row;
26
+ }
27
+ function createMobileAuthMiddleware(opts) {
28
+ const ratePerMinute = opts.ratePerMinute ?? 600;
29
+ const clock = opts.clock ?? (() => Date.now());
30
+ const lastTouch = new Map();
31
+ const ipHits = new Map();
32
+ return function mobileAuth(req, res, next) {
33
+ // 1. Refuse browser-origin requests outright.
34
+ if (req.headers['origin']) {
35
+ res.status(403).json({ error: 'Forbidden: origin not allowed' });
36
+ return;
37
+ }
38
+ // 2. Coarse per-IP rate limit.
39
+ const ip = req.socket?.remoteAddress ?? 'unknown';
40
+ const now = clock();
41
+ const hits = (ipHits.get(ip) ?? []).filter((t) => now - t < 60_000);
42
+ hits.push(now);
43
+ ipHits.set(ip, hits);
44
+ if (hits.length > ratePerMinute) {
45
+ res.status(429).json({ error: 'Too many requests' });
46
+ return;
47
+ }
48
+ // 3. Token → device, fingerprint-bound.
49
+ const device = resolveDevice(opts.db, extractBearer(req), opts.currentFingerprint());
50
+ if (!device) {
51
+ res.status(401).json({ error: 'Unauthorized' });
52
+ return;
53
+ }
54
+ // 4. Throttled last-seen update (≤1/min per device).
55
+ const prev = lastTouch.get(device.id) ?? 0;
56
+ if (now - prev > 60_000) {
57
+ lastTouch.set(device.id, now);
58
+ try {
59
+ (0, mobile_devices_1.touchDevice)(opts.db, device.id, ip);
60
+ }
61
+ catch { /* non-fatal */ }
62
+ }
63
+ ;
64
+ req.mobileDevice = device;
65
+ next();
66
+ };
67
+ }
@@ -0,0 +1,80 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.hashToken = hashToken;
4
+ exports.createDevice = createDevice;
5
+ exports.getActiveDeviceByTokenHash = getActiveDeviceByTokenHash;
6
+ exports.listDevices = listDevices;
7
+ exports.toPublic = toPublic;
8
+ exports.revokeDevice = revokeDevice;
9
+ exports.revokeAllDevices = revokeAllDevices;
10
+ exports.touchDevice = touchDevice;
11
+ exports.sweepExpiredDevices = sweepExpiredDevices;
12
+ const crypto_1 = require("crypto");
13
+ // CRUD over desktop.sqlite `mobile_devices` (table created by desktop-db migration 12).
14
+ // Tokens are stored ONLY as sha256 hashes; the plaintext token is shown to the
15
+ // phone exactly once at approval and never persisted.
16
+ function hashToken(token) {
17
+ return (0, crypto_1.createHash)('sha256').update(token).digest('hex');
18
+ }
19
+ function createDevice(db, opts) {
20
+ const id = (0, crypto_1.randomUUID)();
21
+ db.prepare(`INSERT INTO mobile_devices (id, name, platform, token_hash, scopes, cert_fingerprint)
22
+ VALUES (?, ?, ?, ?, 'companion', ?)`).run(id, opts.name, opts.platform, opts.tokenHash, opts.certFingerprint);
23
+ return db.prepare('SELECT * FROM mobile_devices WHERE id = ?').get(id);
24
+ }
25
+ /** Look up a device by its token hash. Returns undefined if unknown OR revoked —
26
+ * a revoked device must behave as if it never existed. */
27
+ function getActiveDeviceByTokenHash(db, tokenHash) {
28
+ const row = db
29
+ .prepare('SELECT * FROM mobile_devices WHERE token_hash = ?')
30
+ .get(tokenHash);
31
+ if (!row || row.revoked_at)
32
+ return undefined;
33
+ return row;
34
+ }
35
+ function listDevices(db) {
36
+ const rows = db
37
+ .prepare('SELECT * FROM mobile_devices ORDER BY created_at DESC')
38
+ .all();
39
+ return rows.map(toPublic);
40
+ }
41
+ function toPublic(row) {
42
+ return {
43
+ id: row.id,
44
+ name: row.name,
45
+ platform: row.platform,
46
+ scopes: row.scopes,
47
+ createdAt: row.created_at,
48
+ lastSeenAt: row.last_seen_at,
49
+ lastIp: row.last_ip,
50
+ revoked: !!row.revoked_at,
51
+ };
52
+ }
53
+ /** Mark a device revoked (idempotent). Returns true if a row was affected. */
54
+ function revokeDevice(db, id) {
55
+ const res = db
56
+ .prepare("UPDATE mobile_devices SET revoked_at = datetime('now') WHERE id = ? AND revoked_at IS NULL")
57
+ .run(id);
58
+ return res.changes > 0;
59
+ }
60
+ /** Revoke EVERY device — used by cert rotation ("Reset mobile identity"). */
61
+ function revokeAllDevices(db) {
62
+ const res = db
63
+ .prepare("UPDATE mobile_devices SET revoked_at = datetime('now') WHERE revoked_at IS NULL")
64
+ .run();
65
+ return res.changes;
66
+ }
67
+ /** Refresh last_seen_at/last_ip. Callers throttle this to ~1/min per device. */
68
+ function touchDevice(db, id, ip) {
69
+ db.prepare("UPDATE mobile_devices SET last_seen_at = datetime('now'), last_ip = ? WHERE id = ?").run(ip ?? null, id);
70
+ }
71
+ /** Sliding-expiry sweep: revoke devices unseen for `days` (default 90). Devices
72
+ * that have never connected are measured from created_at. Returns count revoked. */
73
+ function sweepExpiredDevices(db, days = 90) {
74
+ const res = db
75
+ .prepare(`UPDATE mobile_devices SET revoked_at = datetime('now')
76
+ WHERE revoked_at IS NULL
77
+ AND COALESCE(last_seen_at, created_at) < datetime('now', ?)`)
78
+ .run(`-${days} days`);
79
+ return res.changes;
80
+ }
@@ -0,0 +1,39 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.getMobileEventBus = getMobileEventBus;
4
+ const events_1 = require("events");
5
+ // In-process fan-out of every WS broadcast to the Mobile Gateway.
6
+ //
7
+ // The plan originally had the gateway hold a client WebSocket to
8
+ // ws://127.0.0.1:4200. But the gateway runs in the SAME process, so a loopback
9
+ // socket would be pure overhead AND force the bridge to JSON.parse the whole
10
+ // firehose (a gap the critic flagged). Instead the main `broadcast()` emits each
11
+ // already-structured WsMessage here; the gateway's WS bridge subscribes and does
12
+ // per-subscription filtering + redaction on plain objects. REST still forwards
13
+ // via a real loopback HTTP request (so it re-enters requireAuth and never hits
14
+ // the SPA catch-all) — only the WS path uses this bus.
15
+ class MobileEventBus extends events_1.EventEmitter {
16
+ /** Emit a broadcast copy to any subscribed gateway sockets. Never throws into
17
+ * the caller (the main broadcast loop must not be perturbed by a mobile bug). */
18
+ publish(msg) {
19
+ try {
20
+ this.emit('message', msg);
21
+ }
22
+ catch {
23
+ /* swallow — a misbehaving mobile listener must not break the main bus */
24
+ }
25
+ }
26
+ onMessage(cb) {
27
+ this.on('message', cb);
28
+ return () => this.off('message', cb);
29
+ }
30
+ }
31
+ // EventEmitter defaults to 10 listeners; the gateway attaches one shared listener
32
+ // that fans out to many sockets, so the default is plenty — but lift it anyway
33
+ // to be safe against future multi-listener designs.
34
+ const bus = new MobileEventBus();
35
+ bus.setMaxListeners(64);
36
+ /** Process-wide singleton bus. */
37
+ function getMobileEventBus() {
38
+ return bus;
39
+ }