opendevbrowser 0.0.28 → 0.0.30

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 (325) hide show
  1. package/README.md +2 -2
  2. package/dist/accessibility-snapshot-CQ4ZKWKC.js +39 -0
  3. package/dist/accessibility-snapshot-CQ4ZKWKC.js.map +1 -0
  4. package/dist/active-window-TD5HYJ72.js +37 -0
  5. package/dist/active-window-TD5HYJ72.js.map +1 -0
  6. package/dist/annotate-VTLFS2XV.js +205 -0
  7. package/dist/annotate-VTLFS2XV.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-BCI5KYCW.js +84 -0
  11. package/dist/attr-BCI5KYCW.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-5DFEEOKM.js +309 -0
  15. package/dist/canvas-5DFEEOKM.js.map +1 -0
  16. package/dist/capture-desktop-HFTTWY4Z.js +38 -0
  17. package/dist/capture-desktop-HFTTWY4Z.js.map +1 -0
  18. package/dist/capture-window-X63XPIFF.js +40 -0
  19. package/dist/capture-window-X63XPIFF.js.map +1 -0
  20. package/dist/check-LWAUY7GC.js +71 -0
  21. package/dist/check-LWAUY7GC.js.map +1 -0
  22. package/dist/checked-ZSOUKVYT.js +71 -0
  23. package/dist/checked-ZSOUKVYT.js.map +1 -0
  24. package/dist/chunk-2SIMIPLY.js +67 -0
  25. package/dist/chunk-2SIMIPLY.js.map +1 -0
  26. package/dist/chunk-37VSRUW4.js +141 -0
  27. package/dist/chunk-37VSRUW4.js.map +1 -0
  28. package/dist/{chunk-T3VVHJTK.js → chunk-4BEJVZRK.js} +1078 -1458
  29. package/dist/chunk-4BEJVZRK.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-AHEWXOKY.js +64 -0
  39. package/dist/chunk-AHEWXOKY.js.map +1 -0
  40. package/dist/chunk-ASMHEEKY.js +10 -0
  41. package/dist/chunk-ASMHEEKY.js.map +1 -0
  42. package/dist/chunk-COAOWH3G.js +3651 -0
  43. package/dist/chunk-COAOWH3G.js.map +1 -0
  44. package/dist/chunk-DBF5OKH3.js +111 -0
  45. package/dist/chunk-DBF5OKH3.js.map +1 -0
  46. package/dist/chunk-DW4TX7MU.js +54 -0
  47. package/dist/chunk-DW4TX7MU.js.map +1 -0
  48. package/dist/chunk-GQJ5S3BL.js +20 -0
  49. package/dist/chunk-GQJ5S3BL.js.map +1 -0
  50. package/dist/chunk-IPE7TF2P.js +54 -0
  51. package/dist/chunk-IPE7TF2P.js.map +1 -0
  52. package/dist/chunk-IQTJHXZJ.js +126 -0
  53. package/dist/chunk-IQTJHXZJ.js.map +1 -0
  54. package/dist/chunk-J47N77VG.js +2969 -0
  55. package/dist/chunk-J47N77VG.js.map +1 -0
  56. package/dist/chunk-JZXD6FWR.js +25 -0
  57. package/dist/chunk-JZXD6FWR.js.map +1 -0
  58. package/dist/{chunk-QVWOPIZJ.js → chunk-KDSNXS6N.js} +75 -149
  59. package/dist/chunk-KDSNXS6N.js.map +1 -0
  60. package/dist/chunk-KZ2IXVQT.js +219 -0
  61. package/dist/chunk-KZ2IXVQT.js.map +1 -0
  62. package/dist/chunk-MD655IPO.js +838 -0
  63. package/dist/chunk-MD655IPO.js.map +1 -0
  64. package/dist/chunk-MX3NFLCE.js +940 -0
  65. package/dist/chunk-MX3NFLCE.js.map +1 -0
  66. package/dist/chunk-OW5HMYMI.js +19 -0
  67. package/dist/chunk-OW5HMYMI.js.map +1 -0
  68. package/dist/chunk-PPUWQKIC.js +26 -0
  69. package/dist/chunk-PPUWQKIC.js.map +1 -0
  70. package/dist/{chunk-I5ZCOZZV.js → chunk-QOMWCRE3.js} +1202 -9561
  71. package/dist/chunk-QOMWCRE3.js.map +1 -0
  72. package/dist/chunk-RCZZGGJS.js +226 -0
  73. package/dist/chunk-RCZZGGJS.js.map +1 -0
  74. package/dist/chunk-RJNI3BHT.js +1 -0
  75. package/dist/chunk-RPXWUCQQ.js +112 -0
  76. package/dist/chunk-RPXWUCQQ.js.map +1 -0
  77. package/dist/chunk-S5KZQJJI.js +107 -0
  78. package/dist/chunk-S5KZQJJI.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-2AILSEIZ.js +81 -0
  102. package/dist/click-2AILSEIZ.js.map +1 -0
  103. package/dist/clone-component-TPJS3PEG.js +82 -0
  104. package/dist/clone-component-TPJS3PEG.js.map +1 -0
  105. package/dist/clone-page-LE74CIFC.js +69 -0
  106. package/dist/clone-page-LE74CIFC.js.map +1 -0
  107. package/dist/close-HN4YI47K.js +63 -0
  108. package/dist/close-HN4YI47K.js.map +1 -0
  109. package/dist/close-WFERRHX6.js +63 -0
  110. package/dist/close-WFERRHX6.js.map +1 -0
  111. package/dist/connect-RWBV2UCQ.js +107 -0
  112. package/dist/connect-RWBV2UCQ.js.map +1 -0
  113. package/dist/console-poll-PP4YYPDF.js +76 -0
  114. package/dist/console-poll-PP4YYPDF.js.map +1 -0
  115. package/dist/cookie-import-6IP776FC.js +177 -0
  116. package/dist/cookie-import-6IP776FC.js.map +1 -0
  117. package/dist/cookie-list-O2KG6DPU.js +117 -0
  118. package/dist/cookie-list-O2KG6DPU.js.map +1 -0
  119. package/dist/daemon-2BSAZXLT.js +194 -0
  120. package/dist/daemon-2BSAZXLT.js.map +1 -0
  121. package/dist/daemon-fingerprint.json +1 -1
  122. package/dist/debug-trace-snapshot-F3BDVZXS.js +136 -0
  123. package/dist/debug-trace-snapshot-F3BDVZXS.js.map +1 -0
  124. package/dist/dialog-6JQYUWMQ.js +75 -0
  125. package/dist/dialog-6JQYUWMQ.js.map +1 -0
  126. package/dist/disconnect-763TP7GH.js +58 -0
  127. package/dist/disconnect-763TP7GH.js.map +1 -0
  128. package/dist/enabled-DLYQFNIP.js +71 -0
  129. package/dist/enabled-DLYQFNIP.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-S346TJJH.js +98 -0
  135. package/dist/goto-S346TJJH.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-6JVJFGO7.js +71 -0
  139. package/dist/hover-6JVJFGO7.js.map +1 -0
  140. package/dist/html-EVOSPBIT.js +84 -0
  141. package/dist/html-EVOSPBIT.js.map +1 -0
  142. package/dist/index.d.ts.map +1 -1
  143. package/dist/index.js +87 -38
  144. package/dist/index.js.map +1 -1
  145. package/dist/inspector-H57BVUJP.js +62 -0
  146. package/dist/inspector-H57BVUJP.js.map +1 -0
  147. package/dist/inspector-audit-NQBAJWC7.js +84 -0
  148. package/dist/inspector-audit-NQBAJWC7.js.map +1 -0
  149. package/dist/inspector-plan-ZDIQVND3.js +69 -0
  150. package/dist/inspector-plan-ZDIQVND3.js.map +1 -0
  151. package/dist/inspiredesign-IEUL4PX3.js +234 -0
  152. package/dist/inspiredesign-IEUL4PX3.js.map +1 -0
  153. package/dist/install-autostart-output-5DOMKCQL.js +41 -0
  154. package/dist/install-autostart-output-5DOMKCQL.js.map +1 -0
  155. package/dist/install-autostart-reconciliation-NHKOFYTD.js +73 -0
  156. package/dist/install-autostart-reconciliation-NHKOFYTD.js.map +1 -0
  157. package/dist/launch-EK66VQPF.js +225 -0
  158. package/dist/launch-EK66VQPF.js.map +1 -0
  159. package/dist/list-ADZAQ2IU.js +51 -0
  160. package/dist/list-ADZAQ2IU.js.map +1 -0
  161. package/dist/list-KKUKN467.js +54 -0
  162. package/dist/list-KKUKN467.js.map +1 -0
  163. package/dist/local-HXJLUUNT.js +54 -0
  164. package/dist/local-HXJLUUNT.js.map +1 -0
  165. package/dist/macro-resolve-6DOQJ7CA.js +253 -0
  166. package/dist/macro-resolve-6DOQJ7CA.js.map +1 -0
  167. package/dist/macros/execute-runtime.d.ts +3 -1
  168. package/dist/macros/execute-runtime.d.ts.map +1 -1
  169. package/dist/macros/execute.d.ts +2 -0
  170. package/dist/macros/execute.d.ts.map +1 -1
  171. package/dist/native-UPLVQ2SG.js +22 -0
  172. package/dist/native-UPLVQ2SG.js.map +1 -0
  173. package/dist/network-poll-NUL4PDPY.js +76 -0
  174. package/dist/network-poll-NUL4PDPY.js.map +1 -0
  175. package/dist/new-5NKYPEFT.js +69 -0
  176. package/dist/new-5NKYPEFT.js.map +1 -0
  177. package/dist/onboarding-metadata-7E3KLYSZ.js +27 -0
  178. package/dist/onboarding-metadata-7E3KLYSZ.js.map +1 -0
  179. package/dist/open-NR3BPLXV.js +81 -0
  180. package/dist/open-NR3BPLXV.js.map +1 -0
  181. package/dist/opendevbrowser.d.ts.map +1 -1
  182. package/dist/opendevbrowser.js +87 -38
  183. package/dist/opendevbrowser.js.map +1 -1
  184. package/dist/perf-HJ36ZI6H.js +58 -0
  185. package/dist/perf-HJ36ZI6H.js.map +1 -0
  186. package/dist/pointer-down-IYTTQWXZ.js +55 -0
  187. package/dist/pointer-down-IYTTQWXZ.js.map +1 -0
  188. package/dist/pointer-drag-A2YC5PWI.js +54 -0
  189. package/dist/pointer-drag-A2YC5PWI.js.map +1 -0
  190. package/dist/pointer-move-W5K5FUI4.js +52 -0
  191. package/dist/pointer-move-W5K5FUI4.js.map +1 -0
  192. package/dist/pointer-up-6GWVO64Y.js +55 -0
  193. package/dist/pointer-up-6GWVO64Y.js.map +1 -0
  194. package/dist/press-A3V5WB3S.js +83 -0
  195. package/dist/press-A3V5WB3S.js.map +1 -0
  196. package/dist/product-video-52REKWF3.js +235 -0
  197. package/dist/product-video-52REKWF3.js.map +1 -0
  198. package/dist/providers/artifacts.d.ts +0 -2
  199. package/dist/providers/artifacts.d.ts.map +1 -1
  200. package/dist/providers/blocker.d.ts.map +1 -1
  201. package/dist/providers/bounded-map.d.ts +2 -0
  202. package/dist/providers/bounded-map.d.ts.map +1 -0
  203. package/dist/providers/community/index.d.ts.map +1 -1
  204. package/dist/providers/constraint.d.ts.map +1 -1
  205. package/dist/providers/index.d.ts +1 -0
  206. package/dist/providers/index.d.ts.map +1 -1
  207. package/dist/providers/renderer.d.ts.map +1 -1
  208. package/dist/providers/research-compiler.d.ts +1 -1
  209. package/dist/providers/research-compiler.d.ts.map +1 -1
  210. package/dist/providers/research-executor.d.ts.map +1 -1
  211. package/dist/providers/runtime-factory.d.ts.map +1 -1
  212. package/dist/providers/shared/traversal-url.d.ts +3 -0
  213. package/dist/providers/shared/traversal-url.d.ts.map +1 -1
  214. package/dist/providers/shopping/index.d.ts.map +1 -1
  215. package/dist/providers/social/search-quality.d.ts.map +1 -1
  216. package/dist/providers/workflow-handoff.d.ts +4 -0
  217. package/dist/providers/workflow-handoff.d.ts.map +1 -1
  218. package/dist/providers/workflow-output-root.d.ts +6 -0
  219. package/dist/providers/workflow-output-root.d.ts.map +1 -0
  220. package/dist/providers/workflows.d.ts.map +1 -1
  221. package/dist/{providers-QF2RFB4J.js → providers-IMFYMMHQ.js} +19 -14
  222. package/dist/providers-IMFYMMHQ.js.map +1 -0
  223. package/dist/public-surface/generated-manifest.d.ts +2 -2
  224. package/dist/public-surface/generated-manifest.d.ts.map +1 -1
  225. package/dist/public-surface/source.d.ts +2 -2
  226. package/dist/public-surface/source.d.ts.map +1 -1
  227. package/dist/relay/protocol.d.ts +3 -1
  228. package/dist/relay/protocol.d.ts.map +1 -1
  229. package/dist/relay/relay-server.d.ts +6 -0
  230. package/dist/relay/relay-server.d.ts.map +1 -1
  231. package/dist/research-WB6BBCDD.js +295 -0
  232. package/dist/research-WB6BBCDD.js.map +1 -0
  233. package/dist/review-BGWVY4RA.js +48 -0
  234. package/dist/review-BGWVY4RA.js.map +1 -0
  235. package/dist/review-desktop-LEORC5VS.js +54 -0
  236. package/dist/review-desktop-LEORC5VS.js.map +1 -0
  237. package/dist/rpc-4TSKSFGC.js +159 -0
  238. package/dist/rpc-4TSKSFGC.js.map +1 -0
  239. package/dist/run-3NBLVWXD.js +180 -0
  240. package/dist/run-3NBLVWXD.js.map +1 -0
  241. package/dist/screencast-start-UZVIT3IN.js +67 -0
  242. package/dist/screencast-start-UZVIT3IN.js.map +1 -0
  243. package/dist/screencast-stop-NOSJSIUO.js +59 -0
  244. package/dist/screencast-stop-NOSJSIUO.js.map +1 -0
  245. package/dist/screenshot-LARG4JQG.js +68 -0
  246. package/dist/screenshot-LARG4JQG.js.map +1 -0
  247. package/dist/scroll-VNFMV6TW.js +84 -0
  248. package/dist/scroll-VNFMV6TW.js.map +1 -0
  249. package/dist/scroll-into-view-VYRT3JPT.js +71 -0
  250. package/dist/scroll-into-view-VYRT3JPT.js.map +1 -0
  251. package/dist/select-KJTUZDVO.js +86 -0
  252. package/dist/select-KJTUZDVO.js.map +1 -0
  253. package/dist/serve-EV7K4HKR.js +498 -0
  254. package/dist/serve-EV7K4HKR.js.map +1 -0
  255. package/dist/shopping-DTXHVQ2X.js +273 -0
  256. package/dist/shopping-DTXHVQ2X.js.map +1 -0
  257. package/dist/skill-lifecycle-5UAZGKSN.js +89 -0
  258. package/dist/skill-lifecycle-5UAZGKSN.js.map +1 -0
  259. package/dist/skills-NSXDX6YM.js +26 -0
  260. package/dist/skills-NSXDX6YM.js.map +1 -0
  261. package/dist/snapshot-3XQMCMRJ.js +113 -0
  262. package/dist/snapshot-3XQMCMRJ.js.map +1 -0
  263. package/dist/status-OXSYA5XD.js +35 -0
  264. package/dist/status-OXSYA5XD.js.map +1 -0
  265. package/dist/status-YUMDP5KY.js +132 -0
  266. package/dist/status-YUMDP5KY.js.map +1 -0
  267. package/dist/status-capabilities-P4KDSE2Y.js +57 -0
  268. package/dist/status-capabilities-P4KDSE2Y.js.map +1 -0
  269. package/dist/text-V3B7UVIH.js +84 -0
  270. package/dist/text-V3B7UVIH.js.map +1 -0
  271. package/dist/tools/deps.d.ts +1 -0
  272. package/dist/tools/deps.d.ts.map +1 -1
  273. package/dist/tools/inspiredesign_run.d.ts.map +1 -1
  274. package/dist/tools/macro_resolve.d.ts.map +1 -1
  275. package/dist/tools/product_video_run.d.ts.map +1 -1
  276. package/dist/tools/research_run.d.ts.map +1 -1
  277. package/dist/tools/shopping_run.d.ts.map +1 -1
  278. package/dist/tools/workflow-output.d.ts +3 -0
  279. package/dist/tools/workflow-output.d.ts.map +1 -0
  280. package/dist/type-IYBN3ZLR.js +94 -0
  281. package/dist/type-IYBN3ZLR.js.map +1 -0
  282. package/dist/uncheck-SG737EGI.js +71 -0
  283. package/dist/uncheck-SG737EGI.js.map +1 -0
  284. package/dist/uninstall-KYKGJAX7.js +91 -0
  285. package/dist/uninstall-KYKGJAX7.js.map +1 -0
  286. package/dist/update-SMXPYGXS.js +305 -0
  287. package/dist/update-SMXPYGXS.js.map +1 -0
  288. package/dist/update-skill-modes-BVX7IVMW.js +38 -0
  289. package/dist/update-skill-modes-BVX7IVMW.js.map +1 -0
  290. package/dist/upload-KH6ZABJA.js +56 -0
  291. package/dist/upload-KH6ZABJA.js.map +1 -0
  292. package/dist/use-7YDKO3U4.js +63 -0
  293. package/dist/use-7YDKO3U4.js.map +1 -0
  294. package/dist/value-RZBWSKKM.js +71 -0
  295. package/dist/value-RZBWSKKM.js.map +1 -0
  296. package/dist/visible-BSFTAKXR.js +71 -0
  297. package/dist/visible-BSFTAKXR.js.map +1 -0
  298. package/dist/wait-TMTEAYOP.js +109 -0
  299. package/dist/wait-TMTEAYOP.js.map +1 -0
  300. package/dist/windows-HIZ23OHS.js +37 -0
  301. package/dist/windows-HIZ23OHS.js.map +1 -0
  302. package/extension/dist/background.js +99 -22
  303. package/extension/dist/ops/ops-runtime.js +85 -7
  304. package/extension/dist/ops/ops-session-store.js +3 -0
  305. package/extension/dist/ops/target-session-coordinator.js +3 -0
  306. package/extension/dist/services/CDPRouter.js +9 -0
  307. package/extension/manifest.json +1 -1
  308. package/package.json +1 -1
  309. package/skills/opendevbrowser-best-practices/SKILL.md +8 -6
  310. package/skills/opendevbrowser-best-practices/artifacts/skill-runtime-surface-matrix.md +1 -1
  311. package/skills/opendevbrowser-best-practices/scripts/odb-workflow.sh +3 -2
  312. package/skills/opendevbrowser-best-practices/scripts/validator-fixture-cli.sh +39 -2
  313. package/skills/opendevbrowser-research/SKILL.md +64 -12
  314. package/skills/opendevbrowser-research/artifacts/research-workflows.md +56 -19
  315. package/skills/opendevbrowser-research/assets/templates/compact.md +31 -5
  316. package/skills/opendevbrowser-research/assets/templates/context.json +52 -1
  317. package/skills/opendevbrowser-research/assets/templates/report.md +57 -4
  318. package/skills/opendevbrowser-research/examples/sample-input.json +1 -1
  319. package/skills/opendevbrowser-research/examples/sample-output.md +27 -2
  320. package/skills/opendevbrowser-research/scripts/run-research.sh +2 -6
  321. package/skills/opendevbrowser-research/scripts/validate-skill-assets.sh +115 -1
  322. package/dist/chunk-I5ZCOZZV.js.map +0 -1
  323. package/dist/chunk-QVWOPIZJ.js.map +0 -1
  324. package/dist/chunk-T3VVHJTK.js.map +0 -1
  325. /package/dist/{providers-QF2RFB4J.js.map → chunk-RJNI3BHT.js.map} +0 -0
@@ -0,0 +1,144 @@
1
+ // src/extension-extractor.ts
2
+ import { existsSync, mkdirSync, cpSync, readFileSync, writeFileSync, rmSync, renameSync } from "fs";
3
+ import { dirname, join } from "path";
4
+ import { homedir } from "os";
5
+ import { fileURLToPath } from "url";
6
+ var EXTENSION_DIR_NAME = "opendevbrowser";
7
+ var VERSION_FILE = ".version";
8
+ function getConfigDir() {
9
+ return join(homedir(), ".config", "opencode", EXTENSION_DIR_NAME, "extension");
10
+ }
11
+ function getPackageVersion() {
12
+ try {
13
+ const pkgPath = join(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
14
+ const pkg = JSON.parse(readFileSync(pkgPath, "utf-8"));
15
+ return pkg.version || "0.0.0";
16
+ } catch (error) {
17
+ console.warn("[opendevbrowser] Failed to read package.json for extension version:", error);
18
+ return "0.0.0";
19
+ }
20
+ }
21
+ function getInstalledVersion(destDir) {
22
+ try {
23
+ const versionPath = join(destDir, VERSION_FILE);
24
+ if (existsSync(versionPath)) {
25
+ return readFileSync(versionPath, "utf-8").trim();
26
+ }
27
+ } catch (error) {
28
+ console.warn("[opendevbrowser] Failed to read installed extension version:", error);
29
+ }
30
+ return null;
31
+ }
32
+ function getBundledExtensionPath() {
33
+ const candidates = [
34
+ join(dirname(fileURLToPath(import.meta.url)), "..", "extension"),
35
+ join(dirname(fileURLToPath(import.meta.url)), "..", "..", "extension")
36
+ ];
37
+ for (const candidate of candidates) {
38
+ if (existsSync(join(candidate, "manifest.json"))) {
39
+ return candidate;
40
+ }
41
+ }
42
+ return null;
43
+ }
44
+ function isCompleteInstall(dir) {
45
+ const required = ["manifest.json", VERSION_FILE];
46
+ return required.every((file) => existsSync(join(dir, file)));
47
+ }
48
+ function hasRequiredFiles(dir, requiredFiles) {
49
+ return requiredFiles.every((file) => existsSync(join(dir, file)));
50
+ }
51
+ function extractExtension() {
52
+ const bundledPath = getBundledExtensionPath();
53
+ if (!bundledPath) {
54
+ return null;
55
+ }
56
+ const destDir = getConfigDir();
57
+ const currentVersion = getPackageVersion();
58
+ const installedVersion = getInstalledVersion(destDir);
59
+ if (installedVersion === currentVersion && isCompleteInstall(destDir)) {
60
+ return destDir;
61
+ }
62
+ const parentDir = dirname(destDir);
63
+ const stagingDir = join(parentDir, `.opendevbrowser-staging-${process.pid}-${Date.now()}`);
64
+ const backupDir = join(parentDir, `.opendevbrowser-backup-${process.pid}-${Date.now()}`);
65
+ try {
66
+ mkdirSync(stagingDir, { recursive: true });
67
+ const itemsToCopy = ["manifest.json", "popup.html", "canvas.html", "dist", "icons"];
68
+ for (const item of itemsToCopy) {
69
+ const src = join(bundledPath, item);
70
+ const dest = join(stagingDir, item);
71
+ if (existsSync(src)) {
72
+ cpSync(src, dest, { recursive: true, force: true });
73
+ }
74
+ }
75
+ writeFileSync(join(stagingDir, VERSION_FILE), currentVersion, "utf-8");
76
+ if (!isCompleteInstall(stagingDir)) {
77
+ throw new Error("Staging directory incomplete after copy");
78
+ }
79
+ if (existsSync(destDir)) {
80
+ renameSync(destDir, backupDir);
81
+ }
82
+ renameSync(stagingDir, destDir);
83
+ if (existsSync(backupDir)) {
84
+ rmSync(backupDir, { recursive: true, force: true });
85
+ }
86
+ return destDir;
87
+ } catch (error) {
88
+ if (existsSync(backupDir) && !existsSync(destDir)) {
89
+ try {
90
+ renameSync(backupDir, destDir);
91
+ } catch (rollbackError) {
92
+ console.warn(`[opendevbrowser] Warning: Rollback failed for ${backupDir}:`, rollbackError);
93
+ }
94
+ }
95
+ if (existsSync(stagingDir)) {
96
+ try {
97
+ rmSync(stagingDir, { recursive: true, force: true });
98
+ } catch (stagingCleanupError) {
99
+ console.warn(`[opendevbrowser] Warning: Failed to clean up staging directory ${stagingDir}:`, stagingCleanupError);
100
+ }
101
+ }
102
+ if (existsSync(backupDir)) {
103
+ try {
104
+ rmSync(backupDir, { recursive: true, force: true });
105
+ } catch (backupCleanupError) {
106
+ console.warn(`[opendevbrowser] Warning: Failed to clean up backup directory ${backupDir}:`, backupCleanupError);
107
+ }
108
+ }
109
+ throw error;
110
+ }
111
+ }
112
+ function getExtensionPath() {
113
+ const destDir = getConfigDir();
114
+ if (isCompleteInstall(destDir)) {
115
+ return destDir;
116
+ }
117
+ return getBundledExtensionPath();
118
+ }
119
+ function getExtensionRuntimePath(options = {}) {
120
+ const requiredFiles = options.requiredFiles ?? [];
121
+ const destDir = getConfigDir();
122
+ const candidates = [
123
+ options.bundledPath ?? getBundledExtensionPath(),
124
+ options.installedPath ?? (isCompleteInstall(destDir) ? destDir : null)
125
+ ];
126
+ const seen = /* @__PURE__ */ new Set();
127
+ for (const candidate of candidates) {
128
+ if (!candidate || seen.has(candidate)) {
129
+ continue;
130
+ }
131
+ seen.add(candidate);
132
+ if (requiredFiles.length === 0 || hasRequiredFiles(candidate, requiredFiles)) {
133
+ return candidate;
134
+ }
135
+ }
136
+ return null;
137
+ }
138
+
139
+ export {
140
+ extractExtension,
141
+ getExtensionPath,
142
+ getExtensionRuntimePath
143
+ };
144
+ //# sourceMappingURL=chunk-5SWZDVOW.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/extension-extractor.ts"],"sourcesContent":["import { existsSync, mkdirSync, cpSync, readFileSync, writeFileSync, rmSync, renameSync } from \"fs\";\nimport { dirname, join } from \"path\";\nimport { homedir } from \"os\";\nimport { fileURLToPath } from \"url\";\n\nconst EXTENSION_DIR_NAME = \"opendevbrowser\";\nconst VERSION_FILE = \".version\";\n\nexport type ExtensionRuntimePathOptions = {\n requiredFiles?: string[];\n bundledPath?: string | null;\n installedPath?: string | null;\n};\n\nfunction getConfigDir(): string {\n return join(homedir(), \".config\", \"opencode\", EXTENSION_DIR_NAME, \"extension\");\n}\n\nfunction getPackageVersion(): string {\n try {\n const pkgPath = join(dirname(fileURLToPath(import.meta.url)), \"..\", \"package.json\");\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf-8\"));\n return pkg.version || \"0.0.0\";\n } catch (error) {\n console.warn(\"[opendevbrowser] Failed to read package.json for extension version:\", error);\n return \"0.0.0\";\n }\n}\n\nfunction getInstalledVersion(destDir: string): string | null {\n try {\n const versionPath = join(destDir, VERSION_FILE);\n if (existsSync(versionPath)) {\n return readFileSync(versionPath, \"utf-8\").trim();\n }\n } catch (error) {\n console.warn(\"[opendevbrowser] Failed to read installed extension version:\", error);\n }\n return null;\n}\n\nfunction getBundledExtensionPath(): string | null {\n const candidates = [\n join(dirname(fileURLToPath(import.meta.url)), \"..\", \"extension\"),\n join(dirname(fileURLToPath(import.meta.url)), \"..\", \"..\", \"extension\")\n ];\n for (const candidate of candidates) {\n if (existsSync(join(candidate, \"manifest.json\"))) {\n return candidate;\n }\n }\n return null;\n}\n\nfunction isCompleteInstall(dir: string): boolean {\n const required = [\"manifest.json\", VERSION_FILE];\n return required.every(file => existsSync(join(dir, file)));\n}\n\nfunction hasRequiredFiles(dir: string, requiredFiles: string[]): boolean {\n return requiredFiles.every((file) => existsSync(join(dir, file)));\n}\n\nexport function extractExtension(): string | null {\n const bundledPath = getBundledExtensionPath();\n if (!bundledPath) {\n return null;\n }\n\n const destDir = getConfigDir();\n const currentVersion = getPackageVersion();\n const installedVersion = getInstalledVersion(destDir);\n\n // Early return if version matches and installation is complete\n if (installedVersion === currentVersion && isCompleteInstall(destDir)) {\n return destDir;\n }\n\n // Create staging directory (sibling to destDir for same-device rename)\n const parentDir = dirname(destDir);\n const stagingDir = join(parentDir, `.opendevbrowser-staging-${process.pid}-${Date.now()}`);\n const backupDir = join(parentDir, `.opendevbrowser-backup-${process.pid}-${Date.now()}`);\n\n try {\n // Step 1: Copy to staging\n mkdirSync(stagingDir, { recursive: true });\n const itemsToCopy = [\"manifest.json\", \"popup.html\", \"canvas.html\", \"dist\", \"icons\"];\n for (const item of itemsToCopy) {\n const src = join(bundledPath, item);\n const dest = join(stagingDir, item);\n if (existsSync(src)) {\n cpSync(src, dest, { recursive: true, force: true });\n }\n }\n writeFileSync(join(stagingDir, VERSION_FILE), currentVersion, \"utf-8\");\n\n // Step 2: Validate staging is complete\n if (!isCompleteInstall(stagingDir)) {\n throw new Error(\"Staging directory incomplete after copy\");\n }\n\n // Step 3: Atomic swap\n if (existsSync(destDir)) {\n renameSync(destDir, backupDir);\n }\n renameSync(stagingDir, destDir);\n\n // Step 4: Cleanup backup\n if (existsSync(backupDir)) {\n rmSync(backupDir, { recursive: true, force: true });\n }\n\n return destDir;\n } catch (error) {\n // Rollback: restore backup if it exists\n if (existsSync(backupDir) && !existsSync(destDir)) {\n try {\n renameSync(backupDir, destDir);\n } catch (rollbackError) {\n console.warn(`[opendevbrowser] Warning: Rollback failed for ${backupDir}:`, rollbackError);\n }\n }\n // Cleanup staging\n if (existsSync(stagingDir)) {\n try {\n rmSync(stagingDir, { recursive: true, force: true });\n } catch (stagingCleanupError) {\n console.warn(`[opendevbrowser] Warning: Failed to clean up staging directory ${stagingDir}:`, stagingCleanupError);\n }\n }\n // Cleanup backup\n if (existsSync(backupDir)) {\n try {\n rmSync(backupDir, { recursive: true, force: true });\n } catch (backupCleanupError) {\n console.warn(`[opendevbrowser] Warning: Failed to clean up backup directory ${backupDir}:`, backupCleanupError);\n }\n }\n throw error;\n }\n}\n\nexport function getExtensionPath(): string | null {\n const destDir = getConfigDir();\n if (isCompleteInstall(destDir)) {\n return destDir;\n }\n return getBundledExtensionPath();\n}\n\nexport function getExtensionRuntimePath(options: ExtensionRuntimePathOptions = {}): string | null {\n const requiredFiles = options.requiredFiles ?? [];\n const destDir = getConfigDir();\n const candidates = [\n options.bundledPath ?? getBundledExtensionPath(),\n options.installedPath ?? (isCompleteInstall(destDir) ? destDir : null)\n ];\n const seen = new Set<string>();\n for (const candidate of candidates) {\n if (!candidate || seen.has(candidate)) {\n continue;\n }\n seen.add(candidate);\n if (requiredFiles.length === 0 || hasRequiredFiles(candidate, requiredFiles)) {\n return candidate;\n }\n }\n return null;\n}\n"],"mappings":"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","names":[]}
@@ -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":[]}