@xopcai/xopc 0.0.265 → 0.0.267

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (148) hide show
  1. package/dist/browser-ext/dist/assets/{auth-CknJ00ae.js → auth-D_IL6naL.js} +603 -203
  2. package/dist/browser-ext/dist/assets/sidepanel-CEPaVLjr.css +155 -0
  3. package/dist/browser-ext/dist/background.js +698 -169
  4. package/dist/browser-ext/dist/sidepanel.html +3 -3
  5. package/dist/browser-ext/dist/sidepanel.js +148 -391
  6. package/dist/browser-ext/manifest.json +3 -6
  7. package/dist/extensions/telegram/xopc.extension.json +1 -1
  8. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DRTTU2H3.js → agent-avatar-dicebear-ZrSAMchm.js} +1 -1
  9. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-BsXF7LVi.js → agent-defaults-settings-panel-DiNFN8qS.js} +1 -1
  10. package/dist/gateway/static/root/assets/{agents-DpjWfxYx.js → agents-Bu6Hf59K.js} +1 -1
  11. package/dist/gateway/static/root/assets/{app-management-settings-panel-33Mc81h2.js → app-management-settings-panel-D-L6yjS7.js} +1 -1
  12. package/dist/gateway/static/root/assets/{appearance-settings-C8JECSiJ.js → appearance-settings-BW5eb53j.js} +1 -1
  13. package/dist/gateway/static/root/assets/{apps-page-t64FcxIZ.js → apps-page-CiQIdz3N.js} +1 -1
  14. package/dist/gateway/static/root/assets/{archive-plugin-PzZ6SzfY.js → archive-plugin-DwXvu1p9.js} +1 -1
  15. package/dist/gateway/static/root/assets/{attachment-load-OhLL6K__.js → attachment-load-DqU2BYBp.js} +1 -1
  16. package/dist/gateway/static/root/assets/{automations-page-BpAYwuvx.js → automations-page-C7qoj9Sd.js} +1 -1
  17. package/dist/gateway/static/root/assets/{automations-workspace-B6aTT5IC.js → automations-workspace-CIARTLHO.js} +1 -1
  18. package/dist/gateway/static/root/assets/{binary-plugins-B5XpGsHg.js → binary-plugins-CfplDak2.js} +1 -1
  19. package/dist/gateway/static/root/assets/{block-editor-BgEhoTnN.js → block-editor-CzLs38ru.js} +1 -1
  20. package/dist/gateway/static/root/assets/{browser-automations-page-CBLunDRH.js → browser-automations-page-_SKi8s9b.js} +1 -1
  21. package/dist/gateway/static/root/assets/browser-settings-page-DTdx66sX.js +8 -0
  22. package/dist/gateway/static/root/assets/{capabilities-settings-panel-DftNnICK.js → capabilities-settings-panel-Ck9U0Olx.js} +1 -1
  23. package/dist/gateway/static/root/assets/{channels-settings-CpuWa5qu.js → channels-settings-I_vDpbnl.js} +1 -1
  24. package/dist/gateway/static/root/assets/{chat-terminal-dock-mnPsS_GJ.js → chat-terminal-dock-snvAu3hJ.js} +1 -1
  25. package/dist/gateway/static/root/assets/{connectors-page-D3nHGnNV.js → connectors-page-BmKTnzo1.js} +1 -1
  26. package/dist/gateway/static/root/assets/{cron-expression-NcGBvIfe.js → cron-expression-BhGZSbT6.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-BrVcl7H5.js → date-picker-Cep5f9b-.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker--edd48Y9.js → dependency-picker-BzSEBQku.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-vuyyb6I6.js → desktop-pet-BwX_6Gah.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-DWredJwO.js → desktop-pet-settings-WrbVsU2b.js} +1 -1
  31. package/dist/gateway/static/root/assets/{extension-debug-page-CtBW4ebj.js → extension-debug-page-BdXSwtAZ.js} +1 -1
  32. package/dist/gateway/static/root/assets/{extension-page-CsUrmtW7.js → extension-page-I95ukbRb.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-settings-page-BUd31AuK.js → extension-settings-page-8zUisBay.js} +1 -1
  34. package/dist/gateway/static/root/assets/{gateway-settings-C6FQv7op.js → gateway-settings-DGj5b9Yv.js} +1 -1
  35. package/dist/gateway/static/root/assets/{heartbeat-settings-CDo1Gjp2.js → heartbeat-settings-BGQxU-Ug.js} +1 -1
  36. package/dist/gateway/static/root/assets/{home-page-D3_uvVJY.js → home-page-BZPpK0A3.js} +1 -1
  37. package/dist/gateway/static/root/assets/{index-Dpu7EKTm.js → index-D2OtD9Wa.js} +8 -8
  38. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-CNVmrCrV.js → keyboard-shortcuts-settings-BUe_om99.js} +1 -1
  39. package/dist/gateway/static/root/assets/{local-app-workbench-page-B0IVDvs-.js → local-app-workbench-page-CbQnffS9.js} +1 -1
  40. package/dist/gateway/static/root/assets/{local-apps-page-DvkarvLt.js → local-apps-page-BZaLzfms.js} +1 -1
  41. package/dist/gateway/static/root/assets/{logs-page-BknY0vZf.js → logs-page-WWCHqW_x.js} +1 -1
  42. package/dist/gateway/static/root/assets/{management-settings-DW6hJINQ.js → management-settings-Duf8w-Bl.js} +1 -1
  43. package/dist/gateway/static/root/assets/{media-plugins-DYautOWY.js → media-plugins-2-QfzHmg.js} +1 -1
  44. package/dist/gateway/static/root/assets/{mobile-pairing-wizard-Dgu03cv-.js → mobile-pairing-wizard-DRaVIAt1.js} +1 -1
  45. package/dist/gateway/static/root/assets/{note-detail-panel-Cv9uH6Jq.js → note-detail-panel-BT-fWGxX.js} +3 -3
  46. package/dist/gateway/static/root/assets/{notes-page-DcIAiYJn.js → notes-page-C4705PzN.js} +1 -1
  47. package/dist/gateway/static/root/assets/{page-tabs-DF6Q5XvA.js → page-tabs-DaZ7QpNO.js} +1 -1
  48. package/dist/gateway/static/root/assets/{preview-open-alternatives-CQJH_jAN.js → preview-open-alternatives-CWEuqCmv.js} +1 -1
  49. package/dist/gateway/static/root/assets/{project-detail-page-D65JfNSw.js → project-detail-page-BZegJ6an.js} +1 -1
  50. package/dist/gateway/static/root/assets/{projects-page-BfWF7Sz-.js → projects-page-B7hUHeLI.js} +1 -1
  51. package/dist/gateway/static/root/assets/{remote-access-hub-DA1g4CUD.js → remote-access-hub-BE9hZpdh.js} +1 -1
  52. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-0-bFSBB8.js → runtime-tools-settings-panel-CslkSM-m.js} +1 -1
  53. package/dist/gateway/static/root/assets/{schema-form-csGbhTUr.js → schema-form-B2gvVrBq.js} +1 -1
  54. package/dist/gateway/static/root/assets/{sessions-page-DXPBNhrZ.js → sessions-page-DmAAPMo1.js} +1 -1
  55. package/dist/gateway/static/root/assets/settings-advanced-gate-CvBocGDA.js +1 -0
  56. package/dist/gateway/static/root/assets/{settings-form-section-YdrdY8B3.js → settings-form-section-CmlnuSO3.js} +1 -1
  57. package/dist/gateway/static/root/assets/{settings-page-Cv9waRn3.js → settings-page-DWWgyelT.js} +1 -1
  58. package/dist/gateway/static/root/assets/{setup-status-panel-DPf-_05Z.js → setup-status-panel-CJrN3m1o.js} +1 -1
  59. package/dist/gateway/static/root/assets/{share-preview-page-DBoEHTPn.js → share-preview-page-C12oyIKk.js} +1 -1
  60. package/dist/gateway/static/root/assets/{shares-settings-BQP5yNcO.js → shares-settings-D4BtSiLq.js} +1 -1
  61. package/dist/gateway/static/root/assets/{skill-reload-api-B5T8cgjq.js → skill-reload-api-CzKGn056.js} +1 -1
  62. package/dist/gateway/static/root/assets/{skills-page-D1G8h2Lt.js → skills-page-yhW7LLqk.js} +1 -1
  63. package/dist/gateway/static/root/assets/{skills-page.utils-BNZYTop7.js → skills-page.utils-FaTlq8t-.js} +1 -1
  64. package/dist/gateway/static/root/assets/{system-settings-panel-ByuppbHi.js → system-settings-panel-CMrkoJLN.js} +1 -1
  65. package/dist/gateway/static/root/assets/{task-detail-page-DNmkrF6y.js → task-detail-page-BUaO62cy.js} +1 -1
  66. package/dist/gateway/static/root/assets/{tunnel-api-CxWGpbwr.js → tunnel-api-C2tAZaJz.js} +1 -1
  67. package/dist/gateway/static/root/assets/{use-autosave-B0l4qubU.js → use-autosave-BsDRt4QI.js} +1 -1
  68. package/dist/gateway/static/root/assets/{user-model-page-DMsI6YI7.js → user-model-page-Dy8h1SSJ.js} +1 -1
  69. package/dist/gateway/static/root/assets/{voice-api-key-field-Bcz7boJg.js → voice-api-key-field-CS5heYMP.js} +1 -1
  70. package/dist/gateway/static/root/assets/{work-discovery-overlay-Dujq1j_u.js → work-discovery-overlay-BeSz5Th5.js} +1 -1
  71. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CxNYbLNB.js → workflow-run-setup-panel-BebW0CDK.js} +1 -1
  72. package/dist/gateway/static/root/assets/{workflows-page-Dk1jK2nv.js → workflows-page-CU8jFgPF.js} +1 -1
  73. package/dist/gateway/static/root/index.html +1 -1
  74. package/dist/package.js +1 -1
  75. package/dist/packages/browser-control-contract/src/index.js +30 -1
  76. package/dist/src/agent/agent-manager.js +4 -4
  77. package/dist/src/agent/background-review/run-background-review.js +1 -1
  78. package/dist/src/agent/embedded/model-runtime.js +1 -1
  79. package/dist/src/agent/embedded/run-for-session.js +1 -1
  80. package/dist/src/agent/external-tools/endpoint-provider.js +3 -1
  81. package/dist/src/agent/image/tool-model-config.js +1 -1
  82. package/dist/src/agent/mcp/oauth/mcp-oauth-store.js +1 -1
  83. package/dist/src/agent/service.js +2 -2
  84. package/dist/src/agent/session/session-inspector.js +1 -1
  85. package/dist/src/agent/skills/hub-lock.js +1 -1
  86. package/dist/src/agent/tasks/task-judge-service.js +3 -3
  87. package/dist/src/agent/tools/factory.js +1 -1
  88. package/dist/src/ai-assist/text-assist.js +1 -1
  89. package/dist/src/auth/credentials.js +2 -2
  90. package/dist/src/auth/oauth/xopc-cloud.js +1 -1
  91. package/dist/src/auth/profiles/store.js +1 -1
  92. package/dist/src/auth/sync-provider-auth.js +2 -2
  93. package/dist/src/browser/automations/runtime-service.d.ts +2 -0
  94. package/dist/src/browser/automations/runtime-service.js +1 -1
  95. package/dist/src/browser/drivers/create-driver.d.ts +2 -1
  96. package/dist/src/browser/drivers/create-driver.js +4 -6
  97. package/dist/src/browser/drivers/extension-driver.d.ts +7 -2
  98. package/dist/src/browser/enrollment.d.ts +8 -0
  99. package/dist/src/browser/enrollment.js +25 -0
  100. package/dist/src/browser/extension-identity.d.ts +2 -0
  101. package/dist/src/browser/extension-identity.js +5 -0
  102. package/dist/src/browser/native-messaging-host.d.ts +6 -3
  103. package/dist/src/browser/native-messaging-host.js +23 -5
  104. package/dist/src/browser/providers/browser-ext-install.d.ts +4 -1
  105. package/dist/src/browser/providers/browser-ext-install.js +47 -8
  106. package/dist/src/browser/providers/extension.js +1 -1
  107. package/dist/src/browser/providers/realtime-extension.d.ts +29 -0
  108. package/dist/src/browser/providers/realtime-extension.js +83 -0
  109. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  110. package/dist/src/cli/commands/doctor/checks/provider-auth.js +1 -1
  111. package/dist/src/cli/commands/models.js +1 -1
  112. package/dist/src/config/index.js +4 -4
  113. package/dist/src/config/loader.js +2 -2
  114. package/dist/src/config/models-json.js +1 -1
  115. package/dist/src/endpoint-tools/policy.js +10 -3
  116. package/dist/src/extensions/lockfile.js +1 -1
  117. package/dist/src/gateway/agents-admin.js +1 -1
  118. package/dist/src/gateway/file-path-classifier.js +1 -1
  119. package/dist/src/gateway/hono/app.js +6 -1
  120. package/dist/src/gateway/hono/lib/config-payload.js +1 -1
  121. package/dist/src/gateway/hono/routes/browser.js +20 -30
  122. package/dist/src/gateway/hono/routes/models.js +1 -1
  123. package/dist/src/gateway/security/origin-check.js +5 -0
  124. package/dist/src/gateway/service/config-coordinator.d.ts +0 -2
  125. package/dist/src/gateway/service/config-coordinator.js +1 -3
  126. package/dist/src/gateway/service.d.ts +0 -11
  127. package/dist/src/gateway/service.js +5 -83
  128. package/dist/src/providers/auth-runtime/resolve-auth.js +1 -1
  129. package/dist/src/providers/index.js +2 -2
  130. package/dist/src/providers/model-registry.js +1 -1
  131. package/dist/src/providers/register-runtime-providers.js +1 -1
  132. package/dist/src/storage/sqlite/device-pairing-approval.js +24 -3
  133. package/dist/src/storage/sqlite/device-pairing-repository.d.ts +10 -1
  134. package/dist/src/storage/sqlite/device-pairing-repository.js +6 -5
  135. package/dist/src/storage/sqlite/migrations/157_browser_endpoint_principals.sql +50 -0
  136. package/dist/src/storage/sqlite/migrations/158_browser_native_enrollment.sql +4 -0
  137. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  138. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  139. package/dist/src/storage/sqlite/migrations/runner.ts +1 -1
  140. package/dist/src/storage/sqlite/schema.js +1 -1
  141. package/dist/src/tui/tui-startup-resources.js +1 -1
  142. package/dist/src/tui/tui.js +1 -1
  143. package/dist/src/work-discovery/service.js +1 -1
  144. package/dist/src/workflows/service/workflow-run-service.js +1 -1
  145. package/package.json +3 -3
  146. package/dist/browser-ext/dist/assets/sidepanel-C69P3v9u.css +0 -113
  147. package/dist/gateway/static/root/assets/browser-settings-page-CSfpPCuD.js +0 -8
  148. package/dist/gateway/static/root/assets/settings-advanced-gate-DxeZm67O.js +0 -1
@@ -1,8 +1,8 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { parseTurnOutcome } from "../../../packages/gateway-contract/src/turn-outcome.js";
4
- import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
5
4
  import { init_providers, resolveModel } from "../../providers/index.js";
5
+ import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
6
6
  import { runWithEmbeddedExecutionSession } from "./execution-context.js";
7
7
  import { resolveAgentTurnTimeoutMs } from "../orchestration/run-agent-turn-with-timeout.js";
8
8
  import { resolvePromptCachePolicy } from "../../providers/prompt-cache-plan.js";
@@ -1,4 +1,5 @@
1
1
  import { externalToolRef, parseExternalToolRef } from "./refs.js";
2
+ import { BROWSER_CONTROL_ENDPOINT_TOOL_NAME } from "../../../packages/browser-control-contract/src/index.js";
2
3
  //#region src/agent/external-tools/endpoint-provider.ts
3
4
  function contentText(content) {
4
5
  if (content.type === "text") return content.text;
@@ -13,7 +14,7 @@ var EndpointToolProvider = class {
13
14
  async search(_query) {
14
15
  const endpoint = this.currentEndpoint();
15
16
  if (!endpoint) return [];
16
- return endpoint.tools.map(({ descriptor }) => ({
17
+ return endpoint.tools.filter(({ descriptor }) => descriptor.name !== BROWSER_CONTROL_ENDPOINT_TOOL_NAME).map(({ descriptor }) => ({
17
18
  toolRef: externalToolRef(this.source, endpoint.endpointId, descriptor.name),
18
19
  source: this.source,
19
20
  namespace: endpoint.endpointId,
@@ -86,6 +87,7 @@ var EndpointToolProvider = class {
86
87
  const endpoint = this.currentEndpoint();
87
88
  if (!endpoint || endpoint.endpointId !== parsed.namespace) return void 0;
88
89
  const tool = this.deps.runtime.registry.getTool(endpoint.endpointId, parsed.toolName);
90
+ if (tool?.descriptor.name === "browser.control") return void 0;
89
91
  return tool ? {
90
92
  endpointId: endpoint.endpointId,
91
93
  displayName: endpoint.displayName,
@@ -1,7 +1,7 @@
1
1
  import { getAgentDefaultImageModelConfig, getAgentDefaultModelRef, init_schema, parseModelRef } from "../../config/schema.js";
2
2
  import { init_agent_scope, resolveDefaultAgentId } from "../agent-scope.js";
3
- import { resolveEffectiveAgentConfigForAgent } from "../../config/agent-profile.js";
4
3
  import { getDefaultModelSync, getModelsByProvider, init_providers, isProviderConfiguredSync, resolveModel } from "../../providers/index.js";
4
+ import { resolveEffectiveAgentConfigForAgent } from "../../config/agent-profile.js";
5
5
  import { resolveAgentModelFallbackValues, resolveAgentModelPrimaryValue } from "../../config/model-input.js";
6
6
  import { buildCapabilityPlansForConfig } from "../../capabilities/readiness/from-config.js";
7
7
  import "../../capabilities/readiness/index.js";
@@ -1,5 +1,5 @@
1
- import { init_paths, resolveMcpOAuthPath } from "../../../config/paths.js";
2
1
  import { init_write_file_atomic, writeTextAtomic } from "../../../infra/write-file-atomic.js";
2
+ import { init_paths, resolveMcpOAuthPath } from "../../../config/paths.js";
3
3
  import { createHash } from "node:crypto";
4
4
  import { readFile, rm } from "node:fs/promises";
5
5
  //#region src/agent/mcp/oauth/mcp-oauth-store.ts
@@ -2,10 +2,10 @@ import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
3
  import { parseNoteAttachmentTarget } from "../notes/attachment-ref.js";
4
4
  import { getAgentDefaultModelRef, init_schema } from "../config/schema.js";
5
- import { applyConfigOverrides } from "../config/runtime-overrides.js";
6
5
  import { init_agent_scope, resolveAgentHomeDir, resolveDefaultAgentId } from "./agent-scope.js";
7
- import { extractProfileAgentId } from "../config/agent-profile.js";
8
6
  import { init_providers, resolveModel } from "../providers/index.js";
7
+ import { applyConfigOverrides } from "../config/runtime-overrides.js";
8
+ import { extractProfileAgentId } from "../config/agent-profile.js";
9
9
  import { extractTextContent } from "./context/workspace.js";
10
10
  import { effectiveWorkspacePathForSession } from "../session/session-workspace.js";
11
11
  import { getProjectForSession } from "../projects/workspace.js";
@@ -1,8 +1,8 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { init_workspace_defaults, resolveDefaultAgentWorkspaceDir } from "../../config/workspace-defaults.js";
4
- import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
5
4
  import { init_providers, resolveModel } from "../../providers/index.js";
5
+ import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
6
6
  import { getExecutionEnvironmentForSession } from "../../execution-environments/subject.js";
7
7
  import { effectiveWorkspacePathForSession, projectWorkspacePath } from "../../session/session-workspace.js";
8
8
  import { getProjectForSession } from "../../projects/workspace.js";
@@ -1,5 +1,5 @@
1
- import { init_paths, resolveSkillsLockPath } from "../../config/paths.js";
2
1
  import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
2
+ import { init_paths, resolveSkillsLockPath } from "../../config/paths.js";
3
3
  import { existsSync, readFileSync } from "node:fs";
4
4
  //#region src/agent/skills/hub-lock.ts
5
5
  /**
@@ -1,15 +1,15 @@
1
1
  import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { TaskRunRepository } from "../../tasks/task-run-repository.js";
4
+ import { extractAssistantText, getAssistantMessageErrorReason, stripCodeFences } from "../../providers/model-response.js";
4
5
  import { getAgentDefaultModelRef, init_schema } from "../../config/schema.js";
5
- import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
6
6
  import { getApiKey, init_providers, resolveModel } from "../../providers/index.js";
7
+ import { completeWithResolvedCredentials } from "../../providers/model-call.js";
8
+ import { resolveEffectiveAgentProfileForSession } from "../../config/agent-profile.js";
7
9
  import { TaskRepository } from "../../tasks/task-repository.js";
8
10
  import { TaskConversationRepository } from "../../tasks/task-conversation-repository.js";
9
11
  import { readWorkspaceRevision } from "../coding/workspace-revision.js";
10
- import { completeWithResolvedCredentials } from "../../providers/model-call.js";
11
12
  import { TaskApplicationService } from "../../tasks/task-application-service.js";
12
- import { extractAssistantText, getAssistantMessageErrorReason, stripCodeFences } from "../../providers/model-response.js";
13
13
  //#region src/agent/tasks/task-judge-service.ts
14
14
  init_schema();
15
15
  init_providers();
@@ -140,7 +140,7 @@ var AgentToolsFactory = class AgentToolsFactory {
140
140
  createDriver: async () => {
141
141
  const config = this.deps.getConfig?.();
142
142
  if (!config) throw new Error("Browser configuration is unavailable");
143
- return createBrowserDriver(config.browser);
143
+ return createBrowserDriver(config.browser, this.deps.endpointTools);
144
144
  },
145
145
  allowedUploadRoots: [this.deps.workspace],
146
146
  emit: this.deps.emitBrowserEvent,
@@ -1,9 +1,9 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
+ import { getAssistantMessageErrorReason, stripCodeFences } from "../providers/model-response.js";
3
4
  import { getDefaultModelSync, init_providers, resolveModel } from "../providers/index.js";
4
5
  import { createExtensionAwareStreamFn } from "../providers/extension-stream-bridge.js";
5
6
  import { isLocalModelBaseUrl, resolveModelCallApiKey, resolveModelCallOptions } from "../providers/model-call.js";
6
- import { getAssistantMessageErrorReason, stripCodeFences } from "../providers/model-response.js";
7
7
  //#region src/ai-assist/text-assist.ts
8
8
  init_providers();
9
9
  init_logger();
@@ -1,10 +1,10 @@
1
1
  import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
2
2
  import { createLogger } from "../utils/logger/index.js";
3
3
  import { init_logger } from "../utils/logger.js";
4
- import { init_paths, resolveAgentAuthProfilesPath, resolveAuthProfilesPath, resolveCredentialsDir, resolveOAuthPath } from "../config/paths.js";
5
4
  import { init_write_file_atomic, writeTextAtomic } from "../infra/write-file-atomic.js";
6
- import { getOAuthProviderDefinition, init_registry } from "./oauth/registry.js";
5
+ import { init_paths, resolveAgentAuthProfilesPath, resolveAuthProfilesPath, resolveCredentialsDir, resolveOAuthPath } from "../config/paths.js";
7
6
  import { getApiKeyFromEnv, init_env_keys } from "../providers/env-keys.js";
7
+ import { getOAuthProviderDefinition, init_registry } from "./oauth/registry.js";
8
8
  import { init_oauth_provider_lock, withOAuthProviderLock } from "./oauth-provider-lock.js";
9
9
  import { dirname, join } from "path";
10
10
  import { mkdir, readFile, readdir, rm } from "fs/promises";
@@ -1,6 +1,6 @@
1
1
  import { __esmMin } from "../../../_virtual/_rolldown/runtime.js";
2
- import { init_resolution, resolveConnectedPlatformEndpoint } from "../../platform/resolution.js";
3
2
  import { generatePKCE, init_pkce } from "./pkce.js";
3
+ import { init_resolution, resolveConnectedPlatformEndpoint } from "../../platform/resolution.js";
4
4
  import { hostname } from "node:os";
5
5
  import { randomBytes } from "node:crypto";
6
6
  import http from "node:http";
@@ -1,5 +1,5 @@
1
- import { init_paths, resolveCredentialsDir } from "../../config/paths.js";
2
1
  import { init_write_file_atomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
2
+ import { init_paths, resolveCredentialsDir } from "../../config/paths.js";
3
3
  import path from "node:path";
4
4
  import { chmodSync, existsSync, mkdirSync, readFileSync } from "node:fs";
5
5
  //#region src/auth/profiles/store.ts
@@ -1,8 +1,8 @@
1
1
  import { __esmMin } from "../../_virtual/_rolldown/runtime.js";
2
- import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
3
2
  import { init_paths, resolveAgentAuthProfilesPath, resolveAuthProfilesPath, resolveOAuthPath } from "../config/paths.js";
4
- import { init_loader, loadConfig } from "../config/loader.js";
5
3
  import { init_registry, isOAuthOnlyProvider } from "./oauth/registry.js";
4
+ import { init_loader, loadConfig } from "../config/loader.js";
5
+ import { getDefaultAgentId, init_resolve_route } from "../routing/resolve-route.js";
6
6
  import { existsSync, readFileSync } from "node:fs";
7
7
  //#region src/auth/sync-provider-auth.ts
8
8
  /**
@@ -1,6 +1,8 @@
1
1
  import type { Config } from '../../config/schema.js';
2
+ import type { EndpointToolRuntime } from '../../endpoint-tools/index.js';
2
3
  import { BrowserAutomationService } from './service.js';
3
4
  export declare function createRuntimeBrowserAutomationService(deps: {
4
5
  getConfig: () => Config;
6
+ endpointTools?: EndpointToolRuntime;
5
7
  emit?: (type: string, payload: unknown) => void;
6
8
  }): BrowserAutomationService;
@@ -6,7 +6,7 @@ import { BrowserAutomationService } from "./service.js";
6
6
  function createRuntimeBrowserAutomationService(deps) {
7
7
  const runtime = new BrowserRuntime({
8
8
  getConfig: () => deps.getConfig().browser,
9
- createDriver: () => createBrowserDriver(deps.getConfig().browser),
9
+ createDriver: () => createBrowserDriver(deps.getConfig().browser, deps.endpointTools),
10
10
  allowedUploadRoots: [process.cwd()],
11
11
  emit: deps.emit
12
12
  });
@@ -1,3 +1,4 @@
1
1
  import type { Config } from '../../config/schema.js';
2
+ import type { EndpointToolRuntime } from '../../endpoint-tools/index.js';
2
3
  import type { BrowserDriver } from './browser-driver.js';
3
- export declare function createBrowserDriver(config: Config['browser']): Promise<BrowserDriver>;
4
+ export declare function createBrowserDriver(config: Config['browser'], endpointTools: EndpointToolRuntime): Promise<BrowserDriver>;
@@ -3,22 +3,20 @@ import { init_logger } from "../../utils/logger.js";
3
3
  import { loadPlaywrightCoreModule } from "../providers/playwright-doctor.js";
4
4
  import { BrowserbaseProvider } from "../providers/browserbase.js";
5
5
  import { BrowserUseProvider } from "../providers/browser-use.js";
6
- import { acquireExtensionBrowserServer } from "../providers/extension-ws-acquire.js";
6
+ import { RealtimeExtensionBrowserProvider } from "../providers/realtime-extension.js";
7
7
  import { ExtensionDriver } from "./extension-driver.js";
8
8
  import { PlaywrightDriver } from "./playwright-driver.js";
9
9
  //#region src/browser/drivers/create-driver.ts
10
10
  init_logger();
11
11
  const log = createLogger("BrowserDriverFactory");
12
- async function createBrowserDriver(config) {
12
+ async function createBrowserDriver(config, endpointTools) {
13
13
  const limits = config.limits;
14
14
  if (config.driver.kind === "extension") {
15
- const { provider, release } = await acquireExtensionBrowserServer({
16
- host: "127.0.0.1",
17
- port: 19820,
15
+ const provider = new RealtimeExtensionBrowserProvider(endpointTools, {
18
16
  connectionTimeout: limits.actionTimeoutMs,
19
17
  commandTimeout: limits.actionTimeoutMs
20
18
  });
21
- return new ExtensionDriver(provider, limits.actionTimeoutMs, config.observation.visualFallback, release);
19
+ return new ExtensionDriver(provider, limits.actionTimeoutMs, config.observation.visualFallback, () => provider.shutdown());
22
20
  }
23
21
  const driver = config.driver;
24
22
  return new PlaywrightDriver({
@@ -1,13 +1,17 @@
1
1
  import type { BrowserControlResult, BrowserNavigateInput, BrowserObservation, BrowserObserveInput, BrowserTabsInput } from '@xopcai/browser-control-contract';
2
- import type { ExtensionBrowserProvider } from '../providers/extension.js';
3
2
  import type { BrowserDriver, BrowserPrimitiveInput } from './browser-driver.js';
3
+ type ExtensionProvider = {
4
+ start(): Promise<void>;
5
+ waitForConnection(timeoutMs?: number): Promise<void>;
6
+ send(input: import('@xopcai/browser-control-contract').BrowserActionInput, timeoutMs?: number, visualFallback?: boolean): Promise<import('@xopcai/browser-control-contract').BrowserWireResult>;
7
+ };
4
8
  export declare class ExtensionDriver implements BrowserDriver {
5
9
  private readonly provider;
6
10
  private readonly timeoutMs;
7
11
  private readonly visualFallback;
8
12
  private readonly release;
9
13
  readonly kind: "extension";
10
- constructor(provider: ExtensionBrowserProvider, timeoutMs: number, visualFallback: boolean, release: () => Promise<void>);
14
+ constructor(provider: ExtensionProvider, timeoutMs: number, visualFallback: boolean, release: () => Promise<void>);
11
15
  connect(): Promise<void>;
12
16
  disconnect(): Promise<void>;
13
17
  createSession(_sessionId: string): Promise<void>;
@@ -18,3 +22,4 @@ export declare class ExtensionDriver implements BrowserDriver {
18
22
  tabs(sessionId: string, input: BrowserTabsInput): Promise<BrowserControlResult>;
19
23
  private send;
20
24
  }
25
+ export {};
@@ -0,0 +1,8 @@
1
+ export type BrowserEnrollmentPublicKeyJwk = {
2
+ kty: 'EC';
3
+ crv: 'P-256';
4
+ x: string;
5
+ y: string;
6
+ };
7
+ export declare function parseBrowserEnrollmentPublicKeyJwk(value: unknown): BrowserEnrollmentPublicKeyJwk;
8
+ export declare function browserEnrollmentPublicKeyThumbprint(value: unknown): string;
@@ -0,0 +1,25 @@
1
+ import crypto from "node:crypto";
2
+ //#region src/browser/enrollment.ts
3
+ function parseBrowserEnrollmentPublicKeyJwk(value) {
4
+ if (!value || typeof value !== "object") throw new Error("Browser enrollment public key is missing");
5
+ const key = value;
6
+ if (key.kty !== "EC" || key.crv !== "P-256" || typeof key.x !== "string" || !key.x || typeof key.y !== "string" || !key.y) throw new Error("Browser enrollment public key is invalid");
7
+ return {
8
+ kty: "EC",
9
+ crv: "P-256",
10
+ x: key.x,
11
+ y: key.y
12
+ };
13
+ }
14
+ function browserEnrollmentPublicKeyThumbprint(value) {
15
+ const key = parseBrowserEnrollmentPublicKeyJwk(value);
16
+ const canonical = JSON.stringify({
17
+ crv: key.crv,
18
+ kty: key.kty,
19
+ x: key.x,
20
+ y: key.y
21
+ });
22
+ return crypto.createHash("sha256").update(canonical).digest("base64url");
23
+ }
24
+ //#endregion
25
+ export { browserEnrollmentPublicKeyThumbprint, parseBrowserEnrollmentPublicKeyJwk };
@@ -0,0 +1,2 @@
1
+ export declare const BROWSER_NATIVE_HOST_NAME = "ai.xopc.browser";
2
+ export declare const BROWSER_EXTENSION_ID = "gopbfhaojnnhiheiikblejnpgmfmkmgd";
@@ -0,0 +1,5 @@
1
+ //#region src/browser/extension-identity.ts
2
+ const BROWSER_NATIVE_HOST_NAME = "ai.xopc.browser";
3
+ const BROWSER_EXTENSION_ID = "gopbfhaojnnhiheiikblejnpgmfmkmgd";
4
+ //#endregion
5
+ export { BROWSER_EXTENSION_ID, BROWSER_NATIVE_HOST_NAME };
@@ -1,7 +1,10 @@
1
- export declare const BROWSER_NATIVE_HOST_NAME = "ai.xopc.browser";
2
- export declare const BROWSER_EXTENSION_ID = "gopbfhaojnnhiheiikblejnpgmfmkmgd";
1
+ export { BROWSER_EXTENSION_ID, BROWSER_NATIVE_HOST_NAME } from './extension-identity.js';
3
2
  export type BrowserNativeBootstrap = {
4
3
  type: 'bootstrap';
4
+ extensionId: string;
5
+ publicKeyJwk: unknown;
6
+ publicKeyThumbprint: string;
7
+ nonce: string;
5
8
  };
6
9
  export type BrowserNativeBootstrapResult = {
7
10
  ok: true;
@@ -11,5 +14,5 @@ export type BrowserNativeBootstrapResult = {
11
14
  };
12
15
  export declare function encodeNativeMessage(value: unknown): Buffer;
13
16
  export declare function decodeNativeMessage(buffer: Buffer): unknown;
14
- export declare function createBrowserNativeBootstrap(configPath: string): BrowserNativeBootstrapResult;
17
+ export declare function createBrowserNativeBootstrap(configPath: string, request: Omit<BrowserNativeBootstrap, 'type'>): BrowserNativeBootstrapResult;
15
18
  export declare function runBrowserNativeMessagingHost(configPath: string): Promise<void>;
@@ -2,11 +2,11 @@ import { closeXopcDatabase, openXopcDatabase } from "../storage/sqlite/connectio
2
2
  import { getGatewayIdentityPublicKeyRaw, getOrCreateGatewayIdentity } from "../storage/sqlite/gateway-identity-repository.js";
3
3
  import { createDevicePairingSetup } from "../storage/sqlite/device-pairing-repository.js";
4
4
  import { init_loader, loadConfig } from "../config/loader.js";
5
+ import { browserEnrollmentPublicKeyThumbprint } from "./enrollment.js";
6
+ import { BROWSER_EXTENSION_ID, BROWSER_NATIVE_HOST_NAME } from "./extension-identity.js";
5
7
  import os from "node:os";
6
8
  //#region src/browser/native-messaging-host.ts
7
9
  init_loader();
8
- const BROWSER_NATIVE_HOST_NAME = "ai.xopc.browser";
9
- const BROWSER_EXTENSION_ID = "gopbfhaojnnhiheiikblejnpgmfmkmgd";
10
10
  function gatewayLoopbackUrl(port) {
11
11
  return `http://127.0.0.1:${port}`;
12
12
  }
@@ -22,7 +22,11 @@ function decodeNativeMessage(buffer) {
22
22
  if (length === 0 || length > 1024 * 1024 || buffer.length !== length + 4) throw new Error("Native message length is invalid");
23
23
  return JSON.parse(buffer.subarray(4).toString("utf8"));
24
24
  }
25
- function createBrowserNativeBootstrap(configPath) {
25
+ function createBrowserNativeBootstrap(configPath, request) {
26
+ if (request.extensionId !== "gopbfhaojnnhiheiikblejnpgmfmkmgd") throw new Error("Browser extension identity is not trusted");
27
+ if (!/^[A-Za-z0-9_-]{24,160}$/.test(request.nonce)) throw new Error("Browser enrollment nonce is invalid");
28
+ const publicKeyThumbprint = browserEnrollmentPublicKeyThumbprint(request.publicKeyJwk);
29
+ if (request.publicKeyThumbprint !== publicKeyThumbprint) throw new Error("Browser enrollment key does not match");
26
30
  const gatewayUrl = gatewayLoopbackUrl(loadConfig(configPath).gateway.port ?? 18790);
27
31
  openXopcDatabase();
28
32
  try {
@@ -31,7 +35,15 @@ function createBrowserNativeBootstrap(configPath) {
31
35
  kind: "local-browser",
32
36
  url: gatewayUrl
33
37
  };
34
- const setup = createDevicePairingSetup([route], Date.now(), 3);
38
+ const setup = createDevicePairingSetup([route], Date.now(), 3, {
39
+ ttlMs: 6e4,
40
+ enrollment: {
41
+ issuer: "browser-native-host",
42
+ extensionId: request.extensionId,
43
+ publicKeyThumbprint,
44
+ nonce: request.nonce
45
+ }
46
+ });
35
47
  const identity = getOrCreateGatewayIdentity();
36
48
  return {
37
49
  ok: true,
@@ -93,7 +105,13 @@ async function runBrowserNativeMessagingHost(configPath) {
93
105
  try {
94
106
  const request = decodeNativeMessage(await readOneNativeMessage(process.stdin));
95
107
  if (!request || typeof request !== "object" || request.type !== "bootstrap") throw new Error("Unsupported native messaging request");
96
- process.stdout.write(encodeNativeMessage(createBrowserNativeBootstrap(configPath)));
108
+ const bootstrap = request;
109
+ process.stdout.write(encodeNativeMessage(createBrowserNativeBootstrap(configPath, {
110
+ extensionId: bootstrap.extensionId,
111
+ publicKeyJwk: bootstrap.publicKeyJwk,
112
+ publicKeyThumbprint: bootstrap.publicKeyThumbprint,
113
+ nonce: bootstrap.nonce
114
+ })));
97
115
  } catch (error) {
98
116
  process.stdout.write(encodeNativeMessage({
99
117
  ok: false,
@@ -26,6 +26,7 @@ export interface BrowserExtDoctor {
26
26
  needsChromeReload?: boolean;
27
27
  bundledFrom?: BrowserExtBundledFrom;
28
28
  runtimeExtensionVersion?: string;
29
+ nativeHost: BrowserNativeHostInstallResult;
29
30
  }
30
31
  export interface EnsureBrowserExtResult {
31
32
  extensionDir: string;
@@ -65,17 +66,19 @@ export declare function ensureBrowserExtensionArtifacts(opts?: {
65
66
  cacheDir?: string;
66
67
  }): Promise<EnsureBrowserExtResult>;
67
68
  export declare function browserNativeManifestDirectories(platform?: NodeJS.Platform, home?: string): string[];
69
+ export declare function browserNativeHostDoctor(platform?: NodeJS.Platform, home?: string): BrowserNativeHostInstallResult;
68
70
  /** Install the local-only bootstrap host used to discover and pair with a Gateway. */
69
71
  export declare function installBrowserNativeMessagingHost(opts?: {
70
72
  cacheDir?: string;
71
73
  cliPath?: string;
72
74
  nodePath?: string;
75
+ tsxCliPath?: string;
73
76
  platform?: NodeJS.Platform;
74
77
  home?: string;
75
78
  configPath?: string;
76
79
  stateDir?: string;
77
80
  }): Promise<BrowserNativeHostInstallResult>;
78
- /** Gateway startup hook: ensure artifacts only while the extension driver is active. */
81
+ /** Gateway startup hook: install/repair extension artifacts and its local enrollment host. */
79
82
  export declare function ensureBrowserExtensionOnStartup(config: Config | undefined): Promise<void>;
80
83
  export declare function readInstalledExtensionDir(cacheDir?: string): Promise<string | null>;
81
84
  export type BrowserExtensionOpenAction = 'chrome' | 'folder' | 'both';
@@ -2,13 +2,14 @@ import { PACKAGE_VERSION, init_package_version } from "../../package-version.js"
2
2
  import { resolveStateDir } from "../../config/paths-state.js";
3
3
  import { createLogger } from "../../utils/logger/index.js";
4
4
  import { init_logger } from "../../utils/logger.js";
5
- import { init_paths, resolveBinDir, resolveConfigPath } from "../../config/paths.js";
6
5
  import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
6
+ import { init_paths, resolveBinDir, resolveConfigPath } from "../../config/paths.js";
7
7
  import { assertCacheDir } from "../cache-dir-policy.js";
8
- import { BROWSER_EXTENSION_ID, BROWSER_NATIVE_HOST_NAME } from "../native-messaging-host.js";
8
+ import { BROWSER_EXTENSION_ID, BROWSER_NATIVE_HOST_NAME } from "../extension-identity.js";
9
+ import "../native-messaging-host.js";
9
10
  import { resolvePackageRoot } from "../../infra/update-check.js";
10
11
  import { dirname, join } from "node:path";
11
- import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
12
+ import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
12
13
  import { fileURLToPath } from "node:url";
13
14
  import { spawn } from "node:child_process";
14
15
  import { createHash } from "node:crypto";
@@ -240,7 +241,8 @@ async function browserExtDoctor(opts) {
240
241
  needsRefresh,
241
242
  needsChromeReload,
242
243
  bundledFrom: bundled?.bundledFrom,
243
- runtimeExtensionVersion: runtimeVer
244
+ runtimeExtensionVersion: runtimeVer,
245
+ nativeHost: browserNativeHostDoctor()
244
246
  };
245
247
  }
246
248
  async function ensureBrowserExtensionArtifacts(opts) {
@@ -302,33 +304,68 @@ function browserNativeManifestDirectories(platform = process.platform, home = pr
302
304
  if (!home) return [];
303
305
  if (platform === "darwin") return [
304
306
  join(home, "Library/Application Support/Google/Chrome/NativeMessagingHosts"),
307
+ join(home, "Library/Application Support/Google/ChromeForTesting/NativeMessagingHosts"),
305
308
  join(home, "Library/Application Support/Chromium/NativeMessagingHosts"),
306
309
  join(home, "Library/Application Support/Microsoft Edge/NativeMessagingHosts"),
307
310
  join(home, "Library/Application Support/BraveSoftware/Brave-Browser/NativeMessagingHosts")
308
311
  ];
309
312
  if (platform === "linux") return [
310
313
  join(home, ".config/google-chrome/NativeMessagingHosts"),
314
+ join(home, ".config/google-chrome-for-testing/NativeMessagingHosts"),
311
315
  join(home, ".config/chromium/NativeMessagingHosts"),
312
316
  join(home, ".config/microsoft-edge/NativeMessagingHosts"),
313
317
  join(home, ".config/BraveSoftware/Brave-Browser/NativeMessagingHosts")
314
318
  ];
315
319
  return [];
316
320
  }
321
+ function browserNativeHostDoctor(platform = process.platform, home = process.env.HOME || process.env.USERPROFILE || "") {
322
+ const directories = browserNativeManifestDirectories(platform, home);
323
+ if (directories.length === 0) return {
324
+ installed: false,
325
+ manifestPaths: [],
326
+ reason: "Automatic local Gateway discovery is supported on macOS and Linux"
327
+ };
328
+ const manifestPaths = directories.map((directory) => join(directory, `${BROWSER_NATIVE_HOST_NAME}.json`)).filter((manifestPath) => {
329
+ try {
330
+ const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
331
+ return manifest.name === "ai.xopc.browser" && typeof manifest.path === "string" && existsSync(manifest.path) && Array.isArray(manifest.allowed_origins) && manifest.allowed_origins.includes(`chrome-extension://gopbfhaojnnhiheiikblejnpgmfmkmgd/`);
332
+ } catch {
333
+ return false;
334
+ }
335
+ });
336
+ return {
337
+ installed: manifestPaths.length > 0,
338
+ manifestPaths,
339
+ ...manifestPaths.length === 0 ? { reason: "Browser native enrollment host is not installed" } : {}
340
+ };
341
+ }
317
342
  /** Install the local-only bootstrap host used to discover and pair with a Gateway. */
318
343
  async function installBrowserNativeMessagingHost(opts) {
319
344
  const directories = browserNativeManifestDirectories(opts?.platform ?? process.platform, opts?.home);
320
345
  if (directories.length === 0) return {
321
346
  installed: false,
322
347
  manifestPaths: [],
323
- reason: "Native bootstrap installation is supported on macOS and Linux"
348
+ reason: "Automatic local Gateway discovery is supported on macOS and Linux"
324
349
  };
325
350
  const cliPath = opts?.cliPath ?? process.argv[1];
326
351
  if (!cliPath) throw new Error("Unable to resolve the xopc CLI entry point");
352
+ const executablePath = opts?.nodePath ?? process.execPath;
353
+ let executableArgs = [
354
+ cliPath,
355
+ "browser",
356
+ "extension",
357
+ "native-host"
358
+ ];
359
+ if (cliPath.endsWith(".ts")) {
360
+ const tsxPath = opts?.tsxCliPath ?? join(process.cwd(), "node_modules", "tsx", "dist", "cli.mjs");
361
+ if (!existsSync(tsxPath)) throw new Error("Unable to install the browser native host in development: the tsx CLI entry was not found");
362
+ executableArgs = [realpathSync(tsxPath), ...executableArgs];
363
+ }
327
364
  const hostPath = join((opts?.cacheDir?.trim() ? assertCacheDir(opts.cacheDir) : resolveBinDir()) || resolveBinDir(), "browser-native-host");
328
365
  mkdirSync(dirname(hostPath), { recursive: true });
329
366
  const stateDir = opts?.stateDir ?? resolveStateDir();
330
367
  const configPath = opts?.configPath ?? resolveConfigPath();
331
- await writeTextAtomic(hostPath, `#!/bin/sh\nexec env XOPC_STATE_DIR=${shellQuote(stateDir)} XOPC_CONFIG_PATH=${shellQuote(configPath)} XOPC_LOG_CONSOLE=false ${shellQuote(opts?.nodePath ?? process.execPath)} ${shellQuote(cliPath)} browser extension native-host\n`);
368
+ await writeTextAtomic(hostPath, `#!/bin/sh\nexec env ELECTRON_RUN_AS_NODE=1 XOPC_STATE_DIR=${shellQuote(stateDir)} XOPC_CONFIG_PATH=${shellQuote(configPath)} XOPC_LOG_CONSOLE=false ${shellQuote(executablePath)} ${executableArgs.map(shellQuote).join(" ")}\n`);
332
369
  chmodSync(hostPath, 493);
333
370
  const manifest = JSON.stringify({
334
371
  name: BROWSER_NATIVE_HOST_NAME,
@@ -349,10 +386,12 @@ async function installBrowserNativeMessagingHost(opts) {
349
386
  manifestPaths
350
387
  };
351
388
  }
352
- /** Gateway startup hook: ensure artifacts only while the extension driver is active. */
389
+ /** Gateway startup hook: install/repair extension artifacts and its local enrollment host. */
353
390
  async function ensureBrowserExtensionOnStartup(config) {
354
391
  if (config?.browser.enabled === false || config?.browser.driver.kind !== "extension") return;
355
392
  await ensureBrowserExtensionArtifacts();
393
+ const nativeHost = await installBrowserNativeMessagingHost();
394
+ if (!nativeHost.installed) log.warn({ reason: nativeHost.reason }, "Browser native enrollment host was not installed");
356
395
  }
357
396
  async function readInstalledExtensionDir(cacheDir) {
358
397
  const resolved = (cacheDir?.trim() ? assertCacheDir(cacheDir) : resolveBinDir()) || resolveBinDir();
@@ -432,4 +471,4 @@ async function openBrowserExtensionInstallUi(opts) {
432
471
  };
433
472
  }
434
473
  //#endregion
435
- export { BROWSER_EXT_REQUIRED_FILES, browserExtContentHash, browserExtDoctor, browserNativeManifestDirectories, computeNeedsRefresh, ensureBrowserExtensionArtifacts, ensureBrowserExtensionOnStartup, installBrowserNativeMessagingHost, openBrowserExtensionInstallUi, readInstalledExtensionDir, resolveBundledBrowserExtDir, resolveInstalledExtensionPath, resolveWindowsExtensionManager, validateBrowserExtLayout };
474
+ export { BROWSER_EXT_REQUIRED_FILES, browserExtContentHash, browserExtDoctor, browserNativeHostDoctor, browserNativeManifestDirectories, computeNeedsRefresh, ensureBrowserExtensionArtifacts, ensureBrowserExtensionOnStartup, installBrowserNativeMessagingHost, openBrowserExtensionInstallUi, readInstalledExtensionDir, resolveBundledBrowserExtDir, resolveInstalledExtensionPath, resolveWindowsExtensionManager, validateBrowserExtLayout };
@@ -2,8 +2,8 @@ import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { deleteBrowserTabBindingsByPrincipal, getBrowserTabBindingById } from "../../storage/sqlite/browser-tab-binding-repository.js";
4
4
  import { getDevice } from "../../storage/sqlite/device-access-repository.js";
5
- import { isChromeExtensionOrigin } from "../../gateway/security/origin-check.js";
6
5
  import { browserWireAuthenticationPayload } from "../../../packages/browser-control-contract/src/index.js";
6
+ import { isChromeExtensionOrigin } from "../../gateway/security/origin-check.js";
7
7
  import crypto from "node:crypto";
8
8
  //#region src/browser/providers/extension.ts
9
9
  /**
@@ -0,0 +1,29 @@
1
+ import { type BrowserActionInput, type BrowserWireResult } from '@xopcai/browser-control-contract';
2
+ import type { EndpointToolRuntime } from '../../endpoint-tools/index.js';
3
+ export interface RealtimeExtensionProviderConfig {
4
+ connectionTimeout?: number;
5
+ commandTimeout?: number;
6
+ }
7
+ export declare class RealtimeExtensionBrowserProvider {
8
+ private readonly runtime;
9
+ readonly name = "extension";
10
+ private readonly connectionTimeout;
11
+ private readonly commandTimeout;
12
+ constructor(runtime: EndpointToolRuntime, config?: RealtimeExtensionProviderConfig);
13
+ start(): Promise<void>;
14
+ waitForConnection(timeoutMs?: number): Promise<void>;
15
+ send(input: BrowserActionInput, timeoutMs?: number, visualFallback?: boolean): Promise<BrowserWireResult>;
16
+ isConnected(): boolean;
17
+ getConnectionStatus(): {
18
+ socketConnected: boolean;
19
+ connected: boolean;
20
+ protocolVersion: number;
21
+ expectedProtocolVersion: number;
22
+ extensionVersion: string;
23
+ principalId: string;
24
+ transport: "gateway-realtime";
25
+ };
26
+ shutdown(): Promise<void>;
27
+ private endpointForInput;
28
+ private currentEndpoint;
29
+ }