opendevbrowser 0.0.28 → 0.0.29

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 (313) hide show
  1. package/README.md +2 -2
  2. package/dist/accessibility-snapshot-PA6NWNS7.js +39 -0
  3. package/dist/accessibility-snapshot-PA6NWNS7.js.map +1 -0
  4. package/dist/active-window-YNYTIPZN.js +37 -0
  5. package/dist/active-window-YNYTIPZN.js.map +1 -0
  6. package/dist/annotate-STYHXZYJ.js +205 -0
  7. package/dist/annotate-STYHXZYJ.js.map +1 -0
  8. package/dist/artifacts-KJ6RNDO2.js +120 -0
  9. package/dist/artifacts-KJ6RNDO2.js.map +1 -0
  10. package/dist/attr-GHFZZ4SA.js +84 -0
  11. package/dist/attr-GHFZZ4SA.js.map +1 -0
  12. package/dist/browser/ops-client.d.ts +1 -0
  13. package/dist/browser/ops-client.d.ts.map +1 -1
  14. package/dist/canvas-54FBOEGP.js +309 -0
  15. package/dist/canvas-54FBOEGP.js.map +1 -0
  16. package/dist/capture-desktop-SNABC24E.js +38 -0
  17. package/dist/capture-desktop-SNABC24E.js.map +1 -0
  18. package/dist/capture-window-UJSB5AMP.js +40 -0
  19. package/dist/capture-window-UJSB5AMP.js.map +1 -0
  20. package/dist/check-ST5UQ2F5.js +71 -0
  21. package/dist/check-ST5UQ2F5.js.map +1 -0
  22. package/dist/checked-IEMWI5CU.js +71 -0
  23. package/dist/checked-IEMWI5CU.js.map +1 -0
  24. package/dist/chunk-2CG4SW3E.js +64 -0
  25. package/dist/chunk-2CG4SW3E.js.map +1 -0
  26. package/dist/chunk-2SIMIPLY.js +67 -0
  27. package/dist/chunk-2SIMIPLY.js.map +1 -0
  28. package/dist/chunk-37VSRUW4.js +141 -0
  29. package/dist/chunk-37VSRUW4.js.map +1 -0
  30. package/dist/chunk-5SWZDVOW.js +144 -0
  31. package/dist/chunk-5SWZDVOW.js.map +1 -0
  32. package/dist/chunk-6PVZ2ABC.js +429 -0
  33. package/dist/chunk-6PVZ2ABC.js.map +1 -0
  34. package/dist/chunk-7GVOUZMQ.js +64 -0
  35. package/dist/chunk-7GVOUZMQ.js.map +1 -0
  36. package/dist/chunk-7THCPS52.js +84 -0
  37. package/dist/chunk-7THCPS52.js.map +1 -0
  38. package/dist/chunk-ASMHEEKY.js +10 -0
  39. package/dist/chunk-ASMHEEKY.js.map +1 -0
  40. package/dist/chunk-DBF5OKH3.js +111 -0
  41. package/dist/chunk-DBF5OKH3.js.map +1 -0
  42. package/dist/chunk-DW4TX7MU.js +54 -0
  43. package/dist/chunk-DW4TX7MU.js.map +1 -0
  44. package/dist/chunk-IPE7TF2P.js +54 -0
  45. package/dist/chunk-IPE7TF2P.js.map +1 -0
  46. package/dist/chunk-IQTJHXZJ.js +126 -0
  47. package/dist/chunk-IQTJHXZJ.js.map +1 -0
  48. package/dist/chunk-J47N77VG.js +2969 -0
  49. package/dist/chunk-J47N77VG.js.map +1 -0
  50. package/dist/chunk-JZXD6FWR.js +25 -0
  51. package/dist/chunk-JZXD6FWR.js.map +1 -0
  52. package/dist/{chunk-QVWOPIZJ.js → chunk-KDSNXS6N.js} +75 -149
  53. package/dist/chunk-KDSNXS6N.js.map +1 -0
  54. package/dist/chunk-KZ2IXVQT.js +219 -0
  55. package/dist/chunk-KZ2IXVQT.js.map +1 -0
  56. package/dist/chunk-LBPELU7L.js +3649 -0
  57. package/dist/chunk-LBPELU7L.js.map +1 -0
  58. package/dist/chunk-MX3NFLCE.js +940 -0
  59. package/dist/chunk-MX3NFLCE.js.map +1 -0
  60. package/dist/chunk-N44UXKIB.js +26 -0
  61. package/dist/chunk-N44UXKIB.js.map +1 -0
  62. package/dist/chunk-OW5HMYMI.js +19 -0
  63. package/dist/chunk-OW5HMYMI.js.map +1 -0
  64. package/dist/chunk-OYNLAZQU.js +838 -0
  65. package/dist/chunk-OYNLAZQU.js.map +1 -0
  66. package/dist/chunk-PDPJN2OP.js +17 -0
  67. package/dist/chunk-PDPJN2OP.js.map +1 -0
  68. package/dist/chunk-RCZZGGJS.js +226 -0
  69. package/dist/chunk-RCZZGGJS.js.map +1 -0
  70. package/dist/chunk-RJNI3BHT.js +1 -0
  71. package/dist/chunk-RPXWUCQQ.js +112 -0
  72. package/dist/chunk-RPXWUCQQ.js.map +1 -0
  73. package/dist/chunk-S5KZQJJI.js +107 -0
  74. package/dist/chunk-S5KZQJJI.js.map +1 -0
  75. package/dist/{chunk-T3VVHJTK.js → chunk-S6S2UP6U.js} +1074 -1459
  76. package/dist/chunk-S6S2UP6U.js.map +1 -0
  77. package/dist/{chunk-I5ZCOZZV.js → chunk-SXAGSEKZ.js} +1202 -9561
  78. package/dist/chunk-SXAGSEKZ.js.map +1 -0
  79. package/dist/chunk-T4GMCW6Z.js +46 -0
  80. package/dist/chunk-T4GMCW6Z.js.map +1 -0
  81. package/dist/chunk-WHQZBUNY.js +982 -0
  82. package/dist/chunk-WHQZBUNY.js.map +1 -0
  83. package/dist/chunk-WOXBLP7V.js +610 -0
  84. package/dist/chunk-WOXBLP7V.js.map +1 -0
  85. package/dist/cli/commands/inspiredesign.d.ts.map +1 -1
  86. package/dist/cli/commands/macro-resolve.d.ts +4 -1
  87. package/dist/cli/commands/macro-resolve.d.ts.map +1 -1
  88. package/dist/cli/commands/product-video.d.ts.map +1 -1
  89. package/dist/cli/commands/research.d.ts.map +1 -1
  90. package/dist/cli/commands/serve.d.ts.map +1 -1
  91. package/dist/cli/commands/shopping.d.ts.map +1 -1
  92. package/dist/cli/commands/workflow-output.d.ts +2 -0
  93. package/dist/cli/commands/workflow-output.d.ts.map +1 -0
  94. package/dist/cli/daemon-commands.d.ts.map +1 -1
  95. package/dist/cli/daemon.d.ts.map +1 -1
  96. package/dist/cli/index.js +204 -8123
  97. package/dist/cli/index.js.map +1 -1
  98. package/dist/cli/installers/postinstall-skill-sync.js +2 -1
  99. package/dist/cli/installers/postinstall-skill-sync.js.map +1 -1
  100. package/dist/cli/remote-relay.d.ts.map +1 -1
  101. package/dist/click-TENZA3Y6.js +81 -0
  102. package/dist/click-TENZA3Y6.js.map +1 -0
  103. package/dist/clone-component-STH5AR6M.js +82 -0
  104. package/dist/clone-component-STH5AR6M.js.map +1 -0
  105. package/dist/clone-page-BSTWAPAJ.js +69 -0
  106. package/dist/clone-page-BSTWAPAJ.js.map +1 -0
  107. package/dist/close-CEMMAAM7.js +63 -0
  108. package/dist/close-CEMMAAM7.js.map +1 -0
  109. package/dist/close-QCWUNRAI.js +63 -0
  110. package/dist/close-QCWUNRAI.js.map +1 -0
  111. package/dist/connect-J3RVSEZF.js +107 -0
  112. package/dist/connect-J3RVSEZF.js.map +1 -0
  113. package/dist/console-poll-HL7BVIVX.js +76 -0
  114. package/dist/console-poll-HL7BVIVX.js.map +1 -0
  115. package/dist/cookie-import-WMUCIIHN.js +177 -0
  116. package/dist/cookie-import-WMUCIIHN.js.map +1 -0
  117. package/dist/cookie-list-PB2N4RPH.js +117 -0
  118. package/dist/cookie-list-PB2N4RPH.js.map +1 -0
  119. package/dist/daemon-5KSVMGN4.js +194 -0
  120. package/dist/daemon-5KSVMGN4.js.map +1 -0
  121. package/dist/daemon-fingerprint.json +1 -1
  122. package/dist/debug-trace-snapshot-RK7KDXA5.js +136 -0
  123. package/dist/debug-trace-snapshot-RK7KDXA5.js.map +1 -0
  124. package/dist/dialog-P6P4U7XE.js +75 -0
  125. package/dist/dialog-P6P4U7XE.js.map +1 -0
  126. package/dist/disconnect-32F7IDIP.js +58 -0
  127. package/dist/disconnect-32F7IDIP.js.map +1 -0
  128. package/dist/enabled-A6C6ZM2O.js +71 -0
  129. package/dist/enabled-A6C6ZM2O.js.map +1 -0
  130. package/dist/extension-extractor-GKWSFHPN.js +11 -0
  131. package/dist/extension-extractor-GKWSFHPN.js.map +1 -0
  132. package/dist/global-D6WLWBXA.js +56 -0
  133. package/dist/global-D6WLWBXA.js.map +1 -0
  134. package/dist/goto-ULTSABDM.js +98 -0
  135. package/dist/goto-ULTSABDM.js.map +1 -0
  136. package/dist/help-EKKKEDL5.js +491 -0
  137. package/dist/help-EKKKEDL5.js.map +1 -0
  138. package/dist/hover-UF2ZUMTQ.js +71 -0
  139. package/dist/hover-UF2ZUMTQ.js.map +1 -0
  140. package/dist/html-B6TX7GK7.js +84 -0
  141. package/dist/html-B6TX7GK7.js.map +1 -0
  142. package/dist/index.js +68 -34
  143. package/dist/index.js.map +1 -1
  144. package/dist/inspector-6S5FKUZQ.js +62 -0
  145. package/dist/inspector-6S5FKUZQ.js.map +1 -0
  146. package/dist/inspector-audit-ARGEGOS7.js +84 -0
  147. package/dist/inspector-audit-ARGEGOS7.js.map +1 -0
  148. package/dist/inspector-plan-CSG5HZOC.js +69 -0
  149. package/dist/inspector-plan-CSG5HZOC.js.map +1 -0
  150. package/dist/inspiredesign-7VRMMZN4.js +234 -0
  151. package/dist/inspiredesign-7VRMMZN4.js.map +1 -0
  152. package/dist/install-autostart-output-5DOMKCQL.js +41 -0
  153. package/dist/install-autostart-output-5DOMKCQL.js.map +1 -0
  154. package/dist/install-autostart-reconciliation-NHKOFYTD.js +73 -0
  155. package/dist/install-autostart-reconciliation-NHKOFYTD.js.map +1 -0
  156. package/dist/launch-REYCIR3Z.js +225 -0
  157. package/dist/launch-REYCIR3Z.js.map +1 -0
  158. package/dist/list-NPRXRQY2.js +51 -0
  159. package/dist/list-NPRXRQY2.js.map +1 -0
  160. package/dist/list-STYD2ZWA.js +54 -0
  161. package/dist/list-STYD2ZWA.js.map +1 -0
  162. package/dist/local-HXJLUUNT.js +54 -0
  163. package/dist/local-HXJLUUNT.js.map +1 -0
  164. package/dist/macro-resolve-ZIJZ65QI.js +253 -0
  165. package/dist/macro-resolve-ZIJZ65QI.js.map +1 -0
  166. package/dist/macros/execute-runtime.d.ts +3 -1
  167. package/dist/macros/execute-runtime.d.ts.map +1 -1
  168. package/dist/macros/execute.d.ts +2 -0
  169. package/dist/macros/execute.d.ts.map +1 -1
  170. package/dist/native-UPLVQ2SG.js +22 -0
  171. package/dist/native-UPLVQ2SG.js.map +1 -0
  172. package/dist/network-poll-HLDOSC72.js +76 -0
  173. package/dist/network-poll-HLDOSC72.js.map +1 -0
  174. package/dist/new-HXLLN6UT.js +69 -0
  175. package/dist/new-HXLLN6UT.js.map +1 -0
  176. package/dist/onboarding-metadata-7E3KLYSZ.js +27 -0
  177. package/dist/onboarding-metadata-7E3KLYSZ.js.map +1 -0
  178. package/dist/open-KDR25LQZ.js +81 -0
  179. package/dist/open-KDR25LQZ.js.map +1 -0
  180. package/dist/opendevbrowser.js +68 -34
  181. package/dist/opendevbrowser.js.map +1 -1
  182. package/dist/perf-EM6SWFJ6.js +58 -0
  183. package/dist/perf-EM6SWFJ6.js.map +1 -0
  184. package/dist/pointer-down-ZYWRZNCH.js +55 -0
  185. package/dist/pointer-down-ZYWRZNCH.js.map +1 -0
  186. package/dist/pointer-drag-LVEAVJO4.js +54 -0
  187. package/dist/pointer-drag-LVEAVJO4.js.map +1 -0
  188. package/dist/pointer-move-7SRKUS66.js +52 -0
  189. package/dist/pointer-move-7SRKUS66.js.map +1 -0
  190. package/dist/pointer-up-KLDBSK37.js +55 -0
  191. package/dist/pointer-up-KLDBSK37.js.map +1 -0
  192. package/dist/press-UIIXFTD7.js +83 -0
  193. package/dist/press-UIIXFTD7.js.map +1 -0
  194. package/dist/product-video-PYOXJVAI.js +235 -0
  195. package/dist/product-video-PYOXJVAI.js.map +1 -0
  196. package/dist/providers/artifacts.d.ts +0 -2
  197. package/dist/providers/artifacts.d.ts.map +1 -1
  198. package/dist/providers/blocker.d.ts.map +1 -1
  199. package/dist/providers/bounded-map.d.ts +2 -0
  200. package/dist/providers/bounded-map.d.ts.map +1 -0
  201. package/dist/providers/community/index.d.ts.map +1 -1
  202. package/dist/providers/constraint.d.ts.map +1 -1
  203. package/dist/providers/index.d.ts +1 -0
  204. package/dist/providers/index.d.ts.map +1 -1
  205. package/dist/providers/renderer.d.ts.map +1 -1
  206. package/dist/providers/research-compiler.d.ts +1 -1
  207. package/dist/providers/research-compiler.d.ts.map +1 -1
  208. package/dist/providers/research-executor.d.ts.map +1 -1
  209. package/dist/providers/runtime-factory.d.ts.map +1 -1
  210. package/dist/providers/shared/traversal-url.d.ts +3 -0
  211. package/dist/providers/shared/traversal-url.d.ts.map +1 -1
  212. package/dist/providers/shopping/index.d.ts.map +1 -1
  213. package/dist/providers/social/search-quality.d.ts.map +1 -1
  214. package/dist/providers/workflow-handoff.d.ts +4 -0
  215. package/dist/providers/workflow-handoff.d.ts.map +1 -1
  216. package/dist/providers/workflows.d.ts.map +1 -1
  217. package/dist/{providers-QF2RFB4J.js → providers-4YY2BLXG.js} +19 -14
  218. package/dist/providers-4YY2BLXG.js.map +1 -0
  219. package/dist/public-surface/generated-manifest.d.ts +2 -2
  220. package/dist/public-surface/generated-manifest.d.ts.map +1 -1
  221. package/dist/public-surface/source.d.ts +2 -2
  222. package/dist/public-surface/source.d.ts.map +1 -1
  223. package/dist/relay/protocol.d.ts +3 -1
  224. package/dist/relay/protocol.d.ts.map +1 -1
  225. package/dist/relay/relay-server.d.ts +6 -0
  226. package/dist/relay/relay-server.d.ts.map +1 -1
  227. package/dist/research-CKXMJ2DK.js +295 -0
  228. package/dist/research-CKXMJ2DK.js.map +1 -0
  229. package/dist/review-7HWJPZOD.js +48 -0
  230. package/dist/review-7HWJPZOD.js.map +1 -0
  231. package/dist/review-desktop-2IBJHFB5.js +54 -0
  232. package/dist/review-desktop-2IBJHFB5.js.map +1 -0
  233. package/dist/rpc-3HGIEJUO.js +159 -0
  234. package/dist/rpc-3HGIEJUO.js.map +1 -0
  235. package/dist/run-ADRYI3MS.js +180 -0
  236. package/dist/run-ADRYI3MS.js.map +1 -0
  237. package/dist/screencast-start-DTLUHD5H.js +67 -0
  238. package/dist/screencast-start-DTLUHD5H.js.map +1 -0
  239. package/dist/screencast-stop-54C5LRSS.js +59 -0
  240. package/dist/screencast-stop-54C5LRSS.js.map +1 -0
  241. package/dist/screenshot-HOAKR7P7.js +68 -0
  242. package/dist/screenshot-HOAKR7P7.js.map +1 -0
  243. package/dist/scroll-IAOO5COY.js +84 -0
  244. package/dist/scroll-IAOO5COY.js.map +1 -0
  245. package/dist/scroll-into-view-RKWSLAPH.js +71 -0
  246. package/dist/scroll-into-view-RKWSLAPH.js.map +1 -0
  247. package/dist/select-IGD3T6X4.js +86 -0
  248. package/dist/select-IGD3T6X4.js.map +1 -0
  249. package/dist/serve-7X4INUCU.js +498 -0
  250. package/dist/serve-7X4INUCU.js.map +1 -0
  251. package/dist/shopping-FC6DRW76.js +273 -0
  252. package/dist/shopping-FC6DRW76.js.map +1 -0
  253. package/dist/skill-lifecycle-5UAZGKSN.js +89 -0
  254. package/dist/skill-lifecycle-5UAZGKSN.js.map +1 -0
  255. package/dist/skills-NSXDX6YM.js +26 -0
  256. package/dist/skills-NSXDX6YM.js.map +1 -0
  257. package/dist/snapshot-X22GG324.js +113 -0
  258. package/dist/snapshot-X22GG324.js.map +1 -0
  259. package/dist/status-SP55LMNW.js +132 -0
  260. package/dist/status-SP55LMNW.js.map +1 -0
  261. package/dist/status-VH2WXIDG.js +35 -0
  262. package/dist/status-VH2WXIDG.js.map +1 -0
  263. package/dist/status-capabilities-YBERLRRA.js +57 -0
  264. package/dist/status-capabilities-YBERLRRA.js.map +1 -0
  265. package/dist/text-6TB5WNLI.js +84 -0
  266. package/dist/text-6TB5WNLI.js.map +1 -0
  267. package/dist/tools/macro_resolve.d.ts.map +1 -1
  268. package/dist/type-3UI3TQH3.js +94 -0
  269. package/dist/type-3UI3TQH3.js.map +1 -0
  270. package/dist/uncheck-5L3D2D4U.js +71 -0
  271. package/dist/uncheck-5L3D2D4U.js.map +1 -0
  272. package/dist/uninstall-KYKGJAX7.js +91 -0
  273. package/dist/uninstall-KYKGJAX7.js.map +1 -0
  274. package/dist/update-SMXPYGXS.js +305 -0
  275. package/dist/update-SMXPYGXS.js.map +1 -0
  276. package/dist/update-skill-modes-BVX7IVMW.js +38 -0
  277. package/dist/update-skill-modes-BVX7IVMW.js.map +1 -0
  278. package/dist/upload-YG4J2EMI.js +56 -0
  279. package/dist/upload-YG4J2EMI.js.map +1 -0
  280. package/dist/use-V3LGFP3K.js +63 -0
  281. package/dist/use-V3LGFP3K.js.map +1 -0
  282. package/dist/value-3247D57X.js +71 -0
  283. package/dist/value-3247D57X.js.map +1 -0
  284. package/dist/visible-A7HEV36U.js +71 -0
  285. package/dist/visible-A7HEV36U.js.map +1 -0
  286. package/dist/wait-UZPP4Y4R.js +109 -0
  287. package/dist/wait-UZPP4Y4R.js.map +1 -0
  288. package/dist/windows-76TR3AIP.js +37 -0
  289. package/dist/windows-76TR3AIP.js.map +1 -0
  290. package/extension/dist/background.js +99 -22
  291. package/extension/dist/ops/ops-runtime.js +85 -7
  292. package/extension/dist/ops/ops-session-store.js +3 -0
  293. package/extension/dist/ops/target-session-coordinator.js +3 -0
  294. package/extension/dist/services/CDPRouter.js +9 -0
  295. package/extension/manifest.json +1 -1
  296. package/package.json +1 -1
  297. package/skills/opendevbrowser-best-practices/SKILL.md +8 -6
  298. package/skills/opendevbrowser-best-practices/artifacts/skill-runtime-surface-matrix.md +1 -1
  299. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +3 -2
  300. package/skills/opendevbrowser-best-practices/scripts/validator-fixture-cli.sh +39 -2
  301. package/skills/opendevbrowser-research/SKILL.md +64 -12
  302. package/skills/opendevbrowser-research/artifacts/research-workflows.md +56 -19
  303. package/skills/opendevbrowser-research/assets/templates/compact.md +31 -5
  304. package/skills/opendevbrowser-research/assets/templates/context.json +52 -1
  305. package/skills/opendevbrowser-research/assets/templates/report.md +57 -4
  306. package/skills/opendevbrowser-research/examples/sample-input.json +1 -1
  307. package/skills/opendevbrowser-research/examples/sample-output.md +27 -2
  308. package/skills/opendevbrowser-research/scripts/run-research.sh +2 -6
  309. package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +115 -1
  310. package/dist/chunk-I5ZCOZZV.js.map +0 -1
  311. package/dist/chunk-QVWOPIZJ.js.map +0 -1
  312. package/dist/chunk-T3VVHJTK.js.map +0 -1
  313. /package/dist/{providers-QF2RFB4J.js.map → chunk-RJNI3BHT.js.map} +0 -0
@@ -0,0 +1,429 @@
1
+ import {
2
+ getChromeUserDataRoots,
3
+ getProfileDirs,
4
+ loadGlobalConfig,
5
+ readProfilePreferences
6
+ } from "./chunk-MX3NFLCE.js";
7
+ import {
8
+ EXIT_DISCONNECTED,
9
+ EXIT_EXECUTION,
10
+ createUsageError
11
+ } from "./chunk-IPE7TF2P.js";
12
+ import {
13
+ getExtensionPath
14
+ } from "./chunk-5SWZDVOW.js";
15
+
16
+ // src/cli/commands/native.ts
17
+ import * as fs from "fs";
18
+ import * as path from "path";
19
+ import { execFileSync } from "child_process";
20
+ import { fileURLToPath } from "url";
21
+ var EXTENSION_ID_RE = /^[a-p]{32}$/;
22
+ var EXTENSION_NAME = "OpenDevBrowser Relay";
23
+ var ANNOTATION_COMMAND_NAME = "toggle-annotation";
24
+ var normalizeExtensionId = (value) => {
25
+ if (!value) return null;
26
+ const trimmed = value.trim();
27
+ if (!trimmed) return null;
28
+ return EXTENSION_ID_RE.test(trimmed) ? trimmed : null;
29
+ };
30
+ var requireExtensionId = (value) => {
31
+ if (!value) {
32
+ throw createUsageError("Missing extension ID. Usage: opendevbrowser native install <extension-id>");
33
+ }
34
+ const normalized = normalizeExtensionId(value);
35
+ if (!normalized) {
36
+ throw createUsageError("Invalid extension ID format. Expected 32 characters (a-p).");
37
+ }
38
+ return normalized;
39
+ };
40
+ var parseNativeArgs = (rawArgs) => {
41
+ const subcommand = rawArgs[0];
42
+ if (subcommand !== "install" && subcommand !== "uninstall" && subcommand !== "status") {
43
+ throw createUsageError("Usage: opendevbrowser native <install|uninstall|status> [extension-id]");
44
+ }
45
+ if (subcommand === "install") {
46
+ const extensionId = requireExtensionId(rawArgs[1]);
47
+ return { subcommand, extensionId };
48
+ }
49
+ return { subcommand };
50
+ };
51
+ var getManifestDir = () => {
52
+ if (process.platform === "darwin") {
53
+ return path.join(process.env.HOME || "", "Library", "Application Support", "Google", "Chrome", "NativeMessagingHosts");
54
+ }
55
+ if (process.platform === "linux") {
56
+ return path.join(process.env.HOME || "", ".config", "google-chrome", "NativeMessagingHosts");
57
+ }
58
+ if (process.platform === "win32") {
59
+ const base = process.env.LOCALAPPDATA || (process.env.USERPROFILE ? path.join(process.env.USERPROFILE, "AppData", "Local") : "");
60
+ if (!base) {
61
+ throw createUsageError("LOCALAPPDATA is not set. Unable to locate NativeMessagingHosts directory.");
62
+ }
63
+ return path.join(base, "Google", "Chrome", "User Data", "NativeMessagingHosts");
64
+ }
65
+ throw createUsageError(`Native messaging is not supported on ${process.platform}.`);
66
+ };
67
+ var getScriptsDir = () => {
68
+ const __filename = fileURLToPath(import.meta.url);
69
+ const startDir = path.dirname(__filename);
70
+ const rootsToScan = [startDir, process.cwd()];
71
+ for (const root of rootsToScan) {
72
+ let current = path.resolve(root);
73
+ while (true) {
74
+ const scriptsDir = path.join(current, "scripts", "native");
75
+ const packageJsonPath = path.join(current, "package.json");
76
+ if (fs.existsSync(scriptsDir) && fs.existsSync(packageJsonPath)) {
77
+ return scriptsDir;
78
+ }
79
+ const parent = path.dirname(current);
80
+ if (parent === current) {
81
+ break;
82
+ }
83
+ current = parent;
84
+ }
85
+ }
86
+ throw createUsageError("Unable to locate scripts/native directory.");
87
+ };
88
+ var getHostScriptPath = () => {
89
+ return path.join(getScriptsDir(), "host.cjs");
90
+ };
91
+ var getManifestPath = () => {
92
+ return path.join(getManifestDir(), "com.opendevbrowser.native.json");
93
+ };
94
+ var getWrapperPath = () => {
95
+ const wrapperName = process.platform === "win32" ? "com.opendevbrowser.native.cmd" : "com.opendevbrowser.native.sh";
96
+ return path.join(getManifestDir(), wrapperName);
97
+ };
98
+ var readManifest = (manifestPath) => {
99
+ try {
100
+ const raw = fs.readFileSync(manifestPath, "utf8");
101
+ const data = JSON.parse(raw);
102
+ const origins = Array.isArray(data.allowed_origins) ? data.allowed_origins : [];
103
+ const match = origins.find((origin) => origin.startsWith("chrome-extension://"));
104
+ if (!match) return { extensionId: null };
105
+ const id = match.replace("chrome-extension://", "").replace("/", "");
106
+ return { extensionId: EXTENSION_ID_RE.test(id) ? id : null };
107
+ } catch {
108
+ return { extensionId: null };
109
+ }
110
+ };
111
+ var runScript = (script, args) => {
112
+ if (process.platform === "win32") {
113
+ execFileSync("powershell", ["-NoProfile", "-ExecutionPolicy", "Bypass", "-File", script, ...args], { stdio: "pipe" });
114
+ return;
115
+ }
116
+ execFileSync("bash", [script, ...args], { stdio: "pipe" });
117
+ };
118
+ var readRegistryPath = () => {
119
+ if (process.platform !== "win32") return null;
120
+ const key = "HKCU\\Software\\Google\\Chrome\\NativeMessagingHosts\\com.opendevbrowser.native";
121
+ try {
122
+ const output = execFileSync("reg", ["query", key, "/ve"], { encoding: "utf8" });
123
+ const lines = output.split(/\r?\n/);
124
+ for (const line of lines) {
125
+ if (line.includes("REG_SZ")) {
126
+ const parts = line.trim().split(/\s{2,}/);
127
+ return parts[parts.length - 1] || null;
128
+ }
129
+ }
130
+ return null;
131
+ } catch {
132
+ return null;
133
+ }
134
+ };
135
+ var normalizePath = (value) => {
136
+ try {
137
+ return fs.realpathSync(value);
138
+ } catch {
139
+ return path.resolve(value);
140
+ }
141
+ };
142
+ var findExtensionIdInCommands = (preferences) => {
143
+ const extensionCommands = preferences.extensions;
144
+ const commandMaps = [
145
+ extensionCommands?.commands,
146
+ preferences.account_values?.extensions?.commands
147
+ ];
148
+ for (const commandMap of commandMaps) {
149
+ if (!commandMap) {
150
+ continue;
151
+ }
152
+ for (const value of Object.values(commandMap)) {
153
+ if (typeof value !== "object" || value === null) {
154
+ continue;
155
+ }
156
+ const entry = value;
157
+ const commandName = typeof entry.command_name === "string" ? entry.command_name : null;
158
+ const extensionId = typeof entry.extension === "string" ? entry.extension : null;
159
+ if (commandName === ANNOTATION_COMMAND_NAME && extensionId && EXTENSION_ID_RE.test(extensionId)) {
160
+ return extensionId;
161
+ }
162
+ }
163
+ }
164
+ return null;
165
+ };
166
+ var findExtensionIdInPreferences = (preferences, extensionPath) => {
167
+ const extensions = preferences.extensions;
168
+ const settings = extensions?.settings;
169
+ if (!settings) return null;
170
+ const normalizedTargetPath = extensionPath ? normalizePath(extensionPath) : null;
171
+ let nameMatch = null;
172
+ for (const [id, entry] of Object.entries(settings)) {
173
+ if (!EXTENSION_ID_RE.test(id) || typeof entry !== "object" || entry === null) {
174
+ continue;
175
+ }
176
+ const record = entry;
177
+ const recordPath = typeof record.path === "string" ? record.path : null;
178
+ if (recordPath && normalizedTargetPath) {
179
+ if (normalizePath(recordPath) === normalizedTargetPath) {
180
+ return { id, matchedBy: "path" };
181
+ }
182
+ }
183
+ const manifest = record.manifest;
184
+ const name = typeof manifest?.name === "string" ? manifest.name : null;
185
+ if (!nameMatch && name === EXTENSION_NAME) {
186
+ nameMatch = id;
187
+ }
188
+ }
189
+ if (nameMatch) {
190
+ return { id: nameMatch, matchedBy: "name" };
191
+ }
192
+ return null;
193
+ };
194
+ var getExtensionPathCandidates = () => {
195
+ const candidates = /* @__PURE__ */ new Set();
196
+ const primary = getExtensionPath();
197
+ if (primary) {
198
+ candidates.add(normalizePath(primary));
199
+ }
200
+ const cwdExtension = path.join(process.cwd(), "extension");
201
+ if (fs.existsSync(path.join(cwdExtension, "manifest.json"))) {
202
+ candidates.add(normalizePath(cwdExtension));
203
+ }
204
+ if (candidates.size === 0) {
205
+ return [null];
206
+ }
207
+ return [...candidates];
208
+ };
209
+ function discoverExtensionId() {
210
+ const extensionPaths = getExtensionPathCandidates();
211
+ const roots = getChromeUserDataRoots();
212
+ for (const root of roots) {
213
+ for (const profileDir of getProfileDirs(root)) {
214
+ let nameFallback = null;
215
+ let commandFallback = null;
216
+ for (const preferences of readProfilePreferences(profileDir)) {
217
+ for (const extensionPath of extensionPaths) {
218
+ const match = findExtensionIdInPreferences(preferences, extensionPath);
219
+ if (!match) {
220
+ continue;
221
+ }
222
+ if (match.matchedBy === "path") {
223
+ return { extensionId: match.id, matchedBy: match.matchedBy };
224
+ }
225
+ if (!nameFallback) {
226
+ nameFallback = { id: match.id, matchedBy: "name" };
227
+ }
228
+ }
229
+ if (!commandFallback) {
230
+ commandFallback = findExtensionIdInCommands(preferences);
231
+ }
232
+ }
233
+ if (nameFallback) {
234
+ return { extensionId: nameFallback.id, matchedBy: nameFallback.matchedBy };
235
+ }
236
+ if (commandFallback) {
237
+ return { extensionId: commandFallback, matchedBy: "command" };
238
+ }
239
+ }
240
+ }
241
+ return { extensionId: null };
242
+ }
243
+ var resolveExpectedExtension = () => {
244
+ let configuredExtensionId = null;
245
+ try {
246
+ configuredExtensionId = normalizeExtensionId(loadGlobalConfig().nativeExtensionId);
247
+ } catch {
248
+ configuredExtensionId = null;
249
+ }
250
+ const discovered = discoverExtensionId();
251
+ const discoveredExtensionId = discovered.extensionId ?? null;
252
+ const discoveredMatchedBy = discovered.matchedBy ?? null;
253
+ if (discoveredExtensionId) {
254
+ return {
255
+ discoveredExtensionId,
256
+ discoveredMatchedBy,
257
+ expectedExtensionId: discoveredExtensionId,
258
+ expectedExtensionSource: discoveredMatchedBy
259
+ };
260
+ }
261
+ if (configuredExtensionId) {
262
+ return {
263
+ discoveredExtensionId,
264
+ discoveredMatchedBy,
265
+ expectedExtensionId: configuredExtensionId,
266
+ expectedExtensionSource: "config"
267
+ };
268
+ }
269
+ return {
270
+ discoveredExtensionId,
271
+ discoveredMatchedBy,
272
+ expectedExtensionId: null,
273
+ expectedExtensionSource: null
274
+ };
275
+ };
276
+ var getNativeStatusSnapshot = () => {
277
+ const expectation = resolveExpectedExtension();
278
+ const hostScript = getHostScriptPath();
279
+ const manifestPath = getManifestPath();
280
+ const wrapperPath = getWrapperPath();
281
+ const registryPath = readRegistryPath();
282
+ let installed = false;
283
+ let manifestExists = false;
284
+ let wrapperExists = false;
285
+ let extensionIdValue = null;
286
+ if (fs.existsSync(manifestPath)) {
287
+ manifestExists = true;
288
+ installed = true;
289
+ const manifest = readManifest(manifestPath);
290
+ extensionIdValue = manifest.extensionId;
291
+ }
292
+ if (fs.existsSync(wrapperPath)) {
293
+ wrapperExists = true;
294
+ }
295
+ if (!manifestExists || !wrapperExists) {
296
+ installed = false;
297
+ }
298
+ if (process.platform === "win32" && !registryPath) {
299
+ installed = false;
300
+ }
301
+ const mismatch = Boolean(
302
+ installed && extensionIdValue && expectation.expectedExtensionId && extensionIdValue !== expectation.expectedExtensionId
303
+ );
304
+ return {
305
+ installed,
306
+ manifestPath: manifestExists ? manifestPath : null,
307
+ wrapperPath: wrapperExists ? wrapperPath : null,
308
+ hostScriptPath: hostScript,
309
+ extensionId: extensionIdValue,
310
+ registryPath,
311
+ discoveredExtensionId: expectation.discoveredExtensionId,
312
+ discoveredMatchedBy: expectation.discoveredMatchedBy,
313
+ expectedExtensionId: expectation.expectedExtensionId,
314
+ expectedExtensionSource: expectation.expectedExtensionSource,
315
+ mismatch
316
+ };
317
+ };
318
+ function assessNativeStatus(data) {
319
+ if (!data.installed) {
320
+ return {
321
+ success: false,
322
+ message: "Native host not installed.",
323
+ summary: "not installed",
324
+ exitCode: EXIT_DISCONNECTED
325
+ };
326
+ }
327
+ if (data.mismatch && data.extensionId && data.expectedExtensionId) {
328
+ return {
329
+ success: false,
330
+ message: `Native host targets ${data.extensionId}, but the current extension is ${data.expectedExtensionId}. Reinstall with \`opendevbrowser native install ${data.expectedExtensionId}\` or rerun \`opendevbrowser serve\`.`,
331
+ summary: `mismatch (${data.extensionId} != ${data.expectedExtensionId})`,
332
+ exitCode: EXIT_DISCONNECTED
333
+ };
334
+ }
335
+ return {
336
+ success: true,
337
+ message: data.extensionId ? `Native host installed for extension ${data.extensionId}.` : "Native host installed (extension id missing).",
338
+ summary: `installed${data.extensionId ? ` (${data.extensionId})` : ""}`,
339
+ exitCode: null
340
+ };
341
+ }
342
+ function installNativeHost(extensionId) {
343
+ const normalized = normalizeExtensionId(extensionId);
344
+ if (!normalized) {
345
+ return {
346
+ success: false,
347
+ message: "Invalid extension ID format. Expected 32 characters (a-p).",
348
+ exitCode: EXIT_EXECUTION
349
+ };
350
+ }
351
+ const hostScript = getHostScriptPath();
352
+ if (!fs.existsSync(hostScript)) {
353
+ return {
354
+ success: false,
355
+ message: `Native host not found at ${hostScript}.`,
356
+ exitCode: EXIT_EXECUTION
357
+ };
358
+ }
359
+ const scriptsDir = getScriptsDir();
360
+ const manifestPath = getManifestPath();
361
+ const installScript = process.platform === "win32" ? path.join(scriptsDir, "install.ps1") : path.join(scriptsDir, "install.sh");
362
+ try {
363
+ runScript(installScript, [normalized]);
364
+ return {
365
+ success: true,
366
+ message: `Native host installed for extension ${normalized}.`,
367
+ data: { manifestPath }
368
+ };
369
+ } catch (error) {
370
+ const message = error instanceof Error ? error.message : String(error);
371
+ return {
372
+ success: false,
373
+ message: `Native install failed: ${message}`,
374
+ exitCode: EXIT_EXECUTION
375
+ };
376
+ }
377
+ }
378
+ async function runNativeCommand(args) {
379
+ const { subcommand, extensionId } = parseNativeArgs(args.rawArgs);
380
+ const scriptsDir = getScriptsDir();
381
+ const uninstallScript = process.platform === "win32" ? path.join(scriptsDir, "uninstall.ps1") : path.join(scriptsDir, "uninstall.sh");
382
+ if (subcommand === "install") {
383
+ return installNativeHost(extensionId);
384
+ }
385
+ if (subcommand === "uninstall") {
386
+ try {
387
+ runScript(uninstallScript, []);
388
+ return { success: true, message: "Native host uninstalled." };
389
+ } catch (error) {
390
+ const message = error instanceof Error ? error.message : String(error);
391
+ return { success: false, message: `Native uninstall failed: ${message}`, exitCode: EXIT_EXECUTION };
392
+ }
393
+ }
394
+ const data = getNativeStatusSnapshot();
395
+ const assessment = assessNativeStatus(data);
396
+ return {
397
+ success: assessment.success,
398
+ message: assessment.message,
399
+ data,
400
+ exitCode: assessment.exitCode
401
+ };
402
+ }
403
+ var __test__ = {
404
+ readManifest,
405
+ getManifestDir,
406
+ getManifestPath,
407
+ getWrapperPath,
408
+ getHostScriptPath,
409
+ parseNativeArgs,
410
+ getNativeStatusSnapshot,
411
+ normalizeExtensionId,
412
+ findExtensionIdInPreferences,
413
+ getProfileDirs,
414
+ readProfilePreferences,
415
+ findExtensionIdInCommands,
416
+ getExtensionPathCandidates,
417
+ resolveExpectedExtension,
418
+ assessNativeStatus
419
+ };
420
+
421
+ export {
422
+ discoverExtensionId,
423
+ getNativeStatusSnapshot,
424
+ assessNativeStatus,
425
+ installNativeHost,
426
+ runNativeCommand,
427
+ __test__
428
+ };
429
+ //# sourceMappingURL=chunk-6PVZ2ABC.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/commands/native.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport { execFileSync } from \"child_process\";\nimport { fileURLToPath } from \"url\";\nimport type { ParsedArgs } from \"../args\";\nimport { loadGlobalConfig } from \"../../config\";\nimport { createUsageError, EXIT_DISCONNECTED, EXIT_EXECUTION } from \"../errors\";\nimport { getExtensionPath } from \"../../extension-extractor\";\nimport {\n getChromeUserDataRoots,\n getProfileDirs,\n readProfilePreferences\n} from \"../../cache/chrome-user-data\";\n\ntype NativeSubcommand = \"install\" | \"uninstall\" | \"status\";\n\nexport type NativeStatus = {\n installed: boolean;\n manifestPath: string | null;\n wrapperPath: string | null;\n hostScriptPath: string;\n extensionId: string | null;\n registryPath: string | null;\n discoveredExtensionId: string | null;\n discoveredMatchedBy: ExtensionIdMatchReason | null;\n expectedExtensionId: string | null;\n expectedExtensionSource: \"config\" | ExtensionIdMatchReason | null;\n mismatch: boolean;\n};\n\ntype NativeStatusAssessment = {\n success: boolean;\n message: string;\n summary: string;\n exitCode: number | null;\n};\n\nconst EXTENSION_ID_RE = /^[a-p]{32}$/;\nconst EXTENSION_NAME = \"OpenDevBrowser Relay\";\nconst ANNOTATION_COMMAND_NAME = \"toggle-annotation\";\ntype ExtensionIdMatchReason = \"path\" | \"name\" | \"command\";\n\nconst normalizeExtensionId = (value: string | undefined): string | null => {\n if (!value) return null;\n const trimmed = value.trim();\n if (!trimmed) return null;\n return EXTENSION_ID_RE.test(trimmed) ? trimmed : null;\n};\n\nconst requireExtensionId = (value: string | undefined): string => {\n if (!value) {\n throw createUsageError(\"Missing extension ID. Usage: opendevbrowser native install <extension-id>\");\n }\n const normalized = normalizeExtensionId(value);\n if (!normalized) {\n throw createUsageError(\"Invalid extension ID format. Expected 32 characters (a-p).\");\n }\n return normalized;\n};\n\nconst parseNativeArgs = (rawArgs: string[]): { subcommand: NativeSubcommand; extensionId?: string } => {\n const subcommand = rawArgs[0];\n if (subcommand !== \"install\" && subcommand !== \"uninstall\" && subcommand !== \"status\") {\n throw createUsageError(\"Usage: opendevbrowser native <install|uninstall|status> [extension-id]\");\n }\n if (subcommand === \"install\") {\n const extensionId = requireExtensionId(rawArgs[1]);\n return { subcommand, extensionId };\n }\n return { subcommand };\n};\n\nconst getManifestDir = (): string => {\n if (process.platform === \"darwin\") {\n return path.join(process.env.HOME || \"\", \"Library\", \"Application Support\", \"Google\", \"Chrome\", \"NativeMessagingHosts\");\n }\n if (process.platform === \"linux\") {\n return path.join(process.env.HOME || \"\", \".config\", \"google-chrome\", \"NativeMessagingHosts\");\n }\n if (process.platform === \"win32\") {\n const base = process.env.LOCALAPPDATA\n || (process.env.USERPROFILE ? path.join(process.env.USERPROFILE, \"AppData\", \"Local\") : \"\");\n if (!base) {\n throw createUsageError(\"LOCALAPPDATA is not set. Unable to locate NativeMessagingHosts directory.\");\n }\n return path.join(base, \"Google\", \"Chrome\", \"User Data\", \"NativeMessagingHosts\");\n }\n throw createUsageError(`Native messaging is not supported on ${process.platform}.`);\n};\n\nconst getScriptsDir = (): string => {\n const __filename = fileURLToPath(import.meta.url);\n const startDir = path.dirname(__filename);\n const rootsToScan = [startDir, process.cwd()];\n\n for (const root of rootsToScan) {\n let current = path.resolve(root);\n while (true) {\n const scriptsDir = path.join(current, \"scripts\", \"native\");\n const packageJsonPath = path.join(current, \"package.json\");\n if (fs.existsSync(scriptsDir) && fs.existsSync(packageJsonPath)) {\n return scriptsDir;\n }\n const parent = path.dirname(current);\n if (parent === current) {\n break;\n }\n current = parent;\n }\n }\n\n throw createUsageError(\"Unable to locate scripts/native directory.\");\n};\n\nconst getHostScriptPath = (): string => {\n return path.join(getScriptsDir(), \"host.cjs\");\n};\n\nconst getManifestPath = (): string => {\n return path.join(getManifestDir(), \"com.opendevbrowser.native.json\");\n};\n\nconst getWrapperPath = (): string => {\n const wrapperName = process.platform === \"win32\"\n ? \"com.opendevbrowser.native.cmd\"\n : \"com.opendevbrowser.native.sh\";\n return path.join(getManifestDir(), wrapperName);\n};\n\nconst readManifest = (manifestPath: string): { extensionId: string | null } => {\n try {\n const raw = fs.readFileSync(manifestPath, \"utf8\");\n const data = JSON.parse(raw) as { allowed_origins?: string[] };\n const origins = Array.isArray(data.allowed_origins) ? data.allowed_origins : [];\n const match = origins.find((origin) => origin.startsWith(\"chrome-extension://\"));\n if (!match) return { extensionId: null };\n const id = match.replace(\"chrome-extension://\", \"\").replace(\"/\", \"\");\n return { extensionId: EXTENSION_ID_RE.test(id) ? id : null };\n } catch {\n return { extensionId: null };\n }\n};\n\nconst runScript = (script: string, args: string[]): void => {\n if (process.platform === \"win32\") {\n execFileSync(\"powershell\", [\"-NoProfile\", \"-ExecutionPolicy\", \"Bypass\", \"-File\", script, ...args], { stdio: \"pipe\" });\n return;\n }\n execFileSync(\"bash\", [script, ...args], { stdio: \"pipe\" });\n};\n\nconst readRegistryPath = (): string | null => {\n if (process.platform !== \"win32\") return null;\n const key = \"HKCU\\\\Software\\\\Google\\\\Chrome\\\\NativeMessagingHosts\\\\com.opendevbrowser.native\";\n try {\n const output = execFileSync(\"reg\", [\"query\", key, \"/ve\"], { encoding: \"utf8\" });\n const lines = output.split(/\\r?\\n/);\n for (const line of lines) {\n if (line.includes(\"REG_SZ\")) {\n const parts = line.trim().split(/\\s{2,}/);\n return parts[parts.length - 1] || null;\n }\n }\n return null;\n } catch {\n return null;\n }\n};\n\nconst normalizePath = (value: string): string => {\n try {\n return fs.realpathSync(value);\n } catch {\n return path.resolve(value);\n }\n};\n\nconst findExtensionIdInCommands = (preferences: Record<string, unknown>): string | null => {\n const extensionCommands = preferences.extensions as Record<string, unknown> | undefined;\n const commandMaps: Array<Record<string, unknown> | undefined> = [\n extensionCommands?.commands as Record<string, unknown> | undefined,\n ((preferences.account_values as Record<string, unknown> | undefined)?.extensions as Record<string, unknown> | undefined)\n ?.commands as Record<string, unknown> | undefined\n ];\n\n for (const commandMap of commandMaps) {\n if (!commandMap) {\n continue;\n }\n for (const value of Object.values(commandMap)) {\n if (typeof value !== \"object\" || value === null) {\n continue;\n }\n const entry = value as Record<string, unknown>;\n const commandName = typeof entry.command_name === \"string\" ? entry.command_name : null;\n const extensionId = typeof entry.extension === \"string\" ? entry.extension : null;\n if (commandName === ANNOTATION_COMMAND_NAME && extensionId && EXTENSION_ID_RE.test(extensionId)) {\n return extensionId;\n }\n }\n }\n\n return null;\n};\n\nconst findExtensionIdInPreferences = (\n preferences: Record<string, unknown>,\n extensionPath: string | null\n): { id: string; matchedBy: \"path\" | \"name\" } | null => {\n const extensions = preferences.extensions as Record<string, unknown> | undefined;\n const settings = extensions?.settings as Record<string, unknown> | undefined;\n if (!settings) return null;\n\n const normalizedTargetPath = extensionPath ? normalizePath(extensionPath) : null;\n let nameMatch: string | null = null;\n\n for (const [id, entry] of Object.entries(settings)) {\n if (!EXTENSION_ID_RE.test(id) || typeof entry !== \"object\" || entry === null) {\n continue;\n }\n const record = entry as Record<string, unknown>;\n const recordPath = typeof record.path === \"string\" ? record.path : null;\n if (recordPath && normalizedTargetPath) {\n if (normalizePath(recordPath) === normalizedTargetPath) {\n return { id, matchedBy: \"path\" };\n }\n }\n const manifest = record.manifest as Record<string, unknown> | undefined;\n const name = typeof manifest?.name === \"string\" ? manifest.name : null;\n if (!nameMatch && name === EXTENSION_NAME) {\n nameMatch = id;\n }\n }\n\n if (nameMatch) {\n return { id: nameMatch, matchedBy: \"name\" };\n }\n return null;\n};\n\nconst getExtensionPathCandidates = (): Array<string | null> => {\n const candidates = new Set<string>();\n const primary = getExtensionPath();\n if (primary) {\n candidates.add(normalizePath(primary));\n }\n\n const cwdExtension = path.join(process.cwd(), \"extension\");\n if (fs.existsSync(path.join(cwdExtension, \"manifest.json\"))) {\n candidates.add(normalizePath(cwdExtension));\n }\n\n if (candidates.size === 0) {\n return [null];\n }\n return [...candidates];\n};\n\nexport function discoverExtensionId(): { extensionId: string | null; matchedBy?: ExtensionIdMatchReason } {\n const extensionPaths = getExtensionPathCandidates();\n const roots = getChromeUserDataRoots();\n for (const root of roots) {\n for (const profileDir of getProfileDirs(root)) {\n let nameFallback: { id: string; matchedBy: \"name\" } | null = null;\n let commandFallback: string | null = null;\n for (const preferences of readProfilePreferences(profileDir)) {\n for (const extensionPath of extensionPaths) {\n const match = findExtensionIdInPreferences(preferences, extensionPath);\n if (!match) {\n continue;\n }\n if (match.matchedBy === \"path\") {\n return { extensionId: match.id, matchedBy: match.matchedBy };\n }\n if (!nameFallback) {\n nameFallback = { id: match.id, matchedBy: \"name\" };\n }\n }\n\n if (!commandFallback) {\n commandFallback = findExtensionIdInCommands(preferences);\n }\n }\n if (nameFallback) {\n return { extensionId: nameFallback.id, matchedBy: nameFallback.matchedBy };\n }\n if (commandFallback) {\n return { extensionId: commandFallback, matchedBy: \"command\" };\n }\n }\n }\n return { extensionId: null };\n}\n\nconst resolveExpectedExtension = (): {\n discoveredExtensionId: string | null;\n discoveredMatchedBy: ExtensionIdMatchReason | null;\n expectedExtensionId: string | null;\n expectedExtensionSource: \"config\" | ExtensionIdMatchReason | null;\n} => {\n let configuredExtensionId: string | null = null;\n try {\n configuredExtensionId = normalizeExtensionId(loadGlobalConfig().nativeExtensionId);\n } catch {\n configuredExtensionId = null;\n }\n\n const discovered = discoverExtensionId();\n const discoveredExtensionId = discovered.extensionId ?? null;\n const discoveredMatchedBy = discovered.matchedBy ?? null;\n if (discoveredExtensionId) {\n return {\n discoveredExtensionId,\n discoveredMatchedBy,\n expectedExtensionId: discoveredExtensionId,\n expectedExtensionSource: discoveredMatchedBy\n };\n }\n if (configuredExtensionId) {\n return {\n discoveredExtensionId,\n discoveredMatchedBy,\n expectedExtensionId: configuredExtensionId,\n expectedExtensionSource: \"config\"\n };\n }\n return {\n discoveredExtensionId,\n discoveredMatchedBy,\n expectedExtensionId: null,\n expectedExtensionSource: null\n };\n};\n\nexport const getNativeStatusSnapshot = (): NativeStatus => {\n const expectation = resolveExpectedExtension();\n const hostScript = getHostScriptPath();\n const manifestPath = getManifestPath();\n const wrapperPath = getWrapperPath();\n const registryPath = readRegistryPath();\n\n let installed = false;\n let manifestExists = false;\n let wrapperExists = false;\n let extensionIdValue: string | null = null;\n if (fs.existsSync(manifestPath)) {\n manifestExists = true;\n installed = true;\n const manifest = readManifest(manifestPath);\n extensionIdValue = manifest.extensionId;\n }\n if (fs.existsSync(wrapperPath)) {\n wrapperExists = true;\n }\n if (!manifestExists || !wrapperExists) {\n installed = false;\n }\n if (process.platform === \"win32\" && !registryPath) {\n installed = false;\n }\n\n const mismatch = Boolean(\n installed\n && extensionIdValue\n && expectation.expectedExtensionId\n && extensionIdValue !== expectation.expectedExtensionId\n );\n\n return {\n installed,\n manifestPath: manifestExists ? manifestPath : null,\n wrapperPath: wrapperExists ? wrapperPath : null,\n hostScriptPath: hostScript,\n extensionId: extensionIdValue,\n registryPath,\n discoveredExtensionId: expectation.discoveredExtensionId,\n discoveredMatchedBy: expectation.discoveredMatchedBy,\n expectedExtensionId: expectation.expectedExtensionId,\n expectedExtensionSource: expectation.expectedExtensionSource,\n mismatch\n };\n};\n\nexport function assessNativeStatus(data: NativeStatus): NativeStatusAssessment {\n if (!data.installed) {\n return {\n success: false,\n message: \"Native host not installed.\",\n summary: \"not installed\",\n exitCode: EXIT_DISCONNECTED\n };\n }\n\n if (data.mismatch && data.extensionId && data.expectedExtensionId) {\n return {\n success: false,\n message: `Native host targets ${data.extensionId}, but the current extension is ${data.expectedExtensionId}. Reinstall with \\`opendevbrowser native install ${data.expectedExtensionId}\\` or rerun \\`opendevbrowser serve\\`.`,\n summary: `mismatch (${data.extensionId} != ${data.expectedExtensionId})`,\n exitCode: EXIT_DISCONNECTED\n };\n }\n\n return {\n success: true,\n message: data.extensionId\n ? `Native host installed for extension ${data.extensionId}.`\n : \"Native host installed (extension id missing).\",\n summary: `installed${data.extensionId ? ` (${data.extensionId})` : \"\"}`,\n exitCode: null\n };\n}\n\nexport function installNativeHost(extensionId: string) {\n const normalized = normalizeExtensionId(extensionId);\n if (!normalized) {\n return {\n success: false,\n message: \"Invalid extension ID format. Expected 32 characters (a-p).\",\n exitCode: EXIT_EXECUTION\n };\n }\n\n const hostScript = getHostScriptPath();\n if (!fs.existsSync(hostScript)) {\n return {\n success: false,\n message: `Native host not found at ${hostScript}.`,\n exitCode: EXIT_EXECUTION\n };\n }\n\n const scriptsDir = getScriptsDir();\n const manifestPath = getManifestPath();\n const installScript = process.platform === \"win32\"\n ? path.join(scriptsDir, \"install.ps1\")\n : path.join(scriptsDir, \"install.sh\");\n\n try {\n runScript(installScript, [normalized]);\n return {\n success: true,\n message: `Native host installed for extension ${normalized}.`,\n data: { manifestPath }\n };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return {\n success: false,\n message: `Native install failed: ${message}`,\n exitCode: EXIT_EXECUTION\n };\n }\n}\n\nexport async function runNativeCommand(args: ParsedArgs) {\n const { subcommand, extensionId } = parseNativeArgs(args.rawArgs);\n const scriptsDir = getScriptsDir();\n const uninstallScript = process.platform === \"win32\"\n ? path.join(scriptsDir, \"uninstall.ps1\")\n : path.join(scriptsDir, \"uninstall.sh\");\n\n if (subcommand === \"install\") {\n return installNativeHost(extensionId as string);\n }\n\n if (subcommand === \"uninstall\") {\n try {\n runScript(uninstallScript, []);\n return { success: true, message: \"Native host uninstalled.\" };\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error);\n return { success: false, message: `Native uninstall failed: ${message}`, exitCode: EXIT_EXECUTION };\n }\n }\n\n const data = getNativeStatusSnapshot();\n const assessment = assessNativeStatus(data);\n return {\n success: assessment.success,\n message: assessment.message,\n data,\n exitCode: assessment.exitCode\n };\n}\n\nexport const __test__ = {\n readManifest,\n getManifestDir,\n getManifestPath,\n getWrapperPath,\n getHostScriptPath,\n parseNativeArgs,\n getNativeStatusSnapshot,\n normalizeExtensionId,\n findExtensionIdInPreferences,\n getProfileDirs,\n readProfilePreferences,\n findExtensionIdInCommands,\n getExtensionPathCandidates,\n resolveExpectedExtension,\n assessNativeStatus\n};\n"],"mappings":"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","names":[]}
@@ -0,0 +1,64 @@
1
+ // src/cli/output.ts
2
+ var normalizeExitCode = (code) => {
3
+ return Number.isInteger(code) ? Number(code) : 0;
4
+ };
5
+ var flushStream = (stream) => {
6
+ return new Promise((resolve) => {
7
+ if (!stream || typeof stream.write !== "function") {
8
+ resolve();
9
+ return;
10
+ }
11
+ try {
12
+ stream.write("", () => resolve());
13
+ } catch {
14
+ resolve();
15
+ }
16
+ });
17
+ };
18
+ async function flushOutputAndExit(code, proc = process, timeoutMs = 250) {
19
+ const finalCode = normalizeExitCode(code);
20
+ proc.exitCode = finalCode;
21
+ await new Promise((resolve) => {
22
+ let settled = false;
23
+ const finish = () => {
24
+ if (settled) return;
25
+ settled = true;
26
+ resolve();
27
+ };
28
+ const timer = setTimeout(finish, Math.max(0, timeoutMs));
29
+ timer.unref?.();
30
+ void Promise.allSettled([flushStream(proc.stdout), flushStream(proc.stderr)]).finally(() => {
31
+ clearTimeout(timer);
32
+ finish();
33
+ });
34
+ });
35
+ proc.exit(finalCode);
36
+ }
37
+ function writeOutput(payload, options) {
38
+ if (options.quiet) {
39
+ return;
40
+ }
41
+ if (options.format === "text") {
42
+ if (typeof payload === "string") {
43
+ console.log(payload);
44
+ } else {
45
+ console.log(JSON.stringify(payload, null, 2));
46
+ }
47
+ return;
48
+ }
49
+ if (options.format === "stream-json") {
50
+ if (Array.isArray(payload)) {
51
+ for (const entry of payload) {
52
+ console.log(JSON.stringify(entry));
53
+ }
54
+ return;
55
+ }
56
+ }
57
+ console.log(JSON.stringify(payload));
58
+ }
59
+
60
+ export {
61
+ flushOutputAndExit,
62
+ writeOutput
63
+ };
64
+ //# sourceMappingURL=chunk-7GVOUZMQ.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/output.ts"],"sourcesContent":["import type { OutputFormat } from \"./args\";\n\nexport type OutputOptions = {\n format: OutputFormat;\n quiet?: boolean;\n};\n\ntype ExitProcessLike = Pick<typeof process, \"exit\" | \"exitCode\" | \"stdout\" | \"stderr\">;\n\nconst normalizeExitCode = (code: number | null | undefined): number => {\n return Number.isInteger(code) ? Number(code) : 0;\n};\n\nconst flushStream = (\n stream: ExitProcessLike[\"stdout\"] | ExitProcessLike[\"stderr\"] | undefined | null\n): Promise<void> => {\n return new Promise((resolve) => {\n if (!stream || typeof stream.write !== \"function\") {\n resolve();\n return;\n }\n try {\n stream.write(\"\", () => resolve());\n } catch {\n resolve();\n }\n });\n};\n\nexport async function flushOutputAndExit(\n code: number | null | undefined,\n proc: ExitProcessLike = process,\n timeoutMs = 250\n): Promise<void> {\n const finalCode = normalizeExitCode(code);\n proc.exitCode = finalCode;\n\n await new Promise<void>((resolve) => {\n let settled = false;\n const finish = () => {\n if (settled) return;\n settled = true;\n resolve();\n };\n const timer = setTimeout(finish, Math.max(0, timeoutMs));\n timer.unref?.();\n void Promise.allSettled([flushStream(proc.stdout), flushStream(proc.stderr)]).finally(() => {\n clearTimeout(timer);\n finish();\n });\n });\n\n proc.exit(finalCode);\n}\n\nexport function writeOutput(payload: unknown, options: OutputOptions): void {\n if (options.quiet) {\n return;\n }\n\n if (options.format === \"text\") {\n if (typeof payload === \"string\") {\n console.log(payload);\n } else {\n console.log(JSON.stringify(payload, null, 2));\n }\n return;\n }\n\n if (options.format === \"stream-json\") {\n if (Array.isArray(payload)) {\n for (const entry of payload) {\n console.log(JSON.stringify(entry));\n }\n return;\n }\n }\n\n console.log(JSON.stringify(payload));\n}\n"],"mappings":";AASA,IAAM,oBAAoB,CAAC,SAA4C;AACrE,SAAO,OAAO,UAAU,IAAI,IAAI,OAAO,IAAI,IAAI;AACjD;AAEA,IAAM,cAAc,CAClB,WACkB;AAClB,SAAO,IAAI,QAAQ,CAAC,YAAY;AAC9B,QAAI,CAAC,UAAU,OAAO,OAAO,UAAU,YAAY;AACjD,cAAQ;AACR;AAAA,IACF;AACA,QAAI;AACF,aAAO,MAAM,IAAI,MAAM,QAAQ,CAAC;AAAA,IAClC,QAAQ;AACN,cAAQ;AAAA,IACV;AAAA,EACF,CAAC;AACH;AAEA,eAAsB,mBACpB,MACA,OAAwB,SACxB,YAAY,KACG;AACf,QAAM,YAAY,kBAAkB,IAAI;AACxC,OAAK,WAAW;AAEhB,QAAM,IAAI,QAAc,CAAC,YAAY;AACnC,QAAI,UAAU;AACd,UAAM,SAAS,MAAM;AACnB,UAAI,QAAS;AACb,gBAAU;AACV,cAAQ;AAAA,IACV;AACA,UAAM,QAAQ,WAAW,QAAQ,KAAK,IAAI,GAAG,SAAS,CAAC;AACvD,UAAM,QAAQ;AACd,SAAK,QAAQ,WAAW,CAAC,YAAY,KAAK,MAAM,GAAG,YAAY,KAAK,MAAM,CAAC,CAAC,EAAE,QAAQ,MAAM;AAC1F,mBAAa,KAAK;AAClB,aAAO;AAAA,IACT,CAAC;AAAA,EACH,CAAC;AAED,OAAK,KAAK,SAAS;AACrB;AAEO,SAAS,YAAY,SAAkB,SAA8B;AAC1E,MAAI,QAAQ,OAAO;AACjB;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,QAAQ;AAC7B,QAAI,OAAO,YAAY,UAAU;AAC/B,cAAQ,IAAI,OAAO;AAAA,IACrB,OAAO;AACL,cAAQ,IAAI,KAAK,UAAU,SAAS,MAAM,CAAC,CAAC;AAAA,IAC9C;AACA;AAAA,EACF;AAEA,MAAI,QAAQ,WAAW,eAAe;AACpC,QAAI,MAAM,QAAQ,OAAO,GAAG;AAC1B,iBAAW,SAAS,SAAS;AAC3B,gBAAQ,IAAI,KAAK,UAAU,KAAK,CAAC;AAAA,MACnC;AACA;AAAA,IACF;AAAA,EACF;AAEA,UAAQ,IAAI,KAAK,UAAU,OAAO,CAAC;AACrC;","names":[]}
@@ -0,0 +1,84 @@
1
+ // src/cli/utils/config.ts
2
+ import * as fs from "fs";
3
+ import * as path from "path";
4
+ import * as os from "os";
5
+ import { parse as parseJsonc, modify, applyEdits } from "jsonc-parser";
6
+ var PLUGIN_NAME = "opendevbrowser";
7
+ var SCHEMA_URL = "https://opencode.ai/config.json";
8
+ function getGlobalConfigPath() {
9
+ const configDir = process.env.OPENCODE_CONFIG_DIR || path.join(os.homedir(), ".config", "opencode");
10
+ return path.join(configDir, "opencode.json");
11
+ }
12
+ function getLocalConfigPath() {
13
+ return path.join(process.cwd(), "opencode.json");
14
+ }
15
+ function ensureDir(dirPath) {
16
+ if (!fs.existsSync(dirPath)) {
17
+ fs.mkdirSync(dirPath, { recursive: true });
18
+ }
19
+ }
20
+ function readConfig(configPath) {
21
+ if (!fs.existsSync(configPath)) {
22
+ return { content: "", config: {} };
23
+ }
24
+ const content = fs.readFileSync(configPath, "utf-8");
25
+ const errors = [];
26
+ const parsed = parseJsonc(content, errors, { allowTrailingComma: true });
27
+ if (errors.length > 0) {
28
+ const firstError = errors[0];
29
+ throw new Error(`Invalid JSONC at ${configPath}: parse error at offset ${firstError?.offset ?? 0}`);
30
+ }
31
+ return { content, config: parsed ?? {} };
32
+ }
33
+ function hasPlugin(config, pluginName = PLUGIN_NAME) {
34
+ return config.plugin?.includes(pluginName) ?? false;
35
+ }
36
+ function createConfigWithPlugin(pluginName = PLUGIN_NAME) {
37
+ return {
38
+ $schema: SCHEMA_URL,
39
+ plugin: [pluginName]
40
+ };
41
+ }
42
+ function updateConfigContent(content, pluginName = PLUGIN_NAME) {
43
+ if (!content.trim()) {
44
+ return JSON.stringify(createConfigWithPlugin(pluginName), null, 2) + "\n";
45
+ }
46
+ const parsed = parseJsonc(content, [], { allowTrailingComma: true }) ?? {};
47
+ if (parsed.plugin?.includes(pluginName)) {
48
+ return content;
49
+ }
50
+ let result = content;
51
+ if (!parsed.$schema) {
52
+ const edits2 = modify(result, ["$schema"], SCHEMA_URL, { formattingOptions: { tabSize: 2, insertSpaces: true } });
53
+ result = applyEdits(result, edits2);
54
+ }
55
+ const newPlugins = parsed.plugin ? [...parsed.plugin, pluginName] : [pluginName];
56
+ const edits = modify(result, ["plugin"], newPlugins, { formattingOptions: { tabSize: 2, insertSpaces: true } });
57
+ result = applyEdits(result, edits);
58
+ return result;
59
+ }
60
+ function removePluginFromContent(content, pluginName = PLUGIN_NAME) {
61
+ if (!content.trim()) {
62
+ return content;
63
+ }
64
+ const parsed = parseJsonc(content, [], { allowTrailingComma: true }) ?? {};
65
+ if (!parsed.plugin?.includes(pluginName)) {
66
+ return content;
67
+ }
68
+ const newPlugins = parsed.plugin.filter((p) => p !== pluginName);
69
+ const edits = modify(content, ["plugin"], newPlugins.length > 0 ? newPlugins : void 0, {
70
+ formattingOptions: { tabSize: 2, insertSpaces: true }
71
+ });
72
+ return applyEdits(content, edits);
73
+ }
74
+
75
+ export {
76
+ getGlobalConfigPath,
77
+ getLocalConfigPath,
78
+ ensureDir,
79
+ readConfig,
80
+ hasPlugin,
81
+ updateConfigContent,
82
+ removePluginFromContent
83
+ };
84
+ //# sourceMappingURL=chunk-7THCPS52.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/cli/utils/config.ts"],"sourcesContent":["import * as fs from \"fs\";\nimport * as path from \"path\";\nimport * as os from \"os\";\nimport { parse as parseJsonc, modify, applyEdits } from \"jsonc-parser\";\nimport { writeFileAtomic } from \"../../utils/fs\";\n\nconst PLUGIN_NAME = \"opendevbrowser\";\nconst SCHEMA_URL = \"https://opencode.ai/config.json\";\n\nexport interface OpenCodeConfig {\n $schema?: string;\n plugin?: string[];\n [key: string]: unknown;\n}\n\nexport function getGlobalConfigPath(): string {\n const configDir = process.env.OPENCODE_CONFIG_DIR\n || path.join(os.homedir(), \".config\", \"opencode\");\n return path.join(configDir, \"opencode.json\");\n}\n\nexport function getLocalConfigPath(): string {\n return path.join(process.cwd(), \"opencode.json\");\n}\n\nexport function ensureDir(dirPath: string): void {\n if (!fs.existsSync(dirPath)) {\n fs.mkdirSync(dirPath, { recursive: true });\n }\n}\n\nexport function readConfig(configPath: string): { content: string; config: OpenCodeConfig } {\n if (!fs.existsSync(configPath)) {\n return { content: \"\", config: {} };\n }\n\n const content = fs.readFileSync(configPath, \"utf-8\");\n const errors: Array<{ error: number; offset: number; length: number }> = [];\n const parsed = parseJsonc(content, errors, { allowTrailingComma: true });\n\n if (errors.length > 0) {\n const firstError = errors[0];\n throw new Error(`Invalid JSONC at ${configPath}: parse error at offset ${firstError?.offset ?? 0}`);\n }\n\n return { content, config: (parsed ?? {}) as OpenCodeConfig };\n}\n\nexport function writeConfig(configPath: string, config: OpenCodeConfig): void {\n ensureDir(path.dirname(configPath));\n const content = JSON.stringify(config, null, 2) + \"\\n\";\n writeFileAtomic(configPath, content);\n}\n\nexport function addPlugin(config: OpenCodeConfig, pluginName: string = PLUGIN_NAME): OpenCodeConfig {\n const result = { ...config };\n\n if (!result.$schema) {\n result.$schema = SCHEMA_URL;\n }\n\n if (!result.plugin) {\n result.plugin = [pluginName];\n } else if (!result.plugin.includes(pluginName)) {\n result.plugin = [...result.plugin, pluginName];\n }\n\n return result;\n}\n\nexport function removePlugin(config: OpenCodeConfig, pluginName: string = PLUGIN_NAME): OpenCodeConfig {\n const result = { ...config };\n\n if (result.plugin) {\n result.plugin = result.plugin.filter((p) => p !== pluginName);\n if (result.plugin.length === 0) {\n delete result.plugin;\n }\n }\n\n return result;\n}\n\nexport function hasPlugin(config: OpenCodeConfig, pluginName: string = PLUGIN_NAME): boolean {\n return config.plugin?.includes(pluginName) ?? false;\n}\n\nexport function createConfigWithPlugin(pluginName: string = PLUGIN_NAME): OpenCodeConfig {\n return {\n $schema: SCHEMA_URL,\n plugin: [pluginName]\n };\n}\n\nexport function updateConfigContent(content: string, pluginName: string = PLUGIN_NAME): string {\n if (!content.trim()) {\n return JSON.stringify(createConfigWithPlugin(pluginName), null, 2) + \"\\n\";\n }\n\n const parsed = parseJsonc(content, [], { allowTrailingComma: true }) as OpenCodeConfig ?? {};\n\n if (parsed.plugin?.includes(pluginName)) {\n return content;\n }\n\n let result = content;\n\n if (!parsed.$schema) {\n const edits = modify(result, [\"$schema\"], SCHEMA_URL, { formattingOptions: { tabSize: 2, insertSpaces: true } });\n result = applyEdits(result, edits);\n }\n\n const newPlugins = parsed.plugin ? [...parsed.plugin, pluginName] : [pluginName];\n const edits = modify(result, [\"plugin\"], newPlugins, { formattingOptions: { tabSize: 2, insertSpaces: true } });\n result = applyEdits(result, edits);\n\n return result;\n}\n\nexport function removePluginFromContent(content: string, pluginName: string = PLUGIN_NAME): string {\n if (!content.trim()) {\n return content;\n }\n\n const parsed = parseJsonc(content, [], { allowTrailingComma: true }) as OpenCodeConfig ?? {};\n\n if (!parsed.plugin?.includes(pluginName)) {\n return content;\n }\n\n const newPlugins = parsed.plugin.filter((p) => p !== pluginName);\n const edits = modify(content, [\"plugin\"], newPlugins.length > 0 ? newPlugins : undefined, {\n formattingOptions: { tabSize: 2, insertSpaces: true }\n });\n\n return applyEdits(content, edits);\n}\n"],"mappings":";AAAA,YAAY,QAAQ;AACpB,YAAY,UAAU;AACtB,YAAY,QAAQ;AACpB,SAAS,SAAS,YAAY,QAAQ,kBAAkB;AAGxD,IAAM,cAAc;AACpB,IAAM,aAAa;AAQZ,SAAS,sBAA8B;AAC5C,QAAM,YAAY,QAAQ,IAAI,uBACpB,UAAQ,WAAQ,GAAG,WAAW,UAAU;AAClD,SAAY,UAAK,WAAW,eAAe;AAC7C;AAEO,SAAS,qBAA6B;AAC3C,SAAY,UAAK,QAAQ,IAAI,GAAG,eAAe;AACjD;AAEO,SAAS,UAAU,SAAuB;AAC/C,MAAI,CAAI,cAAW,OAAO,GAAG;AAC3B,IAAG,aAAU,SAAS,EAAE,WAAW,KAAK,CAAC;AAAA,EAC3C;AACF;AAEO,SAAS,WAAW,YAAiE;AAC1F,MAAI,CAAI,cAAW,UAAU,GAAG;AAC9B,WAAO,EAAE,SAAS,IAAI,QAAQ,CAAC,EAAE;AAAA,EACnC;AAEA,QAAM,UAAa,gBAAa,YAAY,OAAO;AACnD,QAAM,SAAmE,CAAC;AAC1E,QAAM,SAAS,WAAW,SAAS,QAAQ,EAAE,oBAAoB,KAAK,CAAC;AAEvE,MAAI,OAAO,SAAS,GAAG;AACrB,UAAM,aAAa,OAAO,CAAC;AAC3B,UAAM,IAAI,MAAM,oBAAoB,UAAU,2BAA2B,YAAY,UAAU,CAAC,EAAE;AAAA,EACpG;AAEA,SAAO,EAAE,SAAS,QAAS,UAAU,CAAC,EAAqB;AAC7D;AAqCO,SAAS,UAAU,QAAwB,aAAqB,aAAsB;AAC3F,SAAO,OAAO,QAAQ,SAAS,UAAU,KAAK;AAChD;AAEO,SAAS,uBAAuB,aAAqB,aAA6B;AACvF,SAAO;AAAA,IACL,SAAS;AAAA,IACT,QAAQ,CAAC,UAAU;AAAA,EACrB;AACF;AAEO,SAAS,oBAAoB,SAAiB,aAAqB,aAAqB;AAC7F,MAAI,CAAC,QAAQ,KAAK,GAAG;AACnB,WAAO,KAAK,UAAU,uBAAuB,UAAU,GAAG,MAAM,CAAC,IAAI;AAAA,EACvE;AAEA,QAAM,SAAS,WAAW,SAAS,CAAC,GAAG,EAAE,oBAAoB,KAAK,CAAC,KAAuB,CAAC;AAE3F,MAAI,OAAO,QAAQ,SAAS,UAAU,GAAG;AACvC,WAAO;AAAA,EACT;AAEA,MAAI,SAAS;AAEb,MAAI,CAAC,OAAO,SAAS;AACnB,UAAMA,SAAQ,OAAO,QAAQ,CAAC,SAAS,GAAG,YAAY,EAAE,mBAAmB,EAAE,SAAS,GAAG,cAAc,KAAK,EAAE,CAAC;AAC/G,aAAS,WAAW,QAAQA,MAAK;AAAA,EACnC;AAEA,QAAM,aAAa,OAAO,SAAS,CAAC,GAAG,OAAO,QAAQ,UAAU,IAAI,CAAC,UAAU;AAC/E,QAAM,QAAQ,OAAO,QAAQ,CAAC,QAAQ,GAAG,YAAY,EAAE,mBAAmB,EAAE,SAAS,GAAG,cAAc,KAAK,EAAE,CAAC;AAC9G,WAAS,WAAW,QAAQ,KAAK;AAEjC,SAAO;AACT;AAEO,SAAS,wBAAwB,SAAiB,aAAqB,aAAqB;AACjG,MAAI,CAAC,QAAQ,KAAK,GAAG;AACnB,WAAO;AAAA,EACT;AAEA,QAAM,SAAS,WAAW,SAAS,CAAC,GAAG,EAAE,oBAAoB,KAAK,CAAC,KAAuB,CAAC;AAE3F,MAAI,CAAC,OAAO,QAAQ,SAAS,UAAU,GAAG;AACxC,WAAO;AAAA,EACT;AAEA,QAAM,aAAa,OAAO,OAAO,OAAO,CAAC,MAAM,MAAM,UAAU;AAC/D,QAAM,QAAQ,OAAO,SAAS,CAAC,QAAQ,GAAG,WAAW,SAAS,IAAI,aAAa,QAAW;AAAA,IACxF,mBAAmB,EAAE,SAAS,GAAG,cAAc,KAAK;AAAA,EACtD,CAAC;AAED,SAAO,WAAW,SAAS,KAAK;AAClC;","names":["edits"]}
@@ -0,0 +1,10 @@
1
+ // src/utils/crypto.ts
2
+ import { randomBytes } from "crypto";
3
+ function generateSecureToken() {
4
+ return randomBytes(32).toString("hex");
5
+ }
6
+
7
+ export {
8
+ generateSecureToken
9
+ };
10
+ //# sourceMappingURL=chunk-ASMHEEKY.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/crypto.ts"],"sourcesContent":["import { randomBytes } from \"crypto\";\n\nexport function generateSecureToken(): string {\n return randomBytes(32).toString(\"hex\");\n}\n"],"mappings":";AAAA,SAAS,mBAAmB;AAErB,SAAS,sBAA8B;AAC5C,SAAO,YAAY,EAAE,EAAE,SAAS,KAAK;AACvC;","names":[]}