@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.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/feishu/src/adapters/cli-login.js +3 -3
- package/dist/extensions/feishu/src/adapters/cli-login.js.map +1 -1
- package/dist/extensions/feishu/src/outbound/media-load.js +1 -1
- package/dist/extensions/feishu/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.d.ts +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.js +1 -1
- package/dist/extensions/telegram/src/delivery-chat-id.js.map +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/src/routing-integration.js +3 -2
- package/dist/extensions/telegram/src/routing-integration.js.map +1 -1
- package/dist/extensions/telegram/src/workflow-progress.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js +2 -2
- package/dist/extensions/weixin/src/__tests__/workflow-progress.test.js.map +1 -1
- package/dist/extensions/weixin/src/api/api.js +3 -3
- package/dist/extensions/weixin/src/api/api.js.map +1 -1
- package/dist/extensions/weixin/src/auth/accounts.js +12 -12
- package/dist/extensions/weixin/src/auth/accounts.js.map +1 -1
- package/dist/extensions/weixin/src/cdn/upload.js +1 -1
- package/dist/extensions/weixin/src/delivery-to.js +2 -2
- package/dist/extensions/weixin/src/delivery-to.js.map +1 -1
- package/dist/extensions/weixin/src/media/data-url.js +1 -1
- package/dist/extensions/weixin/src/messaging/debug-mode.js +5 -5
- package/dist/extensions/weixin/src/messaging/debug-mode.js.map +1 -1
- package/dist/extensions/weixin/src/messaging/inbound.js +11 -11
- package/dist/extensions/weixin/src/messaging/inbound.js.map +1 -1
- package/dist/extensions/weixin/src/messaging/process-message.js +1 -1
- package/dist/extensions/weixin/src/plugin.js +1 -1
- package/dist/extensions/weixin/src/storage/sync-buf.js +4 -4
- package/dist/extensions/weixin/src/storage/sync-buf.js.map +1 -1
- package/dist/extensions/weixin/src/workflow-progress.d.ts +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js +1 -1
- package/dist/extensions/weixin/src/workflow-progress.js.map +1 -1
- package/dist/gateway/static/root/assets/agents-CRxETUZx.js +222 -0
- package/dist/gateway/static/root/assets/{apps-page-DrfytjOb.js → apps-page-wKWf3l57.js} +1 -1
- package/dist/gateway/static/root/assets/channels-settings-DDbqVNkx.js +1 -0
- package/dist/gateway/static/root/assets/{channels-status-swr-Bs5kMCMI.js → channels-status-swr-DIsl75Y3.js} +1 -1
- package/dist/gateway/static/root/assets/copy-SxMW6Xpc.js +1 -0
- package/dist/gateway/static/root/assets/{cron-api-BuVcZ5zR.js → cron-api-N9hvuRrn.js} +1 -1
- package/dist/gateway/static/root/assets/{cron-page-BMrloeFH.js → cron-page-tlNGNxhP.js} +1 -1
- package/dist/gateway/static/root/assets/{dist-CKU1OOTf.js → dist-CJwfHYvT.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-BdW_46sN.js → extension-debug-page-BVJohZoZ.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-DW47KI82.js → extension-page-BT2tmElC.js} +1 -1
- package/dist/gateway/static/root/assets/extension-settings-page-BSS47c2j.js +1 -0
- package/dist/gateway/static/root/assets/{fetch-B2MYHbWg.js → fetch-BaFNUtkE.js} +1 -1
- package/dist/gateway/static/root/assets/{field-primitives-DPG-oJmx.js → field-primitives-QwYEq6Hz.js} +1 -1
- package/dist/gateway/static/root/assets/{heartbeat-config-api-C8dNts9i.js → heartbeat-config-api-BVSidEDJ.js} +1 -1
- package/dist/gateway/static/root/assets/index-CqZzHNEg.css +1 -0
- package/dist/gateway/static/root/assets/{index-BmVYculr.js → index-qNrVJp-y.js} +97 -95
- package/dist/gateway/static/root/assets/{logs-page-sTsVWz0X.js → logs-page-DDonPVLn.js} +1 -1
- package/dist/gateway/static/root/assets/sessions-page-DKt-Wmib.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-DuvRQW--.js → settings-form-section-B8N3A3Zo.js} +1 -1
- package/dist/gateway/static/root/assets/settings-page-DcJjvvw4.js +3 -0
- package/dist/gateway/static/root/assets/{share-preview-page-BtG2kLDh.js → share-preview-page-Q7KqkO-u.js} +1 -1
- package/dist/gateway/static/root/assets/skills-page-DuJ4BTO3.js +2 -0
- package/dist/gateway/static/root/assets/{theme-store-DryYl3qD.js → theme-store-BbRc5ugR.js} +1 -1
- package/dist/gateway/static/root/assets/url-D6jvVYIA.js +7 -0
- package/dist/gateway/static/root/assets/{utils-BY7bU1DT.js → utils-CxDGduqK.js} +1 -1
- package/dist/gateway/static/root/assets/voice-api-key-field-CTyHz7L_.js +1 -0
- package/dist/gateway/static/root/assets/workflows-page-GacJ41Fv.js +27 -0
- package/dist/gateway/static/root/index.html +6 -5
- package/dist/package.js +1 -1
- package/dist/src/agent/agent-manager.js +7 -7
- package/dist/src/agent/agent-scope.d.ts +4 -0
- package/dist/src/agent/agent-scope.js +53 -10
- package/dist/src/agent/agent-scope.js.map +1 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js +2 -1
- package/dist/src/agent/bootstrap/filter-bootstrap-files.js.map +1 -1
- package/dist/src/agent/bootstrap/load-bootstrap-files.js +1 -1
- package/dist/src/agent/child-agent-factory.d.ts +15 -0
- package/dist/src/agent/child-agent-factory.js +35 -2
- package/dist/src/agent/child-agent-factory.js.map +1 -1
- package/dist/src/agent/client-error-format.d.ts +20 -0
- package/dist/src/agent/client-error-format.js +97 -0
- package/dist/src/agent/client-error-format.js.map +1 -0
- package/dist/src/agent/context/workspace-seed.js +2 -2
- package/dist/src/agent/embedded/run-turn.js +23 -4
- package/dist/src/agent/embedded/run-turn.js.map +1 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js +2 -1
- package/dist/src/agent/embedded/session-tool-result-guard.js.map +1 -1
- package/dist/src/agent/embedded/tool-result-truncation.js +2 -1
- package/dist/src/agent/embedded/tool-result-truncation.js.map +1 -1
- package/dist/src/agent/fallback/candidates.js +2 -2
- package/dist/src/agent/fallback/candidates.js.map +1 -1
- package/dist/src/agent/goals/goal-locale.d.ts +1 -1
- package/dist/src/agent/goals/goal-run-store.js +4 -4
- package/dist/src/agent/goals/persistent-goal-apis.d.ts +0 -2
- package/dist/src/agent/goals/persistent-goal-service.js +1 -2
- package/dist/src/agent/goals/persistent-goal-service.js.map +1 -1
- package/dist/src/agent/goals/post-turn.js +2 -2
- package/dist/src/agent/image/generation/normalization.js +2 -12
- package/dist/src/agent/image/generation/normalization.js.map +1 -1
- package/dist/src/agent/image/generation/provider-registry.d.ts +4 -8
- package/dist/src/agent/image/generation/provider-registry.js.map +1 -1
- package/dist/src/agent/image/generation/runtime.d.ts +2 -2
- package/dist/src/agent/image/generation/runtime.js.map +1 -1
- package/dist/src/agent/image/generation/types.d.ts +0 -18
- package/dist/src/agent/image/image-helpers.js +6 -1
- package/dist/src/agent/image/image-helpers.js.map +1 -1
- package/dist/src/agent/image/index.d.ts +1 -1
- package/dist/src/agent/image/load-image-media.js +2 -2
- package/dist/src/agent/inbound/inbound-loop.d.ts +5 -0
- package/dist/src/agent/inbound/inbound-loop.js +41 -10
- package/dist/src/agent/inbound/inbound-loop.js.map +1 -1
- package/dist/src/agent/inbound/turn-dispatcher.d.ts +4 -0
- package/dist/src/agent/inbound/turn-dispatcher.js +7 -5
- package/dist/src/agent/inbound/turn-dispatcher.js.map +1 -1
- package/dist/src/agent/ipc/bus.js +1 -1
- package/dist/src/agent/ipc/inbox.js +2 -2
- package/dist/src/agent/ipc/socket.js +1 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-materialize.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-names.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-names.js.map +1 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js +2 -1
- package/dist/src/agent/mcp/bundle-mcp-runtime.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport-config.js +2 -1
- package/dist/src/agent/mcp/mcp-transport-config.js.map +1 -1
- package/dist/src/agent/mcp/mcp-transport.js +2 -1
- package/dist/src/agent/mcp/mcp-transport.js.map +1 -1
- package/dist/src/agent/media-generation/runtime-shared.js +2 -9
- package/dist/src/agent/media-generation/runtime-shared.js.map +1 -1
- package/dist/src/agent/memory/builtin-memory-store.js +1 -1
- package/dist/src/agent/memory/dreaming/deep-promotion.js +1 -1
- package/dist/src/agent/memory/dreaming/events.js +1 -1
- package/dist/src/agent/memory/dreaming/last-run.js +1 -1
- package/dist/src/agent/memory/dreaming/light-sweep.js +1 -1
- package/dist/src/agent/memory/dreaming/preview.js +1 -1
- package/dist/src/agent/memory/dreaming/rem-patterns.js +1 -1
- package/dist/src/agent/memory/dreaming/short-term-store.js +1 -1
- package/dist/src/agent/memory/dreaming/utils.js +1 -1
- package/dist/src/agent/memory/plugin-discovery.js +1 -1
- package/dist/src/agent/messaging/command-handler.d.ts +6 -0
- package/dist/src/agent/messaging/command-handler.js +5 -0
- package/dist/src/agent/messaging/command-handler.js.map +1 -1
- package/dist/src/agent/models/manager.js +1 -1
- package/dist/src/agent/orchestration/llm-turn-retry.d.ts +2 -0
- package/dist/src/agent/orchestration/llm-turn-retry.js +9 -1
- package/dist/src/agent/orchestration/llm-turn-retry.js.map +1 -1
- package/dist/src/agent/prompt/safety.d.ts +0 -7
- package/dist/src/agent/prompt/safety.js +1 -20
- package/dist/src/agent/prompt/safety.js.map +1 -1
- package/dist/src/agent/prompt/service-prompt-builder.js +2 -2
- package/dist/src/agent/reply/post-compaction-context.js +1 -1
- package/dist/src/agent/reply/workspace-boundary-read.js +1 -1
- package/dist/src/agent/sandbox/path-policy.js +2 -2
- package/dist/src/agent/service/build-direct-message-content.js +2 -2
- package/dist/src/agent/service/build-direct-message-content.js.map +1 -1
- package/dist/src/agent/service/direct-turn-helpers.d.ts +3 -1
- package/dist/src/agent/service/direct-turn-helpers.js +6 -1
- package/dist/src/agent/service/direct-turn-helpers.js.map +1 -1
- package/dist/src/agent/service/process-direct-one-shot.d.ts +4 -0
- package/dist/src/agent/service/process-direct-one-shot.js +15 -2
- package/dist/src/agent/service/process-direct-one-shot.js.map +1 -1
- package/dist/src/agent/service/process-direct-streaming.d.ts +4 -0
- package/dist/src/agent/service/process-direct-streaming.js +53 -7
- package/dist/src/agent/service/process-direct-streaming.js.map +1 -1
- package/dist/src/agent/service/webchat-tts.d.ts +1 -2
- package/dist/src/agent/service/webchat-tts.js +2 -2
- package/dist/src/agent/service/webchat-tts.js.map +1 -1
- package/dist/src/agent/service.d.ts +8 -0
- package/dist/src/agent/service.js +25 -5
- package/dist/src/agent/service.js.map +1 -1
- package/dist/src/agent/session/session-inspector.js +1 -1
- package/dist/src/agent/skills/config.js +1 -1
- package/dist/src/agent/skills/hub-hash.js +2 -2
- package/dist/src/agent/skills/hub-lock.js +1 -1
- package/dist/src/agent/skills/hub-pull.js +2 -2
- package/dist/src/agent/skills/index.js +1 -1
- package/dist/src/agent/skills/managed-store.js +1 -1
- package/dist/src/agent/skills/scanner.js +1 -1
- package/dist/src/agent/skills/skill-manage-ops.js +1 -1
- package/dist/src/agent/skills/skill-manager.js +1 -1
- package/dist/src/agent/tools/create-share-tool.js +27 -20
- package/dist/src/agent/tools/create-share-tool.js.map +1 -1
- package/dist/src/agent/tools/dreaming-tool.js +1 -1
- package/dist/src/agent/tools/factory.js +2 -2
- package/dist/src/agent/tools/image-generate-tool.js +1 -1
- package/dist/src/agent/tools/index.d.ts +0 -1
- package/dist/src/agent/tools/index.js +4 -5
- package/dist/src/agent/tools/send-media.js +1 -1
- package/dist/src/agent/tools/shell.js +0 -13
- package/dist/src/agent/tools/shell.js.map +1 -1
- package/dist/src/agent/tools/skill-manage-tool.js +1 -1
- package/dist/src/agent/tools/workflow-tool.js +70 -16
- package/dist/src/agent/tools/workflow-tool.js.map +1 -1
- package/dist/src/agent/tools/write.js +1 -1
- package/dist/src/agent/workflow/agent-progress.d.ts +5 -0
- package/dist/src/agent/workflow/agent-progress.js +65 -0
- package/dist/src/agent/workflow/agent-progress.js.map +1 -0
- package/dist/src/agent/workflow/builtins/audit-repo.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/audit-repo.js +14 -0
- package/dist/src/agent/workflow/builtins/audit-repo.js.map +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/debug-incident.js +14 -0
- package/dist/src/agent/workflow/builtins/debug-incident.js.map +1 -1
- package/dist/src/agent/workflow/builtins/implementation-plan.d.ts +12 -0
- package/dist/src/agent/workflow/builtins/implementation-plan.js +175 -0
- package/dist/src/agent/workflow/builtins/implementation-plan.js.map +1 -0
- package/dist/src/agent/workflow/builtins/index.d.ts +3 -1
- package/dist/src/agent/workflow/builtins/index.js +11 -1
- package/dist/src/agent/workflow/builtins/index.js.map +1 -1
- package/dist/src/agent/workflow/builtins/multi-perspective-review.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/multi-perspective-review.js +14 -0
- package/dist/src/agent/workflow/builtins/multi-perspective-review.js.map +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/pr-review.js +14 -0
- package/dist/src/agent/workflow/builtins/pr-review.js.map +1 -1
- package/dist/src/agent/workflow/builtins/release-check.d.ts +11 -0
- package/dist/src/agent/workflow/builtins/release-check.js +165 -0
- package/dist/src/agent/workflow/builtins/release-check.js.map +1 -0
- package/dist/src/agent/workflow/builtins/research.d.ts +1 -1
- package/dist/src/agent/workflow/builtins/research.js +14 -0
- package/dist/src/agent/workflow/builtins/research.js.map +1 -1
- package/dist/src/agent/workflow/catalog.js +1 -1
- package/dist/src/agent/workflow/channel-capability.d.ts +3 -3
- package/dist/src/agent/workflow/index.d.ts +2 -1
- package/dist/src/agent/workflow/index.js +3 -2
- package/dist/src/agent/workflow/lint.d.ts +38 -0
- package/dist/src/agent/workflow/lint.js +74 -0
- package/dist/src/agent/workflow/lint.js.map +1 -0
- package/dist/src/agent/workflow/meta-locale.d.ts +12 -0
- package/dist/src/agent/workflow/meta-locale.js +62 -0
- package/dist/src/agent/workflow/meta-locale.js.map +1 -0
- package/dist/src/agent/workflow/parser.js +7 -1
- package/dist/src/agent/workflow/parser.js.map +1 -1
- package/dist/src/agent/workflow/runtime.d.ts +4 -1
- package/dist/src/agent/workflow/runtime.js +88 -8
- package/dist/src/agent/workflow/runtime.js.map +1 -1
- package/dist/src/agent/workflow/snapshot.js +2 -12
- package/dist/src/agent/workflow/snapshot.js.map +1 -1
- package/dist/src/agent/workflow/step-labels.d.ts +8 -0
- package/dist/src/agent/workflow/step-labels.js +48 -0
- package/dist/src/agent/workflow/step-labels.js.map +1 -0
- package/dist/src/agent/workflow/subagent-runner.js +46 -1
- package/dist/src/agent/workflow/subagent-runner.js.map +1 -1
- package/dist/src/agent/workflow/types.d.ts +76 -1
- package/dist/src/auth/credentials.d.ts +5 -0
- package/dist/src/auth/credentials.js +12 -3
- package/dist/src/auth/credentials.js.map +1 -1
- package/dist/src/auth/profiles/store.js +1 -1
- package/dist/src/auth/sync-provider-auth.js +1 -1
- package/dist/src/browser/cache-dir-policy.js +1 -1
- package/dist/src/browser/cdp-local-launcher.js +2 -2
- package/dist/src/browser/index.js +4 -4
- package/dist/src/browser/manager.d.ts +1 -3
- package/dist/src/browser/manager.js +0 -6
- package/dist/src/browser/manager.js.map +1 -1
- package/dist/src/browser/providers/browser-ext-install.d.ts +4 -4
- package/dist/src/browser/providers/browser-ext-install.js +41 -88
- package/dist/src/browser/providers/browser-ext-install.js.map +1 -1
- package/dist/src/browser/providers/cloakbrowser.d.ts +0 -5
- package/dist/src/browser/providers/cloakbrowser.js +6 -59
- package/dist/src/browser/providers/cloakbrowser.js.map +1 -1
- package/dist/src/browser/providers/playwright-doctor.js +1 -1
- package/dist/src/browser/stealth.js +1 -1
- package/dist/src/channels/attachments/inbound-persist.js +1 -1
- package/dist/src/channels/attachments/outbound-tts-persist.js +1 -1
- package/dist/src/channels/attachments/voice-stt-webchat.js +10 -8
- package/dist/src/channels/attachments/voice-stt-webchat.js.map +1 -1
- package/dist/src/channels/outbound/persist-store.js +1 -1
- package/dist/src/channels/pairing/allow-from-file.js +9 -9
- package/dist/src/channels/pairing/allow-from-file.js.map +1 -1
- package/dist/src/channels/pairing/pairing-store.js +7 -7
- package/dist/src/channels/pairing/pairing-store.js.map +1 -1
- package/dist/src/chat-commands/builtins/config.js +2 -2
- package/dist/src/chat-commands/builtins/session.js +1 -1
- package/dist/src/chat-commands/builtins/session.js.map +1 -1
- package/dist/src/chat-commands/builtins/tts.js +2 -2
- package/dist/src/chat-commands/builtins/tts.js.map +1 -1
- package/dist/src/chat-commands/context.d.ts +3 -0
- package/dist/src/chat-commands/context.js +22 -4
- package/dist/src/chat-commands/context.js.map +1 -1
- package/dist/src/chat-commands/session-key.d.ts +4 -37
- package/dist/src/chat-commands/session-key.js +49 -85
- package/dist/src/chat-commands/session-key.js.map +1 -1
- package/dist/src/chat-commands/types.d.ts +2 -0
- package/dist/src/cli/commands/agent/interactive.js +2 -2
- package/dist/src/cli/commands/agent/interactive.js.map +1 -1
- package/dist/src/cli/commands/agent/sessions.js +2 -2
- package/dist/src/cli/commands/agent/sessions.js.map +1 -1
- package/dist/src/cli/commands/agent.js +4 -5
- package/dist/src/cli/commands/agent.js.map +1 -1
- package/dist/src/cli/commands/channels.js +1 -5
- package/dist/src/cli/commands/channels.js.map +1 -1
- package/dist/src/cli/commands/config.js +1 -1
- package/dist/src/cli/commands/doctor/checks/config-health.js +1 -1
- package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
- package/dist/src/cli/commands/doctor/checks/session-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/state-integrity.js +1 -1
- package/dist/src/cli/commands/doctor/checks/workspace-status.js +1 -1
- package/dist/src/cli/commands/extension-dev.js +1 -1
- package/dist/src/cli/commands/extension-marketplace.js +1 -1
- package/dist/src/cli/commands/extension-pack.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle-core.js +1 -1
- package/dist/src/cli/commands/gateway/lifecycle-core.js.map +1 -1
- package/dist/src/cli/commands/gateway/logs.d.ts +9 -0
- package/dist/src/cli/commands/gateway/logs.js +50 -17
- package/dist/src/cli/commands/gateway/logs.js.map +1 -1
- package/dist/src/cli/commands/image.js +23 -22
- package/dist/src/cli/commands/image.js.map +1 -1
- package/dist/src/cli/commands/init.js +4 -4
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/cli/commands/session/utils.js +2 -2
- package/dist/src/cli/commands/session/utils.js.map +1 -1
- package/dist/src/cli/commands/update.js +26 -46
- package/dist/src/cli/commands/update.js.map +1 -1
- package/dist/src/cli/utils/init-workspace-core.js +2 -2
- package/dist/src/cli/utils/session.d.ts +0 -5
- package/dist/src/cli/utils/session.js +1 -6
- package/dist/src/cli/utils/session.js.map +1 -1
- package/dist/src/commands/agents.config.js +1 -1
- package/dist/src/commands/agents.config.js.map +1 -1
- package/dist/src/config/agent-profile.js +6 -28
- package/dist/src/config/agent-profile.js.map +1 -1
- package/dist/src/config/agent-typed-models.d.ts +18 -0
- package/dist/src/config/agent-typed-models.js +53 -0
- package/dist/src/config/agent-typed-models.js.map +1 -0
- package/dist/src/config/gateway-bind.js +1 -1
- package/dist/src/config/index.js +6 -6
- package/dist/src/config/loader.js +2 -2
- package/dist/src/config/model-input.js +2 -5
- package/dist/src/config/model-input.js.map +1 -1
- package/dist/src/config/models-json.js +2 -2
- package/dist/src/config/paths-state.js +1 -1
- package/dist/src/config/profile.js +2 -2
- package/dist/src/config/schema.d.ts +253 -217
- package/dist/src/config/schema.js +91 -40
- package/dist/src/config/schema.js.map +1 -1
- package/dist/src/config/voice.d.ts +3 -28
- package/dist/src/config/voice.js +27 -261
- package/dist/src/config/voice.js.map +1 -1
- package/dist/src/config/workspace-path-helpers.d.ts +1 -2
- package/dist/src/config/workspace-path-helpers.js.map +1 -1
- package/dist/src/config/workspace-path.js +1 -1
- package/dist/src/cron/executor.js +2 -2
- package/dist/src/cron/persistence.js +1 -1
- package/dist/src/cron/run-log-store.js +1 -1
- package/dist/src/daemon/constants.js +1 -1
- package/dist/src/daemon/install-plan.js +27 -3
- package/dist/src/daemon/install-plan.js.map +1 -1
- package/dist/src/daemon/launchd.d.ts +8 -0
- package/dist/src/daemon/launchd.js +7 -14
- package/dist/src/daemon/launchd.js.map +1 -1
- package/dist/src/daemon/schtasks.d.ts +25 -0
- package/dist/src/daemon/schtasks.js +168 -48
- package/dist/src/daemon/schtasks.js.map +1 -1
- package/dist/src/daemon/service.js +5 -4
- package/dist/src/daemon/service.js.map +1 -1
- package/dist/src/daemon/systemd.d.ts +6 -0
- package/dist/src/daemon/systemd.js +20 -5
- package/dist/src/daemon/systemd.js.map +1 -1
- package/dist/src/extensions/activation-context.js +0 -1
- package/dist/src/extensions/activation-context.js.map +1 -1
- package/dist/src/extensions/bundle-mcp.js +1 -1
- package/dist/src/extensions/discover-extensions.js +1 -1
- package/dist/src/extensions/health.js +1 -1
- package/dist/src/extensions/loader.js +1 -1
- package/dist/src/extensions/lockfile.js +2 -2
- package/dist/src/extensions/normalize-manifest.js +0 -1
- package/dist/src/extensions/normalize-manifest.js.map +1 -1
- package/dist/src/extensions/types/manifest.d.ts +0 -2
- package/dist/src/gateway/agent-builtin-tools.d.ts +1 -1
- package/dist/src/gateway/agent-builtin-tools.js +1 -0
- package/dist/src/gateway/agent-builtin-tools.js.map +1 -1
- package/dist/src/gateway/agents-admin.d.ts +9 -0
- package/dist/src/gateway/agents-admin.js +28 -4
- package/dist/src/gateway/agents-admin.js.map +1 -1
- package/dist/src/gateway/config-tools-web.js +3 -2
- package/dist/src/gateway/config-tools-web.js.map +1 -1
- package/dist/src/gateway/file-path-classifier.js +2 -2
- package/dist/src/gateway/heartbeat/service.js +2 -2
- package/dist/src/gateway/heartbeat/service.js.map +1 -1
- package/dist/src/gateway/hono/app.js +1 -1
- package/dist/src/gateway/hono/lib/agent-model.d.ts +25 -10
- package/dist/src/gateway/hono/lib/agent-model.js +60 -36
- package/dist/src/gateway/hono/lib/agent-model.js.map +1 -1
- package/dist/src/gateway/hono/lib/config-payload.js +29 -6
- package/dist/src/gateway/hono/lib/config-payload.js.map +1 -1
- package/dist/src/gateway/hono/lib/extension-store.js +2 -2
- package/dist/src/gateway/hono/lib/mask-secret-length.d.ts +6 -0
- package/dist/src/gateway/hono/lib/mask-secret-length.js +16 -0
- package/dist/src/gateway/hono/lib/mask-secret-length.js.map +1 -0
- package/dist/src/gateway/hono/lib/safe-providers-config.d.ts +1 -1
- package/dist/src/gateway/hono/lib/safe-providers-config.js +2 -1
- package/dist/src/gateway/hono/lib/safe-providers-config.js.map +1 -1
- package/dist/src/gateway/hono/lib/safe-voice-config.js +16 -54
- package/dist/src/gateway/hono/lib/safe-voice-config.js.map +1 -1
- package/dist/src/gateway/hono/lib/static-ui.js +2 -2
- package/dist/src/gateway/hono/oauth.js +1 -1
- package/dist/src/gateway/hono/routes/agents.js +2 -2
- package/dist/src/gateway/hono/routes/auth-registry-extensions.js +1 -1
- package/dist/src/gateway/hono/routes/config-patch/agents.js +25 -7
- package/dist/src/gateway/hono/routes/config-patch/agents.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/channels.js +0 -11
- package/dist/src/gateway/hono/routes/config-patch/channels.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/gateway.js +3 -2
- package/dist/src/gateway/hono/routes/config-patch/gateway.js.map +1 -1
- package/dist/src/gateway/hono/routes/config-patch/misc.js +8 -3
- package/dist/src/gateway/hono/routes/config-patch/misc.js.map +1 -1
- package/dist/src/gateway/hono/routes/config.js +59 -0
- package/dist/src/gateway/hono/routes/config.js.map +1 -1
- package/dist/src/gateway/hono/routes/dreaming.js +1 -1
- package/dist/src/gateway/hono/routes/goals.js +1 -1
- package/dist/src/gateway/hono/routes/goals.js.map +1 -1
- package/dist/src/gateway/hono/routes/host-fs.js +2 -2
- package/dist/src/gateway/hono/routes/lazy-bundles.js +8 -0
- package/dist/src/gateway/hono/routes/lazy-bundles.js.map +1 -1
- package/dist/src/gateway/hono/routes/models.js +75 -12
- package/dist/src/gateway/hono/routes/models.js.map +1 -1
- package/dist/src/gateway/hono/routes/sessions.js +28 -7
- package/dist/src/gateway/hono/routes/sessions.js.map +1 -1
- package/dist/src/gateway/hono/routes/shares.js +15 -13
- package/dist/src/gateway/hono/routes/shares.js.map +1 -1
- package/dist/src/gateway/hono/routes/tunnel.js +1 -1
- package/dist/src/gateway/hono/routes/update.js +4 -2
- package/dist/src/gateway/hono/routes/update.js.map +1 -1
- package/dist/src/gateway/hono/routes/voice.js +75 -0
- package/dist/src/gateway/hono/routes/voice.js.map +1 -1
- package/dist/src/gateway/hono/routes/workflows.d.ts +3 -0
- package/dist/src/gateway/hono/routes/workflows.js +347 -0
- package/dist/src/gateway/hono/routes/workflows.js.map +1 -0
- package/dist/src/gateway/hono/routes/workspace.js +4 -4
- package/dist/src/gateway/hono/sse.js +16 -33
- package/dist/src/gateway/hono/sse.js.map +1 -1
- package/dist/src/gateway/lock.js +11 -11
- package/dist/src/gateway/lock.js.map +1 -1
- package/dist/src/gateway/ports.js +6 -6
- package/dist/src/gateway/ports.js.map +1 -1
- package/dist/src/gateway/resolve-webchat-session-key.d.ts +19 -0
- package/dist/src/gateway/resolve-webchat-session-key.js +46 -0
- package/dist/src/gateway/resolve-webchat-session-key.js.map +1 -0
- package/dist/src/gateway/service/agent-runner.js +2 -2
- package/dist/src/gateway/service/marketplace-service.js +2 -2
- package/dist/src/gateway/service/run-gateway-agent.js +9 -11
- package/dist/src/gateway/service/run-gateway-agent.js.map +1 -1
- package/dist/src/gateway/service/sessions-api.d.ts +3 -0
- package/dist/src/gateway/service/sessions-api.js +8 -0
- package/dist/src/gateway/service/sessions-api.js.map +1 -1
- package/dist/src/gateway/service.d.ts +3 -2
- package/dist/src/gateway/service.js +9 -8
- package/dist/src/gateway/service.js.map +1 -1
- package/dist/src/gateway/session-reset-service.d.ts +20 -0
- package/dist/src/gateway/session-reset-service.js +54 -0
- package/dist/src/gateway/session-reset-service.js.map +1 -0
- package/dist/src/gateway/startup-readiness.d.ts +1 -1
- package/dist/src/gateway/startup-readiness.js +1 -0
- package/dist/src/gateway/startup-readiness.js.map +1 -1
- package/dist/src/gateway/workspace-fs-file-list.js +1 -1
- package/dist/src/heartbeat/index.js +1 -1
- package/dist/src/infra/gateway-processes.js +2 -2
- package/dist/src/infra/gateway-processes.js.map +1 -1
- package/dist/src/infra/restart.js +2 -2
- package/dist/src/infra/run-command.d.ts +16 -0
- package/dist/src/infra/run-command.js +67 -0
- package/dist/src/infra/run-command.js.map +1 -0
- package/dist/src/infra/update-check.js +1 -1
- package/dist/src/infra/update-global.d.ts +45 -0
- package/dist/src/infra/update-global.js +224 -0
- package/dist/src/infra/update-global.js.map +1 -0
- package/dist/src/infra/update-lock.js +3 -3
- package/dist/src/infra/update-runner.js +1 -1
- package/dist/src/infra/update-startup.js +2 -2
- package/dist/src/infra/write-file-atomic.js +2 -2
- package/dist/src/mcp/channel-shared.js +2 -1
- package/dist/src/mcp/channel-shared.js.map +1 -1
- package/dist/src/providers/auth-runtime/auth-profile-store.js +2 -2
- package/dist/src/providers/auth-runtime/auth-profile-store.js.map +1 -1
- package/dist/src/providers/auth-runtime/resolve-auth.js +1 -12
- package/dist/src/providers/auth-runtime/resolve-auth.js.map +1 -1
- package/dist/src/providers/auth-runtime/types.d.ts +6 -12
- package/dist/src/providers/index.js +2 -2
- package/dist/src/providers/model-registry.js +1 -1
- package/dist/src/routing/agent-session-key.d.ts +58 -0
- package/dist/src/routing/agent-session-key.js +164 -0
- package/dist/src/routing/agent-session-key.js.map +1 -0
- package/dist/src/routing/index.d.ts +1 -1
- package/dist/src/routing/index.js +4 -2
- package/dist/src/routing/index.js.map +1 -1
- package/dist/src/routing/resolve-route.d.ts +15 -0
- package/dist/src/routing/resolve-route.js +41 -20
- package/dist/src/routing/resolve-route.js.map +1 -1
- package/dist/src/routing/resolve-tui-session-key.d.ts +25 -0
- package/dist/src/routing/resolve-tui-session-key.js +54 -0
- package/dist/src/routing/resolve-tui-session-key.js.map +1 -0
- package/dist/src/routing/session-key-utils.d.ts +24 -0
- package/dist/src/routing/session-key-utils.js +92 -0
- package/dist/src/routing/session-key-utils.js.map +1 -0
- package/dist/src/routing/session-key.d.ts +19 -49
- package/dist/src/routing/session-key.js +143 -116
- package/dist/src/routing/session-key.js.map +1 -1
- package/dist/src/session/config-store.js +2 -2
- package/dist/src/session/index.d.ts +6 -0
- package/dist/src/session/index.js +7 -1
- package/dist/src/session/init-session-turn.d.ts +30 -0
- package/dist/src/session/init-session-turn.js +102 -0
- package/dist/src/session/init-session-turn.js.map +1 -0
- package/dist/src/session/lifecycle-timestamps.d.ts +8 -0
- package/dist/src/session/lifecycle-timestamps.js +16 -0
- package/dist/src/session/lifecycle-timestamps.js.map +1 -0
- package/dist/src/session/manager.d.ts +7 -1
- package/dist/src/session/manager.js +8 -1
- package/dist/src/session/manager.js.map +1 -1
- package/dist/src/session/parity/jsonl-transcript-io.js +2 -2
- package/dist/src/session/parity/sessions-json-file.js +1 -1
- package/dist/src/session/parity/transcript-file-lock.js +2 -2
- package/dist/src/session/parity/transcript-paths.js +2 -2
- package/dist/src/session/parity/transcript-paths.js.map +1 -1
- package/dist/src/session/parity/xopc-session-disk-entry.d.ts +6 -0
- package/dist/src/session/reset-policy.d.ts +32 -0
- package/dist/src/session/reset-policy.js +65 -0
- package/dist/src/session/reset-policy.js.map +1 -0
- package/dist/src/session/reset-triggers.d.ts +20 -0
- package/dist/src/session/reset-triggers.js +63 -0
- package/dist/src/session/reset-triggers.js.map +1 -0
- package/dist/src/session/reset-type.d.ts +12 -0
- package/dist/src/session/reset-type.js +25 -0
- package/dist/src/session/reset-type.js.map +1 -0
- package/dist/src/session/resolve-session.d.ts +30 -0
- package/dist/src/session/resolve-session.js +93 -0
- package/dist/src/session/resolve-session.js.map +1 -0
- package/dist/src/session/search-index-cache.js +1 -1
- package/dist/src/session/search-index.js +1 -1
- package/dist/src/session/session-title.js +3 -2
- package/dist/src/session/session-title.js.map +1 -1
- package/dist/src/session/store.d.ts +11 -4
- package/dist/src/session/store.js +62 -11
- package/dist/src/session/store.js.map +1 -1
- package/dist/src/session/transcript-events.js +2 -1
- package/dist/src/session/transcript-events.js.map +1 -1
- package/dist/src/share/share-auto.js +2 -2
- package/dist/src/share/share-store.js +3 -3
- package/dist/src/share/share-thumbnail.js +2 -2
- package/dist/src/share/share-url.d.ts +33 -0
- package/dist/src/share/share-url.js +56 -14
- package/dist/src/share/share-url.js.map +1 -1
- package/dist/src/share/share-zip.js +1 -1
- package/dist/src/share/site-share-store.js +3 -3
- package/dist/src/share/site-static-serve.js +1 -1
- package/dist/src/tui/backends/embedded-backend.js +4 -9
- package/dist/src/tui/backends/embedded-backend.js.map +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.js +1 -1
- package/dist/src/tui/backends/gateway-sse-backend.js.map +1 -1
- package/dist/src/tui/clipboard-image.js +3 -3
- package/dist/src/tui/components/chat-log.js +3 -3
- package/dist/src/tui/components/chat-log.js.map +1 -1
- package/dist/src/tui/theme-manager.js +1 -1
- package/dist/src/tui/theme.d.ts +0 -2
- package/dist/src/tui/theme.js +1 -3
- package/dist/src/tui/theme.js.map +1 -1
- package/dist/src/tui/tui-agent-events.js +2 -1
- package/dist/src/tui/tui-agent-events.js.map +1 -1
- package/dist/src/tui/tui-commands.d.ts +3 -0
- package/dist/src/tui/tui-commands.js +45 -10
- package/dist/src/tui/tui-commands.js.map +1 -1
- package/dist/src/tui/tui-keybindings-file.js +2 -22
- package/dist/src/tui/tui-keybindings-file.js.map +1 -1
- package/dist/src/tui/tui-scoped-models.js +2 -2
- package/dist/src/tui/tui-session-actions.d.ts +28 -0
- package/dist/src/tui/tui-session-actions.js +88 -0
- package/dist/src/tui/tui-session-actions.js.map +1 -0
- package/dist/src/tui/tui-settings.js +1 -1
- package/dist/src/tui/tui.js +54 -49
- package/dist/src/tui/tui.js.map +1 -1
- package/dist/src/tunnel/frpc-binary.js +3 -3
- package/dist/src/tunnel/frpc-config.js +1 -1
- package/dist/src/tunnel/frpc-extract.js +1 -1
- package/dist/src/tunnel/tunnel-state.js +1 -1
- package/dist/src/utils/logger/audit.js +1 -1
- package/dist/src/utils/logger/log-store.js +1 -1
- package/dist/src/utils/logger/rotation.js +1 -1
- package/dist/src/utils/string-coerce.d.ts +2 -0
- package/dist/src/utils/string-coerce.js +10 -1
- package/dist/src/utils/string-coerce.js.map +1 -1
- package/dist/src/voice/metadata/builtin.d.ts +2 -0
- package/dist/src/voice/metadata/builtin.js +420 -0
- package/dist/src/voice/metadata/builtin.js.map +1 -0
- package/dist/src/voice/metadata/index.d.ts +4 -0
- package/dist/src/voice/metadata/index.js +3 -0
- package/dist/src/voice/metadata/registry.d.ts +5 -0
- package/dist/src/voice/metadata/registry.js +34 -0
- package/dist/src/voice/metadata/registry.js.map +1 -0
- package/dist/src/voice/metadata/types.d.ts +41 -0
- package/dist/src/voice/metadata/types.js +1 -0
- package/dist/src/voice/stt/config-slice.d.ts +2 -5
- package/dist/src/voice/stt/config-slice.js +5 -26
- package/dist/src/voice/stt/config-slice.js.map +1 -1
- package/dist/src/voice/stt/list-providers.d.ts +3 -3
- package/dist/src/voice/stt/list-providers.js +41 -6
- package/dist/src/voice/stt/list-providers.js.map +1 -1
- package/dist/src/voice/stt/types.d.ts +1 -18
- package/dist/src/voice/stt/types.js +4 -2
- package/dist/src/voice/stt/types.js.map +1 -1
- package/dist/src/voice/tts/audio.js +1 -1
- package/dist/src/voice/tts/config-slice.d.ts +3 -7
- package/dist/src/voice/tts/config-slice.js +7 -38
- package/dist/src/voice/tts/config-slice.js.map +1 -1
- package/dist/src/voice/tts/list-providers.d.ts +3 -3
- package/dist/src/voice/tts/list-providers.js +41 -6
- package/dist/src/voice/tts/list-providers.js.map +1 -1
- package/dist/src/voice/tts/merge-config.js +2 -48
- package/dist/src/voice/tts/merge-config.js.map +1 -1
- package/dist/src/voice/tts/providers/alibaba-speech.js +1 -1
- package/dist/src/voice/tts/providers/alibaba-speech.js.map +1 -1
- package/dist/src/voice/tts/providers/edge-speech.js +2 -2
- package/dist/src/voice/tts/types.d.ts +1 -29
- package/dist/src/voice/tts/types.js +19 -17
- package/dist/src/voice/tts/types.js.map +1 -1
- package/dist/src/workflows/domain/command.d.ts +18 -0
- package/dist/src/workflows/domain/command.js +1 -0
- package/dist/src/workflows/domain/definition.d.ts +62 -0
- package/dist/src/workflows/domain/definition.js +1 -0
- package/dist/src/workflows/domain/event.d.ts +67 -0
- package/dist/src/workflows/domain/event.js +1 -0
- package/dist/src/workflows/domain/index.d.ts +5 -0
- package/dist/src/workflows/domain/index.js +2 -0
- package/dist/src/workflows/domain/result.d.ts +65 -0
- package/dist/src/workflows/domain/result.js +1 -0
- package/dist/src/workflows/domain/run.d.ts +120 -0
- package/dist/src/workflows/domain/run.js +14 -0
- package/dist/src/workflows/domain/run.js.map +1 -0
- package/dist/src/workflows/engine/index.d.ts +2 -0
- package/dist/src/workflows/engine/index.js +3 -0
- package/dist/src/workflows/engine/projector.d.ts +3 -0
- package/dist/src/workflows/engine/projector.js +205 -0
- package/dist/src/workflows/engine/projector.js.map +1 -0
- package/dist/src/workflows/engine/workflow-engine.d.ts +31 -0
- package/dist/src/workflows/engine/workflow-engine.js +188 -0
- package/dist/src/workflows/engine/workflow-engine.js.map +1 -0
- package/dist/src/workflows/index.d.ts +6 -0
- package/dist/src/workflows/index.js +11 -0
- package/dist/src/workflows/runtime/index.d.ts +1 -0
- package/dist/src/workflows/runtime/index.js +4 -0
- package/dist/src/workflows/runtime/script-runtime.d.ts +3 -0
- package/dist/src/workflows/runtime/script-runtime.js +3 -0
- package/dist/src/workflows/store/event-store.d.ts +17 -0
- package/dist/src/workflows/store/event-store.js +83 -0
- package/dist/src/workflows/store/event-store.js.map +1 -0
- package/dist/src/workflows/store/paths.d.ts +7 -0
- package/dist/src/workflows/store/paths.js +26 -0
- package/dist/src/workflows/store/paths.js.map +1 -0
- package/dist/src/workflows/store/run-store.d.ts +13 -0
- package/dist/src/workflows/store/run-store.js +68 -0
- package/dist/src/workflows/store/run-store.js.map +1 -0
- package/package.json +5 -8
- package/dist/gateway/static/root/assets/agents-mS3_HpRI.js +0 -222
- package/dist/gateway/static/root/assets/channels-settings-BG6b9KrW.js +0 -1
- package/dist/gateway/static/root/assets/extension-settings-page-B-W4x2xP.js +0 -1
- package/dist/gateway/static/root/assets/index-ew_2L2We.css +0 -1
- package/dist/gateway/static/root/assets/sessions-page-FaG_Vlkb.js +0 -1
- package/dist/gateway/static/root/assets/settings-page-Bet1OerL.js +0 -3
- package/dist/gateway/static/root/assets/skills-page-DhUO235y.js +0 -2
- package/dist/gateway/static/root/assets/url-BwNL6Rgk.js +0 -3
- package/dist/gateway/static/root/assets/voice-api-key-field-CGEydndO.js +0 -1
- package/dist/src/agent/tools/browser-legacy-tools.d.ts +0 -17
- package/dist/src/agent/tools/browser-legacy-tools.js +0 -766
- 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 {
|
|
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 {
|
|
6
|
+
import { assertCacheDir, init_cache_dir_policy } from "../cache-dir-policy.js";
|
|
7
7
|
import { resolvePackageRoot } from "../../infra/update-check.js";
|
|
8
|
-
import {
|
|
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
|
|
16
|
-
*
|
|
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
|
|
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
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
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
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
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
|
-
|
|
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
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
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
|
-
|
|
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:
|
|
258
|
+
installPath: extensionDir
|
|
306
259
|
};
|
|
307
260
|
await writeTextAtomic(resolveMetaPath(cacheDir), JSON.stringify(nextMeta, null, 2));
|
|
308
261
|
log.info({
|
|
309
|
-
extensionDir
|
|
262
|
+
extensionDir,
|
|
310
263
|
xopcVersion: PACKAGE_VERSION,
|
|
311
264
|
bundledFrom: bundled.bundledFrom
|
|
312
265
|
}, "Browser extension artifacts installed");
|
|
313
266
|
return {
|
|
314
|
-
extensionDir
|
|
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 {
|
|
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,
|
|
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). */
|