@xopcai/xopc 0.0.395 → 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.
- package/dist/browser-ext/manifest.json +1 -1
- package/dist/extensions/telegram/src/plugin.js +1 -1
- package/dist/extensions/telegram/xopc.extension.json +1 -1
- package/dist/gateway/static/root/assets/{agent-avatar-dicebear-BRtkz-ZU.js → agent-avatar-dicebear-CIEGrioy.js} +1 -1
- package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-Dqg2NOn-.js → agent-defaults-settings-panel-CzKNVkRn.js} +1 -1
- package/dist/gateway/static/root/assets/agent-plugin-dialog-mpA9rwYd.js +1 -0
- package/dist/gateway/static/root/assets/{agents-0zgLsfVA.js → agents-7VMa7Rzo.js} +3 -3
- package/dist/gateway/static/root/assets/{app-management-settings-panel-BZS8FvoL.js → app-management-settings-panel-DIJ0ii-n.js} +1 -1
- package/dist/gateway/static/root/assets/{appearance-settings-RxXMAxiB.js → appearance-settings-BGnyHS-p.js} +1 -1
- package/dist/gateway/static/root/assets/apps-page-CvqDUvof.js +1 -0
- package/dist/gateway/static/root/assets/{archive-plugin-DEnHq3OR.js → archive-plugin-CR8FcRAa.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-page-BwkugzB8.js → automations-page-BLInZo7N.js} +1 -1
- package/dist/gateway/static/root/assets/{automations-workspace-K8aDhoYt.js → automations-workspace-DvTSHLt3.js} +1 -1
- package/dist/gateway/static/root/assets/{binary-plugins-NWeXhh1k.js → binary-plugins-DW9pu205.js} +1 -1
- package/dist/gateway/static/root/assets/{block-editor-D_bKN3BN.js → block-editor-ClgTc5v8.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automation-inputs-vtPkXfJ8.js → browser-automation-inputs-Bn7kDuUB.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-automations-page-DBPbwOG8.js → browser-automations-page-CJGBhDnv.js} +1 -1
- package/dist/gateway/static/root/assets/{browser-settings-page-VBZDYoXD.js → browser-settings-page-tsi5W-cJ.js} +1 -1
- package/dist/gateway/static/root/assets/capabilities-page-CfbGk8q_.js +2 -0
- package/dist/gateway/static/root/assets/{capabilities-settings-panel-C_OMsW_8.js → capabilities-settings-panel-BkO7QEyA.js} +1 -1
- package/dist/gateway/static/root/assets/{capability-header-actions-CMJXWq8a.js → capability-header-actions-9ZG71-BO.js} +1 -1
- package/dist/gateway/static/root/assets/{channels-C_TVCc1N.js → channels-D0CwJktG.js} +1 -1
- package/dist/gateway/static/root/assets/{chat-terminal-dock-9YRAokOl.js → chat-terminal-dock-x1W2_hwc.js} +1 -1
- package/dist/gateway/static/root/assets/{computer-settings-page-BPYAZ4ks.js → computer-settings-page-D_b_bFVz.js} +1 -1
- package/dist/gateway/static/root/assets/{connector-service-page-B81cEAEX.js → connector-service-page-Kf8kaNm_.js} +1 -1
- package/dist/gateway/static/root/assets/{connectors-page-C0NvAP2V.js → connectors-page-DlpfL2Rc.js} +1 -1
- package/dist/gateway/static/root/assets/{date-picker-BvKP4P3n.js → date-picker-d5kiPUG0.js} +1 -1
- package/dist/gateway/static/root/assets/{dependency-picker-TvrNaf8y.js → dependency-picker-BcH76tQC.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-De-_QNSD.js → desktop-pet-B-925tPX.js} +1 -1
- package/dist/gateway/static/root/assets/{desktop-pet-settings-CRSRTIwT.js → desktop-pet-settings-3XJ4qR65.js} +1 -1
- package/dist/gateway/static/root/assets/device-pairing-wizard-12m5Z9-8.js +1 -0
- package/dist/gateway/static/root/assets/{directory-picker-path-field-DOPXwYNR.js → directory-picker-path-field-B-qZCjGR.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-debug-page-DzXvpUwj.js → extension-debug-page-BlQu1u6X.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-page-C0S1zNeP.js → extension-page-CXxM1M62.js} +1 -1
- package/dist/gateway/static/root/assets/{extension-settings-page-C3Z7bFjy.js → extension-settings-page-AF5nvsPP.js} +1 -1
- package/dist/gateway/static/root/assets/{gateway-settings-Btc2wTQe.js → gateway-settings-ABXvW_yL.js} +1 -1
- package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-BFYBbh1P.js → highlighted-body-KQOG7T2V-Czdbbi0H.js} +1 -1
- package/dist/gateway/static/root/assets/{home-page-C5sLR47Q.js → home-page-LXGxGwVl.js} +1 -1
- package/dist/gateway/static/root/assets/{image-generation-api-Vqcyqnzb.js → image-generation-api-DPFPJ2ps.js} +1 -1
- package/dist/gateway/static/root/assets/{imports-page-BJGHrzhX.js → imports-page-Bwyotfbt.js} +1 -1
- package/dist/gateway/static/root/assets/index-BKHxJaGD.css +1 -0
- package/dist/gateway/static/root/assets/{index-BNRLzxpH.js → index-Dsp_gNdl.js} +116 -116
- package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BQkQoPmm.js → keyboard-shortcuts-settings-C20gl-l7.js} +1 -1
- package/dist/gateway/static/root/assets/{local-app-workbench-page-DbxLz9Ms.js → local-app-workbench-page-o0M_OSjC.js} +1 -1
- package/dist/gateway/static/root/assets/{local-apps-page-CaatwSrK.js → local-apps-page-DoWJCmOq.js} +1 -1
- package/dist/gateway/static/root/assets/{logs-page-3Wo4Lmts.js → logs-page-BFTL93RX.js} +1 -1
- package/dist/gateway/static/root/assets/{management-settings-BHlbM8IM.js → management-settings-C52cuMg1.js} +1 -1
- package/dist/gateway/static/root/assets/{media-plugins-Cq1uLrd8.js → media-plugins-DLrTRF0a.js} +1 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-CPYJsRUJ.js +1 -0
- package/dist/gateway/static/root/assets/{note-detail-panel-MjKND8HC.js → note-detail-panel-CNN41byS.js} +3 -3
- package/dist/gateway/static/root/assets/{notes-page-Cv040hVD.js → notes-page-BsfBp_8z.js} +1 -1
- package/dist/gateway/static/root/assets/{page-context-capture-button-Cp71nTq2.js → page-context-capture-button-YTVWZ02-.js} +1 -1
- package/dist/gateway/static/root/assets/{personal-page-CyEUWV2n.js → personal-page-N4KoCZYG.js} +1 -1
- package/dist/gateway/static/root/assets/plugin-details-page-DcrrzQI-.js +1 -0
- package/dist/gateway/static/root/assets/{preview-open-alternatives-gzCecXc4.js → preview-open-alternatives-DzA__S54.js} +1 -1
- package/dist/gateway/static/root/assets/{product-open-page-CWFT7VuQ.js → product-open-page-DvlMKj0T.js} +1 -1
- package/dist/gateway/static/root/assets/{product-preview-content-Dh111Kca.js → product-preview-content-qdFyo4NG.js} +1 -1
- package/dist/gateway/static/root/assets/{project-detail-page-CyhyZiTi.js → project-detail-page-y67s_fA8.js} +1 -1
- package/dist/gateway/static/root/assets/{projects-page-QUdyJino.js → projects-page-D5iYgi0O.js} +1 -1
- package/dist/gateway/static/root/assets/{remote-access-hub-Cd8P0Dxs.js → remote-access-hub-DeFF7Re-.js} +1 -1
- package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-bTjVfYm5.js → runtime-tools-settings-panel-BCHLh-KQ.js} +1 -1
- package/dist/gateway/static/root/assets/{schema-form-BGOzfVyj.js → schema-form-CJvaVHkx.js} +1 -1
- package/dist/gateway/static/root/assets/{sessions-page-BGMemJF6.js → sessions-page-DZ93_D5M.js} +1 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-F1WX7vxq.js +1 -0
- package/dist/gateway/static/root/assets/{settings-form-section-Bqm1IKvR.js → settings-form-section-B3eODxNv.js} +1 -1
- package/dist/gateway/static/root/assets/{settings-page-CniJVL-o.js → settings-page-Dg86uCnr.js} +1 -1
- package/dist/gateway/static/root/assets/{setup-status-panel-JPs4-QRw.js → setup-status-panel-ruFzAArp.js} +1 -1
- package/dist/gateway/static/root/assets/{share-preview-page-BnDGFgBR.js → share-preview-page-DCy1f25V.js} +1 -1
- package/dist/gateway/static/root/assets/{shares-settings-Cgp5BuLt.js → shares-settings-DeIVZvpJ.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-api-CFdrz6tl.js → skill-api-RisyPAMA.js} +1 -1
- package/dist/gateway/static/root/assets/{skill-reload-api-Cy5jVfms.js → skill-reload-api-Dwkm1Fof.js} +1 -1
- package/dist/gateway/static/root/assets/{skills-page-CxaA3P5E.js → skills-page-UiTLsrFc.js} +1 -1
- package/dist/gateway/static/root/assets/{style-C_MAnir7.js → style-CwMX73G7.js} +1 -1
- package/dist/gateway/static/root/assets/{system-settings-panel-BjnIlilP.js → system-settings-panel-Cma37Pfm.js} +1 -1
- package/dist/gateway/static/root/assets/{task-detail-page-Bg79rPnF.js → task-detail-page-BKOF_kxS.js} +1 -1
- package/dist/gateway/static/root/assets/{tracing-settings-page-BCI0tUbe.js → tracing-settings-page-DC-kLysq.js} +1 -1
- package/dist/gateway/static/root/assets/{tunnel-api-0knnta9z.js → tunnel-api-BgdhbR1L.js} +1 -1
- package/dist/gateway/static/root/assets/{usage-page-D5aT1eie.js → usage-page-BSlFg3Xj.js} +1 -1
- package/dist/gateway/static/root/assets/{use-autosave-Ds_mbAfe.js → use-autosave-iKvZ1pvC.js} +1 -1
- package/dist/gateway/static/root/assets/{user-model-page-D7L0-pDt.js → user-model-page-D4GB8QsM.js} +1 -1
- package/dist/gateway/static/root/assets/{voice-api-key-field-CPoGdarN.js → voice-api-key-field-CESbtuwM.js} +1 -1
- package/dist/gateway/static/root/assets/{work-discovery-overlay-CWNguy2Z.js → work-discovery-overlay-dtPpmYyh.js} +1 -1
- package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BcDMFfkT.js → workflow-run-setup-panel-DmFn3E_B.js} +1 -1
- package/dist/gateway/static/root/assets/{workflows-page-BwZB-s4N.js → workflows-page-DEtaRuxH.js} +1 -1
- package/dist/gateway/static/root/assets/{xopc-cloud-account-card-DlKr98VO.js → xopc-cloud-account-card-DTZnabfg.js} +1 -1
- package/dist/gateway/static/root/index.html +2 -2
- package/dist/package.js +1 -1
- package/dist/src/agent/embedded/codemode-extension.d.ts +1 -0
- package/dist/src/agent/embedded/codemode-extension.js +6 -1
- package/dist/src/agent/embedded/run-for-session.js +1 -1
- package/dist/src/agent/embedded/run-turn.js +34 -2
- package/dist/src/agent/embedded/session-runner.js +1 -1
- package/dist/src/agent/mcp/config.d.ts +2 -0
- package/dist/src/agent/mcp/config.js +2 -2
- package/dist/src/agent/mcp/connection-setup.js +13 -1
- package/dist/src/agent/mcp/effective-server.d.ts +3 -0
- package/dist/src/agent/mcp/effective-server.js +27 -0
- package/dist/src/agent/mcp/native-mcp.d.ts +1 -1
- package/dist/src/agent/mcp/native-mcp.js +13 -4
- package/dist/src/agent/mcp/tool-catalog.js +2 -1
- package/dist/src/agent/skills/index.d.ts +1 -0
- package/dist/src/agent/skills/index.js +6 -2
- package/dist/src/agent/skills/skill-manager.d.ts +1 -0
- package/dist/src/agent/skills/skill-manager.js +6 -1
- package/dist/src/agent/skills/skill-sources.d.ts +1 -0
- package/dist/src/agent/skills/skill-sources.js +4 -3
- package/dist/src/agent/skills/types.d.ts +1 -0
- package/dist/src/agent/workspace-runtime/registry.js +6 -2
- package/dist/src/browser/native-messaging-host.js +1 -1
- package/dist/src/browser/providers/browser-ext-install.js +2 -2
- package/dist/src/channels/index.js +1 -1
- package/dist/src/channels/manager.js +1 -1
- package/dist/src/cli/commands/channels.js +1 -1
- package/dist/src/cli/commands/connectors.js +1 -1
- package/dist/src/cli/commands/doctor/checks/database-schema.js +1 -1
- package/dist/src/cli/commands/extension-agent-plugin.js +92 -7
- package/dist/src/cli/commands/extension-marketplace.js +2 -2
- package/dist/src/cli/commands/extension.js +1 -1
- package/dist/src/cli/commands/mcp.js +6 -4
- package/dist/src/cli/commands/models.js +1 -1
- package/dist/src/cli/commands/onboard/model.js +1 -1
- package/dist/src/cli/commands/onboard.js +1 -1
- package/dist/src/extensions/agent-plugins/auth.d.ts +7 -1
- package/dist/src/extensions/agent-plugins/auth.js +53 -12
- package/dist/src/extensions/agent-plugins/branding.d.ts +6 -0
- package/dist/src/extensions/agent-plugins/branding.js +44 -0
- package/dist/src/extensions/agent-plugins/cli-authorization.d.ts +22 -0
- package/dist/src/extensions/agent-plugins/cli-authorization.js +198 -0
- package/dist/src/extensions/agent-plugins/connection-reuse.d.ts +10 -0
- package/dist/src/extensions/agent-plugins/connection-reuse.js +23 -0
- package/dist/src/extensions/agent-plugins/credentials.js +24 -1
- package/dist/src/extensions/agent-plugins/formats.d.ts +27 -0
- package/dist/src/extensions/agent-plugins/formats.js +208 -0
- package/dist/src/extensions/agent-plugins/inventory.d.ts +142 -2
- package/dist/src/extensions/agent-plugins/inventory.js +39 -5
- package/dist/src/extensions/agent-plugins/mcp-adapter.d.ts +2 -1
- package/dist/src/extensions/agent-plugins/mcp-adapter.js +42 -8
- package/dist/src/extensions/agent-plugins/mcp-format.d.ts +2 -0
- package/dist/src/extensions/agent-plugins/mcp-format.js +82 -0
- package/dist/src/extensions/agent-plugins/resources.d.ts +14 -0
- package/dist/src/extensions/agent-plugins/resources.js +112 -0
- package/dist/src/extensions/agent-plugins/setup-contract.d.ts +54 -0
- package/dist/src/extensions/agent-plugins/setup-contract.js +58 -0
- package/dist/src/extensions/agent-plugins/setup.d.ts +119 -0
- package/dist/src/extensions/agent-plugins/setup.js +491 -0
- package/dist/src/extensions/agent-plugins/source-catalog.d.ts +21 -0
- package/dist/src/extensions/agent-plugins/source-catalog.js +175 -0
- package/dist/src/extensions/agent-plugins/sources.d.ts +1 -1
- package/dist/src/extensions/agent-plugins/sources.js +12 -3
- package/dist/src/extensions/agent-plugins/store.d.ts +33 -2
- package/dist/src/extensions/agent-plugins/store.js +175 -25
- package/dist/src/extensions/agent-plugins/user-config.d.ts +5 -0
- package/dist/src/extensions/agent-plugins/user-config.js +49 -0
- package/dist/src/extensions/agent-plugins/validation.d.ts +26 -1
- package/dist/src/extensions/agent-plugins/validation.js +142 -27
- package/dist/src/extensions/sdk/index.js +1 -1
- package/dist/src/gateway/hono/app.js +1 -1
- package/dist/src/gateway/hono/routes/agent-plugins.js +120 -9
- package/dist/src/gateway/hono/routes/browser-install.js +1 -1
- package/dist/src/gateway/hono/routes/composer-history.js +22 -4
- package/dist/src/gateway/hono/routes/mcp.js +6 -4
- package/dist/src/gateway/hono/routes/provider-setup.js +7 -0
- package/dist/src/gateway/service.js +11 -9
- package/dist/src/gateway/session-context-summary.js +1 -1
- package/dist/src/gateway/xopc-cloud-capability-setup.d.ts +4 -0
- package/dist/src/gateway/xopc-cloud-capability-setup.js +90 -26
- package/dist/src/home-intelligence/host.js +2 -2
- package/dist/src/providers/setup/engine.js +12 -10
- package/dist/src/providers/setup/voice.js +24 -6
- package/dist/src/storage/sqlite/composer-input-history-repository.d.ts +4 -3
- package/dist/src/storage/sqlite/composer-input-history-repository.js +10 -8
- package/dist/src/storage/sqlite/device-pairing-approval.js +1 -1
- package/dist/src/storage/sqlite/migrations/257_session_composer_history.sql +11 -0
- package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
- package/dist/src/storage/sqlite/migrations/runner.js +3 -3
- package/dist/src/storage/sqlite/schema.js +1 -1
- package/dist/src/tui/backends/embedded-backend.d.ts +2 -2
- package/dist/src/tui/backends/embedded-backend.js +4 -4
- package/dist/src/tui/backends/gateway-realtime-backend.d.ts +2 -2
- package/dist/src/tui/backends/gateway-realtime-backend.js +7 -4
- package/dist/src/tui/composer-history.d.ts +14 -0
- package/dist/src/tui/composer-history.js +85 -0
- package/dist/src/tui/tui-backend.d.ts +4 -3
- package/dist/src/tui/tui.js +19 -46
- package/package.json +12 -4
- package/dist/gateway/static/root/assets/agent-plugin-dialog-CKK95Jmr.js +0 -1
- package/dist/gateway/static/root/assets/apps-page-mGU9WLjP.js +0 -1
- package/dist/gateway/static/root/assets/capabilities-page-CQsGp9Sx.js +0 -2
- package/dist/gateway/static/root/assets/device-pairing-wizard-DnyJ8Bja.js +0 -1
- package/dist/gateway/static/root/assets/index-zIgp-ZTu.css +0 -1
- package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-XhlIBp5t.js +0 -1
- package/dist/gateway/static/root/assets/settings-advanced-gate-BiySFw1N.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) :
|
|
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
|
|
38
|
-
|
|
39
|
-
const
|
|
40
|
-
|
|
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[];
|