@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
@@ -5099,6 +5099,562 @@ function superRefine(fn, params) {
5099
5099
  return _superRefine(fn, params);
5100
5100
  }
5101
5101
 
5102
+ const ENDPOINT_PROTOCOL_VERSION = 2;
5103
+ const endpointKindSchema = _enum(["web", "desktop", "mobile", "browser"]);
5104
+ const endpointAvailabilitySchema = _enum(["foreground", "background"]);
5105
+ const endpointEffectSchema = _enum(["read", "write", "destructive"]);
5106
+ const endpointConfirmationSchema = _enum(["never", "always"]);
5107
+ const endpointResultKindSchema = _enum(["text", "json", "file"]);
5108
+ const endpointSensitivitySchema = _enum(["public", "personal"]);
5109
+ const identifierSchema = string().min(1).max(160);
5110
+ const turnTokenSchema = string().min(32).max(160).regex(/^[A-Za-z0-9_-]+$/);
5111
+ const turnOriginSchema = discriminatedUnion("type", [
5112
+ strictObject({ type: literal("endpoint"), endpointId: identifierSchema }),
5113
+ strictObject({ type: literal("channel"), channel: string().min(1).max(64) }),
5114
+ strictObject({
5115
+ type: literal("system"),
5116
+ source: _enum(["cli", "automation", "heartbeat", "workflow", "internal"])
5117
+ })
5118
+ ]);
5119
+ const endpointTurnOriginSchema = turnOriginSchema.options[0];
5120
+ endpointTurnOriginSchema.extend({ token: turnTokenSchema });
5121
+ const messageIdSchema$1 = uuid();
5122
+ const timestampSchema$1 = number().int().nonnegative();
5123
+ const jsonObjectSchema = record(string(), unknown());
5124
+ const endpointToolDescriptorSchema = strictObject({
5125
+ name: string().regex(/^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/).max(120),
5126
+ title: string().min(1).max(120),
5127
+ description: string().min(1).max(2e3),
5128
+ inputSchema: jsonObjectSchema,
5129
+ outputSchema: jsonObjectSchema,
5130
+ policyId: string().regex(/^[a-z][a-z0-9_.-]+$/).max(120),
5131
+ sensitivity: endpointSensitivitySchema,
5132
+ effect: endpointEffectSchema,
5133
+ confirmation: endpointConfirmationSchema,
5134
+ requiresForeground: boolean(),
5135
+ requiredPermissions: array(string().min(1).max(120)).max(20),
5136
+ timeoutMs: number().int().min(1e3).max(3e5),
5137
+ maxConcurrency: number().int().min(1).max(4),
5138
+ supportsCancellation: boolean(),
5139
+ idempotent: boolean(),
5140
+ resultKinds: array(endpointResultKindSchema).min(1).max(3)
5141
+ });
5142
+ strictObject({
5143
+ principalId: identifierSchema,
5144
+ displayName: string().min(1).max(120),
5145
+ kind: endpointKindSchema,
5146
+ platform: string().min(1).max(80),
5147
+ publicKey: string().min(32).max(2048)
5148
+ });
5149
+ strictObject({
5150
+ endpointId: identifierSchema
5151
+ });
5152
+ const backgroundCapabilitySchema = string().regex(/^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/).max(120);
5153
+ strictObject({
5154
+ jobId: uuid(),
5155
+ endpointId: identifierSchema,
5156
+ capability: backgroundCapabilitySchema,
5157
+ input: jsonObjectSchema,
5158
+ idempotencyKey: identifierSchema,
5159
+ consentGrantId: identifierSchema,
5160
+ createdAt: timestampSchema$1,
5161
+ expiresAt: timestampSchema$1
5162
+ });
5163
+ strictObject({
5164
+ jobId: uuid(),
5165
+ status: _enum(["queued", "running", "succeeded", "failed", "cancelled"]),
5166
+ updatedAt: timestampSchema$1,
5167
+ output: jsonObjectSchema.optional(),
5168
+ error: strictObject({
5169
+ code: identifierSchema,
5170
+ message: string().min(1).max(2e3)
5171
+ }).optional()
5172
+ });
5173
+ strictObject({
5174
+ eventId: uuid(),
5175
+ endpointId: identifierSchema,
5176
+ subscriptionId: identifierSchema,
5177
+ eventType: backgroundCapabilitySchema,
5178
+ data: jsonObjectSchema,
5179
+ occurredAt: timestampSchema$1
5180
+ });
5181
+ const endpointHelloPayloadSchema = strictObject({
5182
+ principalId: identifierSchema,
5183
+ endpointId: identifierSchema,
5184
+ connectionInstanceId: uuid(),
5185
+ displayName: string().min(1).max(120),
5186
+ kind: endpointKindSchema,
5187
+ platform: string().min(1).max(80),
5188
+ appVersion: string().min(1).max(80),
5189
+ availability: endpointAvailabilitySchema,
5190
+ nonce: identifierSchema,
5191
+ signedAt: timestampSchema$1,
5192
+ signature: string().min(16).max(1024),
5193
+ tools: array(endpointToolDescriptorSchema).max(100)
5194
+ });
5195
+ const toolInvokePayloadSchema = strictObject({
5196
+ invocationId: uuid(),
5197
+ toolCallId: identifierSchema,
5198
+ toolName: endpointToolDescriptorSchema.shape.name,
5199
+ arguments: jsonObjectSchema,
5200
+ descriptorRevision: string().min(1).max(128),
5201
+ confirmationRequired: boolean(),
5202
+ deadlineAt: timestampSchema$1,
5203
+ uploadGrant: strictObject({
5204
+ path: string().startsWith("/").max(500),
5205
+ token: identifierSchema,
5206
+ maxBytes: number().int().positive(),
5207
+ maxFiles: number().int().min(1).max(20),
5208
+ expiresAt: timestampSchema$1
5209
+ }).optional()
5210
+ });
5211
+ const toolCancelPayloadSchema = strictObject({
5212
+ invocationId: uuid(),
5213
+ reason: string().min(1).max(500)
5214
+ });
5215
+ const invocationPayloadSchema = strictObject({ invocationId: uuid() });
5216
+ const endpointToolContentSchema = discriminatedUnion("type", [
5217
+ strictObject({ type: literal("text"), text: string().max(256 * 1024) }),
5218
+ strictObject({ type: literal("json"), value: unknown() }),
5219
+ strictObject({
5220
+ type: literal("file"),
5221
+ fileId: identifierSchema,
5222
+ name: string().min(1).max(255),
5223
+ mimeType: string().min(1).max(255),
5224
+ size: number().int().nonnegative(),
5225
+ sha256: string().regex(/^[a-f0-9]{64}$/)
5226
+ })
5227
+ ]);
5228
+ const endpointToolErrorCodeSchema = _enum([
5229
+ "ENDPOINT_OFFLINE",
5230
+ "ENDPOINT_NOT_FOREGROUND",
5231
+ "ENDPOINT_DISCONNECTED",
5232
+ "TOOL_NOT_FOUND",
5233
+ "TOOL_REVISION_MISMATCH",
5234
+ "INVALID_ARGUMENTS",
5235
+ "PERMISSION_DENIED",
5236
+ "USER_DENIED",
5237
+ "TOOL_BUSY",
5238
+ "TOOL_TIMEOUT",
5239
+ "TOOL_CANCELLED",
5240
+ "RESULT_TOO_LARGE",
5241
+ "PROTOCOL_ERROR"
5242
+ ]);
5243
+ const envelope$1 = (type, payload) => strictObject({
5244
+ protocolVersion: literal(ENDPOINT_PROTOCOL_VERSION),
5245
+ messageId: messageIdSchema$1,
5246
+ type: literal(type),
5247
+ sentAt: timestampSchema$1,
5248
+ payload
5249
+ });
5250
+ const clientEndpointMessageSchema = discriminatedUnion("type", [
5251
+ envelope$1("endpoint.availability_changed", strictObject({ availability: endpointAvailabilitySchema })),
5252
+ envelope$1("tool.received", invocationPayloadSchema),
5253
+ envelope$1("tool.progress", strictObject({
5254
+ invocationId: uuid(),
5255
+ message: string().max(500).optional(),
5256
+ percent: number().min(0).max(100).optional()
5257
+ })),
5258
+ envelope$1("tool.result", strictObject({
5259
+ invocationId: uuid(),
5260
+ content: array(endpointToolContentSchema).min(1).max(20),
5261
+ details: jsonObjectSchema.optional()
5262
+ })),
5263
+ envelope$1("tool.error", strictObject({
5264
+ invocationId: uuid(),
5265
+ code: endpointToolErrorCodeSchema,
5266
+ message: string().min(1).max(2e3)
5267
+ })),
5268
+ envelope$1("tool.cancelled", invocationPayloadSchema)
5269
+ ]);
5270
+ const serverEndpointMessageSchema = discriminatedUnion("type", [
5271
+ envelope$1("tool.invoke", toolInvokePayloadSchema),
5272
+ envelope$1("tool.cancel", toolCancelPayloadSchema)
5273
+ ]);
5274
+ function canonicalJson(value) {
5275
+ if (value === null) return "null";
5276
+ if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
5277
+ if (typeof value === "number") {
5278
+ if (!Number.isFinite(value)) throw new Error("Canonical JSON only supports finite numbers");
5279
+ return JSON.stringify(value);
5280
+ }
5281
+ if (typeof value !== "object") throw new Error(`Canonical JSON does not support ${typeof value}`);
5282
+ if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
5283
+ const prototype = Object.getPrototypeOf(value);
5284
+ if (prototype !== Object.prototype && prototype !== null) {
5285
+ throw new Error("Canonical JSON only supports plain objects");
5286
+ }
5287
+ const record = value;
5288
+ return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
5289
+ }
5290
+ function endpointHelloSigningPayload(payload) {
5291
+ const { signature: _signature, ...unsigned } = payload;
5292
+ return canonicalJson(unsigned);
5293
+ }
5294
+
5295
+ const REALTIME_PROTOCOL_VERSION = 1;
5296
+ const REALTIME_HEARTBEAT_INTERVAL_MS = 15e3;
5297
+ const REALTIME_HEARTBEAT_TIMEOUT_MS = 45e3;
5298
+ const realtimeClientKindSchema = _enum([
5299
+ "web",
5300
+ "desktop",
5301
+ "mobile",
5302
+ "browser_extension",
5303
+ "tui",
5304
+ "mcp"
5305
+ ]);
5306
+ const realtimeTopicSchema = string().min(1).max(512);
5307
+ const realtimeEventNameSchema = string().regex(/^[a-z][a-z0-9_.-]*$/).max(160);
5308
+ const messageIdSchema = uuid();
5309
+ const timestampSchema = number().int().nonnegative();
5310
+ const sequenceSchema = number().int().positive();
5311
+ const envelope = (kind, payload) => strictObject({
5312
+ protocolVersion: literal(REALTIME_PROTOCOL_VERSION),
5313
+ messageId: messageIdSchema,
5314
+ kind: literal(kind),
5315
+ sentAt: timestampSchema,
5316
+ payload
5317
+ });
5318
+ const realtimeSubscriptionSchema = strictObject({
5319
+ topic: realtimeTopicSchema,
5320
+ afterSeq: number().int().nonnegative().optional()
5321
+ });
5322
+ discriminatedUnion("kind", [
5323
+ envelope("realtime.hello", strictObject({
5324
+ ticket: string().min(32).max(512),
5325
+ clientId: string().min(1).max(160),
5326
+ clientKind: realtimeClientKindSchema,
5327
+ subscriptions: array(realtimeSubscriptionSchema).max(100).default([]),
5328
+ endpoint: endpointHelloPayloadSchema.optional()
5329
+ })),
5330
+ envelope("realtime.subscribe", strictObject({
5331
+ subscriptions: array(realtimeSubscriptionSchema).min(1).max(100)
5332
+ })),
5333
+ envelope("realtime.unsubscribe", strictObject({
5334
+ topics: array(realtimeTopicSchema).min(1).max(100)
5335
+ })),
5336
+ envelope("realtime.ping", strictObject({})),
5337
+ envelope("endpoint.message", clientEndpointMessageSchema)
5338
+ ]);
5339
+ const realtimeEventPayloadSchema = strictObject({
5340
+ topic: realtimeTopicSchema,
5341
+ seq: sequenceSchema,
5342
+ event: realtimeEventNameSchema,
5343
+ data: unknown()
5344
+ });
5345
+ const serverRealtimeMessageSchema = discriminatedUnion("kind", [
5346
+ envelope("realtime.ready", strictObject({
5347
+ connectionId: uuid(),
5348
+ heartbeatIntervalMs: literal(REALTIME_HEARTBEAT_INTERVAL_MS),
5349
+ heartbeatTimeoutMs: literal(REALTIME_HEARTBEAT_TIMEOUT_MS),
5350
+ endpoint: strictObject({
5351
+ endpointId: string().min(1).max(160),
5352
+ turnToken: string().min(32).max(160)
5353
+ }).optional()
5354
+ })),
5355
+ envelope("realtime.event", realtimeEventPayloadSchema),
5356
+ envelope("realtime.subscribed", strictObject({
5357
+ topic: realtimeTopicSchema,
5358
+ cursor: number().int().nonnegative()
5359
+ })),
5360
+ envelope("realtime.gap", strictObject({
5361
+ topic: realtimeTopicSchema,
5362
+ requestedSeq: number().int().nonnegative(),
5363
+ earliestSeq: sequenceSchema,
5364
+ recoverable: boolean()
5365
+ })),
5366
+ envelope("realtime.pong", strictObject({})),
5367
+ envelope("realtime.error", strictObject({
5368
+ code: string().min(1).max(80),
5369
+ message: string().min(1).max(500)
5370
+ })),
5371
+ envelope("endpoint.message", serverEndpointMessageSchema)
5372
+ ]);
5373
+ function parseServerRealtimeMessage(value) {
5374
+ return serverRealtimeMessageSchema.parse(value);
5375
+ }
5376
+
5377
+ function frameText(data) {
5378
+ if (typeof data === "string") return data;
5379
+ if (data instanceof ArrayBuffer) return new TextDecoder().decode(data);
5380
+ if (ArrayBuffer.isView(data)) {
5381
+ const bytes = Uint8Array.from(new Uint8Array(data.buffer, data.byteOffset, data.byteLength));
5382
+ return new TextDecoder().decode(bytes);
5383
+ }
5384
+ throw new Error("Realtime server sent a non-text frame");
5385
+ }
5386
+ function isNonRetryableCloseCode(code) {
5387
+ return code === 1009 || code === 4400 || code === 4401 || code === 4413;
5388
+ }
5389
+ class RealtimeClient {
5390
+ constructor(options) {
5391
+ this.options = options;
5392
+ }
5393
+ options;
5394
+ desiredSubscriptions = /* @__PURE__ */ new Map();
5395
+ cursors = /* @__PURE__ */ new Map();
5396
+ socket;
5397
+ reconnectTimer;
5398
+ heartbeatTimer;
5399
+ connectionTimer;
5400
+ ticketAbort;
5401
+ generation = 0;
5402
+ reconnectAttempts = 0;
5403
+ shouldReconnect = false;
5404
+ ready = false;
5405
+ lastServerMessageAt = 0;
5406
+ endpointBinding;
5407
+ reconnectWhenSocketOpens = false;
5408
+ connect() {
5409
+ if (this.shouldReconnect) return;
5410
+ this.shouldReconnect = true;
5411
+ void this.open(false);
5412
+ }
5413
+ disconnect() {
5414
+ this.shouldReconnect = false;
5415
+ this.reconnectWhenSocketOpens = false;
5416
+ this.generation += 1;
5417
+ this.clearTimers();
5418
+ this.ready = false;
5419
+ this.endpointBinding?.onDisconnected?.();
5420
+ this.socket?.close(1e3, "Client disconnected");
5421
+ this.socket = void 0;
5422
+ this.options.onStateChange?.("disconnected");
5423
+ }
5424
+ reconnect() {
5425
+ this.reconnectWhenSocketOpens = false;
5426
+ this.generation += 1;
5427
+ this.clearTimers();
5428
+ this.ready = false;
5429
+ this.endpointBinding?.onDisconnected?.();
5430
+ this.socket?.close(1e3, "Client reconnecting");
5431
+ this.socket = void 0;
5432
+ this.reconnectAttempts = 0;
5433
+ this.shouldReconnect = true;
5434
+ void this.open(true);
5435
+ }
5436
+ subscribe(topic, afterSeq) {
5437
+ this.desiredSubscriptions.set(topic, afterSeq);
5438
+ if (afterSeq !== void 0) this.cursors.set(topic, afterSeq);
5439
+ if (this.ready) {
5440
+ this.sendSubscriptions([{ topic, afterSeq: this.cursors.get(topic) ?? afterSeq }]);
5441
+ }
5442
+ }
5443
+ unsubscribe(topic) {
5444
+ this.desiredSubscriptions.delete(topic);
5445
+ if (this.ready) this.send(this.clientMessage("realtime.unsubscribe", { topics: [topic] }));
5446
+ }
5447
+ sendEndpointMessage(message) {
5448
+ if (!this.ready) throw new Error("Realtime connection is not ready");
5449
+ this.send(this.clientMessage("endpoint.message", message));
5450
+ }
5451
+ setEndpoint(binding) {
5452
+ this.endpointBinding = binding;
5453
+ this.refreshEndpointConnection();
5454
+ }
5455
+ clearEndpoint(binding) {
5456
+ if (binding && this.endpointBinding !== binding) return;
5457
+ const previous = this.endpointBinding;
5458
+ this.endpointBinding = void 0;
5459
+ previous?.onDisconnected?.();
5460
+ this.refreshEndpointConnection();
5461
+ }
5462
+ refreshEndpointConnection() {
5463
+ if (!this.shouldReconnect) return;
5464
+ if (this.socket?.readyState === 0) {
5465
+ this.reconnectWhenSocketOpens = true;
5466
+ return;
5467
+ }
5468
+ this.reconnect();
5469
+ }
5470
+ async open(reconnecting) {
5471
+ const generation = ++this.generation;
5472
+ const timeoutMs = this.options.connectionTimeoutMs ?? 15e3;
5473
+ const ticketAbort = new AbortController();
5474
+ this.ticketAbort?.abort();
5475
+ this.ticketAbort = ticketAbort;
5476
+ let socket;
5477
+ let closed = false;
5478
+ let messageQueue;
5479
+ const failAttempt = (error, retry = true) => {
5480
+ if (closed || generation !== this.generation) return;
5481
+ closed = true;
5482
+ this.clearConnectionTimer();
5483
+ ticketAbort.abort();
5484
+ if (this.ticketAbort === ticketAbort) this.ticketAbort = void 0;
5485
+ this.ready = false;
5486
+ this.endpointBinding?.onDisconnected?.();
5487
+ this.clearHeartbeat();
5488
+ if (this.socket === socket) this.socket = void 0;
5489
+ if (socket) {
5490
+ socket.onopen = null;
5491
+ socket.onmessage = null;
5492
+ socket.onerror = null;
5493
+ socket.onclose = null;
5494
+ socket.close(4e3, error.slice(0, 120));
5495
+ }
5496
+ if (this.shouldReconnect && retry) this.scheduleReconnect(error);
5497
+ else if (this.shouldReconnect) {
5498
+ this.shouldReconnect = false;
5499
+ this.options.onStateChange?.("error", error);
5500
+ } else this.options.onStateChange?.("disconnected");
5501
+ };
5502
+ this.connectionTimer = setTimeout(() => failAttempt("Realtime connection timed out"), timeoutMs);
5503
+ this.options.onStateChange?.(reconnecting ? "reconnecting" : "connecting");
5504
+ try {
5505
+ const [ticket, endpoint] = await Promise.all([
5506
+ this.options.issueTicket(ticketAbort.signal),
5507
+ this.endpointBinding?.createHello()
5508
+ ]);
5509
+ if (closed || !this.shouldReconnect || generation !== this.generation) return;
5510
+ socket = this.options.createWebSocket(this.options.getWebSocketUrl());
5511
+ this.socket = socket;
5512
+ socket.onopen = () => {
5513
+ if (generation !== this.generation) return;
5514
+ if (this.reconnectWhenSocketOpens) {
5515
+ this.reconnect();
5516
+ return;
5517
+ }
5518
+ const subscriptions = [...this.desiredSubscriptions].map(([topic, afterSeq]) => ({
5519
+ topic,
5520
+ afterSeq: this.cursors.get(topic) ?? afterSeq
5521
+ }));
5522
+ this.send(this.clientMessage("realtime.hello", {
5523
+ ticket,
5524
+ clientId: this.options.clientId,
5525
+ clientKind: this.options.clientKind,
5526
+ subscriptions,
5527
+ ...endpoint ? { endpoint } : {}
5528
+ }));
5529
+ };
5530
+ socket.onmessage = (event) => {
5531
+ if (generation !== this.generation) return;
5532
+ const process = () => {
5533
+ if (closed || generation !== this.generation) return;
5534
+ return this.handleServerMessage(frameText(event.data));
5535
+ };
5536
+ if (!messageQueue) {
5537
+ try {
5538
+ const pending = process();
5539
+ if (!pending) return;
5540
+ const current2 = pending.catch((error) => failAttempt(error instanceof Error ? error.message : "Invalid realtime server message")).then(() => void 0);
5541
+ messageQueue = current2;
5542
+ void current2.finally(() => {
5543
+ if (messageQueue === current2) messageQueue = void 0;
5544
+ });
5545
+ } catch (error) {
5546
+ failAttempt(error instanceof Error ? error.message : "Invalid realtime server message");
5547
+ }
5548
+ return;
5549
+ }
5550
+ const current = messageQueue.then(process).catch((error) => failAttempt(error instanceof Error ? error.message : "Invalid realtime server message")).then(() => void 0);
5551
+ messageQueue = current;
5552
+ void current.finally(() => {
5553
+ if (messageQueue === current) messageQueue = void 0;
5554
+ });
5555
+ };
5556
+ socket.onerror = () => {
5557
+ };
5558
+ socket.onclose = (event) => {
5559
+ failAttempt(
5560
+ event.reason || `WebSocket closed (${event.code ?? 0})`,
5561
+ !isNonRetryableCloseCode(event.code)
5562
+ );
5563
+ };
5564
+ } catch (error) {
5565
+ failAttempt(error instanceof Error ? error.message : "Realtime connection failed");
5566
+ }
5567
+ }
5568
+ handleServerMessage(text) {
5569
+ const message = parseServerRealtimeMessage(JSON.parse(text));
5570
+ this.lastServerMessageAt = Date.now();
5571
+ if (message.kind === "realtime.ready") {
5572
+ this.ready = true;
5573
+ this.reconnectAttempts = 0;
5574
+ this.clearConnectionTimer();
5575
+ this.ticketAbort = void 0;
5576
+ this.options.onStateChange?.("connected");
5577
+ if (message.payload.endpoint) this.endpointBinding?.onReady(message.payload.endpoint);
5578
+ this.clearHeartbeat();
5579
+ this.heartbeatTimer = setInterval(() => {
5580
+ if (!this.ready) return;
5581
+ if (Date.now() - this.lastServerMessageAt >= message.payload.heartbeatTimeoutMs) {
5582
+ this.reconnect();
5583
+ return;
5584
+ }
5585
+ this.send(this.clientMessage("realtime.ping", {}));
5586
+ }, message.payload.heartbeatIntervalMs);
5587
+ } else if (message.kind === "realtime.event") {
5588
+ const cursor = this.cursors.get(message.payload.topic);
5589
+ if (cursor !== void 0 && message.payload.seq <= cursor) return;
5590
+ this.options.onEvent?.(message.payload);
5591
+ this.cursors.set(message.payload.topic, message.payload.seq);
5592
+ } else if (message.kind === "realtime.subscribed") {
5593
+ this.cursors.set(message.payload.topic, message.payload.cursor);
5594
+ } else if (message.kind === "realtime.gap") {
5595
+ this.cursors.set(message.payload.topic, message.payload.earliestSeq - 1);
5596
+ return this.options.onGap?.(message.payload);
5597
+ } else if (message.kind === "realtime.error") {
5598
+ this.options.onStateChange?.("error", message.payload.message);
5599
+ } else if (message.kind === "endpoint.message") {
5600
+ this.endpointBinding?.onMessage(message.payload);
5601
+ this.options.onEndpointMessage?.(message.payload);
5602
+ }
5603
+ }
5604
+ sendSubscriptions(subscriptions) {
5605
+ this.send(this.clientMessage("realtime.subscribe", { subscriptions }));
5606
+ }
5607
+ clientMessage(kind, payload) {
5608
+ const messageId = this.options.createMessageId?.() ?? globalThis.crypto?.randomUUID?.();
5609
+ if (!messageId) throw new Error("RealtimeClient requires createMessageId when crypto.randomUUID is unavailable");
5610
+ return {
5611
+ protocolVersion: REALTIME_PROTOCOL_VERSION,
5612
+ messageId,
5613
+ kind,
5614
+ sentAt: Date.now(),
5615
+ payload
5616
+ };
5617
+ }
5618
+ send(message) {
5619
+ if (!this.socket || this.socket.readyState !== 1) return;
5620
+ this.socket.send(JSON.stringify(message));
5621
+ }
5622
+ scheduleReconnect(error) {
5623
+ if (!this.shouldReconnect) return;
5624
+ this.reconnectAttempts += 1;
5625
+ const max = this.options.maxReconnectAttempts;
5626
+ if (max !== void 0 && this.reconnectAttempts > max) {
5627
+ this.shouldReconnect = false;
5628
+ this.options.onStateChange?.("error", error);
5629
+ return;
5630
+ }
5631
+ this.options.onStateChange?.("reconnecting", error);
5632
+ const cap = Math.min(3e4, 1e3 * 2 ** Math.min(this.reconnectAttempts - 1, 5));
5633
+ const delay = Math.round(cap * (0.5 + Math.random() * 0.5));
5634
+ if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
5635
+ this.reconnectTimer = setTimeout(() => {
5636
+ this.reconnectTimer = void 0;
5637
+ void this.open(true);
5638
+ }, delay);
5639
+ }
5640
+ clearHeartbeat() {
5641
+ if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
5642
+ this.heartbeatTimer = void 0;
5643
+ }
5644
+ clearTimers() {
5645
+ if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
5646
+ this.reconnectTimer = void 0;
5647
+ this.clearConnectionTimer();
5648
+ this.ticketAbort?.abort();
5649
+ this.ticketAbort = void 0;
5650
+ this.clearHeartbeat();
5651
+ }
5652
+ clearConnectionTimer() {
5653
+ if (this.connectionTimer) clearTimeout(this.connectionTimer);
5654
+ this.connectionTimer = void 0;
5655
+ }
5656
+ }
5657
+
5102
5658
  const devicePairingKeySchema = strictObject({
5103
5659
  kty: literal("EC"),
5104
5660
  crv: literal("P-256"),
@@ -5312,212 +5868,45 @@ ${marker.timeOrigin}`),
5312
5868
  };
5313
5869
  }
5314
5870
 
5315
- const ENDPOINT_PROTOCOL_VERSION = 2;
5316
- const endpointKindSchema = _enum(["web", "desktop", "mobile", "browser"]);
5317
- const endpointAvailabilitySchema = _enum(["foreground", "background"]);
5318
- const endpointEffectSchema = _enum(["read", "write", "destructive"]);
5319
- const endpointConfirmationSchema = _enum(["never", "always"]);
5320
- const endpointResultKindSchema = _enum(["text", "json", "file"]);
5321
- const endpointSensitivitySchema = _enum(["public", "personal"]);
5322
- const identifierSchema = string().min(1).max(160);
5323
- const turnTokenSchema = string().min(32).max(160).regex(/^[A-Za-z0-9_-]+$/);
5324
- const turnOriginSchema = discriminatedUnion("type", [
5325
- strictObject({ type: literal("endpoint"), endpointId: identifierSchema }),
5326
- strictObject({ type: literal("channel"), channel: string().min(1).max(64) }),
5327
- strictObject({
5328
- type: literal("system"),
5329
- source: _enum(["cli", "automation", "heartbeat", "workflow", "internal"])
5330
- })
5331
- ]);
5332
- const endpointTurnOriginSchema = turnOriginSchema.options[0];
5333
- endpointTurnOriginSchema.extend({ token: turnTokenSchema });
5334
- const messageIdSchema = uuid();
5335
- const timestampSchema = number().int().nonnegative();
5336
- const jsonObjectSchema = record(string(), unknown());
5337
- const endpointToolDescriptorSchema = strictObject({
5338
- name: string().regex(/^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/).max(120),
5339
- title: string().min(1).max(120),
5340
- description: string().min(1).max(2e3),
5341
- inputSchema: jsonObjectSchema,
5342
- outputSchema: jsonObjectSchema,
5343
- policyId: string().regex(/^[a-z][a-z0-9_.-]+$/).max(120),
5344
- sensitivity: endpointSensitivitySchema,
5345
- effect: endpointEffectSchema,
5346
- confirmation: endpointConfirmationSchema,
5347
- requiresForeground: boolean(),
5348
- requiredPermissions: array(string().min(1).max(120)).max(20),
5349
- timeoutMs: number().int().min(1e3).max(3e5),
5350
- maxConcurrency: number().int().min(1).max(4),
5351
- supportsCancellation: boolean(),
5352
- idempotent: boolean(),
5353
- resultKinds: array(endpointResultKindSchema).min(1).max(3)
5354
- });
5355
- strictObject({
5356
- principalId: identifierSchema,
5357
- displayName: string().min(1).max(120),
5358
- kind: endpointKindSchema,
5359
- platform: string().min(1).max(80),
5360
- publicKey: string().min(32).max(2048)
5361
- });
5362
- strictObject({
5363
- endpointId: identifierSchema
5364
- });
5365
- const backgroundCapabilitySchema = string().regex(/^[a-z][a-z0-9_]*(?:\.[a-z][a-z0-9_]*)+$/).max(120);
5366
- strictObject({
5367
- jobId: uuid(),
5368
- endpointId: identifierSchema,
5369
- capability: backgroundCapabilitySchema,
5370
- input: jsonObjectSchema,
5371
- idempotencyKey: identifierSchema,
5372
- consentGrantId: identifierSchema,
5373
- createdAt: timestampSchema,
5374
- expiresAt: timestampSchema
5375
- });
5376
- strictObject({
5377
- jobId: uuid(),
5378
- status: _enum(["queued", "running", "succeeded", "failed", "cancelled"]),
5379
- updatedAt: timestampSchema,
5380
- output: jsonObjectSchema.optional(),
5381
- error: strictObject({
5382
- code: identifierSchema,
5383
- message: string().min(1).max(2e3)
5384
- }).optional()
5385
- });
5386
- strictObject({
5387
- eventId: uuid(),
5388
- endpointId: identifierSchema,
5389
- subscriptionId: identifierSchema,
5390
- eventType: backgroundCapabilitySchema,
5391
- data: jsonObjectSchema,
5392
- occurredAt: timestampSchema
5393
- });
5394
- const endpointHelloPayloadSchema = strictObject({
5395
- principalId: identifierSchema,
5396
- endpointId: identifierSchema,
5397
- connectionInstanceId: uuid(),
5398
- displayName: string().min(1).max(120),
5399
- kind: endpointKindSchema,
5400
- platform: string().min(1).max(80),
5401
- appVersion: string().min(1).max(80),
5402
- availability: endpointAvailabilitySchema,
5403
- nonce: identifierSchema,
5404
- signedAt: timestampSchema,
5405
- signature: string().min(16).max(1024),
5406
- tools: array(endpointToolDescriptorSchema).max(100)
5407
- });
5408
- const toolInvokePayloadSchema = strictObject({
5409
- invocationId: uuid(),
5410
- toolCallId: identifierSchema,
5411
- toolName: endpointToolDescriptorSchema.shape.name,
5412
- arguments: jsonObjectSchema,
5413
- descriptorRevision: string().min(1).max(128),
5414
- confirmationRequired: boolean(),
5415
- deadlineAt: timestampSchema,
5416
- uploadGrant: strictObject({
5417
- path: string().startsWith("/").max(500),
5418
- token: identifierSchema,
5419
- maxBytes: number().int().positive(),
5420
- maxFiles: number().int().min(1).max(20),
5421
- expiresAt: timestampSchema
5422
- }).optional()
5423
- });
5424
- const toolCancelPayloadSchema = strictObject({
5425
- invocationId: uuid(),
5426
- reason: string().min(1).max(500)
5427
- });
5428
- const invocationPayloadSchema = strictObject({ invocationId: uuid() });
5429
- const endpointToolContentSchema = discriminatedUnion("type", [
5430
- strictObject({ type: literal("text"), text: string().max(256 * 1024) }),
5431
- strictObject({ type: literal("json"), value: unknown() }),
5432
- strictObject({
5433
- type: literal("file"),
5434
- fileId: identifierSchema,
5435
- name: string().min(1).max(255),
5436
- mimeType: string().min(1).max(255),
5437
- size: number().int().nonnegative(),
5438
- sha256: string().regex(/^[a-f0-9]{64}$/)
5439
- })
5440
- ]);
5441
- const endpointToolErrorCodeSchema = _enum([
5442
- "ENDPOINT_OFFLINE",
5443
- "ENDPOINT_NOT_FOREGROUND",
5444
- "ENDPOINT_DISCONNECTED",
5445
- "TOOL_NOT_FOUND",
5446
- "TOOL_REVISION_MISMATCH",
5447
- "INVALID_ARGUMENTS",
5448
- "PERMISSION_DENIED",
5449
- "USER_DENIED",
5450
- "TOOL_BUSY",
5451
- "TOOL_TIMEOUT",
5452
- "TOOL_CANCELLED",
5453
- "RESULT_TOO_LARGE",
5454
- "PROTOCOL_ERROR"
5455
- ]);
5456
- const envelope = (type, payload) => strictObject({
5457
- protocolVersion: literal(ENDPOINT_PROTOCOL_VERSION),
5458
- messageId: messageIdSchema,
5459
- type: literal(type),
5460
- sentAt: timestampSchema,
5461
- payload
5462
- });
5463
- const clientEndpointMessageSchema = discriminatedUnion("type", [
5464
- envelope("endpoint.availability_changed", strictObject({ availability: endpointAvailabilitySchema })),
5465
- envelope("tool.received", invocationPayloadSchema),
5466
- envelope("tool.progress", strictObject({
5467
- invocationId: uuid(),
5468
- message: string().max(500).optional(),
5469
- percent: number().min(0).max(100).optional()
5470
- })),
5471
- envelope("tool.result", strictObject({
5472
- invocationId: uuid(),
5473
- content: array(endpointToolContentSchema).min(1).max(20),
5474
- details: jsonObjectSchema.optional()
5475
- })),
5476
- envelope("tool.error", strictObject({
5477
- invocationId: uuid(),
5478
- code: endpointToolErrorCodeSchema,
5479
- message: string().min(1).max(2e3)
5480
- })),
5481
- envelope("tool.cancelled", invocationPayloadSchema)
5482
- ]);
5483
- const serverEndpointMessageSchema = discriminatedUnion("type", [
5484
- envelope("tool.invoke", toolInvokePayloadSchema),
5485
- envelope("tool.cancel", toolCancelPayloadSchema)
5486
- ]);
5487
- function canonicalJson(value) {
5488
- if (value === null) return "null";
5489
- if (typeof value === "string" || typeof value === "boolean") return JSON.stringify(value);
5490
- if (typeof value === "number") {
5491
- if (!Number.isFinite(value)) throw new Error("Canonical JSON only supports finite numbers");
5492
- return JSON.stringify(value);
5493
- }
5494
- if (typeof value !== "object") throw new Error(`Canonical JSON does not support ${typeof value}`);
5495
- if (Array.isArray(value)) return `[${value.map(canonicalJson).join(",")}]`;
5496
- const prototype = Object.getPrototypeOf(value);
5497
- if (prototype !== Object.prototype && prototype !== null) {
5498
- throw new Error("Canonical JSON only supports plain objects");
5499
- }
5500
- const record = value;
5501
- return `{${Object.keys(record).sort().map((key) => `${JSON.stringify(key)}:${canonicalJson(record[key])}`).join(",")}}`;
5502
- }
5503
- function endpointHelloSigningPayload(payload) {
5504
- const { signature: _signature, ...unsigned } = payload;
5505
- return canonicalJson(unsigned);
5506
- }
5507
-
5508
5871
  const PROFILE_KEY = "xopc.browser.profile";
5872
+ const AUTO_CONNECT_KEY = "xopc.browser.auto-connect";
5509
5873
  const KEY_DATABASE = "xopc-browser-identity";
5510
5874
  const KEY_STORE = "identity";
5511
5875
  const KEY_NAME = "device-key";
5512
5876
  const NATIVE_HOST_NAME = "ai.xopc.browser";
5513
5877
  let refreshTask;
5514
- async function discoverLocalGateway() {
5878
+ async function browserPublicKeyThumbprint(jwk) {
5879
+ const canonical = JSON.stringify({ crv: jwk.crv, kty: jwk.kty, x: jwk.x, y: jwk.y });
5880
+ return encodeBase64Url(new Uint8Array(await crypto.subtle.digest(
5881
+ "SHA-256",
5882
+ new TextEncoder().encode(canonical)
5883
+ )));
5884
+ }
5885
+ async function isAutoConnectEnabled() {
5886
+ const stored = await chrome.storage.local.get(AUTO_CONNECT_KEY);
5887
+ return stored[AUTO_CONNECT_KEY] !== false;
5888
+ }
5889
+ async function setAutoConnectEnabled(enabled) {
5890
+ await chrome.storage.local.set({ [AUTO_CONNECT_KEY]: enabled });
5891
+ }
5892
+ async function discoverLocalGateway(options) {
5515
5893
  try {
5894
+ if (!options?.force && !await isAutoConnectEnabled()) return void 0;
5895
+ const pair = await getOrCreateKeyPair();
5896
+ const key = await publicKeyJwk(pair);
5897
+ const nonce = randomNonce();
5516
5898
  const response = await chrome.runtime.sendNativeMessage(
5517
5899
  NATIVE_HOST_NAME,
5518
- { type: "bootstrap" }
5900
+ {
5901
+ type: "bootstrap",
5902
+ extensionId: chrome.runtime.id,
5903
+ publicKeyJwk: key,
5904
+ publicKeyThumbprint: await browserPublicKeyThumbprint(key),
5905
+ nonce
5906
+ }
5519
5907
  );
5520
5908
  if (response.ok !== true || typeof response.gatewayUrl !== "string" || typeof response.pairingLink !== "string" || typeof response.expiresAt !== "number") {
5909
+ if (options?.force) throw new Error(response.error || "The local xopc enrollment host returned an invalid response");
5521
5910
  return void 0;
5522
5911
  }
5523
5912
  return {
@@ -5525,7 +5914,8 @@ async function discoverLocalGateway() {
5525
5914
  pairingLink: response.pairingLink,
5526
5915
  expiresAt: response.expiresAt
5527
5916
  };
5528
- } catch {
5917
+ } catch (cause) {
5918
+ if (options?.force) throw cause;
5529
5919
  return void 0;
5530
5920
  }
5531
5921
  }
@@ -5598,6 +5988,14 @@ async function getOrCreateKeyPair() {
5598
5988
  }).finally(() => database.close());
5599
5989
  return pair;
5600
5990
  }
5991
+ async function forgetIdentity() {
5992
+ await new Promise((resolve, reject) => {
5993
+ const request = indexedDB.deleteDatabase(KEY_DATABASE);
5994
+ request.onsuccess = () => resolve();
5995
+ request.onerror = () => reject(request.error);
5996
+ request.onblocked = () => reject(new Error("Browser identity is still in use"));
5997
+ });
5998
+ }
5601
5999
  async function publicKeyJwk(pair) {
5602
6000
  const exported = await crypto.subtle.exportKey("jwk", pair.publicKey);
5603
6001
  if (!exported.x || !exported.y) throw new Error("Browser identity key export failed");
@@ -5718,7 +6116,7 @@ async function pairGateway(link, onApproval) {
5718
6116
  const requestId = crypto.randomUUID();
5719
6117
  const initialRefreshToken = createRefreshToken();
5720
6118
  let result = await signedPairingRequest(pair, payload, origin, requestId, "request");
5721
- onApproval(result.request.confirmationCode);
6119
+ if (result.request.status === "pending") onApproval(result.request.confirmationCode);
5722
6120
  while (result.request.status === "pending") {
5723
6121
  await wait(1500);
5724
6122
  result = await signedPairingRequest(pair, payload, origin, requestId, "status");
@@ -5801,7 +6199,7 @@ async function registerBrowserEndpoint() {
5801
6199
  });
5802
6200
  if (!response.ok) throw new Error(`Browser endpoint registration failed (${response.status})`);
5803
6201
  }
5804
- async function createBrowserEndpointHello() {
6202
+ async function createBrowserEndpointHello(tools = []) {
5805
6203
  const profile = await getAccessProfile();
5806
6204
  const pair = await getOrCreateKeyPair();
5807
6205
  const unsigned = {
@@ -5816,7 +6214,7 @@ async function createBrowserEndpointHello() {
5816
6214
  nonce: crypto.randomUUID(),
5817
6215
  signedAt: Date.now(),
5818
6216
  signature: "pending",
5819
- tools: []
6217
+ tools
5820
6218
  };
5821
6219
  return {
5822
6220
  ...unsigned,
@@ -5835,10 +6233,12 @@ async function revokeAndForgetProfile() {
5835
6233
  });
5836
6234
  } finally {
5837
6235
  await forgetProfile();
6236
+ try {
6237
+ await forgetIdentity();
6238
+ } finally {
6239
+ await setAutoConnectEnabled(false);
6240
+ }
5838
6241
  }
5839
6242
  }
5840
- async function signBrowserBridgeChallenge(payload) {
5841
- return sign(await getOrCreateKeyPair(), payload);
5842
- }
5843
6243
 
5844
- export { PENDING_CONTEXT_KEY as P, TAB_BINDING_PREFIX as T, _enum as _, activeTabId as a, array as b, boolean as c, captureTabPage as d, captureTabWithPermission as e, clientEndpointMessageSchema as f, createBrowserEndpointHello as g, currentTabDescriptor as h, discoverLocalGateway as i, discriminatedUnion as j, endpointHelloPayloadSchema as k, gatewayFetch as l, getAccessProfile as m, literal as n, number as o, pairGateway as p, registerBrowserEndpoint as q, readProfile as r, revokeAndForgetProfile as s, serverEndpointMessageSchema as t, signBrowserBridgeChallenge as u, strictObject as v, string as w, unknown as x, uuid as y };
6244
+ export { ENDPOINT_PROTOCOL_VERSION as E, PENDING_CONTEXT_KEY as P, RealtimeClient as R, TAB_BINDING_PREFIX as T, activeTabId as a, captureTabPage as b, canonicalJson as c, captureTabWithPermission as d, createBrowserEndpointHello as e, currentTabDescriptor as f, discoverLocalGateway as g, endpointToolContentSchema as h, gatewayFetch as i, getAccessProfile as j, registerBrowserEndpoint as k, revokeAndForgetProfile as l, pairGateway as p, readProfile as r, setAutoConnectEnabled as s };