@xopcai/xopc 0.0.396 → 0.0.397

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 (185) hide show
  1. package/dist/browser-ext/manifest.json +1 -1
  2. package/dist/extensions/telegram/src/plugin.js +1 -1
  3. package/dist/extensions/telegram/xopc.extension.json +1 -1
  4. package/dist/gateway/static/root/assets/{agent-avatar-dicebear-DwTaeL1e.js → agent-avatar-dicebear-CIEGrioy.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-D8Q9Cpge.js → agent-defaults-settings-panel-CzKNVkRn.js} +1 -1
  6. package/dist/gateway/static/root/assets/agent-plugin-dialog-mpA9rwYd.js +1 -0
  7. package/dist/gateway/static/root/assets/{agents-DOv68iBN.js → agents-7VMa7Rzo.js} +3 -3
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-B1ApwlFh.js → app-management-settings-panel-DIJ0ii-n.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-Avd_jVji.js → appearance-settings-BGnyHS-p.js} +1 -1
  10. package/dist/gateway/static/root/assets/apps-page-CvqDUvof.js +1 -0
  11. package/dist/gateway/static/root/assets/{archive-plugin-C26WGbj9.js → archive-plugin-CR8FcRAa.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automations-page-T3FSuURJ.js → automations-page-BLInZo7N.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-workspace-B9r27rPk.js → automations-workspace-DvTSHLt3.js} +1 -1
  14. package/dist/gateway/static/root/assets/{binary-plugins-CLaLkM3M.js → binary-plugins-DW9pu205.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-CB4oRyM5.js → block-editor-ClgTc5v8.js} +1 -1
  16. package/dist/gateway/static/root/assets/{browser-automation-inputs-0nkk3bLA.js → browser-automation-inputs-Bn7kDuUB.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-automations-page-KLG8IXvl.js → browser-automations-page-CJGBhDnv.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-settings-page-Tcejw5fF.js → browser-settings-page-tsi5W-cJ.js} +1 -1
  19. package/dist/gateway/static/root/assets/capabilities-page-CfbGk8q_.js +2 -0
  20. package/dist/gateway/static/root/assets/{capabilities-settings-panel-kEvUR6Yu.js → capabilities-settings-panel-BkO7QEyA.js} +1 -1
  21. package/dist/gateway/static/root/assets/{capability-header-actions-Br5PchG2.js → capability-header-actions-9ZG71-BO.js} +1 -1
  22. package/dist/gateway/static/root/assets/{channels-DRaE6_ub.js → channels-D0CwJktG.js} +1 -1
  23. package/dist/gateway/static/root/assets/{chat-terminal-dock-Cl0hAav9.js → chat-terminal-dock-x1W2_hwc.js} +1 -1
  24. package/dist/gateway/static/root/assets/{computer-settings-page-B6JI2S1b.js → computer-settings-page-D_b_bFVz.js} +1 -1
  25. package/dist/gateway/static/root/assets/{connector-service-page-AqsoqTnF.js → connector-service-page-Kf8kaNm_.js} +1 -1
  26. package/dist/gateway/static/root/assets/{connectors-page-cDRZ8bqm.js → connectors-page-DlpfL2Rc.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-CyFehuto.js → date-picker-d5kiPUG0.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker-Vu_5QGGJ.js → dependency-picker-BcH76tQC.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-Dw9k0Z2p.js → desktop-pet-B-925tPX.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-DKqkhvxu.js → desktop-pet-settings-3XJ4qR65.js} +1 -1
  31. package/dist/gateway/static/root/assets/device-pairing-wizard-12m5Z9-8.js +1 -0
  32. package/dist/gateway/static/root/assets/{directory-picker-path-field-7svbL2tR.js → directory-picker-path-field-B-qZCjGR.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-CFa6PCBV.js → extension-debug-page-BlQu1u6X.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-BD4nZ9sf.js → extension-page-CXxM1M62.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-CxPIMrmn.js → extension-settings-page-AF5nvsPP.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-settings-Da2CtQ7c.js → gateway-settings-ABXvW_yL.js} +1 -1
  37. package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-DzEeyJpH.js → highlighted-body-KQOG7T2V-Czdbbi0H.js} +1 -1
  38. package/dist/gateway/static/root/assets/{home-page-Cp4-sTfX.js → home-page-LXGxGwVl.js} +1 -1
  39. package/dist/gateway/static/root/assets/{image-generation-api-Zo56ZmKs.js → image-generation-api-DPFPJ2ps.js} +1 -1
  40. package/dist/gateway/static/root/assets/{imports-page-C_PPaOFv.js → imports-page-Bwyotfbt.js} +1 -1
  41. package/dist/gateway/static/root/assets/index-BKHxJaGD.css +1 -0
  42. package/dist/gateway/static/root/assets/{index-XRbEWVyZ.js → index-Dsp_gNdl.js} +116 -116
  43. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BGtrzFT6.js → keyboard-shortcuts-settings-C20gl-l7.js} +1 -1
  44. package/dist/gateway/static/root/assets/{local-app-workbench-page-Cu80fCA0.js → local-app-workbench-page-o0M_OSjC.js} +1 -1
  45. package/dist/gateway/static/root/assets/{local-apps-page-Zsu8FnwP.js → local-apps-page-DoWJCmOq.js} +1 -1
  46. package/dist/gateway/static/root/assets/{logs-page-DlIhfEW_.js → logs-page-BFTL93RX.js} +1 -1
  47. package/dist/gateway/static/root/assets/{management-settings-CDV-xItG.js → management-settings-C52cuMg1.js} +1 -1
  48. package/dist/gateway/static/root/assets/{media-plugins-Ba1_QMmZ.js → media-plugins-DLrTRF0a.js} +1 -1
  49. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-CPYJsRUJ.js +1 -0
  50. package/dist/gateway/static/root/assets/{note-detail-panel-BXi6BrXd.js → note-detail-panel-CNN41byS.js} +3 -3
  51. package/dist/gateway/static/root/assets/{notes-page-ClR9R90o.js → notes-page-BsfBp_8z.js} +1 -1
  52. package/dist/gateway/static/root/assets/{page-context-capture-button-BqNWtf_f.js → page-context-capture-button-YTVWZ02-.js} +1 -1
  53. package/dist/gateway/static/root/assets/{personal-page-CSF-sn8w.js → personal-page-N4KoCZYG.js} +1 -1
  54. package/dist/gateway/static/root/assets/plugin-details-page-DcrrzQI-.js +1 -0
  55. package/dist/gateway/static/root/assets/{preview-open-alternatives-kkbrbiVd.js → preview-open-alternatives-DzA__S54.js} +1 -1
  56. package/dist/gateway/static/root/assets/{product-open-page-Dheqo_4J.js → product-open-page-DvlMKj0T.js} +1 -1
  57. package/dist/gateway/static/root/assets/{product-preview-content-B9Y6dIuh.js → product-preview-content-qdFyo4NG.js} +1 -1
  58. package/dist/gateway/static/root/assets/{project-detail-page-l5dXxnSq.js → project-detail-page-y67s_fA8.js} +1 -1
  59. package/dist/gateway/static/root/assets/{projects-page-95Od8gLy.js → projects-page-D5iYgi0O.js} +1 -1
  60. package/dist/gateway/static/root/assets/{remote-access-hub-DPEpPFax.js → remote-access-hub-DeFF7Re-.js} +1 -1
  61. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-BjyZGNP3.js → runtime-tools-settings-panel-BCHLh-KQ.js} +1 -1
  62. package/dist/gateway/static/root/assets/{schema-form-DelMOLjg.js → schema-form-CJvaVHkx.js} +1 -1
  63. package/dist/gateway/static/root/assets/{sessions-page-BN0nMm0w.js → sessions-page-DZ93_D5M.js} +1 -1
  64. package/dist/gateway/static/root/assets/settings-advanced-gate-F1WX7vxq.js +1 -0
  65. package/dist/gateway/static/root/assets/{settings-form-section-DNWEDA71.js → settings-form-section-B3eODxNv.js} +1 -1
  66. package/dist/gateway/static/root/assets/{settings-page-DJ27gC7J.js → settings-page-Dg86uCnr.js} +1 -1
  67. package/dist/gateway/static/root/assets/{setup-status-panel-BWA_puDN.js → setup-status-panel-ruFzAArp.js} +1 -1
  68. package/dist/gateway/static/root/assets/{share-preview-page-Du4mumVM.js → share-preview-page-DCy1f25V.js} +1 -1
  69. package/dist/gateway/static/root/assets/{shares-settings-C0ixka9_.js → shares-settings-DeIVZvpJ.js} +1 -1
  70. package/dist/gateway/static/root/assets/{skill-api-zOxHjU7m.js → skill-api-RisyPAMA.js} +1 -1
  71. package/dist/gateway/static/root/assets/{skill-reload-api-743oJIiS.js → skill-reload-api-Dwkm1Fof.js} +1 -1
  72. package/dist/gateway/static/root/assets/{skills-page-DBYhEjP9.js → skills-page-UiTLsrFc.js} +1 -1
  73. package/dist/gateway/static/root/assets/{style-DsnKw5jo.js → style-CwMX73G7.js} +1 -1
  74. package/dist/gateway/static/root/assets/{system-settings-panel-mz9hWo_H.js → system-settings-panel-Cma37Pfm.js} +1 -1
  75. package/dist/gateway/static/root/assets/{task-detail-page-Brp2wrEc.js → task-detail-page-BKOF_kxS.js} +1 -1
  76. package/dist/gateway/static/root/assets/{tracing-settings-page-aC-ziRbY.js → tracing-settings-page-DC-kLysq.js} +1 -1
  77. package/dist/gateway/static/root/assets/{tunnel-api-Ch2Veztk.js → tunnel-api-BgdhbR1L.js} +1 -1
  78. package/dist/gateway/static/root/assets/{usage-page-KfKZ2a3t.js → usage-page-BSlFg3Xj.js} +1 -1
  79. package/dist/gateway/static/root/assets/{use-autosave-BLW3t_OK.js → use-autosave-iKvZ1pvC.js} +1 -1
  80. package/dist/gateway/static/root/assets/{user-model-page-BSsT8WjA.js → user-model-page-D4GB8QsM.js} +1 -1
  81. package/dist/gateway/static/root/assets/{voice-api-key-field-DulF6Cm4.js → voice-api-key-field-CESbtuwM.js} +1 -1
  82. package/dist/gateway/static/root/assets/{work-discovery-overlay-bBMZM8tN.js → work-discovery-overlay-dtPpmYyh.js} +1 -1
  83. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-CsxXS1WI.js → workflow-run-setup-panel-DmFn3E_B.js} +1 -1
  84. package/dist/gateway/static/root/assets/{workflows-page-a-mfjQ2h.js → workflows-page-DEtaRuxH.js} +1 -1
  85. package/dist/gateway/static/root/assets/{xopc-cloud-account-card-wwIRBFCs.js → xopc-cloud-account-card-DTZnabfg.js} +1 -1
  86. package/dist/gateway/static/root/index.html +2 -2
  87. package/dist/package.js +1 -1
  88. package/dist/src/agent/embedded/codemode-extension.d.ts +1 -0
  89. package/dist/src/agent/embedded/codemode-extension.js +6 -1
  90. package/dist/src/agent/embedded/run-for-session.js +1 -1
  91. package/dist/src/agent/embedded/run-turn.js +34 -2
  92. package/dist/src/agent/embedded/session-runner.js +1 -1
  93. package/dist/src/agent/mcp/config.d.ts +2 -0
  94. package/dist/src/agent/mcp/config.js +2 -2
  95. package/dist/src/agent/mcp/connection-setup.js +13 -1
  96. package/dist/src/agent/mcp/effective-server.d.ts +3 -0
  97. package/dist/src/agent/mcp/effective-server.js +27 -0
  98. package/dist/src/agent/mcp/native-mcp.d.ts +1 -1
  99. package/dist/src/agent/mcp/native-mcp.js +13 -4
  100. package/dist/src/agent/mcp/tool-catalog.js +2 -1
  101. package/dist/src/agent/skills/index.d.ts +1 -0
  102. package/dist/src/agent/skills/index.js +6 -2
  103. package/dist/src/agent/skills/skill-manager.d.ts +1 -0
  104. package/dist/src/agent/skills/skill-manager.js +6 -1
  105. package/dist/src/agent/skills/skill-sources.d.ts +1 -0
  106. package/dist/src/agent/skills/skill-sources.js +4 -3
  107. package/dist/src/agent/skills/types.d.ts +1 -0
  108. package/dist/src/agent/workspace-runtime/registry.js +6 -2
  109. package/dist/src/browser/native-messaging-host.js +1 -1
  110. package/dist/src/browser/providers/browser-ext-install.js +2 -2
  111. package/dist/src/channels/index.js +1 -1
  112. package/dist/src/channels/manager.js +1 -1
  113. package/dist/src/cli/commands/channels.js +1 -1
  114. package/dist/src/cli/commands/connectors.js +1 -1
  115. package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
  116. package/dist/src/cli/commands/extension-agent-plugin.js +92 -7
  117. package/dist/src/cli/commands/extension-marketplace.js +2 -2
  118. package/dist/src/cli/commands/extension.js +1 -1
  119. package/dist/src/cli/commands/mcp.js +6 -4
  120. package/dist/src/cli/commands/models.js +1 -1
  121. package/dist/src/cli/commands/onboard.js +1 -1
  122. package/dist/src/extensions/agent-plugins/auth.d.ts +7 -1
  123. package/dist/src/extensions/agent-plugins/auth.js +53 -12
  124. package/dist/src/extensions/agent-plugins/branding.d.ts +6 -0
  125. package/dist/src/extensions/agent-plugins/branding.js +44 -0
  126. package/dist/src/extensions/agent-plugins/cli-authorization.d.ts +22 -0
  127. package/dist/src/extensions/agent-plugins/cli-authorization.js +198 -0
  128. package/dist/src/extensions/agent-plugins/connection-reuse.d.ts +10 -0
  129. package/dist/src/extensions/agent-plugins/connection-reuse.js +23 -0
  130. package/dist/src/extensions/agent-plugins/credentials.js +24 -1
  131. package/dist/src/extensions/agent-plugins/formats.d.ts +27 -0
  132. package/dist/src/extensions/agent-plugins/formats.js +208 -0
  133. package/dist/src/extensions/agent-plugins/inventory.d.ts +142 -2
  134. package/dist/src/extensions/agent-plugins/inventory.js +39 -5
  135. package/dist/src/extensions/agent-plugins/mcp-adapter.d.ts +2 -1
  136. package/dist/src/extensions/agent-plugins/mcp-adapter.js +42 -8
  137. package/dist/src/extensions/agent-plugins/mcp-format.d.ts +2 -0
  138. package/dist/src/extensions/agent-plugins/mcp-format.js +82 -0
  139. package/dist/src/extensions/agent-plugins/resources.d.ts +14 -0
  140. package/dist/src/extensions/agent-plugins/resources.js +112 -0
  141. package/dist/src/extensions/agent-plugins/setup-contract.d.ts +54 -0
  142. package/dist/src/extensions/agent-plugins/setup-contract.js +58 -0
  143. package/dist/src/extensions/agent-plugins/setup.d.ts +119 -0
  144. package/dist/src/extensions/agent-plugins/setup.js +491 -0
  145. package/dist/src/extensions/agent-plugins/source-catalog.d.ts +21 -0
  146. package/dist/src/extensions/agent-plugins/source-catalog.js +175 -0
  147. package/dist/src/extensions/agent-plugins/sources.d.ts +1 -1
  148. package/dist/src/extensions/agent-plugins/sources.js +12 -3
  149. package/dist/src/extensions/agent-plugins/store.d.ts +33 -2
  150. package/dist/src/extensions/agent-plugins/store.js +175 -25
  151. package/dist/src/extensions/agent-plugins/user-config.d.ts +5 -0
  152. package/dist/src/extensions/agent-plugins/user-config.js +49 -0
  153. package/dist/src/extensions/agent-plugins/validation.d.ts +26 -1
  154. package/dist/src/extensions/agent-plugins/validation.js +142 -27
  155. package/dist/src/extensions/sdk/index.js +1 -1
  156. package/dist/src/gateway/hono/app.js +1 -1
  157. package/dist/src/gateway/hono/routes/agent-plugins.js +120 -9
  158. package/dist/src/gateway/hono/routes/browser-install.js +1 -1
  159. package/dist/src/gateway/hono/routes/composer-history.js +22 -4
  160. package/dist/src/gateway/hono/routes/mcp.js +6 -4
  161. package/dist/src/gateway/service.js +5 -3
  162. package/dist/src/gateway/session-context-summary.js +1 -1
  163. package/dist/src/storage/sqlite/composer-input-history-repository.d.ts +4 -3
  164. package/dist/src/storage/sqlite/composer-input-history-repository.js +10 -8
  165. package/dist/src/storage/sqlite/device-pairing-approval.js +1 -1
  166. package/dist/src/storage/sqlite/migrations/257_session_composer_history.sql +11 -0
  167. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  168. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  169. package/dist/src/storage/sqlite/schema.js +1 -1
  170. package/dist/src/tui/backends/embedded-backend.d.ts +2 -2
  171. package/dist/src/tui/backends/embedded-backend.js +4 -4
  172. package/dist/src/tui/backends/gateway-realtime-backend.d.ts +2 -2
  173. package/dist/src/tui/backends/gateway-realtime-backend.js +7 -4
  174. package/dist/src/tui/composer-history.d.ts +14 -0
  175. package/dist/src/tui/composer-history.js +85 -0
  176. package/dist/src/tui/tui-backend.d.ts +4 -3
  177. package/dist/src/tui/tui.js +19 -46
  178. package/package.json +12 -4
  179. package/dist/gateway/static/root/assets/agent-plugin-dialog-C-UKhDkS.js +0 -1
  180. package/dist/gateway/static/root/assets/apps-page-Da6Ar2U3.js +0 -1
  181. package/dist/gateway/static/root/assets/capabilities-page-BJlw9rhA.js +0 -2
  182. package/dist/gateway/static/root/assets/device-pairing-wizard-4l4ESMon.js +0 -1
  183. package/dist/gateway/static/root/assets/index-zIgp-ZTu.css +0 -1
  184. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-CpK57Kgp.js +0 -1
  185. package/dist/gateway/static/root/assets/settings-advanced-gate-BvfEKyfy.js +0 -1
@@ -9,6 +9,11 @@ declare const bindingSchema: z.ZodObject<{
9
9
  }>;
10
10
  identityScope: z.ZodLiteral<"owner">;
11
11
  endpointFingerprint: z.ZodString;
12
+ oauthReference: z.ZodOptional<z.ZodObject<{
13
+ sourceServerId: z.ZodString;
14
+ credentialId: z.ZodString;
15
+ fingerprint: z.ZodString;
16
+ }, z.core.$strict>>;
12
17
  fields: z.ZodArray<z.ZodObject<{
13
18
  target: z.ZodEnum<{
14
19
  headers: "headers";
@@ -23,7 +28,7 @@ export type PluginAuthBinding = z.infer<typeof bindingSchema>;
23
28
  export declare const pluginCredentialProviderPrefix: (id: string) => string;
24
29
  export declare const parsePluginAuthBinding: (value: unknown) => PluginAuthBinding;
25
30
  export declare function pluginEndpointFingerprint(server: PluginServer): string;
26
- export declare function readPluginAuthBinding(store: AgentPluginStore, id: string, name: string, server: PluginServer): PluginAuthBinding | undefined;
31
+ export declare function readPluginAuthBinding(store: AgentPluginStore, id: string, name: string, server: PluginServer, revision?: string): PluginAuthBinding | undefined;
27
32
  export declare function savePluginAuthBinding(store: AgentPluginStore, id: string, name: string, input: {
28
33
  mode: PluginAuthBinding['mode'];
29
34
  secrets?: Array<{
@@ -33,5 +38,6 @@ export declare function savePluginAuthBinding(store: AgentPluginStore, id: strin
33
38
  prefix?: string;
34
39
  }>;
35
40
  }): Promise<void>;
41
+ export declare function savePluginOAuthReference(store: AgentPluginStore, id: string, name: string, reference: NonNullable<PluginAuthBinding['oauthReference']>): void;
36
42
  export declare function applyPluginAuthBinding(raw: Record<string, unknown>, binding: PluginAuthBinding | undefined): Record<string, unknown>;
37
43
  export {};
@@ -1,5 +1,5 @@
1
1
  import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
2
- import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
2
+ import { init_write_file_atomic, writeTextAtomic, writeTextAtomicSync } from "../../infra/write-file-atomic.js";
3
3
  import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
4
4
  import { isDangerousHostEnvVarName } from "../../infra/host-env-security.js";
5
5
  import { pluginName } from "./validation.js";
@@ -17,6 +17,11 @@ const bindingSchema = z.strictObject({
17
17
  mode: z.enum(["auto", "api-key"]),
18
18
  identityScope: z.literal("owner"),
19
19
  endpointFingerprint: z.string(),
20
+ oauthReference: z.strictObject({
21
+ sourceServerId: z.string(),
22
+ credentialId: z.string().regex(/^mcp_draft_[a-f0-9]{32}$/),
23
+ fingerprint: z.string()
24
+ }).optional(),
20
25
  fields: z.array(z.strictObject({
21
26
  target: z.enum(["headers", "env"]),
22
27
  key: z.string(),
@@ -28,19 +33,36 @@ const hash = (value) => createHash("sha256").update(value).digest("hex");
28
33
  const pluginCredentialProviderPrefix = (id) => `plugin-${hash(id).slice(0, 16)}-`;
29
34
  const parsePluginAuthBinding = (value) => bindingSchema.parse(value);
30
35
  function pluginEndpointFingerprint(server) {
31
- return hash(server.type === "stdio" ? JSON.stringify(server) : new URL(server.url).toString());
36
+ return hash(server.type === "stdio" ? JSON.stringify(server) : JSON.stringify([
37
+ new URL(server.url).toString(),
38
+ server.oauth ?? null,
39
+ server.connectionAuth ?? null
40
+ ]));
32
41
  }
33
- function bindingPath(store, id, name) {
34
- return join(store.stateDir, "plugin-auth", pluginName.parse(id), `${hash(name)}.json`);
42
+ function bindingPath(store, id, name, revision) {
43
+ return join(store.stateDir, "plugin-auth", pluginName.parse(id), `${hash(name)}${revision ? `-${z.string().uuid().parse(revision)}` : ""}.json`);
35
44
  }
36
- function readPluginAuthBinding(store, id, name, server) {
37
- const path = bindingPath(store, id, name);
38
- if (!existsSync(path)) return void 0;
39
- const binding = bindingSchema.parse(JSON.parse(readFileSync(path, "utf8")));
40
- return binding.endpointFingerprint === pluginEndpointFingerprint(server) ? binding : void 0;
45
+ function readPluginAuthBinding(store, id, name, server, revision) {
46
+ const current = store.receipt(id);
47
+ const targetRevision = revision ?? current?.revision;
48
+ const revisions = [...new Set([
49
+ targetRevision,
50
+ current?.revision,
51
+ current?.previous?.revision
52
+ ].filter((value) => !!value))];
53
+ for (const candidate of [...revisions.map((value) => bindingPath(store, id, name, value)), bindingPath(store, id, name)]) {
54
+ if (!existsSync(candidate)) continue;
55
+ const binding = bindingSchema.parse(JSON.parse(readFileSync(candidate, "utf8")));
56
+ const fingerprint = pluginEndpointFingerprint(server);
57
+ const legacy = server.type !== "stdio" && !server.oauth && !server.connectionAuth && binding.endpointFingerprint === hash(new URL(server.url).toString());
58
+ if (binding.endpointFingerprint !== fingerprint && !legacy) continue;
59
+ if (legacy) binding.endpointFingerprint = fingerprint;
60
+ if (targetRevision && candidate !== bindingPath(store, id, name, targetRevision)) writeTextAtomicSync(bindingPath(store, id, name, targetRevision), JSON.stringify(binding));
61
+ return binding;
62
+ }
41
63
  }
42
64
  async function savePluginAuthBinding(store, id, name, input) {
43
- const plugin = store.get(id);
65
+ const plugin = store.pending(id) ?? store.get(id);
44
66
  const server = plugin?.servers[name];
45
67
  if (!server || plugin?.readiness === "blocked") throw new Error("Plugin MCP server unavailable");
46
68
  const endpointFingerprint = pluginEndpointFingerprint(server);
@@ -67,6 +89,7 @@ async function savePluginAuthBinding(store, id, name, input) {
67
89
  const provider = `${pluginCredentialProviderPrefix(id)}${hash(JSON.stringify([
68
90
  "owner",
69
91
  id,
92
+ plugin.receipt.revision,
70
93
  name,
71
94
  endpointFingerprint,
72
95
  field.target,
@@ -87,7 +110,21 @@ async function savePluginAuthBinding(store, id, name, input) {
87
110
  endpointFingerprint,
88
111
  fields
89
112
  });
90
- await writeTextAtomic(bindingPath(store, id, name), JSON.stringify(binding));
113
+ await writeTextAtomic(bindingPath(store, id, name, plugin.receipt.revision), JSON.stringify(binding));
114
+ }
115
+ function savePluginOAuthReference(store, id, name, reference) {
116
+ const plugin = store.pending(id) ?? store.get(id);
117
+ const server = plugin?.servers[name];
118
+ if (!server || !plugin || plugin.readiness === "blocked") throw new Error("Plugin MCP server unavailable");
119
+ const binding = bindingSchema.parse({
120
+ serverName: name,
121
+ mode: "auto",
122
+ identityScope: "owner",
123
+ endpointFingerprint: pluginEndpointFingerprint(server),
124
+ fields: [],
125
+ oauthReference: reference
126
+ });
127
+ writeTextAtomicSync(bindingPath(store, id, name, plugin.receipt.revision), JSON.stringify(binding));
91
128
  }
92
129
  function applyPluginAuthBinding(raw, binding) {
93
130
  if (!binding) return raw;
@@ -103,8 +140,12 @@ function applyPluginAuthBinding(raw, binding) {
103
140
  } };
104
141
  result[field.target] = values;
105
142
  }
143
+ if (binding.oauthReference) {
144
+ result.xopcOAuthCredentialId = binding.oauthReference.credentialId;
145
+ result.xopcPluginOAuthReference = binding.oauthReference;
146
+ }
106
147
  result.xopcAuthRevision = hash(JSON.stringify(binding));
107
148
  return result;
108
149
  }
109
150
  //#endregion
110
- export { applyPluginAuthBinding, parsePluginAuthBinding, pluginCredentialProviderPrefix, pluginEndpointFingerprint, readPluginAuthBinding, savePluginAuthBinding };
151
+ export { applyPluginAuthBinding, parsePluginAuthBinding, pluginCredentialProviderPrefix, pluginEndpointFingerprint, readPluginAuthBinding, savePluginAuthBinding, savePluginOAuthReference };
@@ -0,0 +1,6 @@
1
+ import { type PluginManifest } from './validation.js';
2
+ /** Inline bounded package assets so authenticated and offline inventories need no extra fetch. */
3
+ export declare function pluginBranding(root: string, manifest: PluginManifest): {
4
+ iconUrl: string;
5
+ iconSha256: string;
6
+ };
@@ -0,0 +1,44 @@
1
+ import { containedPath } from "./validation.js";
2
+ import { extname, resolve } from "node:path";
3
+ import { readFileSync, statSync } from "node:fs";
4
+ import { createHash } from "node:crypto";
5
+ //#region src/extensions/agent-plugins/branding.ts
6
+ /** Inline bounded package assets so authenticated and offline inventories need no extra fetch. */
7
+ function pluginBranding(root, manifest) {
8
+ const icon = (manifest.extensions?.["ai.xopc"])?.branding?.icon;
9
+ if (typeof icon !== "string" || !icon || icon.includes("\0")) return void 0;
10
+ try {
11
+ const file = containedPath(root, resolve(root, icon));
12
+ const info = statSync(file);
13
+ if (!info.isFile() || info.size < 1 || info.size > 128 * 1024) return void 0;
14
+ const type = extname(file).toLowerCase();
15
+ const mime = {
16
+ ".svg": "image/svg+xml",
17
+ ".png": "image/png",
18
+ ".webp": "image/webp"
19
+ }[type];
20
+ if (!mime) return void 0;
21
+ const bytes = readFileSync(file);
22
+ if (type === ".svg") {
23
+ const source = bytes.toString("utf8");
24
+ if (!/<svg\b/i.test(source) || /<(?:script|foreignObject|iframe|object|embed)\b|\son[a-z]+\s*=|(?:href|src)\s*=\s*["']\s*(?:https?:|\/\/|data:)/i.test(source)) return void 0;
25
+ } else if (type === ".png" ? !bytes.subarray(0, 8).equals(Buffer.from([
26
+ 137,
27
+ 80,
28
+ 78,
29
+ 71,
30
+ 13,
31
+ 10,
32
+ 26,
33
+ 10
34
+ ])) : bytes.subarray(0, 4).toString() !== "RIFF" || bytes.subarray(8, 12).toString() !== "WEBP") return void 0;
35
+ return {
36
+ iconUrl: `data:${mime};base64,${bytes.toString("base64")}`,
37
+ iconSha256: createHash("sha256").update(bytes).digest("hex")
38
+ };
39
+ } catch {
40
+ return;
41
+ }
42
+ }
43
+ //#endregion
44
+ export { pluginBranding };
@@ -0,0 +1,22 @@
1
+ import { type PluginAuthorization } from './setup-contract.js';
2
+ import type { AgentPluginStore, InstalledAgentPlugin } from './store.js';
3
+ type CliMethod = Extract<PluginAuthorization['methods'][number], {
4
+ type: 'cli';
5
+ }>;
6
+ export type PluginCliAuthorization = {
7
+ id: string;
8
+ state: 'preparing' | 'awaiting_user' | 'connected' | 'error' | 'cancelled';
9
+ expiresAt: number;
10
+ challenge?: {
11
+ type: 'url' | 'qr';
12
+ url: string;
13
+ message?: string;
14
+ };
15
+ error?: string;
16
+ };
17
+ export declare function checkPluginCliAuthorization(store: AgentPluginStore, plugin: InstalledAgentPlugin, authorization: string, method: CliMethod, signal: AbortSignal): Promise<boolean>;
18
+ export declare function startPluginCliAuthorization(store: AgentPluginStore, plugin: InstalledAgentPlugin, authorization: string, method: CliMethod, owner: string): PluginCliAuthorization;
19
+ export declare function getPluginCliAuthorization(id: string, owner: string, revision: string): PluginCliAuthorization | undefined;
20
+ export declare function cancelPluginCliAuthorizations(pluginId: string, owner?: string): void;
21
+ export declare function cancelAllPluginCliAuthorizations(): void;
22
+ export {};
@@ -0,0 +1,198 @@
1
+ import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
2
+ import { spawnProcess } from "../../process/run-process.js";
3
+ import { safeAuthorizationUrl } from "./setup-contract.js";
4
+ import { containedPath, expandPluginVariables, resolvePluginCwd, validatePluginServer } from "./validation.js";
5
+ import { expandUserConfig, readPluginUserConfig } from "./user-config.js";
6
+ import { homedir } from "node:os";
7
+ import { join, resolve } from "node:path";
8
+ import { mkdirSync, readFileSync } from "node:fs";
9
+ import { randomUUID } from "node:crypto";
10
+ //#region src/extensions/agent-plugins/cli-authorization.ts
11
+ init_credentials();
12
+ const attempts = /* @__PURE__ */ new Map();
13
+ async function execute(store, plugin, authorization, command, signal, timeoutMs, onLine) {
14
+ validatePluginServer({
15
+ type: "stdio",
16
+ ...command
17
+ }, plugin.rootDir, store.dataDir(plugin.id));
18
+ const data = store.dataDir(plugin.id), home = join(data, "accounts", plugin.receipt.revision, authorization);
19
+ mkdirSync(home, {
20
+ recursive: true,
21
+ mode: 448
22
+ });
23
+ const values = {
24
+ ...Object.fromEntries(Object.entries(plugin.layout?.userConfig ?? {}).filter(([, field]) => field.default !== void 0).map(([key, field]) => [key, field.default])),
25
+ ...readPluginUserConfig(store, plugin.id, plugin.receipt.revision)
26
+ };
27
+ const expand = (value) => expandUserConfig(expandPluginVariables(value.replace(/\$\{PLUGIN_RESOURCES\}/g, join(data, "resources", plugin.receipt.revision)), plugin.rootDir, data), values);
28
+ const environment = Object.fromEntries([
29
+ "PATH",
30
+ "SystemRoot",
31
+ "WINDIR",
32
+ "TMPDIR",
33
+ "TEMP",
34
+ "TMP",
35
+ "LANG"
36
+ ].flatMap((key) => process.env[key] === void 0 ? [] : [[key, process.env[key]]]));
37
+ Object.assign(environment, {
38
+ HOME: home,
39
+ USERPROFILE: home,
40
+ XDG_CONFIG_HOME: join(home, "config"),
41
+ PLUGIN_HOST_HOME: homedir(),
42
+ PLUGIN_ACCOUNT_HOME: home,
43
+ PLUGIN_ROOT: plugin.rootDir,
44
+ PLUGIN_DATA: data,
45
+ PLUGIN_RESOURCES: join(data, "resources", plugin.receipt.revision)
46
+ });
47
+ const resolver = new CredentialResolver({ stateDir: store.stateDir });
48
+ for (const [key, value] of Object.entries(command.env)) {
49
+ const expanded = expand(value);
50
+ if (typeof expanded === "string") environment[key] = expanded;
51
+ else {
52
+ const reference = expanded;
53
+ if (!reference.xopcSecretRef) throw new Error("Invalid login credential reference");
54
+ const secret = await resolver.resolveApiKey(reference.xopcSecretRef.provider);
55
+ if (!secret) throw new Error("Login credential is unavailable");
56
+ environment[key] = reference.xopcSecretRef.prefix + secret;
57
+ }
58
+ }
59
+ const program = command.command.startsWith("./") ? containedPath(plugin.rootDir, resolve(plugin.rootDir, command.command)) : command.command.startsWith("${PLUGIN_RESOURCES}/") ? containedPath(data, join(data, "resources", plugin.receipt.revision, command.command.slice(20))) : command.command;
60
+ let pending = "";
61
+ const result = await spawnProcess({
62
+ program,
63
+ args: command.args.map((arg) => {
64
+ const value = expand(arg);
65
+ if (typeof value !== "string") throw new Error("Use environment variables for login secrets");
66
+ return value;
67
+ }),
68
+ cwd: resolvePluginCwd(command.cwd, plugin.rootDir, data),
69
+ env: environment,
70
+ signal,
71
+ timeoutMs,
72
+ maxOutputBytes: 65536,
73
+ terminationPolicy: "tree",
74
+ shell: false,
75
+ onOutput(stream, chunk) {
76
+ if (stream !== "stdout" || !onLine) return;
77
+ pending = (pending + chunk.toString("utf8")).slice(-65536);
78
+ let boundary;
79
+ while ((boundary = pending.indexOf("\n")) >= 0) {
80
+ const line = pending.slice(0, boundary);
81
+ pending = pending.slice(boundary + 1);
82
+ onLine(line);
83
+ }
84
+ }
85
+ }).completion;
86
+ if (result.exitCode !== 0 || result.timedOut || result.aborted || result.outputTruncated) throw new Error("CLI login or account check failed. Retry authorization.");
87
+ return result.stdout;
88
+ }
89
+ async function checkPluginCliAuthorization(store, plugin, authorization, method, signal) {
90
+ try {
91
+ const last = (await execute(store, plugin, authorization, method.check, signal, 15e3)).trim().split("\n").at(-1);
92
+ return !!last && JSON.parse(last).authenticated === true;
93
+ } catch {
94
+ signal.throwIfAborted();
95
+ return false;
96
+ }
97
+ }
98
+ function startPluginCliAuthorization(store, plugin, authorization, method, owner) {
99
+ for (const [key, attempt] of attempts) if (attempt.view.expiresAt < Date.now()) {
100
+ attempt.controller.abort();
101
+ attempts.delete(key);
102
+ } else if (attempt.pluginId === plugin.id && attempt.authorization === authorization) {
103
+ if (attempt.owner !== owner) throw new Error("Authorization belongs to another principal");
104
+ attempt.controller.abort();
105
+ attempt.view.state = "cancelled";
106
+ }
107
+ const controller = new AbortController();
108
+ const view = {
109
+ id: randomUUID(),
110
+ state: "preparing",
111
+ expiresAt: Date.now() + method.timeoutSeconds * 1e3
112
+ };
113
+ const attempt = {
114
+ owner,
115
+ pluginId: plugin.id,
116
+ revision: plugin.receipt.revision,
117
+ authorization,
118
+ view,
119
+ controller
120
+ };
121
+ attempts.set(view.id, attempt);
122
+ const watcher = setInterval(() => {
123
+ try {
124
+ const current = store.pendingReceipt(plugin.id) ?? store.receipt(plugin.id);
125
+ const job = JSON.parse(readFileSync(join(store.stateDir, "plugin-setup", `${plugin.id}.json`), "utf8"));
126
+ const target = job.authorizations?.find((value) => value.id === authorization);
127
+ if (current?.revision !== plugin.receipt.revision || job.packageRevision !== plugin.receipt.revision || target?.attemptId !== view.id || ["cancelled", "completed"].includes(job.state)) controller.abort();
128
+ } catch {
129
+ controller.abort();
130
+ }
131
+ }, 500);
132
+ watcher.unref();
133
+ (async () => {
134
+ try {
135
+ await execute(store, plugin, authorization, method.login, controller.signal, method.timeoutSeconds * 1e3, (line) => {
136
+ try {
137
+ const value = JSON.parse(line);
138
+ if (value.type === "challenge" && ["qr", "url"].includes(value.kind) && typeof value.url === "string" && value.url.length <= 8192) {
139
+ view.challenge = {
140
+ type: value.kind,
141
+ url: safeAuthorizationUrl(value.url),
142
+ ...typeof value.message === "string" && value.message.length <= 300 ? { message: value.message } : {}
143
+ };
144
+ view.state = "awaiting_user";
145
+ }
146
+ } catch {}
147
+ });
148
+ controller.signal.throwIfAborted();
149
+ if ((store.pending(plugin.id) ?? store.get(plugin.id))?.receipt.revision !== plugin.receipt.revision) throw new Error("Plugin revision changed");
150
+ if (!await checkPluginCliAuthorization(store, plugin, authorization, method, controller.signal)) throw new Error("Account verification failed");
151
+ view.state = "connected";
152
+ delete view.challenge;
153
+ } catch {
154
+ view.state = controller.signal.aborted ? "cancelled" : "error";
155
+ view.error = controller.signal.aborted ? "Sign-in cancelled." : "Sign-in or account verification failed. Retry authorization.";
156
+ delete view.challenge;
157
+ } finally {
158
+ clearInterval(watcher);
159
+ }
160
+ })();
161
+ return view;
162
+ }
163
+ function getPluginCliAuthorization(id, owner, revision) {
164
+ const attempt = attempts.get(id);
165
+ if (!attempt) return;
166
+ if (attempt.owner !== owner || attempt.revision !== revision) throw new Error("Authorization does not match this installation");
167
+ if (attempt.view.expiresAt <= Date.now() && ![
168
+ "connected",
169
+ "error",
170
+ "cancelled"
171
+ ].includes(attempt.view.state)) {
172
+ attempt.controller.abort();
173
+ attempt.view.state = "error";
174
+ attempt.view.error = "Sign-in expired. Try again.";
175
+ delete attempt.view.challenge;
176
+ }
177
+ return attempt.view;
178
+ }
179
+ function cancelPluginCliAuthorizations(pluginId, owner) {
180
+ for (const attempt of attempts.values()) if (attempt.pluginId === pluginId && (owner === void 0 || attempt.owner === owner)) {
181
+ attempt.controller.abort();
182
+ attempt.view.state = "cancelled";
183
+ delete attempt.view.challenge;
184
+ }
185
+ }
186
+ function cancelAllPluginCliAuthorizations() {
187
+ for (const attempt of attempts.values()) {
188
+ attempt.controller.abort();
189
+ if (![
190
+ "connected",
191
+ "error",
192
+ "cancelled"
193
+ ].includes(attempt.view.state)) attempt.view.state = "cancelled";
194
+ delete attempt.view.challenge;
195
+ }
196
+ }
197
+ //#endregion
198
+ export { cancelAllPluginCliAuthorizations, cancelPluginCliAuthorizations, checkPluginCliAuthorization, getPluginCliAuthorization, startPluginCliAuthorization };
@@ -0,0 +1,10 @@
1
+ import type { Config } from '../../config/schema.js';
2
+ import type { PluginServer } from './validation.js';
3
+ export interface PluginOAuthReference {
4
+ sourceServerId: string;
5
+ credentialId: string;
6
+ fingerprint: string;
7
+ }
8
+ export declare function connectionFingerprint(server: Record<string, unknown>): string;
9
+ export declare function matchingReusableConnection(target: PluginServer, source: Record<string, unknown>): boolean;
10
+ export declare function validPluginOAuthReference(reference: PluginOAuthReference, config: Config, target?: PluginServer): boolean;
@@ -0,0 +1,23 @@
1
+ import { createHash } from "node:crypto";
2
+ //#region src/extensions/agent-plugins/connection-reuse.ts
3
+ function connectionFingerprint(server) {
4
+ return createHash("sha256").update(JSON.stringify([
5
+ server.url,
6
+ server.oauth ?? null,
7
+ server.auth ?? null,
8
+ server.headers ?? null,
9
+ server.xopcOAuthCredentialId
10
+ ])).digest("hex");
11
+ }
12
+ function settings(value) {
13
+ return JSON.stringify(Object.fromEntries(Object.entries(value && typeof value === "object" ? value : {}).sort(([a], [b]) => a.localeCompare(b))));
14
+ }
15
+ function matchingReusableConnection(target, source) {
16
+ return target.type !== "stdio" && target.connectionAuth?.mode !== "api-key" && source.enabled !== false && source.url === target.url && typeof source.xopcOAuthCredentialId === "string" && /^mcp_draft_[a-f0-9]{32}$/.test(source.xopcOAuthCredentialId) && !source.auth && !Object.keys(source.headers ?? {}).some((key) => key.toLowerCase() === "authorization") && !Object.keys(target.headers ?? {}).some((key) => key.toLowerCase() === "authorization") && settings(source.oauth) === settings(target.oauth);
17
+ }
18
+ function validPluginOAuthReference(reference, config, target) {
19
+ const source = config.mcp?.servers?.[reference.sourceServerId];
20
+ return !!source && (!target || matchingReusableConnection(target, source)) && source.enabled !== false && source.xopcOAuthCredentialId === reference.credentialId && connectionFingerprint(source) === reference.fingerprint;
21
+ }
22
+ //#endregion
23
+ export { connectionFingerprint, matchingReusableConnection, validPluginOAuthReference };
@@ -1,7 +1,10 @@
1
1
  import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
2
2
  import { CredentialResolver, init_credentials } from "../../auth/credentials.js";
3
- import { pluginName } from "./validation.js";
3
+ import { pluginName, pluginServerId } from "./validation.js";
4
+ import { createNativeMcpCredentials } from "../../agent/mcp/credential-store.js";
4
5
  import { pluginCredentialProviderPrefix } from "./auth.js";
6
+ import { pluginOAuthCredentialId } from "./mcp-adapter.js";
7
+ import { getNativePiAgentDir } from "../../agent/mcp/native-mcp.js";
5
8
  import { join } from "node:path";
6
9
  import { existsSync, rmSync } from "node:fs";
7
10
  //#region src/extensions/agent-plugins/credentials.ts
@@ -9,6 +12,19 @@ init_credentials();
9
12
  init_paths_state();
10
13
  async function removePluginCredentials(store, id) {
11
14
  pluginName.parse(id);
15
+ const history = store.history(id);
16
+ if (store.stateDir === resolveStateDir()) {
17
+ getNativePiAgentDir();
18
+ const native = await createNativeMcpCredentials();
19
+ for (const plugin of history) {
20
+ const servers = plugin.receipt.oauthServers ?? Object.fromEntries(Object.entries(plugin.servers).filter(([, server]) => server.type !== "stdio").map(([name, server]) => [name, server.type !== "stdio" ? server.url : ""]));
21
+ for (const [name, url] of Object.entries(servers)) {
22
+ const alias = plugin.receipt.credentialScope === "revision" ? pluginOAuthCredentialId(id, plugin.receipt.revision, name) : pluginServerId(id, name);
23
+ await native.forServer(alias, url).save({ serverUrl: url });
24
+ native.remove(alias, url);
25
+ }
26
+ }
27
+ }
12
28
  const dir = join(store.stateDir, "plugin-auth", id);
13
29
  const resolver = new CredentialResolver(store.stateDir === resolveStateDir() ? {} : { stateDir: store.stateDir });
14
30
  for (const profile of await resolver.listProfiles()) if (profile.provider.startsWith(pluginCredentialProviderPrefix(id))) await resolver.deleteProviderCredential(profile.provider);
@@ -16,6 +32,13 @@ async function removePluginCredentials(store, id) {
16
32
  recursive: true,
17
33
  force: true
18
34
  });
35
+ for (const plugin of history) {
36
+ rmSync(join(store.stateDir, "plugin-config", `${id}-${plugin.receipt.revision}.json`), { force: true });
37
+ rmSync(join(store.dataDir(id), "accounts", plugin.receipt.revision), {
38
+ recursive: true,
39
+ force: true
40
+ });
41
+ }
19
42
  }
20
43
  //#endregion
21
44
  export { removePluginCredentials };
@@ -0,0 +1,27 @@
1
+ export declare const PLUGIN_MANIFEST_PATHS: readonly ["plugin.json", ".codex-plugin/plugin.json", ".claude-plugin/plugin.json"];
2
+ export type PluginDialect = 'portable' | 'codex' | 'claude';
3
+ export interface CompatibilityItem {
4
+ component: string;
5
+ support: 'supported' | 'needs_adapter' | 'unsupported' | 'invalid';
6
+ message: string;
7
+ }
8
+ export interface PluginLayout {
9
+ descriptorVersion: 1;
10
+ adapterVersion: 'xopc-plugin-v1';
11
+ dialect: PluginDialect;
12
+ manifest: Record<string, unknown>;
13
+ skillRoots: string[];
14
+ mcpConfigs: unknown[];
15
+ compatibility: CompatibilityItem[];
16
+ userConfig: Record<string, {
17
+ type: 'string' | 'number' | 'boolean';
18
+ title: string;
19
+ required: boolean;
20
+ sensitive: boolean;
21
+ default?: string | number | boolean;
22
+ }>;
23
+ tasks: string[];
24
+ }
25
+ /** Interpret each dialect before applying the common package and execution checks. */
26
+ export declare function readPluginLayout(root: string, read: (path: string) => string, safe: (path: string) => string, importManifest?: Record<string, unknown>): PluginLayout;
27
+ export declare function collectPluginSkillFiles(root: string, safe: (path: string) => string): string[];