@xopcai/xopc 0.0.86 → 0.0.88

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 (658) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/feishu/src/adapters/cli-login.js +3 -3
  3. package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -1
  4. package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
  5. package/dist/extensions/feishu/src/workflow-progress.js +1 -1
  6. package/dist/extensions/telegram/src/delivery-chat-id.d.ts +1 -1
  7. package/dist/extensions/telegram/src/delivery-chat-id.js +1 -1
  8. package/dist/extensions/telegram/src/delivery-chat-id.js.map +1 -1
  9. package/dist/extensions/telegram/src/plugin.js +1 -1
  10. package/dist/extensions/telegram/src/routing-integration.js +3 -2
  11. package/dist/extensions/telegram/src/routing-integration.js.map +1 -1
  12. package/dist/extensions/telegram/src/workflow-progress.js +1 -1
  13. package/dist/extensions/telegram/xopc.extension.json +1 -1
  14. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +2 -2
  15. package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -1
  16. package/dist/extensions/weixin/src/api/api.js +3 -3
  17. package/dist/extensions/weixin/src/api/api.js.map +1 -1
  18. package/dist/extensions/weixin/src/auth/accounts.js +12 -12
  19. package/dist/extensions/weixin/src/auth/accounts.js.map +1 -1
  20. package/dist/extensions/weixin/src/cdn/upload.js +1 -1
  21. package/dist/extensions/weixin/src/delivery-to.js +2 -2
  22. package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
  23. package/dist/extensions/weixin/src/media/data-url.js +1 -1
  24. package/dist/extensions/weixin/src/messaging/debug-mode.js +5 -5
  25. package/dist/extensions/weixin/src/messaging/debug-mode.js.map +1 -1
  26. package/dist/extensions/weixin/src/messaging/inbound.js +11 -11
  27. package/dist/extensions/weixin/src/messaging/inbound.js.map +1 -1
  28. package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
  29. package/dist/extensions/weixin/src/plugin.js +1 -1
  30. package/dist/extensions/weixin/src/storage/sync-buf.js +4 -4
  31. package/dist/extensions/weixin/src/storage/sync-buf.js.map +1 -1
  32. package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
  33. package/dist/extensions/weixin/src/workflow-progress.js +1 -1
  34. package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
  35. package/dist/gateway/static/root/assets/agents-CRxETUZx.js +222 -0
  36. package/dist/gateway/static/root/assets/{apps-page-DrfytjOb.js → apps-page-wKWf3l57.js} +1 -1
  37. package/dist/gateway/static/root/assets/channels-settings-DDbqVNkx.js +1 -0
  38. package/dist/gateway/static/root/assets/{channels-status-swr-Bs5kMCMI.js → channels-status-swr-DIsl75Y3.js} +1 -1
  39. package/dist/gateway/static/root/assets/copy-SxMW6Xpc.js +1 -0
  40. package/dist/gateway/static/root/assets/{cron-api-BuVcZ5zR.js → cron-api-N9hvuRrn.js} +1 -1
  41. package/dist/gateway/static/root/assets/{cron-page-BMrloeFH.js → cron-page-tlNGNxhP.js} +1 -1
  42. package/dist/gateway/static/root/assets/{dist-CKU1OOTf.js → dist-CJwfHYvT.js} +1 -1
  43. package/dist/gateway/static/root/assets/{extension-debug-page-BdW_46sN.js → extension-debug-page-BVJohZoZ.js} +1 -1
  44. package/dist/gateway/static/root/assets/{extension-page-DW47KI82.js → extension-page-BT2tmElC.js} +1 -1
  45. package/dist/gateway/static/root/assets/extension-settings-page-BSS47c2j.js +1 -0
  46. package/dist/gateway/static/root/assets/{fetch-B2MYHbWg.js → fetch-BaFNUtkE.js} +1 -1
  47. package/dist/gateway/static/root/assets/{field-primitives-DPG-oJmx.js → field-primitives-QwYEq6Hz.js} +1 -1
  48. package/dist/gateway/static/root/assets/{heartbeat-config-api-C8dNts9i.js → heartbeat-config-api-BVSidEDJ.js} +1 -1
  49. package/dist/gateway/static/root/assets/index-CqZzHNEg.css +1 -0
  50. package/dist/gateway/static/root/assets/{index-BmVYculr.js → index-qNrVJp-y.js} +97 -95
  51. package/dist/gateway/static/root/assets/{logs-page-sTsVWz0X.js → logs-page-DDonPVLn.js} +1 -1
  52. package/dist/gateway/static/root/assets/sessions-page-DKt-Wmib.js +1 -0
  53. package/dist/gateway/static/root/assets/{settings-form-section-DuvRQW--.js → settings-form-section-B8N3A3Zo.js} +1 -1
  54. package/dist/gateway/static/root/assets/settings-page-DcJjvvw4.js +3 -0
  55. package/dist/gateway/static/root/assets/{share-preview-page-BtG2kLDh.js → share-preview-page-Q7KqkO-u.js} +1 -1
  56. package/dist/gateway/static/root/assets/skills-page-DuJ4BTO3.js +2 -0
  57. package/dist/gateway/static/root/assets/{theme-store-DryYl3qD.js → theme-store-BbRc5ugR.js} +1 -1
  58. package/dist/gateway/static/root/assets/url-D6jvVYIA.js +7 -0
  59. package/dist/gateway/static/root/assets/{utils-BY7bU1DT.js → utils-CxDGduqK.js} +1 -1
  60. package/dist/gateway/static/root/assets/voice-api-key-field-CTyHz7L_.js +1 -0
  61. package/dist/gateway/static/root/assets/workflows-page-GacJ41Fv.js +27 -0
  62. package/dist/gateway/static/root/index.html +6 -5
  63. package/dist/package.js +1 -1
  64. package/dist/src/agent/agent-manager.js +7 -7
  65. package/dist/src/agent/agent-scope.d.ts +4 -0
  66. package/dist/src/agent/agent-scope.js +53 -10
  67. package/dist/src/agent/agent-scope.js.map +1 -1
  68. package/dist/src/agent/bootstrap/filter-bootstrap-files.js +2 -1
  69. package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
  70. package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
  71. package/dist/src/agent/child-agent-factory.d.ts +15 -0
  72. package/dist/src/agent/child-agent-factory.js +35 -2
  73. package/dist/src/agent/child-agent-factory.js.map +1 -1
  74. package/dist/src/agent/client-error-format.d.ts +20 -0
  75. package/dist/src/agent/client-error-format.js +97 -0
  76. package/dist/src/agent/client-error-format.js.map +1 -0
  77. package/dist/src/agent/context/workspace-seed.js +2 -2
  78. package/dist/src/agent/embedded/run-turn.js +23 -4
  79. package/dist/src/agent/embedded/run-turn.js.map +1 -1
  80. package/dist/src/agent/embedded/session-tool-result-guard.js +2 -1
  81. package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
  82. package/dist/src/agent/embedded/tool-result-truncation.js +2 -1
  83. package/dist/src/agent/embedded/tool-result-truncation.js.map +1 -1
  84. package/dist/src/agent/fallback/candidates.js +2 -2
  85. package/dist/src/agent/fallback/candidates.js.map +1 -1
  86. package/dist/src/agent/goals/goal-locale.d.ts +1 -1
  87. package/dist/src/agent/goals/goal-run-store.js +4 -4
  88. package/dist/src/agent/goals/persistent-goal-apis.d.ts +0 -2
  89. package/dist/src/agent/goals/persistent-goal-service.js +1 -2
  90. package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
  91. package/dist/src/agent/goals/post-turn.js +2 -2
  92. package/dist/src/agent/image/generation/normalization.js +2 -12
  93. package/dist/src/agent/image/generation/normalization.js.map +1 -1
  94. package/dist/src/agent/image/generation/provider-registry.d.ts +4 -8
  95. package/dist/src/agent/image/generation/provider-registry.js.map +1 -1
  96. package/dist/src/agent/image/generation/runtime.d.ts +2 -2
  97. package/dist/src/agent/image/generation/runtime.js.map +1 -1
  98. package/dist/src/agent/image/generation/types.d.ts +0 -18
  99. package/dist/src/agent/image/image-helpers.js +6 -1
  100. package/dist/src/agent/image/image-helpers.js.map +1 -1
  101. package/dist/src/agent/image/index.d.ts +1 -1
  102. package/dist/src/agent/image/load-image-media.js +2 -2
  103. package/dist/src/agent/inbound/inbound-loop.d.ts +5 -0
  104. package/dist/src/agent/inbound/inbound-loop.js +41 -10
  105. package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
  106. package/dist/src/agent/inbound/turn-dispatcher.d.ts +4 -0
  107. package/dist/src/agent/inbound/turn-dispatcher.js +7 -5
  108. package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
  109. package/dist/src/agent/ipc/bus.js +1 -1
  110. package/dist/src/agent/ipc/inbox.js +2 -2
  111. package/dist/src/agent/ipc/socket.js +1 -1
  112. package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -1
  113. package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
  114. package/dist/src/agent/mcp/bundle-mcp-names.js +2 -1
  115. package/dist/src/agent/mcp/bundle-mcp-names.js.map +1 -1
  116. package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -1
  117. package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
  118. package/dist/src/agent/mcp/mcp-transport-config.js +2 -1
  119. package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
  120. package/dist/src/agent/mcp/mcp-transport.js +2 -1
  121. package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
  122. package/dist/src/agent/media-generation/runtime-shared.js +2 -9
  123. package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
  124. package/dist/src/agent/memory/builtin-memory-store.js +1 -1
  125. package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
  126. package/dist/src/agent/memory/dreaming/events.js +1 -1
  127. package/dist/src/agent/memory/dreaming/last-run.js +1 -1
  128. package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
  129. package/dist/src/agent/memory/dreaming/preview.js +1 -1
  130. package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
  131. package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
  132. package/dist/src/agent/memory/dreaming/utils.js +1 -1
  133. package/dist/src/agent/memory/plugin-discovery.js +1 -1
  134. package/dist/src/agent/messaging/command-handler.d.ts +6 -0
  135. package/dist/src/agent/messaging/command-handler.js +5 -0
  136. package/dist/src/agent/messaging/command-handler.js.map +1 -1
  137. package/dist/src/agent/models/manager.js +1 -1
  138. package/dist/src/agent/orchestration/llm-turn-retry.d.ts +2 -0
  139. package/dist/src/agent/orchestration/llm-turn-retry.js +9 -1
  140. package/dist/src/agent/orchestration/llm-turn-retry.js.map +1 -1
  141. package/dist/src/agent/prompt/safety.d.ts +0 -7
  142. package/dist/src/agent/prompt/safety.js +1 -20
  143. package/dist/src/agent/prompt/safety.js.map +1 -1
  144. package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
  145. package/dist/src/agent/reply/post-compaction-context.js +1 -1
  146. package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
  147. package/dist/src/agent/sandbox/path-policy.js +2 -2
  148. package/dist/src/agent/service/build-direct-message-content.js +2 -2
  149. package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
  150. package/dist/src/agent/service/direct-turn-helpers.d.ts +3 -1
  151. package/dist/src/agent/service/direct-turn-helpers.js +6 -1
  152. package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
  153. package/dist/src/agent/service/process-direct-one-shot.d.ts +4 -0
  154. package/dist/src/agent/service/process-direct-one-shot.js +15 -2
  155. package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
  156. package/dist/src/agent/service/process-direct-streaming.d.ts +4 -0
  157. package/dist/src/agent/service/process-direct-streaming.js +53 -7
  158. package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
  159. package/dist/src/agent/service/webchat-tts.d.ts +1 -2
  160. package/dist/src/agent/service/webchat-tts.js +2 -2
  161. package/dist/src/agent/service/webchat-tts.js.map +1 -1
  162. package/dist/src/agent/service.d.ts +8 -0
  163. package/dist/src/agent/service.js +25 -5
  164. package/dist/src/agent/service.js.map +1 -1
  165. package/dist/src/agent/session/session-inspector.js +1 -1
  166. package/dist/src/agent/skills/config.js +1 -1
  167. package/dist/src/agent/skills/hub-hash.js +2 -2
  168. package/dist/src/agent/skills/hub-lock.js +1 -1
  169. package/dist/src/agent/skills/hub-pull.js +2 -2
  170. package/dist/src/agent/skills/index.js +1 -1
  171. package/dist/src/agent/skills/managed-store.js +1 -1
  172. package/dist/src/agent/skills/scanner.js +1 -1
  173. package/dist/src/agent/skills/skill-manage-ops.js +1 -1
  174. package/dist/src/agent/skills/skill-manager.js +1 -1
  175. package/dist/src/agent/tools/create-share-tool.js +27 -20
  176. package/dist/src/agent/tools/create-share-tool.js.map +1 -1
  177. package/dist/src/agent/tools/dreaming-tool.js +1 -1
  178. package/dist/src/agent/tools/factory.js +2 -2
  179. package/dist/src/agent/tools/image-generate-tool.js +1 -1
  180. package/dist/src/agent/tools/index.d.ts +0 -1
  181. package/dist/src/agent/tools/index.js +4 -5
  182. package/dist/src/agent/tools/send-media.js +1 -1
  183. package/dist/src/agent/tools/shell.js +0 -13
  184. package/dist/src/agent/tools/shell.js.map +1 -1
  185. package/dist/src/agent/tools/skill-manage-tool.js +1 -1
  186. package/dist/src/agent/tools/workflow-tool.js +70 -16
  187. package/dist/src/agent/tools/workflow-tool.js.map +1 -1
  188. package/dist/src/agent/tools/write.js +1 -1
  189. package/dist/src/agent/workflow/agent-progress.d.ts +5 -0
  190. package/dist/src/agent/workflow/agent-progress.js +65 -0
  191. package/dist/src/agent/workflow/agent-progress.js.map +1 -0
  192. package/dist/src/agent/workflow/builtins/audit-repo.d.ts +1 -1
  193. package/dist/src/agent/workflow/builtins/audit-repo.js +14 -0
  194. package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -1
  195. package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
  196. package/dist/src/agent/workflow/builtins/debug-incident.js +14 -0
  197. package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
  198. package/dist/src/agent/workflow/builtins/implementation-plan.d.ts +12 -0
  199. package/dist/src/agent/workflow/builtins/implementation-plan.js +175 -0
  200. package/dist/src/agent/workflow/builtins/implementation-plan.js.map +1 -0
  201. package/dist/src/agent/workflow/builtins/index.d.ts +3 -1
  202. package/dist/src/agent/workflow/builtins/index.js +11 -1
  203. package/dist/src/agent/workflow/builtins/index.js.map +1 -1
  204. package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +1 -1
  205. package/dist/src/agent/workflow/builtins/multi-perspective-review.js +14 -0
  206. package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -1
  207. package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
  208. package/dist/src/agent/workflow/builtins/pr-review.js +14 -0
  209. package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
  210. package/dist/src/agent/workflow/builtins/release-check.d.ts +11 -0
  211. package/dist/src/agent/workflow/builtins/release-check.js +165 -0
  212. package/dist/src/agent/workflow/builtins/release-check.js.map +1 -0
  213. package/dist/src/agent/workflow/builtins/research.d.ts +1 -1
  214. package/dist/src/agent/workflow/builtins/research.js +14 -0
  215. package/dist/src/agent/workflow/builtins/research.js.map +1 -1
  216. package/dist/src/agent/workflow/catalog.js +1 -1
  217. package/dist/src/agent/workflow/channel-capability.d.ts +3 -3
  218. package/dist/src/agent/workflow/index.d.ts +2 -1
  219. package/dist/src/agent/workflow/index.js +3 -2
  220. package/dist/src/agent/workflow/lint.d.ts +38 -0
  221. package/dist/src/agent/workflow/lint.js +74 -0
  222. package/dist/src/agent/workflow/lint.js.map +1 -0
  223. package/dist/src/agent/workflow/meta-locale.d.ts +12 -0
  224. package/dist/src/agent/workflow/meta-locale.js +62 -0
  225. package/dist/src/agent/workflow/meta-locale.js.map +1 -0
  226. package/dist/src/agent/workflow/parser.js +7 -1
  227. package/dist/src/agent/workflow/parser.js.map +1 -1
  228. package/dist/src/agent/workflow/runtime.d.ts +4 -1
  229. package/dist/src/agent/workflow/runtime.js +88 -8
  230. package/dist/src/agent/workflow/runtime.js.map +1 -1
  231. package/dist/src/agent/workflow/snapshot.js +2 -12
  232. package/dist/src/agent/workflow/snapshot.js.map +1 -1
  233. package/dist/src/agent/workflow/step-labels.d.ts +8 -0
  234. package/dist/src/agent/workflow/step-labels.js +48 -0
  235. package/dist/src/agent/workflow/step-labels.js.map +1 -0
  236. package/dist/src/agent/workflow/subagent-runner.js +46 -1
  237. package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
  238. package/dist/src/agent/workflow/types.d.ts +76 -1
  239. package/dist/src/auth/credentials.d.ts +5 -0
  240. package/dist/src/auth/credentials.js +12 -3
  241. package/dist/src/auth/credentials.js.map +1 -1
  242. package/dist/src/auth/profiles/store.js +1 -1
  243. package/dist/src/auth/sync-provider-auth.js +1 -1
  244. package/dist/src/browser/cache-dir-policy.js +1 -1
  245. package/dist/src/browser/cdp-local-launcher.js +2 -2
  246. package/dist/src/browser/index.js +4 -4
  247. package/dist/src/browser/manager.d.ts +1 -3
  248. package/dist/src/browser/manager.js +0 -6
  249. package/dist/src/browser/manager.js.map +1 -1
  250. package/dist/src/browser/providers/browser-ext-install.d.ts +4 -4
  251. package/dist/src/browser/providers/browser-ext-install.js +41 -88
  252. package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
  253. package/dist/src/browser/providers/cloakbrowser.d.ts +0 -5
  254. package/dist/src/browser/providers/cloakbrowser.js +6 -59
  255. package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
  256. package/dist/src/browser/providers/playwright-doctor.js +1 -1
  257. package/dist/src/browser/stealth.js +1 -1
  258. package/dist/src/channels/attachments/inbound-persist.js +1 -1
  259. package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
  260. package/dist/src/channels/attachments/voice-stt-webchat.js +10 -8
  261. package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
  262. package/dist/src/channels/outbound/persist-store.js +1 -1
  263. package/dist/src/channels/pairing/allow-from-file.js +9 -9
  264. package/dist/src/channels/pairing/allow-from-file.js.map +1 -1
  265. package/dist/src/channels/pairing/pairing-store.js +7 -7
  266. package/dist/src/channels/pairing/pairing-store.js.map +1 -1
  267. package/dist/src/chat-commands/builtins/config.js +2 -2
  268. package/dist/src/chat-commands/builtins/session.js +1 -1
  269. package/dist/src/chat-commands/builtins/session.js.map +1 -1
  270. package/dist/src/chat-commands/builtins/tts.js +2 -2
  271. package/dist/src/chat-commands/builtins/tts.js.map +1 -1
  272. package/dist/src/chat-commands/context.d.ts +3 -0
  273. package/dist/src/chat-commands/context.js +22 -4
  274. package/dist/src/chat-commands/context.js.map +1 -1
  275. package/dist/src/chat-commands/session-key.d.ts +4 -37
  276. package/dist/src/chat-commands/session-key.js +49 -85
  277. package/dist/src/chat-commands/session-key.js.map +1 -1
  278. package/dist/src/chat-commands/types.d.ts +2 -0
  279. package/dist/src/cli/commands/agent/interactive.js +2 -2
  280. package/dist/src/cli/commands/agent/interactive.js.map +1 -1
  281. package/dist/src/cli/commands/agent/sessions.js +2 -2
  282. package/dist/src/cli/commands/agent/sessions.js.map +1 -1
  283. package/dist/src/cli/commands/agent.js +4 -5
  284. package/dist/src/cli/commands/agent.js.map +1 -1
  285. package/dist/src/cli/commands/channels.js +1 -5
  286. package/dist/src/cli/commands/channels.js.map +1 -1
  287. package/dist/src/cli/commands/config.js +1 -1
  288. package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
  289. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  290. package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
  291. package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
  292. package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
  293. package/dist/src/cli/commands/extension-dev.js +1 -1
  294. package/dist/src/cli/commands/extension-marketplace.js +1 -1
  295. package/dist/src/cli/commands/extension-pack.js +1 -1
  296. package/dist/src/cli/commands/gateway/lifecycle-core.js +1 -1
  297. package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
  298. package/dist/src/cli/commands/gateway/logs.d.ts +9 -0
  299. package/dist/src/cli/commands/gateway/logs.js +50 -17
  300. package/dist/src/cli/commands/gateway/logs.js.map +1 -1
  301. package/dist/src/cli/commands/image.js +23 -22
  302. package/dist/src/cli/commands/image.js.map +1 -1
  303. package/dist/src/cli/commands/init.js +4 -4
  304. package/dist/src/cli/commands/onboard.js +1 -1
  305. package/dist/src/cli/commands/session/utils.js +2 -2
  306. package/dist/src/cli/commands/session/utils.js.map +1 -1
  307. package/dist/src/cli/commands/update.js +26 -46
  308. package/dist/src/cli/commands/update.js.map +1 -1
  309. package/dist/src/cli/utils/init-workspace-core.js +2 -2
  310. package/dist/src/cli/utils/session.d.ts +0 -5
  311. package/dist/src/cli/utils/session.js +1 -6
  312. package/dist/src/cli/utils/session.js.map +1 -1
  313. package/dist/src/commands/agents.config.js +1 -1
  314. package/dist/src/commands/agents.config.js.map +1 -1
  315. package/dist/src/config/agent-profile.js +6 -28
  316. package/dist/src/config/agent-profile.js.map +1 -1
  317. package/dist/src/config/agent-typed-models.d.ts +18 -0
  318. package/dist/src/config/agent-typed-models.js +53 -0
  319. package/dist/src/config/agent-typed-models.js.map +1 -0
  320. package/dist/src/config/gateway-bind.js +1 -1
  321. package/dist/src/config/index.js +6 -6
  322. package/dist/src/config/loader.js +2 -2
  323. package/dist/src/config/model-input.js +2 -5
  324. package/dist/src/config/model-input.js.map +1 -1
  325. package/dist/src/config/models-json.js +2 -2
  326. package/dist/src/config/paths-state.js +1 -1
  327. package/dist/src/config/profile.js +2 -2
  328. package/dist/src/config/schema.d.ts +253 -217
  329. package/dist/src/config/schema.js +91 -40
  330. package/dist/src/config/schema.js.map +1 -1
  331. package/dist/src/config/voice.d.ts +3 -28
  332. package/dist/src/config/voice.js +27 -261
  333. package/dist/src/config/voice.js.map +1 -1
  334. package/dist/src/config/workspace-path-helpers.d.ts +1 -2
  335. package/dist/src/config/workspace-path-helpers.js.map +1 -1
  336. package/dist/src/config/workspace-path.js +1 -1
  337. package/dist/src/cron/executor.js +2 -2
  338. package/dist/src/cron/persistence.js +1 -1
  339. package/dist/src/cron/run-log-store.js +1 -1
  340. package/dist/src/daemon/constants.js +1 -1
  341. package/dist/src/daemon/install-plan.js +27 -3
  342. package/dist/src/daemon/install-plan.js.map +1 -1
  343. package/dist/src/daemon/launchd.d.ts +8 -0
  344. package/dist/src/daemon/launchd.js +7 -14
  345. package/dist/src/daemon/launchd.js.map +1 -1
  346. package/dist/src/daemon/schtasks.d.ts +25 -0
  347. package/dist/src/daemon/schtasks.js +168 -48
  348. package/dist/src/daemon/schtasks.js.map +1 -1
  349. package/dist/src/daemon/service.js +5 -4
  350. package/dist/src/daemon/service.js.map +1 -1
  351. package/dist/src/daemon/systemd.d.ts +6 -0
  352. package/dist/src/daemon/systemd.js +20 -5
  353. package/dist/src/daemon/systemd.js.map +1 -1
  354. package/dist/src/extensions/activation-context.js +0 -1
  355. package/dist/src/extensions/activation-context.js.map +1 -1
  356. package/dist/src/extensions/bundle-mcp.js +1 -1
  357. package/dist/src/extensions/discover-extensions.js +1 -1
  358. package/dist/src/extensions/health.js +1 -1
  359. package/dist/src/extensions/loader.js +1 -1
  360. package/dist/src/extensions/lockfile.js +2 -2
  361. package/dist/src/extensions/normalize-manifest.js +0 -1
  362. package/dist/src/extensions/normalize-manifest.js.map +1 -1
  363. package/dist/src/extensions/types/manifest.d.ts +0 -2
  364. package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
  365. package/dist/src/gateway/agent-builtin-tools.js +1 -0
  366. package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
  367. package/dist/src/gateway/agents-admin.d.ts +9 -0
  368. package/dist/src/gateway/agents-admin.js +28 -4
  369. package/dist/src/gateway/agents-admin.js.map +1 -1
  370. package/dist/src/gateway/config-tools-web.js +3 -2
  371. package/dist/src/gateway/config-tools-web.js.map +1 -1
  372. package/dist/src/gateway/file-path-classifier.js +2 -2
  373. package/dist/src/gateway/heartbeat/service.js +2 -2
  374. package/dist/src/gateway/heartbeat/service.js.map +1 -1
  375. package/dist/src/gateway/hono/app.js +1 -1
  376. package/dist/src/gateway/hono/lib/agent-model.d.ts +25 -10
  377. package/dist/src/gateway/hono/lib/agent-model.js +60 -36
  378. package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
  379. package/dist/src/gateway/hono/lib/config-payload.js +29 -6
  380. package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
  381. package/dist/src/gateway/hono/lib/extension-store.js +2 -2
  382. package/dist/src/gateway/hono/lib/mask-secret-length.d.ts +6 -0
  383. package/dist/src/gateway/hono/lib/mask-secret-length.js +16 -0
  384. package/dist/src/gateway/hono/lib/mask-secret-length.js.map +1 -0
  385. package/dist/src/gateway/hono/lib/safe-providers-config.d.ts +1 -1
  386. package/dist/src/gateway/hono/lib/safe-providers-config.js +2 -1
  387. package/dist/src/gateway/hono/lib/safe-providers-config.js.map +1 -1
  388. package/dist/src/gateway/hono/lib/safe-voice-config.js +16 -54
  389. package/dist/src/gateway/hono/lib/safe-voice-config.js.map +1 -1
  390. package/dist/src/gateway/hono/lib/static-ui.js +2 -2
  391. package/dist/src/gateway/hono/oauth.js +1 -1
  392. package/dist/src/gateway/hono/routes/agents.js +2 -2
  393. package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
  394. package/dist/src/gateway/hono/routes/config-patch/agents.js +25 -7
  395. package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
  396. package/dist/src/gateway/hono/routes/config-patch/channels.js +0 -11
  397. package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
  398. package/dist/src/gateway/hono/routes/config-patch/gateway.js +3 -2
  399. package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
  400. package/dist/src/gateway/hono/routes/config-patch/misc.js +8 -3
  401. package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
  402. package/dist/src/gateway/hono/routes/config.js +59 -0
  403. package/dist/src/gateway/hono/routes/config.js.map +1 -1
  404. package/dist/src/gateway/hono/routes/dreaming.js +1 -1
  405. package/dist/src/gateway/hono/routes/goals.js +1 -1
  406. package/dist/src/gateway/hono/routes/goals.js.map +1 -1
  407. package/dist/src/gateway/hono/routes/host-fs.js +2 -2
  408. package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
  409. package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
  410. package/dist/src/gateway/hono/routes/models.js +75 -12
  411. package/dist/src/gateway/hono/routes/models.js.map +1 -1
  412. package/dist/src/gateway/hono/routes/sessions.js +28 -7
  413. package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
  414. package/dist/src/gateway/hono/routes/shares.js +15 -13
  415. package/dist/src/gateway/hono/routes/shares.js.map +1 -1
  416. package/dist/src/gateway/hono/routes/tunnel.js +1 -1
  417. package/dist/src/gateway/hono/routes/update.js +4 -2
  418. package/dist/src/gateway/hono/routes/update.js.map +1 -1
  419. package/dist/src/gateway/hono/routes/voice.js +75 -0
  420. package/dist/src/gateway/hono/routes/voice.js.map +1 -1
  421. package/dist/src/gateway/hono/routes/workflows.d.ts +3 -0
  422. package/dist/src/gateway/hono/routes/workflows.js +347 -0
  423. package/dist/src/gateway/hono/routes/workflows.js.map +1 -0
  424. package/dist/src/gateway/hono/routes/workspace.js +4 -4
  425. package/dist/src/gateway/hono/sse.js +16 -33
  426. package/dist/src/gateway/hono/sse.js.map +1 -1
  427. package/dist/src/gateway/lock.js +11 -11
  428. package/dist/src/gateway/lock.js.map +1 -1
  429. package/dist/src/gateway/ports.js +6 -6
  430. package/dist/src/gateway/ports.js.map +1 -1
  431. package/dist/src/gateway/resolve-webchat-session-key.d.ts +19 -0
  432. package/dist/src/gateway/resolve-webchat-session-key.js +46 -0
  433. package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -0
  434. package/dist/src/gateway/service/agent-runner.js +2 -2
  435. package/dist/src/gateway/service/marketplace-service.js +2 -2
  436. package/dist/src/gateway/service/run-gateway-agent.js +9 -11
  437. package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
  438. package/dist/src/gateway/service/sessions-api.d.ts +3 -0
  439. package/dist/src/gateway/service/sessions-api.js +8 -0
  440. package/dist/src/gateway/service/sessions-api.js.map +1 -1
  441. package/dist/src/gateway/service.d.ts +3 -2
  442. package/dist/src/gateway/service.js +9 -8
  443. package/dist/src/gateway/service.js.map +1 -1
  444. package/dist/src/gateway/session-reset-service.d.ts +20 -0
  445. package/dist/src/gateway/session-reset-service.js +54 -0
  446. package/dist/src/gateway/session-reset-service.js.map +1 -0
  447. package/dist/src/gateway/startup-readiness.d.ts +1 -1
  448. package/dist/src/gateway/startup-readiness.js +1 -0
  449. package/dist/src/gateway/startup-readiness.js.map +1 -1
  450. package/dist/src/gateway/workspace-fs-file-list.js +1 -1
  451. package/dist/src/heartbeat/index.js +1 -1
  452. package/dist/src/infra/gateway-processes.js +2 -2
  453. package/dist/src/infra/gateway-processes.js.map +1 -1
  454. package/dist/src/infra/restart.js +2 -2
  455. package/dist/src/infra/run-command.d.ts +16 -0
  456. package/dist/src/infra/run-command.js +67 -0
  457. package/dist/src/infra/run-command.js.map +1 -0
  458. package/dist/src/infra/update-check.js +1 -1
  459. package/dist/src/infra/update-global.d.ts +45 -0
  460. package/dist/src/infra/update-global.js +224 -0
  461. package/dist/src/infra/update-global.js.map +1 -0
  462. package/dist/src/infra/update-lock.js +3 -3
  463. package/dist/src/infra/update-runner.js +1 -1
  464. package/dist/src/infra/update-startup.js +2 -2
  465. package/dist/src/infra/write-file-atomic.js +2 -2
  466. package/dist/src/mcp/channel-shared.js +2 -1
  467. package/dist/src/mcp/channel-shared.js.map +1 -1
  468. package/dist/src/providers/auth-runtime/auth-profile-store.js +2 -2
  469. package/dist/src/providers/auth-runtime/auth-profile-store.js.map +1 -1
  470. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -12
  471. package/dist/src/providers/auth-runtime/resolve-auth.js.map +1 -1
  472. package/dist/src/providers/auth-runtime/types.d.ts +6 -12
  473. package/dist/src/providers/index.js +2 -2
  474. package/dist/src/providers/model-registry.js +1 -1
  475. package/dist/src/routing/agent-session-key.d.ts +58 -0
  476. package/dist/src/routing/agent-session-key.js +164 -0
  477. package/dist/src/routing/agent-session-key.js.map +1 -0
  478. package/dist/src/routing/index.d.ts +1 -1
  479. package/dist/src/routing/index.js +4 -2
  480. package/dist/src/routing/index.js.map +1 -1
  481. package/dist/src/routing/resolve-route.d.ts +15 -0
  482. package/dist/src/routing/resolve-route.js +41 -20
  483. package/dist/src/routing/resolve-route.js.map +1 -1
  484. package/dist/src/routing/resolve-tui-session-key.d.ts +25 -0
  485. package/dist/src/routing/resolve-tui-session-key.js +54 -0
  486. package/dist/src/routing/resolve-tui-session-key.js.map +1 -0
  487. package/dist/src/routing/session-key-utils.d.ts +24 -0
  488. package/dist/src/routing/session-key-utils.js +92 -0
  489. package/dist/src/routing/session-key-utils.js.map +1 -0
  490. package/dist/src/routing/session-key.d.ts +19 -49
  491. package/dist/src/routing/session-key.js +143 -116
  492. package/dist/src/routing/session-key.js.map +1 -1
  493. package/dist/src/session/config-store.js +2 -2
  494. package/dist/src/session/index.d.ts +6 -0
  495. package/dist/src/session/index.js +7 -1
  496. package/dist/src/session/init-session-turn.d.ts +30 -0
  497. package/dist/src/session/init-session-turn.js +102 -0
  498. package/dist/src/session/init-session-turn.js.map +1 -0
  499. package/dist/src/session/lifecycle-timestamps.d.ts +8 -0
  500. package/dist/src/session/lifecycle-timestamps.js +16 -0
  501. package/dist/src/session/lifecycle-timestamps.js.map +1 -0
  502. package/dist/src/session/manager.d.ts +7 -1
  503. package/dist/src/session/manager.js +8 -1
  504. package/dist/src/session/manager.js.map +1 -1
  505. package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
  506. package/dist/src/session/parity/sessions-json-file.js +1 -1
  507. package/dist/src/session/parity/transcript-file-lock.js +2 -2
  508. package/dist/src/session/parity/transcript-paths.js +2 -2
  509. package/dist/src/session/parity/transcript-paths.js.map +1 -1
  510. package/dist/src/session/parity/xopc-session-disk-entry.d.ts +6 -0
  511. package/dist/src/session/reset-policy.d.ts +32 -0
  512. package/dist/src/session/reset-policy.js +65 -0
  513. package/dist/src/session/reset-policy.js.map +1 -0
  514. package/dist/src/session/reset-triggers.d.ts +20 -0
  515. package/dist/src/session/reset-triggers.js +63 -0
  516. package/dist/src/session/reset-triggers.js.map +1 -0
  517. package/dist/src/session/reset-type.d.ts +12 -0
  518. package/dist/src/session/reset-type.js +25 -0
  519. package/dist/src/session/reset-type.js.map +1 -0
  520. package/dist/src/session/resolve-session.d.ts +30 -0
  521. package/dist/src/session/resolve-session.js +93 -0
  522. package/dist/src/session/resolve-session.js.map +1 -0
  523. package/dist/src/session/search-index-cache.js +1 -1
  524. package/dist/src/session/search-index.js +1 -1
  525. package/dist/src/session/session-title.js +3 -2
  526. package/dist/src/session/session-title.js.map +1 -1
  527. package/dist/src/session/store.d.ts +11 -4
  528. package/dist/src/session/store.js +62 -11
  529. package/dist/src/session/store.js.map +1 -1
  530. package/dist/src/session/transcript-events.js +2 -1
  531. package/dist/src/session/transcript-events.js.map +1 -1
  532. package/dist/src/share/share-auto.js +2 -2
  533. package/dist/src/share/share-store.js +3 -3
  534. package/dist/src/share/share-thumbnail.js +2 -2
  535. package/dist/src/share/share-url.d.ts +33 -0
  536. package/dist/src/share/share-url.js +56 -14
  537. package/dist/src/share/share-url.js.map +1 -1
  538. package/dist/src/share/share-zip.js +1 -1
  539. package/dist/src/share/site-share-store.js +3 -3
  540. package/dist/src/share/site-static-serve.js +1 -1
  541. package/dist/src/tui/backends/embedded-backend.js +4 -9
  542. package/dist/src/tui/backends/embedded-backend.js.map +1 -1
  543. package/dist/src/tui/backends/gateway-sse-backend.js +1 -1
  544. package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
  545. package/dist/src/tui/clipboard-image.js +3 -3
  546. package/dist/src/tui/components/chat-log.js +3 -3
  547. package/dist/src/tui/components/chat-log.js.map +1 -1
  548. package/dist/src/tui/theme-manager.js +1 -1
  549. package/dist/src/tui/theme.d.ts +0 -2
  550. package/dist/src/tui/theme.js +1 -3
  551. package/dist/src/tui/theme.js.map +1 -1
  552. package/dist/src/tui/tui-agent-events.js +2 -1
  553. package/dist/src/tui/tui-agent-events.js.map +1 -1
  554. package/dist/src/tui/tui-commands.d.ts +3 -0
  555. package/dist/src/tui/tui-commands.js +45 -10
  556. package/dist/src/tui/tui-commands.js.map +1 -1
  557. package/dist/src/tui/tui-keybindings-file.js +2 -22
  558. package/dist/src/tui/tui-keybindings-file.js.map +1 -1
  559. package/dist/src/tui/tui-scoped-models.js +2 -2
  560. package/dist/src/tui/tui-session-actions.d.ts +28 -0
  561. package/dist/src/tui/tui-session-actions.js +88 -0
  562. package/dist/src/tui/tui-session-actions.js.map +1 -0
  563. package/dist/src/tui/tui-settings.js +1 -1
  564. package/dist/src/tui/tui.js +54 -49
  565. package/dist/src/tui/tui.js.map +1 -1
  566. package/dist/src/tunnel/frpc-binary.js +3 -3
  567. package/dist/src/tunnel/frpc-config.js +1 -1
  568. package/dist/src/tunnel/frpc-extract.js +1 -1
  569. package/dist/src/tunnel/tunnel-state.js +1 -1
  570. package/dist/src/utils/logger/audit.js +1 -1
  571. package/dist/src/utils/logger/log-store.js +1 -1
  572. package/dist/src/utils/logger/rotation.js +1 -1
  573. package/dist/src/utils/string-coerce.d.ts +2 -0
  574. package/dist/src/utils/string-coerce.js +10 -1
  575. package/dist/src/utils/string-coerce.js.map +1 -1
  576. package/dist/src/voice/metadata/builtin.d.ts +2 -0
  577. package/dist/src/voice/metadata/builtin.js +420 -0
  578. package/dist/src/voice/metadata/builtin.js.map +1 -0
  579. package/dist/src/voice/metadata/index.d.ts +4 -0
  580. package/dist/src/voice/metadata/index.js +3 -0
  581. package/dist/src/voice/metadata/registry.d.ts +5 -0
  582. package/dist/src/voice/metadata/registry.js +34 -0
  583. package/dist/src/voice/metadata/registry.js.map +1 -0
  584. package/dist/src/voice/metadata/types.d.ts +41 -0
  585. package/dist/src/voice/metadata/types.js +1 -0
  586. package/dist/src/voice/stt/config-slice.d.ts +2 -5
  587. package/dist/src/voice/stt/config-slice.js +5 -26
  588. package/dist/src/voice/stt/config-slice.js.map +1 -1
  589. package/dist/src/voice/stt/list-providers.d.ts +3 -3
  590. package/dist/src/voice/stt/list-providers.js +41 -6
  591. package/dist/src/voice/stt/list-providers.js.map +1 -1
  592. package/dist/src/voice/stt/types.d.ts +1 -18
  593. package/dist/src/voice/stt/types.js +4 -2
  594. package/dist/src/voice/stt/types.js.map +1 -1
  595. package/dist/src/voice/tts/audio.js +1 -1
  596. package/dist/src/voice/tts/config-slice.d.ts +3 -7
  597. package/dist/src/voice/tts/config-slice.js +7 -38
  598. package/dist/src/voice/tts/config-slice.js.map +1 -1
  599. package/dist/src/voice/tts/list-providers.d.ts +3 -3
  600. package/dist/src/voice/tts/list-providers.js +41 -6
  601. package/dist/src/voice/tts/list-providers.js.map +1 -1
  602. package/dist/src/voice/tts/merge-config.js +2 -48
  603. package/dist/src/voice/tts/merge-config.js.map +1 -1
  604. package/dist/src/voice/tts/providers/alibaba-speech.js +1 -1
  605. package/dist/src/voice/tts/providers/alibaba-speech.js.map +1 -1
  606. package/dist/src/voice/tts/providers/edge-speech.js +2 -2
  607. package/dist/src/voice/tts/types.d.ts +1 -29
  608. package/dist/src/voice/tts/types.js +19 -17
  609. package/dist/src/voice/tts/types.js.map +1 -1
  610. package/dist/src/workflows/domain/command.d.ts +18 -0
  611. package/dist/src/workflows/domain/command.js +1 -0
  612. package/dist/src/workflows/domain/definition.d.ts +62 -0
  613. package/dist/src/workflows/domain/definition.js +1 -0
  614. package/dist/src/workflows/domain/event.d.ts +67 -0
  615. package/dist/src/workflows/domain/event.js +1 -0
  616. package/dist/src/workflows/domain/index.d.ts +5 -0
  617. package/dist/src/workflows/domain/index.js +2 -0
  618. package/dist/src/workflows/domain/result.d.ts +65 -0
  619. package/dist/src/workflows/domain/result.js +1 -0
  620. package/dist/src/workflows/domain/run.d.ts +120 -0
  621. package/dist/src/workflows/domain/run.js +14 -0
  622. package/dist/src/workflows/domain/run.js.map +1 -0
  623. package/dist/src/workflows/engine/index.d.ts +2 -0
  624. package/dist/src/workflows/engine/index.js +3 -0
  625. package/dist/src/workflows/engine/projector.d.ts +3 -0
  626. package/dist/src/workflows/engine/projector.js +205 -0
  627. package/dist/src/workflows/engine/projector.js.map +1 -0
  628. package/dist/src/workflows/engine/workflow-engine.d.ts +31 -0
  629. package/dist/src/workflows/engine/workflow-engine.js +188 -0
  630. package/dist/src/workflows/engine/workflow-engine.js.map +1 -0
  631. package/dist/src/workflows/index.d.ts +6 -0
  632. package/dist/src/workflows/index.js +11 -0
  633. package/dist/src/workflows/runtime/index.d.ts +1 -0
  634. package/dist/src/workflows/runtime/index.js +4 -0
  635. package/dist/src/workflows/runtime/script-runtime.d.ts +3 -0
  636. package/dist/src/workflows/runtime/script-runtime.js +3 -0
  637. package/dist/src/workflows/store/event-store.d.ts +17 -0
  638. package/dist/src/workflows/store/event-store.js +83 -0
  639. package/dist/src/workflows/store/event-store.js.map +1 -0
  640. package/dist/src/workflows/store/paths.d.ts +7 -0
  641. package/dist/src/workflows/store/paths.js +26 -0
  642. package/dist/src/workflows/store/paths.js.map +1 -0
  643. package/dist/src/workflows/store/run-store.d.ts +13 -0
  644. package/dist/src/workflows/store/run-store.js +68 -0
  645. package/dist/src/workflows/store/run-store.js.map +1 -0
  646. package/package.json +5 -8
  647. package/dist/gateway/static/root/assets/agents-mS3_HpRI.js +0 -222
  648. package/dist/gateway/static/root/assets/channels-settings-BG6b9KrW.js +0 -1
  649. package/dist/gateway/static/root/assets/extension-settings-page-B-W4x2xP.js +0 -1
  650. package/dist/gateway/static/root/assets/index-ew_2L2We.css +0 -1
  651. package/dist/gateway/static/root/assets/sessions-page-FaG_Vlkb.js +0 -1
  652. package/dist/gateway/static/root/assets/settings-page-Bet1OerL.js +0 -3
  653. package/dist/gateway/static/root/assets/skills-page-DhUO235y.js +0 -2
  654. package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +0 -3
  655. package/dist/gateway/static/root/assets/voice-api-key-field-CGEydndO.js +0 -1
  656. package/dist/src/agent/tools/browser-legacy-tools.d.ts +0 -17
  657. package/dist/src/agent/tools/browser-legacy-tools.js +0 -766
  658. package/dist/src/agent/tools/browser-legacy-tools.js.map +0 -1
@@ -1,19 +1,19 @@
1
1
  import { PACKAGE_VERSION, init_package_version } from "../../package-version.js";
2
- import { assertCacheDir, init_cache_dir_policy } from "../cache-dir-policy.js";
2
+ import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
3
3
  import { createLogger } from "../../utils/logger/index.js";
4
4
  import { init_logger } from "../../utils/logger.js";
5
5
  import { init_paths, resolveBinDir } from "../../config/paths.js";
6
- import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
6
+ import { assertCacheDir, init_cache_dir_policy } from "../cache-dir-policy.js";
7
7
  import { resolvePackageRoot } from "../../infra/update-check.js";
8
- import { dirname, join } from "node:path";
9
- import { existsSync, mkdirSync, readFileSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
8
+ import { existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
10
9
  import { readFile, readdir, rm } from "node:fs/promises";
10
+ import { dirname, join } from "node:path";
11
11
  import { spawn } from "node:child_process";
12
12
  import { fileURLToPath } from "node:url";
13
13
  //#region src/browser/providers/browser-ext-install.ts
14
14
  /**
15
- * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/{version}/.
16
- * Single version directory per install direct overwrite, no `current` symlink.
15
+ * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.
16
+ * Fixed path gateway upgrades overwrite in place so Chrome sideload paths stay stable.
17
17
  */
18
18
  init_package_version();
19
19
  init_paths();
@@ -22,9 +22,13 @@ init_logger();
22
22
  init_cache_dir_policy();
23
23
  const log = createLogger("BrowserExtInstall");
24
24
  const META_FILENAME = ".meta.json";
25
- const LEGACY_CURRENT_LINK = "current";
26
25
  const STAGING_MAX_AGE_MS = 3600 * 1e3;
27
- const VERSION_DIR_RE = /^\d+\.\d+\.\d+/;
26
+ const INSTALLED_ARTIFACT_NAMES = [
27
+ "manifest.json",
28
+ "popup.html",
29
+ "dist",
30
+ "icons"
31
+ ];
28
32
  const BROWSER_EXT_REQUIRED_FILES = [
29
33
  "manifest.json",
30
34
  "popup.html",
@@ -64,19 +68,10 @@ function browserExtRoot(cacheDir) {
64
68
  function resolveMetaPath(cacheDir) {
65
69
  return join(browserExtRoot(cacheDir), META_FILENAME);
66
70
  }
67
- function resolveVersionDir(cacheDir, version) {
68
- return join(browserExtRoot(cacheDir), version);
69
- }
70
- /** Resolve the installed extension directory (version folder, not a symlink). */
71
- function resolveInstalledExtensionPath(cacheDir, meta) {
72
- if (meta?.installPath && validateBrowserExtLayout(meta.installPath)) return meta.installPath;
73
- const expectedDir = resolveVersionDir(cacheDir, PACKAGE_VERSION);
74
- if (validateBrowserExtLayout(expectedDir)) return expectedDir;
75
- const legacyCurrent = join(browserExtRoot(cacheDir), LEGACY_CURRENT_LINK);
76
- if (existsSync(legacyCurrent)) try {
77
- const real = realpathSync(legacyCurrent);
78
- if (validateBrowserExtLayout(real)) return real;
79
- } catch {}
71
+ /** Resolve the installed extension directory (fixed `browser-ext/` root). */
72
+ function resolveInstalledExtensionPath(cacheDir, _meta) {
73
+ const root = browserExtRoot(cacheDir);
74
+ if (validateBrowserExtLayout(root)) return root;
80
75
  return null;
81
76
  }
82
77
  function walkAncestorsForGitDevBundled(start) {
@@ -150,55 +145,23 @@ async function cleanupStaleStaging(root) {
150
145
  } catch {}
151
146
  }
152
147
  }
153
- /** Remove legacy `current` link only (safe before a fresh install). */
154
- function removeLegacyCurrentLink(root) {
155
- const legacyCurrent = join(root, LEGACY_CURRENT_LINK);
156
- if (!existsSync(legacyCurrent)) return;
157
- rmSync(legacyCurrent, {
148
+ function removeInstalledArtifacts(root) {
149
+ for (const name of INSTALLED_ARTIFACT_NAMES) {
150
+ const full = join(root, name);
151
+ if (existsSync(full)) rmSync(full, {
152
+ recursive: true,
153
+ force: true
154
+ });
155
+ }
156
+ }
157
+ function promoteStagingToRoot(stagingDir, root) {
158
+ removeInstalledArtifacts(root);
159
+ for (const name of readdirSync(stagingDir)) renameSync(join(stagingDir, name), join(root, name));
160
+ rmSync(stagingDir, {
158
161
  recursive: true,
159
162
  force: true
160
163
  });
161
- log.info("Removed legacy browser-ext/current");
162
- }
163
- async function cleanupSiblingVersionDirs(root, keepVersion) {
164
- if (!existsSync(root)) return;
165
- let entries;
166
- try {
167
- entries = await readdir(root);
168
- } catch {
169
- return;
170
- }
171
- for (const name of entries) {
172
- if (name === META_FILENAME || name.startsWith(".")) continue;
173
- if (name === LEGACY_CURRENT_LINK) {
174
- try {
175
- await rm(join(root, name), {
176
- recursive: true,
177
- force: true
178
- });
179
- } catch (err) {
180
- log.warn({
181
- err,
182
- name
183
- }, "Failed to remove legacy browser extension path");
184
- }
185
- continue;
186
- }
187
- if (!VERSION_DIR_RE.test(name)) continue;
188
- if (name === keepVersion) continue;
189
- try {
190
- await rm(join(root, name), {
191
- recursive: true,
192
- force: true
193
- });
194
- log.info({ version: name }, "Removed old browser extension version directory");
195
- } catch (err) {
196
- log.warn({
197
- err,
198
- version: name
199
- }, "Failed to remove old browser extension version");
200
- }
201
- }
164
+ if (!validateBrowserExtLayout(root)) throw new Error("Bundled browser extension copy failed validation");
202
165
  }
203
166
  /** Copy one bundled file (read/write works when src is inside Electron app.asar). */
204
167
  function copyBundledFile(src, dest) {
@@ -273,45 +236,35 @@ async function ensureBrowserExtensionArtifacts(opts) {
273
236
  installedPath,
274
237
  meta
275
238
  });
276
- const versionKey = bundledManifestVersion;
277
- removeLegacyCurrentLink(root);
278
- if (!needsRefresh && installedPath) {
279
- await cleanupSiblingVersionDirs(root, versionKey);
280
- return {
281
- extensionDir: installedPath,
282
- xopcVersion: PACKAGE_VERSION,
283
- copied: false
284
- };
285
- }
286
- const versionDir = join(root, versionKey);
287
- const stagingDir = join(root, `.staging-${versionKey}-${process.pid}`);
239
+ const extensionDir = root;
240
+ if (!needsRefresh && installedPath) return {
241
+ extensionDir: installedPath,
242
+ xopcVersion: PACKAGE_VERSION,
243
+ copied: false
244
+ };
245
+ const stagingDir = join(root, `.staging-${process.pid}`);
288
246
  if (existsSync(stagingDir)) rmSync(stagingDir, {
289
247
  recursive: true,
290
248
  force: true
291
249
  });
292
250
  copyBundledTree(bundled.dir, stagingDir);
293
- if (existsSync(versionDir)) rmSync(versionDir, {
294
- recursive: true,
295
- force: true
296
- });
297
- renameSync(stagingDir, versionDir);
298
- await cleanupSiblingVersionDirs(root, versionKey);
251
+ promoteStagingToRoot(stagingDir, root);
299
252
  const nextMeta = {
300
253
  xopcVersion: PACKAGE_VERSION,
301
254
  manifestVersion: bundledManifestVersion,
302
255
  source: "bundled",
303
256
  bundledFrom: bundled.bundledFrom,
304
257
  installedAt: (/* @__PURE__ */ new Date()).toISOString(),
305
- installPath: versionDir
258
+ installPath: extensionDir
306
259
  };
307
260
  await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));
308
261
  log.info({
309
- extensionDir: versionDir,
262
+ extensionDir,
310
263
  xopcVersion: PACKAGE_VERSION,
311
264
  bundledFrom: bundled.bundledFrom
312
265
  }, "Browser extension artifacts installed");
313
266
  return {
314
- extensionDir: versionDir,
267
+ extensionDir,
315
268
  xopcVersion: PACKAGE_VERSION,
316
269
  copied: true
317
270
  };
@@ -1 +1 @@
1
- {"version":3,"file":"browser-ext-install.js","names":[],"sources":["../../../../src/browser/providers/browser-ext-install.ts"],"sourcesContent":["/**\n * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/{version}/.\n * Single version directory per install — direct overwrite, no `current` symlink.\n */\n\nimport {\n existsSync,\n mkdirSync,\n readFileSync,\n realpathSync,\n renameSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { readFile, readdir, rm } from 'node:fs/promises';\nimport { spawn } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { resolvePackageRoot } from '../../infra/update-check.js';\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { assertCacheDir } from '../cache-dir-policy.js';\n\nconst log = createLogger('BrowserExtInstall');\n\nconst META_FILENAME = '.meta.json';\nconst LEGACY_CURRENT_LINK = 'current';\nconst STAGING_MAX_AGE_MS = 60 * 60 * 1000;\nconst VERSION_DIR_RE = /^\\d+\\.\\d+\\.\\d+/;\n\nexport const BROWSER_EXT_REQUIRED_FILES = [\n 'manifest.json',\n 'popup.html',\n 'dist/background.js',\n 'dist/content.js',\n 'dist/popup.js',\n] as const;\n\nexport type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';\n\nexport interface BrowserExtInstallMeta {\n xopcVersion: string;\n manifestVersion: string;\n source: 'bundled';\n bundledFrom: BrowserExtBundledFrom;\n installedAt: string;\n installPath: string;\n}\n\nexport interface BrowserExtDoctor {\n bundledAvailable: boolean;\n installed: boolean;\n xopcVersion: string;\n installedVersion?: string;\n manifestVersion?: string;\n extensionDir?: string;\n cacheDir: string;\n needsRefresh: boolean;\n needsChromeReload?: boolean;\n bundledFrom?: BrowserExtBundledFrom;\n runtimeExtensionVersion?: string;\n}\n\nexport interface EnsureBrowserExtResult {\n extensionDir: string;\n xopcVersion: string;\n copied: boolean;\n}\n\nfunction moduleDir(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\n/** Validate a directory contains a loadable extension tree. */\nexport function validateBrowserExtLayout(dir: string): boolean {\n return BROWSER_EXT_REQUIRED_FILES.every((rel) => existsSync(join(dir, rel)));\n}\n\nfunction readManifestVersion(dir: string): string | undefined {\n try {\n const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');\n const parsed = JSON.parse(raw) as { version?: unknown };\n return typeof parsed.version === 'string' ? parsed.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readMeta(metaPath: string): Promise<BrowserExtInstallMeta | null> {\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(raw) as BrowserExtInstallMeta;\n if (parsed && typeof parsed === 'object' && typeof parsed.xopcVersion === 'string') {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction browserExtRoot(cacheDir: string): string {\n return join(cacheDir, 'browser-ext');\n}\n\nfunction resolveMetaPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), META_FILENAME);\n}\n\nfunction resolveVersionDir(cacheDir: string, version: string): string {\n return join(browserExtRoot(cacheDir), version);\n}\n\n/** Resolve the installed extension directory (version folder, not a symlink). */\nexport function resolveInstalledExtensionPath(\n cacheDir: string,\n meta: BrowserExtInstallMeta | null,\n): string | null {\n if (meta?.installPath && validateBrowserExtLayout(meta.installPath)) {\n return meta.installPath;\n }\n\n const expectedDir = resolveVersionDir(cacheDir, PACKAGE_VERSION);\n if (validateBrowserExtLayout(expectedDir)) {\n return expectedDir;\n }\n\n const root = browserExtRoot(cacheDir);\n const legacyCurrent = join(root, LEGACY_CURRENT_LINK);\n if (existsSync(legacyCurrent)) {\n try {\n const real = realpathSync(legacyCurrent);\n if (validateBrowserExtLayout(real)) return real;\n } catch {\n /* legacy path unreadable */\n }\n }\n\n return null;\n}\n\nfunction walkAncestorsForGitDevBundled(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'packages/browser-ext');\n if (validateBrowserExtLayout(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the bundled extension source directory (read-only).\n */\nexport async function resolveBundledBrowserExtDir(): Promise<{\n dir: string;\n bundledFrom: BrowserExtBundledFrom;\n} | null> {\n const envOverride = process.env.XOPC_BROWSER_EXT_BUNDLED_ROOT?.trim();\n if (envOverride && validateBrowserExtLayout(envOverride)) {\n return { dir: envOverride, bundledFrom: 'env-override' };\n }\n\n const fromModule = join(moduleDir(), '../../../browser-ext');\n if (validateBrowserExtLayout(fromModule)) {\n const root = await resolvePackageRoot();\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: fromModule, bundledFrom };\n }\n\n const gitDev = walkAncestorsForGitDevBundled(moduleDir());\n if (gitDev) {\n return { dir: gitDev, bundledFrom: 'git-dev' };\n }\n\n const root = await resolvePackageRoot();\n if (root) {\n const distBundled = join(root, 'dist/browser-ext');\n if (validateBrowserExtLayout(distBundled)) {\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: distBundled, bundledFrom };\n }\n }\n\n return null;\n}\n\nexport function computeNeedsRefresh(params: {\n force?: boolean;\n bundledManifestVersion: string;\n installedPath: string | null;\n meta: BrowserExtInstallMeta | null;\n}): boolean {\n if (params.force) return true;\n if (!params.installedPath || !validateBrowserExtLayout(params.installedPath)) return true;\n\n const installedManifest = readManifestVersion(params.installedPath);\n if (!installedManifest || installedManifest !== params.bundledManifestVersion) return true;\n\n if (!params.meta || params.meta.xopcVersion !== PACKAGE_VERSION) return true;\n\n return false;\n}\n\nasync function cleanupStaleStaging(root: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n const now = Date.now();\n for (const name of entries) {\n if (!name.startsWith('.staging-')) continue;\n const full = join(root, name);\n try {\n const st = statSync(full);\n if (now - st.mtimeMs > STAGING_MAX_AGE_MS) {\n await rm(full, { recursive: true, force: true });\n }\n } catch {\n /* */\n }\n }\n}\n\n/** Remove legacy `current` link only (safe before a fresh install). */\nfunction removeLegacyCurrentLink(root: string): void {\n const legacyCurrent = join(root, LEGACY_CURRENT_LINK);\n if (!existsSync(legacyCurrent)) return;\n rmSync(legacyCurrent, { recursive: true, force: true });\n log.info('Removed legacy browser-ext/current');\n}\n\nasync function cleanupSiblingVersionDirs(root: string, keepVersion: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n for (const name of entries) {\n if (name === META_FILENAME || name.startsWith('.')) continue;\n if (name === LEGACY_CURRENT_LINK) {\n try {\n await rm(join(root, name), { recursive: true, force: true });\n } catch (err) {\n log.warn({ err, name }, 'Failed to remove legacy browser extension path');\n }\n continue;\n }\n if (!VERSION_DIR_RE.test(name)) continue;\n if (name === keepVersion) continue;\n try {\n await rm(join(root, name), { recursive: true, force: true });\n log.info({ version: name }, 'Removed old browser extension version directory');\n } catch (err) {\n log.warn({ err, version: name }, 'Failed to remove old browser extension version');\n }\n }\n}\n\n/** Copy one bundled file (read/write works when src is inside Electron app.asar). */\nfunction copyBundledFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, readFileSync(src));\n}\n\nconst BROWSER_EXT_DIST_FILES = ['background.js', 'content.js', 'popup.js'] as const;\nconst BROWSER_EXT_ICON_FILES = ['icon-16.png', 'icon-32.png', 'icon-48.png', 'icon-128.png'] as const;\n\nfunction copyBundledTree(src: string, dest: string): void {\n mkdirSync(dest, { recursive: true });\n for (const name of ['manifest.json', 'popup.html']) {\n copyBundledFile(join(src, name), join(dest, name));\n }\n for (const file of BROWSER_EXT_DIST_FILES) {\n copyBundledFile(join(src, 'dist', file), join(dest, 'dist', file));\n }\n for (const icon of BROWSER_EXT_ICON_FILES) {\n const iconSrc = join(src, 'icons', icon);\n if (existsSync(iconSrc)) {\n copyBundledFile(iconSrc, join(dest, 'icons', icon));\n }\n }\n if (!validateBrowserExtLayout(dest)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\nexport async function browserExtDoctor(opts?: {\n cacheDir?: string;\n runtimeExtensionVersion?: string;\n}): Promise<BrowserExtDoctor> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n const bundledManifestVersion = bundled ? readManifestVersion(bundled.dir) : undefined;\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n\n const needsRefresh = bundled\n ? computeNeedsRefresh({\n force: false,\n bundledManifestVersion: bundledManifestVersion ?? PACKAGE_VERSION,\n installedPath,\n meta,\n })\n : false;\n\n const installed = Boolean(installedPath) && !needsRefresh;\n const manifestVersion = installedPath ? readManifestVersion(installedPath) : undefined;\n\n let needsChromeReload: boolean | undefined;\n const runtimeVer = opts?.runtimeExtensionVersion?.trim();\n if (runtimeVer && manifestVersion && runtimeVer !== manifestVersion) {\n needsChromeReload = true;\n }\n\n return {\n bundledAvailable: Boolean(bundled),\n installed,\n xopcVersion: PACKAGE_VERSION,\n installedVersion: meta?.xopcVersion,\n manifestVersion,\n extensionDir: installedPath ?? undefined,\n cacheDir,\n needsRefresh,\n needsChromeReload,\n bundledFrom: bundled?.bundledFrom,\n runtimeExtensionVersion: runtimeVer,\n };\n}\n\nexport async function ensureBrowserExtensionArtifacts(opts?: {\n force?: boolean;\n cacheDir?: string;\n}): Promise<EnsureBrowserExtResult> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n if (!bundled) {\n throw new Error(\n 'Bundled browser extension not found. Reinstall xopc or run from a built checkout (pnpm run build).',\n );\n }\n\n const bundledManifestVersion = readManifestVersion(bundled.dir) ?? PACKAGE_VERSION;\n const root = browserExtRoot(cacheDir);\n mkdirSync(root, { recursive: true });\n await cleanupStaleStaging(root);\n\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n const needsRefresh = computeNeedsRefresh({\n force: opts?.force,\n bundledManifestVersion,\n installedPath,\n meta,\n });\n\n const versionKey = bundledManifestVersion;\n removeLegacyCurrentLink(root);\n\n if (!needsRefresh && installedPath) {\n await cleanupSiblingVersionDirs(root, versionKey);\n return {\n extensionDir: installedPath,\n xopcVersion: PACKAGE_VERSION,\n copied: false,\n };\n }\n\n const versionDir = join(root, versionKey);\n const stagingDir = join(root, `.staging-${versionKey}-${process.pid}`);\n\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n copyBundledTree(bundled.dir, stagingDir);\n\n if (existsSync(versionDir)) {\n rmSync(versionDir, { recursive: true, force: true });\n }\n renameSync(stagingDir, versionDir);\n\n await cleanupSiblingVersionDirs(root, versionKey);\n\n const nextMeta: BrowserExtInstallMeta = {\n xopcVersion: PACKAGE_VERSION,\n manifestVersion: bundledManifestVersion,\n source: 'bundled',\n bundledFrom: bundled.bundledFrom,\n installedAt: new Date().toISOString(),\n installPath: versionDir,\n };\n await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));\n\n log.info(\n { extensionDir: versionDir, xopcVersion: PACKAGE_VERSION, bundledFrom: bundled.bundledFrom },\n 'Browser extension artifacts installed',\n );\n\n return {\n extensionDir: versionDir,\n xopcVersion: PACKAGE_VERSION,\n copied: true,\n };\n}\n\n/**\n * Gateway startup hook: ensure artifacts when extension backend is enabled or prior install exists.\n */\nexport async function ensureBrowserExtensionOnStartup(config: {\n agents?: { defaults?: { browser?: { backend?: string } } };\n}): Promise<void> {\n const backend = config.agents?.defaults?.browser?.backend;\n const cacheDir = resolveBinDir();\n const metaExists = existsSync(resolveMetaPath(cacheDir));\n if (backend !== 'extension' && !metaExists) {\n return;\n }\n await ensureBrowserExtensionArtifacts();\n}\n\nexport async function readInstalledExtensionDir(cacheDir?: string): Promise<string | null> {\n const dir = cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir();\n const resolved = dir || resolveBinDir();\n const meta = await readMeta(resolveMetaPath(resolved));\n return resolveInstalledExtensionPath(resolved, meta);\n}\n\nexport type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';\n\nfunction spawnDetached(command: string, args: readonly string[]): void {\n spawn(command, [...args], { stdio: 'ignore', detached: true }).unref();\n}\n\nfunction openChromeExtensionsPage(): void {\n const chromeUrl = 'chrome://extensions';\n if (process.platform === 'darwin') {\n spawnDetached('open', ['-a', 'Google Chrome', chromeUrl]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('cmd', ['/c', 'start', 'chrome', chromeUrl]);\n return;\n }\n spawnDetached('xdg-open', [chromeUrl]);\n}\n\nfunction revealFolderInFileManager(dir: string): void {\n if (process.platform === 'darwin') {\n spawnDetached('open', [dir]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('explorer', [dir]);\n return;\n }\n spawnDetached('xdg-open', [dir]);\n}\n\n/**\n * Open chrome://extensions and/or reveal the installed extension folder on the gateway host.\n */\nexport async function openBrowserExtensionInstallUi(opts: {\n action: BrowserExtensionOpenAction;\n cacheDir?: string;\n}): Promise<{ extensionDir: string }> {\n const doctor = await browserExtDoctor({ cacheDir: opts.cacheDir });\n const dir = doctor.extensionDir;\n if (!dir) {\n throw new Error('Extension not installed. Run xopc browser extension install first.');\n }\n\n if (opts.action === 'chrome' || opts.action === 'both') {\n openChromeExtensionsPage();\n }\n if (opts.action === 'folder' || opts.action === 'both') {\n revealFolderInFileManager(dir);\n }\n\n return { extensionDir: dir };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"browser-ext-install.js","names":[],"sources":["../../../../src/browser/providers/browser-ext-install.ts"],"sourcesContent":["/**\n * Install bundled Chrome extension artifacts into {resolveBinDir()}/browser-ext/.\n * Fixed path — gateway upgrades overwrite in place so Chrome sideload paths stay stable.\n */\n\nimport {\n existsSync,\n mkdirSync,\n readdirSync,\n readFileSync,\n renameSync,\n rmSync,\n statSync,\n writeFileSync,\n} from 'node:fs';\nimport { readFile, readdir, rm } from 'node:fs/promises';\nimport { spawn } from 'node:child_process';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nimport { PACKAGE_VERSION } from '../../package-version.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { resolvePackageRoot } from '../../infra/update-check.js';\nimport { writeTextAtomic } from '../../infra/write-file-atomic.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { assertCacheDir } from '../cache-dir-policy.js';\n\nconst log = createLogger('BrowserExtInstall');\n\nconst META_FILENAME = '.meta.json';\nconst STAGING_MAX_AGE_MS = 60 * 60 * 1000;\nconst INSTALLED_ARTIFACT_NAMES = ['manifest.json', 'popup.html', 'dist', 'icons'] as const;\n\nexport const BROWSER_EXT_REQUIRED_FILES = [\n 'manifest.json',\n 'popup.html',\n 'dist/background.js',\n 'dist/content.js',\n 'dist/popup.js',\n] as const;\n\nexport type BrowserExtBundledFrom = 'npm-dist' | 'git-dev' | 'electron-asar' | 'env-override';\n\nexport interface BrowserExtInstallMeta {\n xopcVersion: string;\n manifestVersion: string;\n source: 'bundled';\n bundledFrom: BrowserExtBundledFrom;\n installedAt: string;\n installPath: string;\n}\n\nexport interface BrowserExtDoctor {\n bundledAvailable: boolean;\n installed: boolean;\n xopcVersion: string;\n installedVersion?: string;\n manifestVersion?: string;\n extensionDir?: string;\n cacheDir: string;\n needsRefresh: boolean;\n needsChromeReload?: boolean;\n bundledFrom?: BrowserExtBundledFrom;\n runtimeExtensionVersion?: string;\n}\n\nexport interface EnsureBrowserExtResult {\n extensionDir: string;\n xopcVersion: string;\n copied: boolean;\n}\n\nfunction moduleDir(): string {\n return dirname(fileURLToPath(import.meta.url));\n}\n\n/** Validate a directory contains a loadable extension tree. */\nexport function validateBrowserExtLayout(dir: string): boolean {\n return BROWSER_EXT_REQUIRED_FILES.every((rel) => existsSync(join(dir, rel)));\n}\n\nfunction readManifestVersion(dir: string): string | undefined {\n try {\n const raw = readFileSync(join(dir, 'manifest.json'), 'utf8');\n const parsed = JSON.parse(raw) as { version?: unknown };\n return typeof parsed.version === 'string' ? parsed.version : undefined;\n } catch {\n return undefined;\n }\n}\n\nasync function readMeta(metaPath: string): Promise<BrowserExtInstallMeta | null> {\n try {\n const raw = await readFile(metaPath, 'utf8');\n const parsed = JSON.parse(raw) as BrowserExtInstallMeta;\n if (parsed && typeof parsed === 'object' && typeof parsed.xopcVersion === 'string') {\n return parsed;\n }\n return null;\n } catch {\n return null;\n }\n}\n\nfunction browserExtRoot(cacheDir: string): string {\n return join(cacheDir, 'browser-ext');\n}\n\nfunction resolveMetaPath(cacheDir: string): string {\n return join(browserExtRoot(cacheDir), META_FILENAME);\n}\n\n/** Resolve the installed extension directory (fixed `browser-ext/` root). */\nexport function resolveInstalledExtensionPath(\n cacheDir: string,\n _meta: BrowserExtInstallMeta | null,\n): string | null {\n const root = browserExtRoot(cacheDir);\n if (validateBrowserExtLayout(root)) {\n return root;\n }\n\n return null;\n}\n\nfunction walkAncestorsForGitDevBundled(start: string): string | null {\n let dir = start;\n for (let i = 0; i < 12; i++) {\n const candidate = join(dir, 'packages/browser-ext');\n if (validateBrowserExtLayout(candidate)) {\n return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n return null;\n}\n\n/**\n * Resolve the bundled extension source directory (read-only).\n */\nexport async function resolveBundledBrowserExtDir(): Promise<{\n dir: string;\n bundledFrom: BrowserExtBundledFrom;\n} | null> {\n const envOverride = process.env.XOPC_BROWSER_EXT_BUNDLED_ROOT?.trim();\n if (envOverride && validateBrowserExtLayout(envOverride)) {\n return { dir: envOverride, bundledFrom: 'env-override' };\n }\n\n const fromModule = join(moduleDir(), '../../../browser-ext');\n if (validateBrowserExtLayout(fromModule)) {\n const root = await resolvePackageRoot();\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: fromModule, bundledFrom };\n }\n\n const gitDev = walkAncestorsForGitDevBundled(moduleDir());\n if (gitDev) {\n return { dir: gitDev, bundledFrom: 'git-dev' };\n }\n\n const root = await resolvePackageRoot();\n if (root) {\n const distBundled = join(root, 'dist/browser-ext');\n if (validateBrowserExtLayout(distBundled)) {\n const bundledFrom: BrowserExtBundledFrom =\n process.versions.electron && root.includes('app.asar') ? 'electron-asar' : 'npm-dist';\n return { dir: distBundled, bundledFrom };\n }\n }\n\n return null;\n}\n\nexport function computeNeedsRefresh(params: {\n force?: boolean;\n bundledManifestVersion: string;\n installedPath: string | null;\n meta: BrowserExtInstallMeta | null;\n}): boolean {\n if (params.force) return true;\n if (!params.installedPath || !validateBrowserExtLayout(params.installedPath)) return true;\n\n const installedManifest = readManifestVersion(params.installedPath);\n if (!installedManifest || installedManifest !== params.bundledManifestVersion) return true;\n\n if (!params.meta || params.meta.xopcVersion !== PACKAGE_VERSION) return true;\n\n return false;\n}\n\nasync function cleanupStaleStaging(root: string): Promise<void> {\n if (!existsSync(root)) return;\n let entries: string[];\n try {\n entries = await readdir(root);\n } catch {\n return;\n }\n const now = Date.now();\n for (const name of entries) {\n if (!name.startsWith('.staging-')) continue;\n const full = join(root, name);\n try {\n const st = statSync(full);\n if (now - st.mtimeMs > STAGING_MAX_AGE_MS) {\n await rm(full, { recursive: true, force: true });\n }\n } catch {\n /* */\n }\n }\n}\n\nfunction removeInstalledArtifacts(root: string): void {\n for (const name of INSTALLED_ARTIFACT_NAMES) {\n const full = join(root, name);\n if (existsSync(full)) {\n rmSync(full, { recursive: true, force: true });\n }\n }\n}\n\nfunction promoteStagingToRoot(stagingDir: string, root: string): void {\n removeInstalledArtifacts(root);\n for (const name of readdirSync(stagingDir)) {\n renameSync(join(stagingDir, name), join(root, name));\n }\n rmSync(stagingDir, { recursive: true, force: true });\n if (!validateBrowserExtLayout(root)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\n/** Copy one bundled file (read/write works when src is inside Electron app.asar). */\nfunction copyBundledFile(src: string, dest: string): void {\n mkdirSync(dirname(dest), { recursive: true });\n writeFileSync(dest, readFileSync(src));\n}\n\nconst BROWSER_EXT_DIST_FILES = ['background.js', 'content.js', 'popup.js'] as const;\nconst BROWSER_EXT_ICON_FILES = ['icon-16.png', 'icon-32.png', 'icon-48.png', 'icon-128.png'] as const;\n\nfunction copyBundledTree(src: string, dest: string): void {\n mkdirSync(dest, { recursive: true });\n for (const name of ['manifest.json', 'popup.html']) {\n copyBundledFile(join(src, name), join(dest, name));\n }\n for (const file of BROWSER_EXT_DIST_FILES) {\n copyBundledFile(join(src, 'dist', file), join(dest, 'dist', file));\n }\n for (const icon of BROWSER_EXT_ICON_FILES) {\n const iconSrc = join(src, 'icons', icon);\n if (existsSync(iconSrc)) {\n copyBundledFile(iconSrc, join(dest, 'icons', icon));\n }\n }\n if (!validateBrowserExtLayout(dest)) {\n throw new Error('Bundled browser extension copy failed validation');\n }\n}\n\nexport async function browserExtDoctor(opts?: {\n cacheDir?: string;\n runtimeExtensionVersion?: string;\n}): Promise<BrowserExtDoctor> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n const bundledManifestVersion = bundled ? readManifestVersion(bundled.dir) : undefined;\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n\n const needsRefresh = bundled\n ? computeNeedsRefresh({\n force: false,\n bundledManifestVersion: bundledManifestVersion ?? PACKAGE_VERSION,\n installedPath,\n meta,\n })\n : false;\n\n const installed = Boolean(installedPath) && !needsRefresh;\n const manifestVersion = installedPath ? readManifestVersion(installedPath) : undefined;\n\n let needsChromeReload: boolean | undefined;\n const runtimeVer = opts?.runtimeExtensionVersion?.trim();\n if (runtimeVer && manifestVersion && runtimeVer !== manifestVersion) {\n needsChromeReload = true;\n }\n\n return {\n bundledAvailable: Boolean(bundled),\n installed,\n xopcVersion: PACKAGE_VERSION,\n installedVersion: meta?.xopcVersion,\n manifestVersion,\n extensionDir: installedPath ?? undefined,\n cacheDir,\n needsRefresh,\n needsChromeReload,\n bundledFrom: bundled?.bundledFrom,\n runtimeExtensionVersion: runtimeVer,\n };\n}\n\nexport async function ensureBrowserExtensionArtifacts(opts?: {\n force?: boolean;\n cacheDir?: string;\n}): Promise<EnsureBrowserExtResult> {\n const resolvedCache = opts?.cacheDir?.trim()\n ? assertCacheDir(opts.cacheDir)\n : resolveBinDir();\n const cacheDir = resolvedCache || resolveBinDir();\n\n const bundled = await resolveBundledBrowserExtDir();\n if (!bundled) {\n throw new Error(\n 'Bundled browser extension not found. Reinstall xopc or run from a built checkout (pnpm run build).',\n );\n }\n\n const bundledManifestVersion = readManifestVersion(bundled.dir) ?? PACKAGE_VERSION;\n const root = browserExtRoot(cacheDir);\n mkdirSync(root, { recursive: true });\n await cleanupStaleStaging(root);\n\n const meta = await readMeta(resolveMetaPath(cacheDir));\n const installedPath = resolveInstalledExtensionPath(cacheDir, meta);\n const needsRefresh = computeNeedsRefresh({\n force: opts?.force,\n bundledManifestVersion,\n installedPath,\n meta,\n });\n\n const extensionDir = root;\n\n if (!needsRefresh && installedPath) {\n return {\n extensionDir: installedPath,\n xopcVersion: PACKAGE_VERSION,\n copied: false,\n };\n }\n\n const stagingDir = join(root, `.staging-${process.pid}`);\n\n if (existsSync(stagingDir)) {\n rmSync(stagingDir, { recursive: true, force: true });\n }\n copyBundledTree(bundled.dir, stagingDir);\n promoteStagingToRoot(stagingDir, root);\n\n const nextMeta: BrowserExtInstallMeta = {\n xopcVersion: PACKAGE_VERSION,\n manifestVersion: bundledManifestVersion,\n source: 'bundled',\n bundledFrom: bundled.bundledFrom,\n installedAt: new Date().toISOString(),\n installPath: extensionDir,\n };\n await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));\n\n log.info(\n { extensionDir, xopcVersion: PACKAGE_VERSION, bundledFrom: bundled.bundledFrom },\n 'Browser extension artifacts installed',\n );\n\n return {\n extensionDir,\n xopcVersion: PACKAGE_VERSION,\n copied: true,\n };\n}\n\n/**\n * Gateway startup hook: ensure artifacts when extension backend is enabled or prior install exists.\n */\nexport async function ensureBrowserExtensionOnStartup(config: {\n agents?: { defaults?: { browser?: { backend?: string } } };\n}): Promise<void> {\n const backend = config.agents?.defaults?.browser?.backend;\n const cacheDir = resolveBinDir();\n const metaExists = existsSync(resolveMetaPath(cacheDir));\n if (backend !== 'extension' && !metaExists) {\n return;\n }\n await ensureBrowserExtensionArtifacts();\n}\n\nexport async function readInstalledExtensionDir(cacheDir?: string): Promise<string | null> {\n const dir = cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir();\n const resolved = dir || resolveBinDir();\n const meta = await readMeta(resolveMetaPath(resolved));\n return resolveInstalledExtensionPath(resolved, meta);\n}\n\nexport type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';\n\nfunction spawnDetached(command: string, args: readonly string[]): void {\n spawn(command, [...args], { stdio: 'ignore', detached: true }).unref();\n}\n\nfunction openChromeExtensionsPage(): void {\n const chromeUrl = 'chrome://extensions';\n if (process.platform === 'darwin') {\n spawnDetached('open', ['-a', 'Google Chrome', chromeUrl]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('cmd', ['/c', 'start', 'chrome', chromeUrl]);\n return;\n }\n spawnDetached('xdg-open', [chromeUrl]);\n}\n\nfunction revealFolderInFileManager(dir: string): void {\n if (process.platform === 'darwin') {\n spawnDetached('open', [dir]);\n return;\n }\n if (process.platform === 'win32') {\n spawnDetached('explorer', [dir]);\n return;\n }\n spawnDetached('xdg-open', [dir]);\n}\n\n/**\n * Open chrome://extensions and/or reveal the installed extension folder on the gateway host.\n */\nexport async function openBrowserExtensionInstallUi(opts: {\n action: BrowserExtensionOpenAction;\n cacheDir?: string;\n}): Promise<{ extensionDir: string }> {\n const doctor = await browserExtDoctor({ cacheDir: opts.cacheDir });\n const dir = doctor.extensionDir;\n if (!dir) {\n throw new Error('Extension not installed. Run xopc browser extension install first.');\n }\n\n if (opts.action === 'chrome' || opts.action === 'both') {\n openChromeExtensionsPage();\n }\n if (opts.action === 'folder' || opts.action === 'both') {\n revealFolderInFileManager(dir);\n }\n\n return { extensionDir: dir };\n}\n"],"mappings":"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"}
@@ -31,11 +31,6 @@ export declare function cloakBrowserArchiveDownloadUrls(platformInfo: PlatformIn
31
31
  export declare function defaultCloakBrowserCacheDir(): string;
32
32
  /** Resolve configured or default CloakBrowser cache root. */
33
33
  export declare function resolveCloakBrowserCacheDir(configured?: string): string;
34
- /**
35
- * Move legacy layout (~/.xopc/bin/chromium-v* and profiles/) into ~/.xopc/bin/cloakbrowser/.
36
- * No-op when using a custom cacheDir or when the new layout already exists.
37
- */
38
- export declare function migrateLegacyCloakBrowserLayout(cacheDir: string): Promise<void>;
39
34
  export interface CloakBrowserLaunchResult {
40
35
  browser?: Browser;
41
36
  context?: BrowserContext;
@@ -1,15 +1,15 @@
1
- import { assertCacheDir, expandHome, init_cache_dir_policy } from "../cache-dir-policy.js";
2
1
  import { createLogger } from "../../utils/logger/index.js";
3
2
  import { init_logger } from "../../utils/logger.js";
4
3
  import { init_paths, resolveBinDir } from "../../config/paths.js";
4
+ import { assertCacheDir, expandHome, init_cache_dir_policy } from "../cache-dir-policy.js";
5
5
  import { loadPlaywrightCoreModule } from "./playwright-doctor.js";
6
6
  import { WEBDRIVER_OVERRIDE_SCRIPT, buildStealthArgs, filterCloakBrowserExtraArgs, generateFingerprintSeed, makeExecutable, removeQuarantineAttr } from "../stealth.js";
7
7
  import { pickFreePort } from "../free-port.js";
8
- import { arch, platform, tmpdir } from "node:os";
9
- import { join, resolve } from "node:path";
10
- import { createReadStream, createWriteStream } from "node:fs";
11
8
  import { createHash } from "node:crypto";
12
- import { mkdir, mkdtemp, readdir, rename, rm, stat } from "node:fs/promises";
9
+ import { createReadStream, createWriteStream } from "node:fs";
10
+ import { mkdir, mkdtemp, rm, stat } from "node:fs/promises";
11
+ import { join, resolve } from "node:path";
12
+ import { arch, platform, tmpdir } from "node:os";
13
13
  import { spawn } from "node:child_process";
14
14
  import { Readable, Transform } from "node:stream";
15
15
  import AdmZip from "adm-zip";
@@ -146,57 +146,6 @@ async function resolveCloakExecutablePath(cacheDir, platformInfo, configuredBina
146
146
  customBinaryPath: true
147
147
  };
148
148
  }
149
- /**
150
- * Move legacy layout (~/.xopc/bin/chromium-v* and profiles/) into ~/.xopc/bin/cloakbrowser/.
151
- * No-op when using a custom cacheDir or when the new layout already exists.
152
- */
153
- async function migrateLegacyCloakBrowserLayout(cacheDir) {
154
- if (cacheDir !== defaultCloakBrowserCacheDir()) return;
155
- const binDir = resolveBinDir();
156
- await mkdir(cacheDir, { recursive: true });
157
- let entries;
158
- try {
159
- entries = await readdir(binDir);
160
- } catch {
161
- return;
162
- }
163
- for (const name of entries) {
164
- if (!name.startsWith("chromium-v")) continue;
165
- const from = join(binDir, name);
166
- const to = join(cacheDir, name);
167
- if (await fileExists(to)) continue;
168
- if (!await fileExists(from)) continue;
169
- try {
170
- await rename(from, to);
171
- log.info({
172
- from,
173
- to
174
- }, "Migrated legacy CloakBrowser binary directory");
175
- } catch (err) {
176
- log.warn({
177
- err,
178
- from,
179
- to
180
- }, "Failed to migrate legacy CloakBrowser binary directory");
181
- }
182
- }
183
- const legacyProfiles = join(binDir, "profiles");
184
- const newProfiles = join(cacheDir, "profiles");
185
- if (await fileExists(newProfiles) || !await fileExists(legacyProfiles)) return;
186
- try {
187
- await rename(legacyProfiles, newProfiles);
188
- log.info({
189
- from: legacyProfiles,
190
- to: newProfiles
191
- }, "Migrated legacy CloakBrowser profiles directory");
192
- } catch (err) {
193
- log.warn({
194
- err,
195
- from: legacyProfiles,
196
- to: newProfiles
197
- }, "Failed to migrate legacy CloakBrowser profiles");
198
- }
199
- }
200
149
  function binaryDir(cacheDir, platformInfo) {
201
150
  return join(cacheDir, `chromium-v${platformInfo.chromiumVersion}`);
202
151
  }
@@ -466,7 +415,6 @@ function launchResultMeta(cdpPort, userDataDir, reused, pid, childProcess, tempo
466
415
  async function launchCloakBrowser(config = {}) {
467
416
  const platformInfo = detectPlatform();
468
417
  const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);
469
- await migrateLegacyCloakBrowserLayout(cacheDir);
470
418
  const keepOpen = config.keepOpen ?? true;
471
419
  const reuseExisting = config.reuseExisting ?? keepOpen;
472
420
  const configuredBinary = config.binaryPath?.trim() || void 0;
@@ -646,7 +594,6 @@ async function installCloakBrowser(config = {}) {
646
594
  async function cloakBrowserDoctor(config = {}) {
647
595
  const platformInfo = detectPlatform();
648
596
  const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);
649
- await migrateLegacyCloakBrowserLayout(cacheDir);
650
597
  const { execPath, installed, customBinaryPath } = await resolveCloakExecutablePath(cacheDir, platformInfo, config.binaryPath);
651
598
  const [primary, ...fallbacks] = archiveDownloadUrls(platformInfo);
652
599
  return {
@@ -662,6 +609,6 @@ async function cloakBrowserDoctor(config = {}) {
662
609
  };
663
610
  }
664
611
  //#endregion
665
- export { cleanupCloakBrowser, cloakBrowserArchiveDownloadUrls, cloakBrowserDoctor, defaultCloakBrowserCacheDir, installCloakBrowser, launchCloakBrowser, listCloakBrowserPlatforms, migrateLegacyCloakBrowserLayout, probeCloakBrowserRuntime, resolveCloakBrowserCacheDir, resolveCloakBrowserPersistentProfileDir };
612
+ export { cleanupCloakBrowser, cloakBrowserArchiveDownloadUrls, cloakBrowserDoctor, defaultCloakBrowserCacheDir, installCloakBrowser, launchCloakBrowser, listCloakBrowserPlatforms, probeCloakBrowserRuntime, resolveCloakBrowserCacheDir, resolveCloakBrowserPersistentProfileDir };
666
613
 
667
614
  //# sourceMappingURL=cloakbrowser.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"cloakbrowser.js","names":["osPlatform","osArch"],"sources":["../../../../src/browser/providers/cloakbrowser.ts"],"sourcesContent":["/**\n * CloakBrowser provider — anti-fingerprint Chromium with stealth capabilities.\n *\n * Manages CloakBrowser binary download, stealth launch, CDP connection,\n * keep-open process reuse, and temporary profile lifecycle.\n *\n * Ported from brocli's cloak.rs to TypeScript, using Playwright's connectOverCDP\n * to produce a standard Browser/BrowserContext pair.\n */\n\nimport { createHash } from 'node:crypto';\nimport { createReadStream, createWriteStream } from 'node:fs';\nimport { mkdir, mkdtemp, readdir, rename, rm, stat } from 'node:fs/promises';\nimport { platform as osPlatform, arch as osArch, tmpdir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { pipeline } from 'node:stream/promises';\nimport { Readable, Transform } from 'node:stream';\nimport { ChildProcess, spawn } from 'node:child_process';\n\nimport AdmZip from 'adm-zip';\nimport type { Browser, BrowserContext } from 'playwright-core';\n\nimport type { BrowserInstallProgress } from '../install-progress.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { assertCacheDir, expandHome } from '../cache-dir-policy.js';\nimport { pickFreePort } from '../free-port.js';\nimport { loadPlaywrightCoreModule } from './playwright-doctor.js';\nimport {\n buildStealthArgs,\n filterCloakBrowserExtraArgs,\n generateFingerprintSeed,\n makeExecutable,\n removeQuarantineAttr,\n WEBDRIVER_OVERRIDE_SCRIPT,\n} from '../stealth.js';\nimport type { CloakBrowserConfig } from './types.js';\n\nconst log = createLogger('CloakBrowser');\n\n// ── Platform info ───────────────────────────────────────────────────────────\n\ninterface PlatformInfo {\n tag: string;\n chromiumVersion: string;\n archiveExt: string;\n executableRelativePath: string;\n fingerprintPlatform: string;\n /**\n * Expected SHA-256 of the downloaded archive (lowercase hex). Empty string =\n * verification opt-out for this platform; warned but not fatal. To populate:\n * download the archive once, run `shasum -a 256 <file>`, paste here.\n */\n expectedSha256: string;\n}\n\nconst DOWNLOAD_BASE_URL = 'https://cloakbrowser.dev';\nconst GITHUB_DOWNLOAD_BASE_URL = 'https://github.com/CloakHQ/CloakBrowser/releases/download';\nconst XOPC_CLOAKBROWSER_PROXY_BASE =\n process.env.XOPC_CLOAKBROWSER_DOWNLOAD_BASE?.trim().replace(/\\/$/, '') ||\n 'https://xopc.ai/api/cloakbrowser/download';\nconst READY_TIMEOUT_MS = 45_000;\nconst READY_POLL_INTERVAL_MS = 300;\nconst DEFAULT_KEEP_OPEN_CDP_PORT = 9222;\n\nconst PLATFORMS: Record<string, PlatformInfo> = {\n 'darwin-arm64': {\n tag: 'darwin-arm64',\n chromiumVersion: '145.0.7632.109.2',\n archiveExt: '.tar.gz',\n executableRelativePath: 'Chromium.app/Contents/MacOS/Chromium',\n fingerprintPlatform: 'macos',\n expectedSha256: '',\n },\n 'darwin-x64': {\n tag: 'darwin-x64',\n chromiumVersion: '145.0.7632.109.2',\n archiveExt: '.tar.gz',\n executableRelativePath: 'Chromium.app/Contents/MacOS/Chromium',\n fingerprintPlatform: 'macos',\n expectedSha256: '',\n },\n 'linux-arm64': {\n tag: 'linux-arm64',\n chromiumVersion: '146.0.7680.177.4',\n archiveExt: '.tar.gz',\n executableRelativePath: 'chrome',\n fingerprintPlatform: 'windows',\n expectedSha256: '',\n },\n 'linux-x64': {\n tag: 'linux-x64',\n chromiumVersion: '146.0.7680.177.4',\n archiveExt: '.tar.gz',\n executableRelativePath: 'chrome',\n fingerprintPlatform: 'windows',\n expectedSha256: '',\n },\n 'win32-x64': {\n tag: 'windows-x64',\n chromiumVersion: '146.0.7680.177.4',\n archiveExt: '.zip',\n executableRelativePath: 'chrome.exe',\n fingerprintPlatform: 'windows',\n expectedSha256: '',\n },\n};\n\nfunction detectPlatform(): PlatformInfo {\n const os = osPlatform();\n const architecture = osArch();\n const archMap: Record<string, string> = { arm64: 'arm64', x64: 'x64' };\n const key = `${os}-${archMap[architecture] ?? architecture}`;\n const info = PLATFORMS[key];\n if (!info) {\n throw new Error(`Unsupported CloakBrowser platform: ${os}/${architecture}`);\n }\n return info;\n}\n\n/** Test-only: enumerate platform manifests. */\nexport function listCloakBrowserPlatforms(): PlatformInfo[] {\n return Object.values(PLATFORMS);\n}\n\nfunction archiveDownloadUrls(platformInfo: PlatformInfo): string[] {\n const archiveName = `cloakbrowser-${platformInfo.tag}${platformInfo.archiveExt}`;\n return [\n `${XOPC_CLOAKBROWSER_PROXY_BASE}/${archiveName}`,\n `${GITHUB_DOWNLOAD_BASE_URL}/chromium-v${platformInfo.chromiumVersion}/${archiveName}`,\n `${DOWNLOAD_BASE_URL}/download/${archiveName}`,\n ];\n}\n\n/** Test-only: resolved download URLs for a platform manifest (proxy first). */\nexport function cloakBrowserArchiveDownloadUrls(platformInfo: PlatformInfo): string[] {\n return archiveDownloadUrls(platformInfo);\n}\n\nasync function sha256OfFile(path: string): Promise<string> {\n const hash = createHash('sha256');\n await pipeline(createReadStream(path), hash);\n return hash.digest('hex');\n}\n\n// ── Binary management ───────────────────────────────────────────────────────\n\nconst CLOAKBROWSER_DIR_NAME = 'cloakbrowser';\n\n/** Default CloakBrowser home: ~/.xopc/bin/cloakbrowser (chromium-v*, profiles/, …). */\nexport function defaultCloakBrowserCacheDir(): string {\n return join(resolveBinDir(), CLOAKBROWSER_DIR_NAME);\n}\n\n/** Resolve configured or default CloakBrowser cache root. */\nexport function resolveCloakBrowserCacheDir(configured?: string): string {\n if (configured?.trim()) {\n const resolved = assertCacheDir(configured.trim());\n // Legacy configs used ~/.xopc/bin — normalize to ~/.xopc/bin/cloakbrowser.\n if (resolve(resolved) === resolve(resolveBinDir())) {\n return defaultCloakBrowserCacheDir();\n }\n return resolved;\n }\n return defaultCloakBrowserCacheDir();\n}\n\nasync function resolveCloakExecutablePath(\n cacheDir: string,\n platformInfo: PlatformInfo,\n configuredBinaryPath?: string,\n): Promise<{ execPath: string; installed: boolean; customBinaryPath: boolean }> {\n const trimmed = configuredBinaryPath?.trim();\n const autoPath = binaryPath(cacheDir, platformInfo);\n if (!trimmed) {\n return {\n execPath: autoPath,\n installed: await fileExists(autoPath),\n customBinaryPath: false,\n };\n }\n\n const customPath = resolve(expandHome(trimmed));\n if (await fileExists(customPath)) {\n return { execPath: customPath, installed: true, customBinaryPath: true };\n }\n\n if (await fileExists(autoPath)) {\n return { execPath: autoPath, installed: true, customBinaryPath: true };\n }\n\n return { execPath: customPath, installed: false, customBinaryPath: true };\n}\n\n/**\n * Move legacy layout (~/.xopc/bin/chromium-v* and profiles/) into ~/.xopc/bin/cloakbrowser/.\n * No-op when using a custom cacheDir or when the new layout already exists.\n */\nexport async function migrateLegacyCloakBrowserLayout(cacheDir: string): Promise<void> {\n if (cacheDir !== defaultCloakBrowserCacheDir()) return;\n\n const binDir = resolveBinDir();\n await mkdir(cacheDir, { recursive: true });\n\n let entries: string[];\n try {\n entries = await readdir(binDir);\n } catch {\n return;\n }\n\n for (const name of entries) {\n if (!name.startsWith('chromium-v')) continue;\n const from = join(binDir, name);\n const to = join(cacheDir, name);\n if (await fileExists(to)) continue;\n if (!(await fileExists(from))) continue;\n try {\n await rename(from, to);\n log.info({ from, to }, 'Migrated legacy CloakBrowser binary directory');\n } catch (err) {\n log.warn({ err, from, to }, 'Failed to migrate legacy CloakBrowser binary directory');\n }\n }\n\n const legacyProfiles = join(binDir, 'profiles');\n const newProfiles = join(cacheDir, 'profiles');\n if (await fileExists(newProfiles) || !(await fileExists(legacyProfiles))) return;\n\n try {\n await rename(legacyProfiles, newProfiles);\n log.info({ from: legacyProfiles, to: newProfiles }, 'Migrated legacy CloakBrowser profiles directory');\n } catch (err) {\n log.warn({ err, from: legacyProfiles, to: newProfiles }, 'Failed to migrate legacy CloakBrowser profiles');\n }\n}\n\nfunction binaryDir(cacheDir: string, platformInfo: PlatformInfo): string {\n return join(cacheDir, `chromium-v${platformInfo.chromiumVersion}`);\n}\n\nfunction binaryPath(cacheDir: string, platformInfo: PlatformInfo): string {\n return join(binaryDir(cacheDir, platformInfo), platformInfo.executableRelativePath);\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction runCommand(command: string, args: string[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, { stdio: ['ignore', 'ignore', 'pipe'] });\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n child.once('error', reject);\n child.once('exit', (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n const reason = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n const detail = stderr.trim() ? `: ${stderr.trim().slice(0, 500)}` : '';\n reject(new Error(`${command} failed with ${reason}${detail}`));\n });\n });\n}\n\nasync function extractArchive(archivePath: string, targetDir: string, platformInfo: PlatformInfo): Promise<void> {\n if (platformInfo.archiveExt === '.tar.gz') {\n await runCommand('tar', ['-xzf', archivePath, '-C', targetDir]);\n return;\n }\n\n if (platformInfo.archiveExt === '.zip') {\n const zip = new AdmZip(archivePath);\n zip.extractAllTo(targetDir, true);\n return;\n }\n\n throw new Error(`Unsupported CloakBrowser archive format: ${platformInfo.archiveExt}`);\n}\n\n/**\n * Download and extract CloakBrowser binary.\n *\n * After download, verifies SHA-256 against the platform manifest when one is\n * present. Set `XOPC_CLOAKBROWSER_SKIP_HASH=1` to bypass (development only;\n * the gateway logs a warning when the env var is honoured).\n */\nasync function downloadArchiveToFile(\n url: string,\n archivePath: string,\n onProgress?: (progress: BrowserInstallProgress) => void | Promise<void>,\n signal?: AbortSignal,\n): Promise<void> {\n if (signal?.aborted) throw new Error('Install cancelled');\n\n const response = await fetch(url, { redirect: 'follow', signal });\n if (!response.ok || !response.body) {\n throw new Error(`download returned HTTP ${response.status}`);\n }\n\n const contentLength = response.headers.get('content-length');\n const totalBytes =\n contentLength && Number.isFinite(Number(contentLength)) ? Number(contentLength) : null;\n let bytesReceived = 0;\n\n let lastReportAt = 0;\n const report = (force = false) => {\n const now = Date.now();\n if (!force && now - lastReportAt < 250) return;\n lastReportAt = now;\n void onProgress?.({\n phase: 'downloading',\n message: 'Downloading CloakBrowser archive',\n bytesReceived,\n totalBytes,\n percent:\n totalBytes && totalBytes > 0\n ? Math.min(100, Math.round((bytesReceived / totalBytes) * 100))\n : null,\n });\n };\n\n report(true);\n\n const nodeStream = Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]);\n const counting = new Transform({\n transform(chunk, _encoding, callback) {\n bytesReceived += chunk.length;\n report();\n callback(null, chunk);\n },\n });\n\n await pipeline(nodeStream, counting, createWriteStream(archivePath));\n report(true);\n}\n\nasync function downloadBinary(\n cacheDir: string,\n platformInfo: PlatformInfo,\n onProgress?: (progress: BrowserInstallProgress) => void | Promise<void>,\n signal?: AbortSignal,\n): Promise<string> {\n const targetDir = binaryDir(cacheDir, platformInfo);\n const execPath = binaryPath(cacheDir, platformInfo);\n\n if (await fileExists(execPath)) {\n log.info({ path: execPath }, 'CloakBrowser binary already cached');\n await onProgress?.({ phase: 'ready', message: 'CloakBrowser binary already cached', percent: 100 });\n return execPath;\n }\n\n await mkdir(cacheDir, { recursive: true });\n await onProgress?.({ phase: 'starting', message: 'Preparing CloakBrowser download' });\n\n const archiveName = `cloakbrowser-${platformInfo.tag}${platformInfo.archiveExt}`;\n const urls = archiveDownloadUrls(platformInfo);\n const expectedSha256 = platformInfo.expectedSha256.trim().toLowerCase();\n const skipHash = process.env.XOPC_CLOAKBROWSER_SKIP_HASH === '1';\n\n log.info({ version: platformInfo.chromiumVersion, platform: platformInfo.tag }, 'Downloading CloakBrowser...');\n\n let downloadError: Error | undefined;\n for (const url of urls) {\n if (signal?.aborted) throw new Error('Install cancelled');\n const stagingDir = await mkdtemp(join(cacheDir, '.download-'));\n const archivePath = join(stagingDir, archiveName);\n try {\n await downloadArchiveToFile(url, archivePath, onProgress, signal);\n\n if (expectedSha256) {\n if (signal?.aborted) throw new Error('Install cancelled');\n await onProgress?.({ phase: 'verifying', message: 'Verifying SHA-256 checksum' });\n const actual = await sha256OfFile(archivePath);\n if (actual !== expectedSha256) {\n throw new Error(\n `SHA-256 mismatch: expected ${expectedSha256}, got ${actual}. Aborted to avoid running unverified binary.`,\n );\n }\n log.info({ archivePath }, 'SHA-256 verified');\n } else if (skipHash) {\n log.warn(\n { platform: platformInfo.tag, version: platformInfo.chromiumVersion },\n 'CloakBrowser SHA-256 verification skipped (XOPC_CLOAKBROWSER_SKIP_HASH=1)',\n );\n } else {\n log.warn(\n { platform: platformInfo.tag, version: platformInfo.chromiumVersion },\n 'CloakBrowser manifest has no expectedSha256; integrity NOT verified',\n );\n }\n\n await onProgress?.({ phase: 'extracting', message: 'Extracting CloakBrowser archive' });\n log.info({ archivePath }, 'Extracting CloakBrowser archive...');\n await rm(targetDir, { recursive: true, force: true }).catch(() => {});\n await mkdir(targetDir, { recursive: true });\n await extractArchive(archivePath, targetDir, platformInfo);\n\n if (!(await fileExists(execPath))) {\n throw new Error(`archive did not contain expected executable: ${execPath}`);\n }\n\n await makeExecutable(execPath);\n await removeQuarantineAttr(execPath);\n await rm(stagingDir, { recursive: true, force: true }).catch(() => {});\n\n await onProgress?.({ phase: 'ready', message: 'CloakBrowser binary ready', percent: 100 });\n log.info({ path: execPath }, 'CloakBrowser binary ready');\n return execPath;\n } catch (e) {\n await rm(stagingDir, { recursive: true, force: true }).catch(() => {});\n await rm(targetDir, { recursive: true, force: true }).catch(() => {});\n downloadError = e instanceof Error ? e : new Error(String(e));\n log.debug({ url, errorMessage: downloadError.message }, 'Download attempt failed');\n }\n }\n\n throw new Error(\n `Failed to download CloakBrowser v${platformInfo.chromiumVersion} for ${platformInfo.tag}: ${downloadError?.message ?? 'all URLs failed'}`,\n );\n}\n\n// ── CDP endpoint discovery ──────────────────────────────────────────────────\n\nasync function waitForCdpEndpoint(port: number): Promise<string> {\n const deadline = Date.now() + READY_TIMEOUT_MS;\n\n while (Date.now() < deadline) {\n try {\n const response = await fetch(`http://127.0.0.1:${port}/json/version`);\n if (response.ok) {\n const data = (await response.json()) as { webSocketDebuggerUrl?: string };\n if (data.webSocketDebuggerUrl) {\n return data.webSocketDebuggerUrl;\n }\n }\n } catch {\n // Not ready yet\n }\n await new Promise((resolve) => setTimeout(resolve, READY_POLL_INTERVAL_MS));\n }\n\n throw new Error(`CloakBrowser did not expose CDP page within ${READY_TIMEOUT_MS / 1000}s on port ${port}`);\n}\n\n/** Try to find an existing CDP page endpoint on the given port. */\nasync function reuseOrCreatePageEndpoint(port: number): Promise<string | null> {\n try {\n const response = await fetch(`http://127.0.0.1:${port}/json/list`, {\n signal: AbortSignal.timeout(2000),\n });\n if (!response.ok) return null;\n const pages = (await response.json()) as Array<{ webSocketDebuggerUrl?: string; type?: string }>;\n const page = pages.find((p) => p.type === 'page' && p.webSocketDebuggerUrl);\n if (page?.webSocketDebuggerUrl) return page.webSocketDebuggerUrl;\n\n // No pages — create one\n const newResponse = await fetch(`http://127.0.0.1:${port}/json/new`);\n if (newResponse.ok) {\n const newPage = (await newResponse.json()) as { webSocketDebuggerUrl?: string };\n if (newPage.webSocketDebuggerUrl) return newPage.webSocketDebuggerUrl;\n }\n } catch {\n // Not running\n }\n return null;\n}\n\n// ── Provider ────────────────────────────────────────────────────────────────\n\nexport interface CloakBrowserLaunchResult {\n browser?: Browser;\n context?: BrowserContext;\n childProcess: ChildProcess | null;\n temporaryProfileDir: string | null;\n cdpPort: number;\n userDataDir: string;\n reused: boolean;\n pid: number | null;\n}\n\nfunction resolveCloakBrowserProfilePaths(\n config: CloakBrowserConfig,\n cacheDir: string,\n): { userDataDir: string; temporaryProfileDir: string | null } {\n if (config.userDataDir) {\n return { userDataDir: config.userDataDir, temporaryProfileDir: null };\n }\n if (config.temporaryProfile) {\n const userDataDir = join(tmpdir(), `xopc-cloakbrowser-${process.pid}-${generateFingerprintSeed()}`);\n return { userDataDir, temporaryProfileDir: userDataDir };\n }\n return { userDataDir: join(cacheDir, 'profiles', 'default'), temporaryProfileDir: null };\n}\n\n/** Resolve the persistent profile directory agents use (not ephemeral temp dirs). */\nexport function resolveCloakBrowserPersistentProfileDir(config: CloakBrowserConfig = {}): string {\n if (config.userDataDir) return config.userDataDir;\n const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);\n return join(cacheDir, 'profiles', 'default');\n}\n\nexport interface CloakBrowserRuntimeStatus {\n running: boolean;\n port: number;\n userDataDir: string;\n temporaryProfile: boolean;\n}\n\nasync function probeCdpPort(port: number): Promise<boolean> {\n try {\n const response = await fetch(`http://127.0.0.1:${port}/json/version`, {\n signal: AbortSignal.timeout(2000),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n\n/** Probe whether CloakBrowser CDP is listening on the configured keep-open port. */\nexport async function probeCloakBrowserRuntime(\n config: CloakBrowserConfig = {},\n): Promise<CloakBrowserRuntimeStatus> {\n const keepOpen = config.keepOpen ?? true;\n const cdpPort = config.cdpPort ?? (keepOpen ? DEFAULT_KEEP_OPEN_CDP_PORT : DEFAULT_KEEP_OPEN_CDP_PORT);\n const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);\n const { userDataDir } = resolveCloakBrowserProfilePaths(config, cacheDir);\n const running = await probeCdpPort(cdpPort);\n return {\n running,\n port: cdpPort,\n userDataDir,\n temporaryProfile: config.temporaryProfile === true,\n };\n}\n\nfunction launchResultMeta(\n cdpPort: number,\n userDataDir: string,\n reused: boolean,\n pid: number | null,\n childProcess: ChildProcess | null,\n temporaryProfileDir: string | null,\n): Pick<\n CloakBrowserLaunchResult,\n 'cdpPort' | 'userDataDir' | 'reused' | 'pid' | 'childProcess' | 'temporaryProfileDir'\n> {\n return { cdpPort, userDataDir, reused, pid, childProcess, temporaryProfileDir };\n}\n\n/**\n * Launch or connect to a CloakBrowser instance and return a Playwright Browser + Context.\n */\nexport async function launchCloakBrowser(\n config: CloakBrowserConfig = {},\n): Promise<CloakBrowserLaunchResult> {\n const platformInfo = detectPlatform();\n const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);\n await migrateLegacyCloakBrowserLayout(cacheDir);\n const keepOpen = config.keepOpen ?? true;\n const reuseExisting = config.reuseExisting ?? keepOpen;\n\n // Resolve binary\n const configuredBinary = config.binaryPath?.trim() || undefined;\n const execPath = configuredBinary\n ? (await resolveCloakExecutablePath(cacheDir, platformInfo, configuredBinary)).execPath\n : await downloadBinary(cacheDir, platformInfo, config.onProgress, config.signal);\n if (configuredBinary) {\n await makeExecutable(execPath);\n await removeQuarantineAttr(execPath);\n }\n\n // Resolve CDP port\n const cdpPort = config.cdpPort ?? (keepOpen ? DEFAULT_KEEP_OPEN_CDP_PORT : await pickFreePort());\n const skipPlaywrightConnect = config.skipPlaywrightConnect === true;\n const { userDataDir, temporaryProfileDir: plannedTempProfileDir } = resolveCloakBrowserProfilePaths(\n config,\n cacheDir,\n );\n\n // Try to reuse existing instance\n if (reuseExisting) {\n const existingEndpoint = await reuseOrCreatePageEndpoint(cdpPort);\n if (existingEndpoint) {\n log.info({ port: cdpPort }, 'Reusing existing CloakBrowser instance');\n const meta = launchResultMeta(cdpPort, userDataDir, true, null, null, null);\n if (skipPlaywrightConnect) {\n return meta;\n }\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as { default?: { chromium?: (typeof pw)['chromium'] } }).default?.chromium;\n if (!chromium?.connectOverCDP) throw new Error('playwright-core does not support connectOverCDP');\n\n const wsUrl = `ws://127.0.0.1:${cdpPort}`;\n // connectOverCDP wants the browser-level WS URL\n const versionResp = await fetch(`http://127.0.0.1:${cdpPort}/json/version`);\n const versionData = (await versionResp.json()) as { webSocketDebuggerUrl?: string };\n const browserWsUrl = versionData.webSocketDebuggerUrl ?? wsUrl;\n\n const browser = await chromium.connectOverCDP(browserWsUrl);\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : await browser.newContext();\n\n // Inject stealth script\n await context.addInitScript(WEBDRIVER_OVERRIDE_SCRIPT);\n\n return { browser, context, ...meta };\n }\n }\n\n // Resolve user data dir for a new launch\n let temporaryProfileDir: string | null = plannedTempProfileDir;\n await mkdir(userDataDir, { recursive: true });\n\n // Build launch args\n const stealthArgs = buildStealthArgs(filterCloakBrowserExtraArgs(config.extraArgs ?? []), {\n timezone: config.timezone,\n locale: config.locale,\n webrtcIp: config.webrtcIp,\n fingerprintPlatform: config.fingerprintPlatform ?? platformInfo.fingerprintPlatform,\n });\n\n const launchArgs = [\n `--remote-debugging-address=127.0.0.1`,\n `--remote-debugging-port=${cdpPort}`,\n `--user-data-dir=${userDataDir}`,\n '--no-first-run',\n '--no-default-browser-check',\n ...stealthArgs,\n ];\n\n if (config.headless) {\n launchArgs.push('--headless=new');\n }\n\n // macOS keychain bypass\n if (osPlatform() === 'darwin') {\n launchArgs.push('--use-mock-keychain');\n }\n\n await config.onProgress?.({ phase: 'running', message: 'Launching CloakBrowser for verification' });\n if (config.signal?.aborted) throw new Error('Install cancelled');\n\n log.info(\n { execPath, port: cdpPort, headless: !!config.headless, keepOpen },\n 'Launching CloakBrowser',\n );\n\n // Spawn browser process\n const child = spawn(execPath, launchArgs, {\n stdio: ['ignore', 'ignore', 'ignore'],\n detached: keepOpen, // Detach so it survives parent exit if keep-open\n });\n\n let onLaunchError: ((error: Error) => void) | null = null;\n let onLaunchExit: ((code: number | null, signal: NodeJS.Signals | null) => void) | null = null;\n const launchFailure = new Promise<never>((_resolve, reject) => {\n onLaunchError = (error) => {\n reject(new Error(`Failed to launch CloakBrowser at ${execPath}: ${error.message}`));\n };\n onLaunchExit = (code, signal) => {\n const reason = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n reject(new Error(`CloakBrowser exited before CDP became ready (${reason})`));\n };\n child.once('error', onLaunchError);\n child.once('exit', onLaunchExit);\n });\n\n if (keepOpen) {\n child.unref();\n }\n\n // Wait for CDP to become available\n let browserWsUrl: string;\n try {\n browserWsUrl = await Promise.race([waitForCdpEndpoint(cdpPort), launchFailure]);\n if (onLaunchError) child.off('error', onLaunchError);\n if (onLaunchExit) child.off('exit', onLaunchExit);\n } catch (e) {\n if (onLaunchError) child.off('error', onLaunchError);\n if (onLaunchExit) child.off('exit', onLaunchExit);\n child.kill();\n if (temporaryProfileDir) {\n await rm(temporaryProfileDir, { recursive: true, force: true }).catch(() => {});\n }\n throw e;\n }\n\n // Get browser-level WS URL\n let browserLevelWsUrl: string;\n try {\n const versionResp = await fetch(`http://127.0.0.1:${cdpPort}/json/version`);\n const versionData = (await versionResp.json()) as { webSocketDebuggerUrl?: string };\n browserLevelWsUrl = versionData.webSocketDebuggerUrl ?? browserWsUrl;\n } catch {\n browserLevelWsUrl = browserWsUrl;\n }\n\n const meta = launchResultMeta(\n cdpPort,\n userDataDir,\n false,\n child.pid ?? null,\n keepOpen ? null : child,\n temporaryProfileDir,\n );\n\n if (skipPlaywrightConnect) {\n log.info({ port: cdpPort, pid: child.pid }, 'CloakBrowser launched (CDP only)');\n return meta;\n }\n\n // Connect Playwright over CDP\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as { default?: { chromium?: (typeof pw)['chromium'] } }).default?.chromium;\n if (!chromium?.connectOverCDP) {\n child.kill();\n throw new Error('playwright-core does not support connectOverCDP');\n }\n\n const browser = await chromium.connectOverCDP(browserLevelWsUrl);\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : await browser.newContext();\n\n // Inject stealth overrides\n await context.addInitScript(WEBDRIVER_OVERRIDE_SCRIPT);\n\n log.info({ port: cdpPort, pid: child.pid }, 'CloakBrowser launched and connected');\n\n return {\n browser,\n context,\n ...meta,\n };\n}\n\n/**\n * Cleanup a CloakBrowser session — kill process and remove temp profile if applicable.\n */\nexport async function cleanupCloakBrowser(\n childProcess: ChildProcess | null,\n temporaryProfileDir: string | null,\n): Promise<void> {\n if (childProcess) {\n childProcess.kill();\n // Wait briefly for exit\n await new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, 2000);\n childProcess.once('exit', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n if (temporaryProfileDir) {\n await rm(temporaryProfileDir, { recursive: true, force: true }).catch(() => {});\n log.debug({ dir: temporaryProfileDir }, 'Cleaned up temporary profile');\n }\n}\n\n// ── Doctor / status ─────────────────────────────────────────────────────────\n\nexport interface CloakBrowserDoctorResult {\n installed: boolean;\n version: string | null;\n binaryPath: string | null;\n platform: string;\n cacheDir: string;\n expectedSha256: string;\n /** Primary URL the install flow would fetch from. */\n downloadUrl: string;\n /** Fallback URLs (rendered as alternatives in the install confirm dialog). */\n fallbackUrls: string[];\n /** True when `binaryPath` was user-supplied (UI should surface a warning). */\n customBinaryPath: boolean;\n}\n\n/**\n * Download (if needed), launch headlessly to verify, then return doctor status.\n * Used by gateway install endpoints and CLI.\n */\nexport async function installCloakBrowser(\n config: CloakBrowserConfig = {},\n): Promise<CloakBrowserDoctorResult> {\n const result = await launchCloakBrowser({\n headless: true,\n temporaryProfile: true,\n keepOpen: false,\n cacheDir: config.cacheDir,\n binaryPath: config.binaryPath,\n onProgress: config.onProgress,\n signal: config.signal,\n });\n await result.browser?.close().catch(() => {});\n await cleanupCloakBrowser(result.childProcess, result.temporaryProfileDir);\n return cloakBrowserDoctor({ cacheDir: config.cacheDir, binaryPath: config.binaryPath });\n}\n\n/** Check CloakBrowser installation status. */\nexport async function cloakBrowserDoctor(\n config: CloakBrowserConfig = {},\n): Promise<CloakBrowserDoctorResult> {\n const platformInfo = detectPlatform();\n const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);\n await migrateLegacyCloakBrowserLayout(cacheDir);\n const { execPath, installed, customBinaryPath } = await resolveCloakExecutablePath(\n cacheDir,\n platformInfo,\n config.binaryPath,\n );\n const [primary, ...fallbacks] = archiveDownloadUrls(platformInfo);\n\n return {\n installed,\n version: installed ? platformInfo.chromiumVersion : null,\n binaryPath: installed ? execPath : null,\n platform: platformInfo.tag,\n cacheDir,\n expectedSha256: platformInfo.expectedSha256,\n downloadUrl: primary ?? '',\n fallbackUrls: fallbacks,\n customBinaryPath,\n };\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cloakbrowser.js","names":["osPlatform","osArch"],"sources":["../../../../src/browser/providers/cloakbrowser.ts"],"sourcesContent":["/**\n * CloakBrowser provider — anti-fingerprint Chromium with stealth capabilities.\n *\n * Manages CloakBrowser binary download, stealth launch, CDP connection,\n * keep-open process reuse, and temporary profile lifecycle.\n *\n * Ported from brocli's cloak.rs to TypeScript, using Playwright's connectOverCDP\n * to produce a standard Browser/BrowserContext pair.\n */\n\nimport { createHash } from 'node:crypto';\nimport { createReadStream, createWriteStream } from 'node:fs';\nimport { mkdir, mkdtemp, rm, stat } from 'node:fs/promises';\nimport { platform as osPlatform, arch as osArch, tmpdir } from 'node:os';\nimport { join, resolve } from 'node:path';\nimport { pipeline } from 'node:stream/promises';\nimport { Readable, Transform } from 'node:stream';\nimport { ChildProcess, spawn } from 'node:child_process';\n\nimport AdmZip from 'adm-zip';\nimport type { Browser, BrowserContext } from 'playwright-core';\n\nimport type { BrowserInstallProgress } from '../install-progress.js';\nimport { createLogger } from '../../utils/logger.js';\nimport { resolveBinDir } from '../../config/paths.js';\nimport { assertCacheDir, expandHome } from '../cache-dir-policy.js';\nimport { pickFreePort } from '../free-port.js';\nimport { loadPlaywrightCoreModule } from './playwright-doctor.js';\nimport {\n buildStealthArgs,\n filterCloakBrowserExtraArgs,\n generateFingerprintSeed,\n makeExecutable,\n removeQuarantineAttr,\n WEBDRIVER_OVERRIDE_SCRIPT,\n} from '../stealth.js';\nimport type { CloakBrowserConfig } from './types.js';\n\nconst log = createLogger('CloakBrowser');\n\n// ── Platform info ───────────────────────────────────────────────────────────\n\ninterface PlatformInfo {\n tag: string;\n chromiumVersion: string;\n archiveExt: string;\n executableRelativePath: string;\n fingerprintPlatform: string;\n /**\n * Expected SHA-256 of the downloaded archive (lowercase hex). Empty string =\n * verification opt-out for this platform; warned but not fatal. To populate:\n * download the archive once, run `shasum -a 256 <file>`, paste here.\n */\n expectedSha256: string;\n}\n\nconst DOWNLOAD_BASE_URL = 'https://cloakbrowser.dev';\nconst GITHUB_DOWNLOAD_BASE_URL = 'https://github.com/CloakHQ/CloakBrowser/releases/download';\nconst XOPC_CLOAKBROWSER_PROXY_BASE =\n process.env.XOPC_CLOAKBROWSER_DOWNLOAD_BASE?.trim().replace(/\\/$/, '') ||\n 'https://xopc.ai/api/cloakbrowser/download';\nconst READY_TIMEOUT_MS = 45_000;\nconst READY_POLL_INTERVAL_MS = 300;\nconst DEFAULT_KEEP_OPEN_CDP_PORT = 9222;\n\nconst PLATFORMS: Record<string, PlatformInfo> = {\n 'darwin-arm64': {\n tag: 'darwin-arm64',\n chromiumVersion: '145.0.7632.109.2',\n archiveExt: '.tar.gz',\n executableRelativePath: 'Chromium.app/Contents/MacOS/Chromium',\n fingerprintPlatform: 'macos',\n expectedSha256: '',\n },\n 'darwin-x64': {\n tag: 'darwin-x64',\n chromiumVersion: '145.0.7632.109.2',\n archiveExt: '.tar.gz',\n executableRelativePath: 'Chromium.app/Contents/MacOS/Chromium',\n fingerprintPlatform: 'macos',\n expectedSha256: '',\n },\n 'linux-arm64': {\n tag: 'linux-arm64',\n chromiumVersion: '146.0.7680.177.4',\n archiveExt: '.tar.gz',\n executableRelativePath: 'chrome',\n fingerprintPlatform: 'windows',\n expectedSha256: '',\n },\n 'linux-x64': {\n tag: 'linux-x64',\n chromiumVersion: '146.0.7680.177.4',\n archiveExt: '.tar.gz',\n executableRelativePath: 'chrome',\n fingerprintPlatform: 'windows',\n expectedSha256: '',\n },\n 'win32-x64': {\n tag: 'windows-x64',\n chromiumVersion: '146.0.7680.177.4',\n archiveExt: '.zip',\n executableRelativePath: 'chrome.exe',\n fingerprintPlatform: 'windows',\n expectedSha256: '',\n },\n};\n\nfunction detectPlatform(): PlatformInfo {\n const os = osPlatform();\n const architecture = osArch();\n const archMap: Record<string, string> = { arm64: 'arm64', x64: 'x64' };\n const key = `${os}-${archMap[architecture] ?? architecture}`;\n const info = PLATFORMS[key];\n if (!info) {\n throw new Error(`Unsupported CloakBrowser platform: ${os}/${architecture}`);\n }\n return info;\n}\n\n/** Test-only: enumerate platform manifests. */\nexport function listCloakBrowserPlatforms(): PlatformInfo[] {\n return Object.values(PLATFORMS);\n}\n\nfunction archiveDownloadUrls(platformInfo: PlatformInfo): string[] {\n const archiveName = `cloakbrowser-${platformInfo.tag}${platformInfo.archiveExt}`;\n return [\n `${XOPC_CLOAKBROWSER_PROXY_BASE}/${archiveName}`,\n `${GITHUB_DOWNLOAD_BASE_URL}/chromium-v${platformInfo.chromiumVersion}/${archiveName}`,\n `${DOWNLOAD_BASE_URL}/download/${archiveName}`,\n ];\n}\n\n/** Test-only: resolved download URLs for a platform manifest (proxy first). */\nexport function cloakBrowserArchiveDownloadUrls(platformInfo: PlatformInfo): string[] {\n return archiveDownloadUrls(platformInfo);\n}\n\nasync function sha256OfFile(path: string): Promise<string> {\n const hash = createHash('sha256');\n await pipeline(createReadStream(path), hash);\n return hash.digest('hex');\n}\n\n// ── Binary management ───────────────────────────────────────────────────────\n\nconst CLOAKBROWSER_DIR_NAME = 'cloakbrowser';\n\n/** Default CloakBrowser home: ~/.xopc/bin/cloakbrowser (chromium-v*, profiles/, …). */\nexport function defaultCloakBrowserCacheDir(): string {\n return join(resolveBinDir(), CLOAKBROWSER_DIR_NAME);\n}\n\n/** Resolve configured or default CloakBrowser cache root. */\nexport function resolveCloakBrowserCacheDir(configured?: string): string {\n if (configured?.trim()) {\n const resolved = assertCacheDir(configured.trim());\n // Legacy configs used ~/.xopc/bin — normalize to ~/.xopc/bin/cloakbrowser.\n if (resolve(resolved) === resolve(resolveBinDir())) {\n return defaultCloakBrowserCacheDir();\n }\n return resolved;\n }\n return defaultCloakBrowserCacheDir();\n}\n\nasync function resolveCloakExecutablePath(\n cacheDir: string,\n platformInfo: PlatformInfo,\n configuredBinaryPath?: string,\n): Promise<{ execPath: string; installed: boolean; customBinaryPath: boolean }> {\n const trimmed = configuredBinaryPath?.trim();\n const autoPath = binaryPath(cacheDir, platformInfo);\n if (!trimmed) {\n return {\n execPath: autoPath,\n installed: await fileExists(autoPath),\n customBinaryPath: false,\n };\n }\n\n const customPath = resolve(expandHome(trimmed));\n if (await fileExists(customPath)) {\n return { execPath: customPath, installed: true, customBinaryPath: true };\n }\n\n if (await fileExists(autoPath)) {\n return { execPath: autoPath, installed: true, customBinaryPath: true };\n }\n\n return { execPath: customPath, installed: false, customBinaryPath: true };\n}\n\nfunction binaryDir(cacheDir: string, platformInfo: PlatformInfo): string {\n return join(cacheDir, `chromium-v${platformInfo.chromiumVersion}`);\n}\n\nfunction binaryPath(cacheDir: string, platformInfo: PlatformInfo): string {\n return join(binaryDir(cacheDir, platformInfo), platformInfo.executableRelativePath);\n}\n\nasync function fileExists(path: string): Promise<boolean> {\n try {\n await stat(path);\n return true;\n } catch {\n return false;\n }\n}\n\nfunction runCommand(command: string, args: string[]): Promise<void> {\n return new Promise((resolve, reject) => {\n const child = spawn(command, args, { stdio: ['ignore', 'ignore', 'pipe'] });\n let stderr = '';\n child.stderr?.on('data', (data: Buffer) => {\n stderr += data.toString();\n });\n child.once('error', reject);\n child.once('exit', (code, signal) => {\n if (code === 0) {\n resolve();\n return;\n }\n const reason = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n const detail = stderr.trim() ? `: ${stderr.trim().slice(0, 500)}` : '';\n reject(new Error(`${command} failed with ${reason}${detail}`));\n });\n });\n}\n\nasync function extractArchive(archivePath: string, targetDir: string, platformInfo: PlatformInfo): Promise<void> {\n if (platformInfo.archiveExt === '.tar.gz') {\n await runCommand('tar', ['-xzf', archivePath, '-C', targetDir]);\n return;\n }\n\n if (platformInfo.archiveExt === '.zip') {\n const zip = new AdmZip(archivePath);\n zip.extractAllTo(targetDir, true);\n return;\n }\n\n throw new Error(`Unsupported CloakBrowser archive format: ${platformInfo.archiveExt}`);\n}\n\n/**\n * Download and extract CloakBrowser binary.\n *\n * After download, verifies SHA-256 against the platform manifest when one is\n * present. Set `XOPC_CLOAKBROWSER_SKIP_HASH=1` to bypass (development only;\n * the gateway logs a warning when the env var is honoured).\n */\nasync function downloadArchiveToFile(\n url: string,\n archivePath: string,\n onProgress?: (progress: BrowserInstallProgress) => void | Promise<void>,\n signal?: AbortSignal,\n): Promise<void> {\n if (signal?.aborted) throw new Error('Install cancelled');\n\n const response = await fetch(url, { redirect: 'follow', signal });\n if (!response.ok || !response.body) {\n throw new Error(`download returned HTTP ${response.status}`);\n }\n\n const contentLength = response.headers.get('content-length');\n const totalBytes =\n contentLength && Number.isFinite(Number(contentLength)) ? Number(contentLength) : null;\n let bytesReceived = 0;\n\n let lastReportAt = 0;\n const report = (force = false) => {\n const now = Date.now();\n if (!force && now - lastReportAt < 250) return;\n lastReportAt = now;\n void onProgress?.({\n phase: 'downloading',\n message: 'Downloading CloakBrowser archive',\n bytesReceived,\n totalBytes,\n percent:\n totalBytes && totalBytes > 0\n ? Math.min(100, Math.round((bytesReceived / totalBytes) * 100))\n : null,\n });\n };\n\n report(true);\n\n const nodeStream = Readable.fromWeb(response.body as Parameters<typeof Readable.fromWeb>[0]);\n const counting = new Transform({\n transform(chunk, _encoding, callback) {\n bytesReceived += chunk.length;\n report();\n callback(null, chunk);\n },\n });\n\n await pipeline(nodeStream, counting, createWriteStream(archivePath));\n report(true);\n}\n\nasync function downloadBinary(\n cacheDir: string,\n platformInfo: PlatformInfo,\n onProgress?: (progress: BrowserInstallProgress) => void | Promise<void>,\n signal?: AbortSignal,\n): Promise<string> {\n const targetDir = binaryDir(cacheDir, platformInfo);\n const execPath = binaryPath(cacheDir, platformInfo);\n\n if (await fileExists(execPath)) {\n log.info({ path: execPath }, 'CloakBrowser binary already cached');\n await onProgress?.({ phase: 'ready', message: 'CloakBrowser binary already cached', percent: 100 });\n return execPath;\n }\n\n await mkdir(cacheDir, { recursive: true });\n await onProgress?.({ phase: 'starting', message: 'Preparing CloakBrowser download' });\n\n const archiveName = `cloakbrowser-${platformInfo.tag}${platformInfo.archiveExt}`;\n const urls = archiveDownloadUrls(platformInfo);\n const expectedSha256 = platformInfo.expectedSha256.trim().toLowerCase();\n const skipHash = process.env.XOPC_CLOAKBROWSER_SKIP_HASH === '1';\n\n log.info({ version: platformInfo.chromiumVersion, platform: platformInfo.tag }, 'Downloading CloakBrowser...');\n\n let downloadError: Error | undefined;\n for (const url of urls) {\n if (signal?.aborted) throw new Error('Install cancelled');\n const stagingDir = await mkdtemp(join(cacheDir, '.download-'));\n const archivePath = join(stagingDir, archiveName);\n try {\n await downloadArchiveToFile(url, archivePath, onProgress, signal);\n\n if (expectedSha256) {\n if (signal?.aborted) throw new Error('Install cancelled');\n await onProgress?.({ phase: 'verifying', message: 'Verifying SHA-256 checksum' });\n const actual = await sha256OfFile(archivePath);\n if (actual !== expectedSha256) {\n throw new Error(\n `SHA-256 mismatch: expected ${expectedSha256}, got ${actual}. Aborted to avoid running unverified binary.`,\n );\n }\n log.info({ archivePath }, 'SHA-256 verified');\n } else if (skipHash) {\n log.warn(\n { platform: platformInfo.tag, version: platformInfo.chromiumVersion },\n 'CloakBrowser SHA-256 verification skipped (XOPC_CLOAKBROWSER_SKIP_HASH=1)',\n );\n } else {\n log.warn(\n { platform: platformInfo.tag, version: platformInfo.chromiumVersion },\n 'CloakBrowser manifest has no expectedSha256; integrity NOT verified',\n );\n }\n\n await onProgress?.({ phase: 'extracting', message: 'Extracting CloakBrowser archive' });\n log.info({ archivePath }, 'Extracting CloakBrowser archive...');\n await rm(targetDir, { recursive: true, force: true }).catch(() => {});\n await mkdir(targetDir, { recursive: true });\n await extractArchive(archivePath, targetDir, platformInfo);\n\n if (!(await fileExists(execPath))) {\n throw new Error(`archive did not contain expected executable: ${execPath}`);\n }\n\n await makeExecutable(execPath);\n await removeQuarantineAttr(execPath);\n await rm(stagingDir, { recursive: true, force: true }).catch(() => {});\n\n await onProgress?.({ phase: 'ready', message: 'CloakBrowser binary ready', percent: 100 });\n log.info({ path: execPath }, 'CloakBrowser binary ready');\n return execPath;\n } catch (e) {\n await rm(stagingDir, { recursive: true, force: true }).catch(() => {});\n await rm(targetDir, { recursive: true, force: true }).catch(() => {});\n downloadError = e instanceof Error ? e : new Error(String(e));\n log.debug({ url, errorMessage: downloadError.message }, 'Download attempt failed');\n }\n }\n\n throw new Error(\n `Failed to download CloakBrowser v${platformInfo.chromiumVersion} for ${platformInfo.tag}: ${downloadError?.message ?? 'all URLs failed'}`,\n );\n}\n\n// ── CDP endpoint discovery ──────────────────────────────────────────────────\n\nasync function waitForCdpEndpoint(port: number): Promise<string> {\n const deadline = Date.now() + READY_TIMEOUT_MS;\n\n while (Date.now() < deadline) {\n try {\n const response = await fetch(`http://127.0.0.1:${port}/json/version`);\n if (response.ok) {\n const data = (await response.json()) as { webSocketDebuggerUrl?: string };\n if (data.webSocketDebuggerUrl) {\n return data.webSocketDebuggerUrl;\n }\n }\n } catch {\n // Not ready yet\n }\n await new Promise((resolve) => setTimeout(resolve, READY_POLL_INTERVAL_MS));\n }\n\n throw new Error(`CloakBrowser did not expose CDP page within ${READY_TIMEOUT_MS / 1000}s on port ${port}`);\n}\n\n/** Try to find an existing CDP page endpoint on the given port. */\nasync function reuseOrCreatePageEndpoint(port: number): Promise<string | null> {\n try {\n const response = await fetch(`http://127.0.0.1:${port}/json/list`, {\n signal: AbortSignal.timeout(2000),\n });\n if (!response.ok) return null;\n const pages = (await response.json()) as Array<{ webSocketDebuggerUrl?: string; type?: string }>;\n const page = pages.find((p) => p.type === 'page' && p.webSocketDebuggerUrl);\n if (page?.webSocketDebuggerUrl) return page.webSocketDebuggerUrl;\n\n // No pages — create one\n const newResponse = await fetch(`http://127.0.0.1:${port}/json/new`);\n if (newResponse.ok) {\n const newPage = (await newResponse.json()) as { webSocketDebuggerUrl?: string };\n if (newPage.webSocketDebuggerUrl) return newPage.webSocketDebuggerUrl;\n }\n } catch {\n // Not running\n }\n return null;\n}\n\n// ── Provider ────────────────────────────────────────────────────────────────\n\nexport interface CloakBrowserLaunchResult {\n browser?: Browser;\n context?: BrowserContext;\n childProcess: ChildProcess | null;\n temporaryProfileDir: string | null;\n cdpPort: number;\n userDataDir: string;\n reused: boolean;\n pid: number | null;\n}\n\nfunction resolveCloakBrowserProfilePaths(\n config: CloakBrowserConfig,\n cacheDir: string,\n): { userDataDir: string; temporaryProfileDir: string | null } {\n if (config.userDataDir) {\n return { userDataDir: config.userDataDir, temporaryProfileDir: null };\n }\n if (config.temporaryProfile) {\n const userDataDir = join(tmpdir(), `xopc-cloakbrowser-${process.pid}-${generateFingerprintSeed()}`);\n return { userDataDir, temporaryProfileDir: userDataDir };\n }\n return { userDataDir: join(cacheDir, 'profiles', 'default'), temporaryProfileDir: null };\n}\n\n/** Resolve the persistent profile directory agents use (not ephemeral temp dirs). */\nexport function resolveCloakBrowserPersistentProfileDir(config: CloakBrowserConfig = {}): string {\n if (config.userDataDir) return config.userDataDir;\n const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);\n return join(cacheDir, 'profiles', 'default');\n}\n\nexport interface CloakBrowserRuntimeStatus {\n running: boolean;\n port: number;\n userDataDir: string;\n temporaryProfile: boolean;\n}\n\nasync function probeCdpPort(port: number): Promise<boolean> {\n try {\n const response = await fetch(`http://127.0.0.1:${port}/json/version`, {\n signal: AbortSignal.timeout(2000),\n });\n return response.ok;\n } catch {\n return false;\n }\n}\n\n/** Probe whether CloakBrowser CDP is listening on the configured keep-open port. */\nexport async function probeCloakBrowserRuntime(\n config: CloakBrowserConfig = {},\n): Promise<CloakBrowserRuntimeStatus> {\n const keepOpen = config.keepOpen ?? true;\n const cdpPort = config.cdpPort ?? (keepOpen ? DEFAULT_KEEP_OPEN_CDP_PORT : DEFAULT_KEEP_OPEN_CDP_PORT);\n const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);\n const { userDataDir } = resolveCloakBrowserProfilePaths(config, cacheDir);\n const running = await probeCdpPort(cdpPort);\n return {\n running,\n port: cdpPort,\n userDataDir,\n temporaryProfile: config.temporaryProfile === true,\n };\n}\n\nfunction launchResultMeta(\n cdpPort: number,\n userDataDir: string,\n reused: boolean,\n pid: number | null,\n childProcess: ChildProcess | null,\n temporaryProfileDir: string | null,\n): Pick<\n CloakBrowserLaunchResult,\n 'cdpPort' | 'userDataDir' | 'reused' | 'pid' | 'childProcess' | 'temporaryProfileDir'\n> {\n return { cdpPort, userDataDir, reused, pid, childProcess, temporaryProfileDir };\n}\n\n/**\n * Launch or connect to a CloakBrowser instance and return a Playwright Browser + Context.\n */\nexport async function launchCloakBrowser(\n config: CloakBrowserConfig = {},\n): Promise<CloakBrowserLaunchResult> {\n const platformInfo = detectPlatform();\n const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);\n const keepOpen = config.keepOpen ?? true;\n const reuseExisting = config.reuseExisting ?? keepOpen;\n\n // Resolve binary\n const configuredBinary = config.binaryPath?.trim() || undefined;\n const execPath = configuredBinary\n ? (await resolveCloakExecutablePath(cacheDir, platformInfo, configuredBinary)).execPath\n : await downloadBinary(cacheDir, platformInfo, config.onProgress, config.signal);\n if (configuredBinary) {\n await makeExecutable(execPath);\n await removeQuarantineAttr(execPath);\n }\n\n // Resolve CDP port\n const cdpPort = config.cdpPort ?? (keepOpen ? DEFAULT_KEEP_OPEN_CDP_PORT : await pickFreePort());\n const skipPlaywrightConnect = config.skipPlaywrightConnect === true;\n const { userDataDir, temporaryProfileDir: plannedTempProfileDir } = resolveCloakBrowserProfilePaths(\n config,\n cacheDir,\n );\n\n // Try to reuse existing instance\n if (reuseExisting) {\n const existingEndpoint = await reuseOrCreatePageEndpoint(cdpPort);\n if (existingEndpoint) {\n log.info({ port: cdpPort }, 'Reusing existing CloakBrowser instance');\n const meta = launchResultMeta(cdpPort, userDataDir, true, null, null, null);\n if (skipPlaywrightConnect) {\n return meta;\n }\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as { default?: { chromium?: (typeof pw)['chromium'] } }).default?.chromium;\n if (!chromium?.connectOverCDP) throw new Error('playwright-core does not support connectOverCDP');\n\n const wsUrl = `ws://127.0.0.1:${cdpPort}`;\n // connectOverCDP wants the browser-level WS URL\n const versionResp = await fetch(`http://127.0.0.1:${cdpPort}/json/version`);\n const versionData = (await versionResp.json()) as { webSocketDebuggerUrl?: string };\n const browserWsUrl = versionData.webSocketDebuggerUrl ?? wsUrl;\n\n const browser = await chromium.connectOverCDP(browserWsUrl);\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : await browser.newContext();\n\n // Inject stealth script\n await context.addInitScript(WEBDRIVER_OVERRIDE_SCRIPT);\n\n return { browser, context, ...meta };\n }\n }\n\n // Resolve user data dir for a new launch\n let temporaryProfileDir: string | null = plannedTempProfileDir;\n await mkdir(userDataDir, { recursive: true });\n\n // Build launch args\n const stealthArgs = buildStealthArgs(filterCloakBrowserExtraArgs(config.extraArgs ?? []), {\n timezone: config.timezone,\n locale: config.locale,\n webrtcIp: config.webrtcIp,\n fingerprintPlatform: config.fingerprintPlatform ?? platformInfo.fingerprintPlatform,\n });\n\n const launchArgs = [\n `--remote-debugging-address=127.0.0.1`,\n `--remote-debugging-port=${cdpPort}`,\n `--user-data-dir=${userDataDir}`,\n '--no-first-run',\n '--no-default-browser-check',\n ...stealthArgs,\n ];\n\n if (config.headless) {\n launchArgs.push('--headless=new');\n }\n\n // macOS keychain bypass\n if (osPlatform() === 'darwin') {\n launchArgs.push('--use-mock-keychain');\n }\n\n await config.onProgress?.({ phase: 'running', message: 'Launching CloakBrowser for verification' });\n if (config.signal?.aborted) throw new Error('Install cancelled');\n\n log.info(\n { execPath, port: cdpPort, headless: !!config.headless, keepOpen },\n 'Launching CloakBrowser',\n );\n\n // Spawn browser process\n const child = spawn(execPath, launchArgs, {\n stdio: ['ignore', 'ignore', 'ignore'],\n detached: keepOpen, // Detach so it survives parent exit if keep-open\n });\n\n let onLaunchError: ((error: Error) => void) | null = null;\n let onLaunchExit: ((code: number | null, signal: NodeJS.Signals | null) => void) | null = null;\n const launchFailure = new Promise<never>((_resolve, reject) => {\n onLaunchError = (error) => {\n reject(new Error(`Failed to launch CloakBrowser at ${execPath}: ${error.message}`));\n };\n onLaunchExit = (code, signal) => {\n const reason = signal ? `signal ${signal}` : `exit code ${code ?? 'unknown'}`;\n reject(new Error(`CloakBrowser exited before CDP became ready (${reason})`));\n };\n child.once('error', onLaunchError);\n child.once('exit', onLaunchExit);\n });\n\n if (keepOpen) {\n child.unref();\n }\n\n // Wait for CDP to become available\n let browserWsUrl: string;\n try {\n browserWsUrl = await Promise.race([waitForCdpEndpoint(cdpPort), launchFailure]);\n if (onLaunchError) child.off('error', onLaunchError);\n if (onLaunchExit) child.off('exit', onLaunchExit);\n } catch (e) {\n if (onLaunchError) child.off('error', onLaunchError);\n if (onLaunchExit) child.off('exit', onLaunchExit);\n child.kill();\n if (temporaryProfileDir) {\n await rm(temporaryProfileDir, { recursive: true, force: true }).catch(() => {});\n }\n throw e;\n }\n\n // Get browser-level WS URL\n let browserLevelWsUrl: string;\n try {\n const versionResp = await fetch(`http://127.0.0.1:${cdpPort}/json/version`);\n const versionData = (await versionResp.json()) as { webSocketDebuggerUrl?: string };\n browserLevelWsUrl = versionData.webSocketDebuggerUrl ?? browserWsUrl;\n } catch {\n browserLevelWsUrl = browserWsUrl;\n }\n\n const meta = launchResultMeta(\n cdpPort,\n userDataDir,\n false,\n child.pid ?? null,\n keepOpen ? null : child,\n temporaryProfileDir,\n );\n\n if (skipPlaywrightConnect) {\n log.info({ port: cdpPort, pid: child.pid }, 'CloakBrowser launched (CDP only)');\n return meta;\n }\n\n // Connect Playwright over CDP\n const pw = await loadPlaywrightCoreModule();\n const chromium = pw.chromium ?? (pw as { default?: { chromium?: (typeof pw)['chromium'] } }).default?.chromium;\n if (!chromium?.connectOverCDP) {\n child.kill();\n throw new Error('playwright-core does not support connectOverCDP');\n }\n\n const browser = await chromium.connectOverCDP(browserLevelWsUrl);\n const contexts = browser.contexts();\n const context = contexts.length > 0 ? contexts[0] : await browser.newContext();\n\n // Inject stealth overrides\n await context.addInitScript(WEBDRIVER_OVERRIDE_SCRIPT);\n\n log.info({ port: cdpPort, pid: child.pid }, 'CloakBrowser launched and connected');\n\n return {\n browser,\n context,\n ...meta,\n };\n}\n\n/**\n * Cleanup a CloakBrowser session — kill process and remove temp profile if applicable.\n */\nexport async function cleanupCloakBrowser(\n childProcess: ChildProcess | null,\n temporaryProfileDir: string | null,\n): Promise<void> {\n if (childProcess) {\n childProcess.kill();\n // Wait briefly for exit\n await new Promise<void>((resolve) => {\n const timer = setTimeout(resolve, 2000);\n childProcess.once('exit', () => {\n clearTimeout(timer);\n resolve();\n });\n });\n }\n if (temporaryProfileDir) {\n await rm(temporaryProfileDir, { recursive: true, force: true }).catch(() => {});\n log.debug({ dir: temporaryProfileDir }, 'Cleaned up temporary profile');\n }\n}\n\n// ── Doctor / status ─────────────────────────────────────────────────────────\n\nexport interface CloakBrowserDoctorResult {\n installed: boolean;\n version: string | null;\n binaryPath: string | null;\n platform: string;\n cacheDir: string;\n expectedSha256: string;\n /** Primary URL the install flow would fetch from. */\n downloadUrl: string;\n /** Fallback URLs (rendered as alternatives in the install confirm dialog). */\n fallbackUrls: string[];\n /** True when `binaryPath` was user-supplied (UI should surface a warning). */\n customBinaryPath: boolean;\n}\n\n/**\n * Download (if needed), launch headlessly to verify, then return doctor status.\n * Used by gateway install endpoints and CLI.\n */\nexport async function installCloakBrowser(\n config: CloakBrowserConfig = {},\n): Promise<CloakBrowserDoctorResult> {\n const result = await launchCloakBrowser({\n headless: true,\n temporaryProfile: true,\n keepOpen: false,\n cacheDir: config.cacheDir,\n binaryPath: config.binaryPath,\n onProgress: config.onProgress,\n signal: config.signal,\n });\n await result.browser?.close().catch(() => {});\n await cleanupCloakBrowser(result.childProcess, result.temporaryProfileDir);\n return cloakBrowserDoctor({ cacheDir: config.cacheDir, binaryPath: config.binaryPath });\n}\n\n/** Check CloakBrowser installation status. */\nexport async function cloakBrowserDoctor(\n config: CloakBrowserConfig = {},\n): Promise<CloakBrowserDoctorResult> {\n const platformInfo = detectPlatform();\n const cacheDir = resolveCloakBrowserCacheDir(config.cacheDir);\n const { execPath, installed, customBinaryPath } = await resolveCloakExecutablePath(\n cacheDir,\n platformInfo,\n config.binaryPath,\n );\n const [primary, ...fallbacks] = archiveDownloadUrls(platformInfo);\n\n return {\n installed,\n version: installed ? platformInfo.chromiumVersion : null,\n binaryPath: installed ? execPath : null,\n platform: platformInfo.tag,\n cacheDir,\n expectedSha256: platformInfo.expectedSha256,\n downloadUrl: primary ?? '',\n fallbackUrls: fallbacks,\n customBinaryPath,\n };\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  import { createRequire } from "node:module";
2
- import { dirname, join } from "node:path";
3
2
  import { existsSync } from "node:fs";
4
3
  import { stat } from "node:fs/promises";
4
+ import { dirname, join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
  //#region src/browser/providers/playwright-doctor.ts
7
7
  /** Root directory of the `playwright-core` package (Electron extraResources or node_modules). */