@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.
Files changed (192) 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-BRtkz-ZU.js → agent-avatar-dicebear-CIEGrioy.js} +1 -1
  5. package/dist/gateway/static/root/assets/{agent-defaults-settings-panel-Dqg2NOn-.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-0zgLsfVA.js → agents-7VMa7Rzo.js} +3 -3
  8. package/dist/gateway/static/root/assets/{app-management-settings-panel-BZS8FvoL.js → app-management-settings-panel-DIJ0ii-n.js} +1 -1
  9. package/dist/gateway/static/root/assets/{appearance-settings-RxXMAxiB.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-DEnHq3OR.js → archive-plugin-CR8FcRAa.js} +1 -1
  12. package/dist/gateway/static/root/assets/{automations-page-BwkugzB8.js → automations-page-BLInZo7N.js} +1 -1
  13. package/dist/gateway/static/root/assets/{automations-workspace-K8aDhoYt.js → automations-workspace-DvTSHLt3.js} +1 -1
  14. package/dist/gateway/static/root/assets/{binary-plugins-NWeXhh1k.js → binary-plugins-DW9pu205.js} +1 -1
  15. package/dist/gateway/static/root/assets/{block-editor-D_bKN3BN.js → block-editor-ClgTc5v8.js} +1 -1
  16. package/dist/gateway/static/root/assets/{browser-automation-inputs-vtPkXfJ8.js → browser-automation-inputs-Bn7kDuUB.js} +1 -1
  17. package/dist/gateway/static/root/assets/{browser-automations-page-DBPbwOG8.js → browser-automations-page-CJGBhDnv.js} +1 -1
  18. package/dist/gateway/static/root/assets/{browser-settings-page-VBZDYoXD.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-C_OMsW_8.js → capabilities-settings-panel-BkO7QEyA.js} +1 -1
  21. package/dist/gateway/static/root/assets/{capability-header-actions-CMJXWq8a.js → capability-header-actions-9ZG71-BO.js} +1 -1
  22. package/dist/gateway/static/root/assets/{channels-C_TVCc1N.js → channels-D0CwJktG.js} +1 -1
  23. package/dist/gateway/static/root/assets/{chat-terminal-dock-9YRAokOl.js → chat-terminal-dock-x1W2_hwc.js} +1 -1
  24. package/dist/gateway/static/root/assets/{computer-settings-page-BPYAZ4ks.js → computer-settings-page-D_b_bFVz.js} +1 -1
  25. package/dist/gateway/static/root/assets/{connector-service-page-B81cEAEX.js → connector-service-page-Kf8kaNm_.js} +1 -1
  26. package/dist/gateway/static/root/assets/{connectors-page-C0NvAP2V.js → connectors-page-DlpfL2Rc.js} +1 -1
  27. package/dist/gateway/static/root/assets/{date-picker-BvKP4P3n.js → date-picker-d5kiPUG0.js} +1 -1
  28. package/dist/gateway/static/root/assets/{dependency-picker-TvrNaf8y.js → dependency-picker-BcH76tQC.js} +1 -1
  29. package/dist/gateway/static/root/assets/{desktop-pet-De-_QNSD.js → desktop-pet-B-925tPX.js} +1 -1
  30. package/dist/gateway/static/root/assets/{desktop-pet-settings-CRSRTIwT.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-DOPXwYNR.js → directory-picker-path-field-B-qZCjGR.js} +1 -1
  33. package/dist/gateway/static/root/assets/{extension-debug-page-DzXvpUwj.js → extension-debug-page-BlQu1u6X.js} +1 -1
  34. package/dist/gateway/static/root/assets/{extension-page-C0S1zNeP.js → extension-page-CXxM1M62.js} +1 -1
  35. package/dist/gateway/static/root/assets/{extension-settings-page-C3Z7bFjy.js → extension-settings-page-AF5nvsPP.js} +1 -1
  36. package/dist/gateway/static/root/assets/{gateway-settings-Btc2wTQe.js → gateway-settings-ABXvW_yL.js} +1 -1
  37. package/dist/gateway/static/root/assets/{highlighted-body-KQOG7T2V-BFYBbh1P.js → highlighted-body-KQOG7T2V-Czdbbi0H.js} +1 -1
  38. package/dist/gateway/static/root/assets/{home-page-C5sLR47Q.js → home-page-LXGxGwVl.js} +1 -1
  39. package/dist/gateway/static/root/assets/{image-generation-api-Vqcyqnzb.js → image-generation-api-DPFPJ2ps.js} +1 -1
  40. package/dist/gateway/static/root/assets/{imports-page-BJGHrzhX.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-BNRLzxpH.js → index-Dsp_gNdl.js} +116 -116
  43. package/dist/gateway/static/root/assets/{keyboard-shortcuts-settings-BQkQoPmm.js → keyboard-shortcuts-settings-C20gl-l7.js} +1 -1
  44. package/dist/gateway/static/root/assets/{local-app-workbench-page-DbxLz9Ms.js → local-app-workbench-page-o0M_OSjC.js} +1 -1
  45. package/dist/gateway/static/root/assets/{local-apps-page-CaatwSrK.js → local-apps-page-DoWJCmOq.js} +1 -1
  46. package/dist/gateway/static/root/assets/{logs-page-3Wo4Lmts.js → logs-page-BFTL93RX.js} +1 -1
  47. package/dist/gateway/static/root/assets/{management-settings-BHlbM8IM.js → management-settings-C52cuMg1.js} +1 -1
  48. package/dist/gateway/static/root/assets/{media-plugins-Cq1uLrd8.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-MjKND8HC.js → note-detail-panel-CNN41byS.js} +3 -3
  51. package/dist/gateway/static/root/assets/{notes-page-Cv040hVD.js → notes-page-BsfBp_8z.js} +1 -1
  52. package/dist/gateway/static/root/assets/{page-context-capture-button-Cp71nTq2.js → page-context-capture-button-YTVWZ02-.js} +1 -1
  53. package/dist/gateway/static/root/assets/{personal-page-CyEUWV2n.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-gzCecXc4.js → preview-open-alternatives-DzA__S54.js} +1 -1
  56. package/dist/gateway/static/root/assets/{product-open-page-CWFT7VuQ.js → product-open-page-DvlMKj0T.js} +1 -1
  57. package/dist/gateway/static/root/assets/{product-preview-content-Dh111Kca.js → product-preview-content-qdFyo4NG.js} +1 -1
  58. package/dist/gateway/static/root/assets/{project-detail-page-CyhyZiTi.js → project-detail-page-y67s_fA8.js} +1 -1
  59. package/dist/gateway/static/root/assets/{projects-page-QUdyJino.js → projects-page-D5iYgi0O.js} +1 -1
  60. package/dist/gateway/static/root/assets/{remote-access-hub-Cd8P0Dxs.js → remote-access-hub-DeFF7Re-.js} +1 -1
  61. package/dist/gateway/static/root/assets/{runtime-tools-settings-panel-bTjVfYm5.js → runtime-tools-settings-panel-BCHLh-KQ.js} +1 -1
  62. package/dist/gateway/static/root/assets/{schema-form-BGOzfVyj.js → schema-form-CJvaVHkx.js} +1 -1
  63. package/dist/gateway/static/root/assets/{sessions-page-BGMemJF6.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-Bqm1IKvR.js → settings-form-section-B3eODxNv.js} +1 -1
  66. package/dist/gateway/static/root/assets/{settings-page-CniJVL-o.js → settings-page-Dg86uCnr.js} +1 -1
  67. package/dist/gateway/static/root/assets/{setup-status-panel-JPs4-QRw.js → setup-status-panel-ruFzAArp.js} +1 -1
  68. package/dist/gateway/static/root/assets/{share-preview-page-BnDGFgBR.js → share-preview-page-DCy1f25V.js} +1 -1
  69. package/dist/gateway/static/root/assets/{shares-settings-Cgp5BuLt.js → shares-settings-DeIVZvpJ.js} +1 -1
  70. package/dist/gateway/static/root/assets/{skill-api-CFdrz6tl.js → skill-api-RisyPAMA.js} +1 -1
  71. package/dist/gateway/static/root/assets/{skill-reload-api-Cy5jVfms.js → skill-reload-api-Dwkm1Fof.js} +1 -1
  72. package/dist/gateway/static/root/assets/{skills-page-CxaA3P5E.js → skills-page-UiTLsrFc.js} +1 -1
  73. package/dist/gateway/static/root/assets/{style-C_MAnir7.js → style-CwMX73G7.js} +1 -1
  74. package/dist/gateway/static/root/assets/{system-settings-panel-BjnIlilP.js → system-settings-panel-Cma37Pfm.js} +1 -1
  75. package/dist/gateway/static/root/assets/{task-detail-page-Bg79rPnF.js → task-detail-page-BKOF_kxS.js} +1 -1
  76. package/dist/gateway/static/root/assets/{tracing-settings-page-BCI0tUbe.js → tracing-settings-page-DC-kLysq.js} +1 -1
  77. package/dist/gateway/static/root/assets/{tunnel-api-0knnta9z.js → tunnel-api-BgdhbR1L.js} +1 -1
  78. package/dist/gateway/static/root/assets/{usage-page-D5aT1eie.js → usage-page-BSlFg3Xj.js} +1 -1
  79. package/dist/gateway/static/root/assets/{use-autosave-Ds_mbAfe.js → use-autosave-iKvZ1pvC.js} +1 -1
  80. package/dist/gateway/static/root/assets/{user-model-page-D7L0-pDt.js → user-model-page-D4GB8QsM.js} +1 -1
  81. package/dist/gateway/static/root/assets/{voice-api-key-field-CPoGdarN.js → voice-api-key-field-CESbtuwM.js} +1 -1
  82. package/dist/gateway/static/root/assets/{work-discovery-overlay-CWNguy2Z.js → work-discovery-overlay-dtPpmYyh.js} +1 -1
  83. package/dist/gateway/static/root/assets/{workflow-run-setup-panel-BcDMFfkT.js → workflow-run-setup-panel-DmFn3E_B.js} +1 -1
  84. package/dist/gateway/static/root/assets/{workflows-page-BwZB-s4N.js → workflows-page-DEtaRuxH.js} +1 -1
  85. package/dist/gateway/static/root/assets/{xopc-cloud-account-card-DlKr98VO.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/model.js +1 -1
  122. package/dist/src/cli/commands/onboard.js +1 -1
  123. package/dist/src/extensions/agent-plugins/auth.d.ts +7 -1
  124. package/dist/src/extensions/agent-plugins/auth.js +53 -12
  125. package/dist/src/extensions/agent-plugins/branding.d.ts +6 -0
  126. package/dist/src/extensions/agent-plugins/branding.js +44 -0
  127. package/dist/src/extensions/agent-plugins/cli-authorization.d.ts +22 -0
  128. package/dist/src/extensions/agent-plugins/cli-authorization.js +198 -0
  129. package/dist/src/extensions/agent-plugins/connection-reuse.d.ts +10 -0
  130. package/dist/src/extensions/agent-plugins/connection-reuse.js +23 -0
  131. package/dist/src/extensions/agent-plugins/credentials.js +24 -1
  132. package/dist/src/extensions/agent-plugins/formats.d.ts +27 -0
  133. package/dist/src/extensions/agent-plugins/formats.js +208 -0
  134. package/dist/src/extensions/agent-plugins/inventory.d.ts +142 -2
  135. package/dist/src/extensions/agent-plugins/inventory.js +39 -5
  136. package/dist/src/extensions/agent-plugins/mcp-adapter.d.ts +2 -1
  137. package/dist/src/extensions/agent-plugins/mcp-adapter.js +42 -8
  138. package/dist/src/extensions/agent-plugins/mcp-format.d.ts +2 -0
  139. package/dist/src/extensions/agent-plugins/mcp-format.js +82 -0
  140. package/dist/src/extensions/agent-plugins/resources.d.ts +14 -0
  141. package/dist/src/extensions/agent-plugins/resources.js +112 -0
  142. package/dist/src/extensions/agent-plugins/setup-contract.d.ts +54 -0
  143. package/dist/src/extensions/agent-plugins/setup-contract.js +58 -0
  144. package/dist/src/extensions/agent-plugins/setup.d.ts +119 -0
  145. package/dist/src/extensions/agent-plugins/setup.js +491 -0
  146. package/dist/src/extensions/agent-plugins/source-catalog.d.ts +21 -0
  147. package/dist/src/extensions/agent-plugins/source-catalog.js +175 -0
  148. package/dist/src/extensions/agent-plugins/sources.d.ts +1 -1
  149. package/dist/src/extensions/agent-plugins/sources.js +12 -3
  150. package/dist/src/extensions/agent-plugins/store.d.ts +33 -2
  151. package/dist/src/extensions/agent-plugins/store.js +175 -25
  152. package/dist/src/extensions/agent-plugins/user-config.d.ts +5 -0
  153. package/dist/src/extensions/agent-plugins/user-config.js +49 -0
  154. package/dist/src/extensions/agent-plugins/validation.d.ts +26 -1
  155. package/dist/src/extensions/agent-plugins/validation.js +142 -27
  156. package/dist/src/extensions/sdk/index.js +1 -1
  157. package/dist/src/gateway/hono/app.js +1 -1
  158. package/dist/src/gateway/hono/routes/agent-plugins.js +120 -9
  159. package/dist/src/gateway/hono/routes/browser-install.js +1 -1
  160. package/dist/src/gateway/hono/routes/composer-history.js +22 -4
  161. package/dist/src/gateway/hono/routes/mcp.js +6 -4
  162. package/dist/src/gateway/hono/routes/provider-setup.js +7 -0
  163. package/dist/src/gateway/service.js +11 -9
  164. package/dist/src/gateway/session-context-summary.js +1 -1
  165. package/dist/src/gateway/xopc-cloud-capability-setup.d.ts +4 -0
  166. package/dist/src/gateway/xopc-cloud-capability-setup.js +90 -26
  167. package/dist/src/home-intelligence/host.js +2 -2
  168. package/dist/src/providers/setup/engine.js +12 -10
  169. package/dist/src/providers/setup/voice.js +24 -6
  170. package/dist/src/storage/sqlite/composer-input-history-repository.d.ts +4 -3
  171. package/dist/src/storage/sqlite/composer-input-history-repository.js +10 -8
  172. package/dist/src/storage/sqlite/device-pairing-approval.js +1 -1
  173. package/dist/src/storage/sqlite/migrations/257_session_composer_history.sql +11 -0
  174. package/dist/src/storage/sqlite/migrations/runner.d.ts +1 -1
  175. package/dist/src/storage/sqlite/migrations/runner.js +3 -3
  176. package/dist/src/storage/sqlite/schema.js +1 -1
  177. package/dist/src/tui/backends/embedded-backend.d.ts +2 -2
  178. package/dist/src/tui/backends/embedded-backend.js +4 -4
  179. package/dist/src/tui/backends/gateway-realtime-backend.d.ts +2 -2
  180. package/dist/src/tui/backends/gateway-realtime-backend.js +7 -4
  181. package/dist/src/tui/composer-history.d.ts +14 -0
  182. package/dist/src/tui/composer-history.js +85 -0
  183. package/dist/src/tui/tui-backend.d.ts +4 -3
  184. package/dist/src/tui/tui.js +19 -46
  185. package/package.json +12 -4
  186. package/dist/gateway/static/root/assets/agent-plugin-dialog-CKK95Jmr.js +0 -1
  187. package/dist/gateway/static/root/assets/apps-page-mGU9WLjP.js +0 -1
  188. package/dist/gateway/static/root/assets/capabilities-page-CQsGp9Sx.js +0 -2
  189. package/dist/gateway/static/root/assets/device-pairing-wizard-DnyJ8Bja.js +0 -1
  190. package/dist/gateway/static/root/assets/index-zIgp-ZTu.css +0 -1
  191. package/dist/gateway/static/root/assets/mermaid-MCJ5UELQ-XhlIBp5t.js +0 -1
  192. package/dist/gateway/static/root/assets/settings-advanced-gate-BiySFw1N.js +0 -1
@@ -2,6 +2,7 @@ import { createLogger } from "../../utils/logger/index.js";
2
2
  import { init_logger } from "../../utils/logger.js";
3
3
  import { isManagedConnectorServer } from "../../connectors/materialize.js";
4
4
  import { prepareNativeMcpConfig } from "./native-mcp.js";
5
+ import { resolveMcpSetupConfig } from "./effective-server.js";
5
6
  import { classifyMcpConnectionError } from "./connection-errors.js";
6
7
  import { McpAuthenticationRequiredError, discoverMcpTools, signInNativeMcp } from "./tool-catalog.js";
7
8
  import { createHash, randomUUID } from "node:crypto";
@@ -83,6 +84,7 @@ async function advertisesOAuth(config, workspace, serverId, signal) {
83
84
  return Boolean(legacy && legacy.issuer === url.origin && typeof legacy.authorization_endpoint === "string" && typeof legacy.token_endpoint === "string");
84
85
  }
85
86
  async function probeMcpConnection(config, workspace, serverId, options) {
87
+ config = resolveMcpSetupConfig(config, serverId);
86
88
  try {
87
89
  return {
88
90
  state: "connected",
@@ -116,6 +118,7 @@ async function probeMcpConnection(config, workspace, serverId, options) {
116
118
  }
117
119
  const attempts = /* @__PURE__ */ new Map();
118
120
  function fingerprint(config, serverId) {
121
+ config = resolveMcpSetupConfig(config, serverId);
119
122
  const server = config.mcp?.servers?.[serverId];
120
123
  return createHash("sha256").update(JSON.stringify(server ? {
121
124
  ...server,
@@ -138,6 +141,7 @@ function cancel(attempt) {
138
141
  }
139
142
  /** A UI bridge to native pi's login command; no host-owned OAuth client or token store. */
140
143
  function startMcpAuthorization(config, workspace, serverId, owner, options) {
144
+ config = resolveMcpSetupConfig(config, serverId);
141
145
  const server = config.mcp?.servers?.[serverId];
142
146
  if (!server?.url || server.enabled === false || isManagedConnectorServer(server) && server.xopcConnector.enabled === false) throw new Error("An enabled HTTP MCP server is required.");
143
147
  httpUrl(server.url);
@@ -227,7 +231,15 @@ function submitMcpRedirect(id, owner, redirectUrl, config) {
227
231
  if (!expected) return false;
228
232
  const target = new URL(expected);
229
233
  const actual = httpUrl(redirectUrl);
230
- if (actual.origin !== target.origin || actual.pathname !== target.pathname || actual.searchParams.get("state") !== authorization.searchParams.get("state") || !actual.searchParams.get("code")) return false;
234
+ if (actual.origin !== target.origin || actual.pathname !== target.pathname || actual.searchParams.get("state") !== authorization.searchParams.get("state")) return false;
235
+ if (actual.searchParams.has("error")) {
236
+ cancel(attempt);
237
+ attempt.result.state = "error";
238
+ attempt.result.error = "Sign-in was declined or could not be completed. Try again.";
239
+ delete attempt.result.authorizationUrl;
240
+ return true;
241
+ }
242
+ if (!actual.searchParams.get("code")) return false;
231
243
  attempt.redirect(actual.href);
232
244
  attempt.redirect = void 0;
233
245
  return true;
@@ -0,0 +1,3 @@
1
+ import type { Config } from '../../config/schema.js';
2
+ /** Resolve a single explicit setup target without enabling it for any agent. */
3
+ export declare function resolveMcpSetupConfig(config: Config, serverId: string): Config;
@@ -0,0 +1,27 @@
1
+ import { AgentPluginStore } from "../../extensions/agent-plugins/store.js";
2
+ import { materializePluginServers } from "../../extensions/agent-plugins/mcp-adapter.js";
3
+ //#region src/agent/mcp/effective-server.ts
4
+ /** Resolve a single explicit setup target without enabling it for any agent. */
5
+ function resolveMcpSetupConfig(config, serverId) {
6
+ if (Object.hasOwn(config.mcp?.servers ?? {}, serverId)) return config;
7
+ const store = new AgentPluginStore();
8
+ for (const installed of store.list()) {
9
+ const plugin = store.pending(installed.id) ?? installed;
10
+ if (plugin.readiness === "blocked") continue;
11
+ const servers = materializePluginServers(plugin, store, [], true);
12
+ if (!Object.hasOwn(servers, serverId)) continue;
13
+ return {
14
+ ...config,
15
+ mcp: {
16
+ ...config.mcp,
17
+ servers: {
18
+ ...config.mcp?.servers,
19
+ [serverId]: servers[serverId]
20
+ }
21
+ }
22
+ };
23
+ }
24
+ return config;
25
+ }
26
+ //#endregion
27
+ export { resolveMcpSetupConfig };
@@ -8,4 +8,4 @@ export type NativeMcpConfig = LoadedMcpConfig & {
8
8
  credentialAliases?: Record<string, string>;
9
9
  };
10
10
  /** Only projects host configuration and secret references; all MCP execution belongs to pi. */
11
- export declare function prepareNativeMcpConfig(config: Config, workspaceDir: string): Promise<NativeMcpConfig>;
11
+ export declare function prepareNativeMcpConfig(config: Config, workspaceDir: string, agentId?: string): Promise<NativeMcpConfig>;
@@ -1,6 +1,7 @@
1
1
  import { init_paths_state, resolveStateDir } from "../../config/paths-state.js";
2
2
  import { McpServerSchema, init_schema } from "../../config/schema.js";
3
3
  import { resolveConnectorSecretReferences } from "../../connectors/secret-store.js";
4
+ import { validPluginOAuthReference } from "../../extensions/agent-plugins/connection-reuse.js";
4
5
  import { createNativeMcpCredentials, routeNativeMcpCredentials } from "./credential-store.js";
5
6
  import { loadMergedMcpConfig } from "./config.js";
6
7
  import { join } from "node:path";
@@ -20,17 +21,19 @@ function getNativePiAgentDir() {
20
21
  return directory;
21
22
  }
22
23
  /** Only projects host configuration and secret references; all MCP execution belongs to pi. */
23
- async function prepareNativeMcpConfig(config, workspaceDir) {
24
+ async function prepareNativeMcpConfig(config, workspaceDir, agentId) {
24
25
  getNativePiAgentDir();
25
26
  const merged = loadMergedMcpConfig({
26
27
  cfg: config,
27
- workspaceDir
28
+ workspaceDir,
29
+ agentId
28
30
  });
29
31
  const result = {
30
32
  servers: [],
31
33
  errors: merged.diagnostics.map((item) => item.message)
32
34
  };
33
35
  const names = /* @__PURE__ */ new Set();
36
+ const aliases = /* @__PURE__ */ new Map();
34
37
  for (const [name, raw] of Object.entries(merged.config.mcpServers)) {
35
38
  const normalized = name.replace(/-/g, "_");
36
39
  if (!/^[a-zA-Z0-9_-]+$/.test(name) || names.has(normalized)) {
@@ -38,6 +41,12 @@ async function prepareNativeMcpConfig(config, workspaceDir) {
38
41
  continue;
39
42
  }
40
43
  names.add(normalized);
44
+ const reference = raw.xopcPluginOAuthReference;
45
+ if (reference && !validPluginOAuthReference(reference, config, raw)) {
46
+ result.errors.push(`Shared MCP connection changed: ${name}. Reconnect this plugin.`);
47
+ continue;
48
+ }
49
+ if (typeof raw.xopcOAuthCredentialId === "string") aliases.set(name, raw.xopcOAuthCredentialId);
41
50
  const parsed = McpServerSchema.safeParse(raw);
42
51
  if (!parsed.success) {
43
52
  result.errors.push(`Invalid MCP server ${name}: ${parsed.error.message}`);
@@ -61,14 +70,14 @@ async function prepareNativeMcpConfig(config, workspaceDir) {
61
70
  "description"
62
71
  ].filter((key) => value[key] !== void 0).map((key) => [key, value[key]]));
63
72
  if (projected.type === "streamable-http") projected.type = "http";
73
+ const plugin = raw.xopcPlugin;
64
74
  result.servers.push({
65
75
  name,
66
76
  config: projected,
67
- source: "xopc.json",
77
+ source: plugin?.revision ? `plugin:${plugin.id}@${plugin.revision}` : "xopc.json",
68
78
  scope: "extension"
69
79
  });
70
80
  }
71
- const aliases = new Map(Object.entries(config.mcp?.servers ?? {}).filter(([, value]) => typeof value.xopcOAuthCredentialId === "string").map(([name, value]) => [name, value.xopcOAuthCredentialId]));
72
81
  if (aliases.size) {
73
82
  result.credentials = routeNativeMcpCredentials(await createNativeMcpCredentials(), aliases);
74
83
  result.credentialAliases = Object.fromEntries(aliases);
@@ -1,5 +1,6 @@
1
1
  import { createEmbeddedModelRuntime } from "../embedded/model-runtime.js";
2
2
  import { getNativePiAgentDir, prepareNativeMcpConfig } from "./native-mcp.js";
3
+ import { resolveMcpSetupConfig } from "./effective-server.js";
3
4
  import { join } from "node:path";
4
5
  import { InMemoryCredentialStore, InMemoryModelsStore } from "@earendil-works/pi-ai";
5
6
  import { DefaultResourceLoader, ModelRuntime, SessionManager, SettingsManager, createAgentSession, createMcpExtension, createToolSearchExtension } from "@earendil-works/pi-coding-agent";
@@ -16,7 +17,7 @@ async function signInNativeMcp(config, workspaceDir, serverId, interaction, opti
16
17
  async function runNativeMcpSession(config, workspaceDir, serverId, interaction, options) {
17
18
  const signal = interaction?.signal ?? options?.signal;
18
19
  signal?.throwIfAborted();
19
- const loaded = await prepareNativeMcpConfig(config, workspaceDir);
20
+ const loaded = await prepareNativeMcpConfig(resolveMcpSetupConfig(config, serverId), workspaceDir);
20
21
  signal?.throwIfAborted();
21
22
  const entry = loaded.servers.find((server) => server.name === serverId);
22
23
  if (!entry) throw new Error(`MCP server "${serverId}" is not configured or has invalid configuration.`);
@@ -40,6 +40,7 @@ export interface SkillLoader {
40
40
  getEnabledSkills: (config?: Record<string, SkillConfig>) => Skill[];
41
41
  }
42
42
  export interface SkillLoaderOptions {
43
+ agentId?: string;
43
44
  /** Re-evaluated on every load so trust changes take effect without recreating the runtime. */
44
45
  isWorkspaceTrusted?: (workspaceDir: string) => boolean;
45
46
  }
@@ -135,7 +135,10 @@ function discoverAndMergeSkills(sources, maxSkillFileBytes, limits = {}, initial
135
135
  skills: source.skillFiles.slice(0, limits.maxSkillsLoadedPerSource).flatMap((path) => {
136
136
  const result = loadSkillFromFile(path, source, source.rootDir, maxSkillFileBytes);
137
137
  if (result.diagnostic) diagnostics.push(result.diagnostic);
138
- return result.skill ? [result.skill] : [];
138
+ return result.skill ? [{
139
+ ...result.skill,
140
+ name: source.skillAliases?.[path] ?? result.skill.name
141
+ }] : [];
139
142
  }),
140
143
  diagnostics: []
141
144
  } : discoverSkills(source, maxSkillFileBytes, limits.maxSkillsLoadedPerSource, limits.maxCandidatesPerRoot);
@@ -320,7 +323,8 @@ function createSkillLoader(options = {}) {
320
323
  return loadSkills({
321
324
  workspaceDir,
322
325
  builtinDir,
323
- workspaceTrust
326
+ workspaceTrust,
327
+ agentId: options.agentId
324
328
  });
325
329
  }
326
330
  return {
@@ -10,6 +10,7 @@ export interface SkillLoadResult {
10
10
  diagnostics: SkillDiagnostic[];
11
11
  }
12
12
  export interface SkillManagerOptions {
13
+ agentId?: string;
13
14
  isWorkspaceTrusted?: (workspaceDir: string) => boolean;
14
15
  }
15
16
  export declare class SkillManager {
@@ -35,7 +35,10 @@ var SkillManager = class {
35
35
  constructor(workspace, bundledSkillsDir, options = {}) {
36
36
  this.workspace = workspace;
37
37
  this.bundledSkillsDir = bundledSkillsDir || resolveBundledSkillsDir();
38
- this.skillLoader = createSkillLoader({ isWorkspaceTrusted: options.isWorkspaceTrusted });
38
+ this.skillLoader = createSkillLoader({
39
+ agentId: options.agentId,
40
+ isWorkspaceTrusted: options.isWorkspaceTrusted
41
+ });
39
42
  this.initialize();
40
43
  }
41
44
  /**
@@ -216,12 +219,14 @@ var SkillManager = class {
216
219
  * Find a skill by name
217
220
  */
218
221
  findSkill(name) {
222
+ this.refreshPlugins();
219
223
  return this.skills.find((s) => s.name === name);
220
224
  }
221
225
  /**
222
226
  * Check if a skill exists
223
227
  */
224
228
  hasSkill(name) {
229
+ this.refreshPlugins();
225
230
  return this.skills.some((s) => s.name === name);
226
231
  }
227
232
  /**
@@ -1,6 +1,7 @@
1
1
  import type { SkillDiagnostic, SkillSourceDescriptor, SkillsConfig } from './types.js';
2
2
  export interface ResolveSkillSourcesOptions {
3
3
  workspaceDir?: string;
4
+ agentId?: string;
4
5
  globalDir?: string;
5
6
  builtinDir?: string;
6
7
  agentsDir?: string;
@@ -48,15 +48,16 @@ function resolveSkillSources(options, skillsConfig) {
48
48
  const extraDirs = [...configuredExtraDirs, ...optionExtraDirs];
49
49
  const sources = [];
50
50
  const diagnostics = [];
51
- for (const plugin of new AgentPluginStore().active()) {
51
+ for (const plugin of new AgentPluginStore().active(options.agentId, options.workspaceDir)) {
52
52
  sources.push({
53
53
  id: `plugin:${plugin.id}`,
54
- rootDir: join(plugin.rootDir, "skills"),
54
+ rootDir: plugin.rootDir,
55
55
  priority: 150,
56
56
  scope: "global",
57
57
  managed: false,
58
58
  writable: false,
59
- skillFiles: plugin.skills.map((skill) => skill.filePath)
59
+ skillFiles: plugin.skills.map((skill) => skill.filePath),
60
+ skillAliases: plugin.layout?.dialect !== "portable" ? Object.fromEntries(plugin.skills.map((skill) => [skill.filePath, `${plugin.id}.${skill.name}`])) : void 0
60
61
  });
61
62
  diagnostics.push(...plugin.diagnostics.map((diagnostic) => ({
62
63
  type: "warning",
@@ -111,6 +111,7 @@ export interface SkillSourceDescriptor {
111
111
  writable: boolean;
112
112
  /** Validated portable plugin files; bypass recursive discovery. */
113
113
  skillFiles?: string[];
114
+ skillAliases?: Record<string, string>;
114
115
  }
115
116
  export type SkillOrigin = SkillSourceDescriptor;
116
117
  export interface SkillsLimitsConfig {
@@ -23,11 +23,15 @@ var WorkspaceRuntimeRegistry = class {
23
23
  /** Lazily construct and cache an agent-scoped runtime for a workspace. */
24
24
  getOrCreate(resolvedPath, requestedAgentId) {
25
25
  const cfg = this.getConfig();
26
- const runtimeKey = `${normalizeAgentId(requestedAgentId?.trim() || resolveAgentIdForWorkspacePath(resolvedPath))}\u0000${resolvedPath}`;
26
+ const agentId = normalizeAgentId(requestedAgentId?.trim() || resolveAgentIdForWorkspacePath(resolvedPath));
27
+ const runtimeKey = `${agentId}\u0000${resolvedPath}`;
27
28
  const existing = this.runtimes.get(runtimeKey);
28
29
  if (existing) return existing;
29
30
  const { memoryManager } = this.userContextRuntimes.getOrCreate(cfg);
30
- const skillManager = new SkillManager(resolvedPath, this.bundledSkillsDir, { isWorkspaceTrusted: () => this.isWorkspaceTrusted?.(resolvedPath) === true });
31
+ const skillManager = new SkillManager(resolvedPath, this.bundledSkillsDir, {
32
+ agentId,
33
+ isWorkspaceTrusted: () => this.isWorkspaceTrusted?.(resolvedPath) === true
34
+ });
31
35
  const rt = {
32
36
  skillManager,
33
37
  systemPromptBuilder: new SystemPromptBuilder({
@@ -4,8 +4,8 @@ import { init_src } from "../../packages/gateway-contract/src/index.js";
4
4
  import { getGatewayIdentityPublicKeyRaw, getOrCreateGatewayIdentity, init_gateway_identity_repository } from "../storage/sqlite/gateway-identity-repository.js";
5
5
  import { createDevicePairingSetup, init_device_pairing_repository } from "../storage/sqlite/device-pairing-repository.js";
6
6
  import { loadConfig } from "../config/loader.js";
7
- import { browserEnrollmentPublicKeyThumbprint } from "./enrollment.js";
8
7
  import { BROWSER_EXTENSION_ID, BROWSER_NATIVE_HOST_NAME } from "./extension-identity.js";
8
+ import { browserEnrollmentPublicKeyThumbprint } from "./enrollment.js";
9
9
  import os from "node:os";
10
10
  //#region src/browser/native-messaging-host.ts
11
11
  init_src();
@@ -4,10 +4,10 @@ import { createLogger } from "../../utils/logger/index.js";
4
4
  import { init_logger } from "../../utils/logger.js";
5
5
  import { init_write_file_atomic, writeTextAtomic } from "../../infra/write-file-atomic.js";
6
6
  import { init_paths, resolveBinDir, resolveConfigPath } from "../../config/paths.js";
7
- import { assertCacheDir } from "../cache-dir-policy.js";
7
+ import { resolvePackageRoot } from "../../infra/update-check.js";
8
8
  import { BROWSER_EXTENSION_ID, BROWSER_NATIVE_HOST_NAME } from "../extension-identity.js";
9
+ import { assertCacheDir } from "../cache-dir-policy.js";
9
10
  import "../native-messaging-host.js";
10
- import { resolvePackageRoot } from "../../infra/update-check.js";
11
11
  import { dirname, join } from "node:path";
12
12
  import { chmodSync, existsSync, mkdirSync, readFileSync, readdirSync, realpathSync, renameSync, rmSync, statSync, writeFileSync } from "node:fs";
13
13
  import { fileURLToPath } from "node:url";
@@ -7,8 +7,8 @@ import { compileAllowlist, evaluateAccess, hasBotMention, removeBotMention, reso
7
7
  import { renderMarkdownWithMarkers } from "../markdown/render.js";
8
8
  import { convertMarkdownTables } from "../markdown/tables.js";
9
9
  import { buildCodeSpanIndex, createInlineCodeState } from "../markdown/code-spans.js";
10
+ import { ChannelManager, createChannelManager } from "./manager.js";
10
11
  import "./format.js";
11
12
  import { MessagePipeline, createEnvelopeTimestampHandler, createFilterCommandsHandler, createFilterEmptyHandler, createFilterSelfHandler, createPipeline, standardPreflightHandlers, standardProcessHandlers } from "./pipeline.js";
12
- import { ChannelManager, createChannelManager } from "./manager.js";
13
13
  import { collectSetupWizardChannels } from "./setup-wizard-discovery.js";
14
14
  export { ChannelManager, MessagePipeline, buildCodeSpanIndex, chunkMarkdownIR, chunkText, collectSetupWizardChannels, compileAllowlist, convertMarkdownTables, createChannelManager, createEnvelopeTimestampHandler, createFilterCommandsHandler, createFilterEmptyHandler, createFilterSelfHandler, createInlineCodeState, createPipeline, evaluateAccess, findFenceSpanAt, getChannelPlugin, getChannelRegistryVersion, hasBotMention, isSafeFenceBreak, listChannelPlugins, markdownToIR, markdownToIRWithMeta, parseFenceSpans, parseFrontmatterBlock, removeBotMention, renderMarkdownWithMarkers, resolveAllowlistMatch, resolveAllowlistMatchSimple, resolveDmPolicy, resolveGroupPolicy, standardPreflightHandlers, standardProcessHandlers, syncChannelPluginsFromManager };
@@ -1,8 +1,8 @@
1
1
  import { createLogger } from "../utils/logger/index.js";
2
2
  import { init_logger } from "../utils/logger.js";
3
3
  import { ChannelHealthMonitor } from "./health-monitor.js";
4
- import { ChannelHeartbeatScheduler } from "./heartbeat-scheduler.js";
5
4
  import { ChannelPluginRegistry } from "./plugin-registry.js";
5
+ import { ChannelHeartbeatScheduler } from "./heartbeat-scheduler.js";
6
6
  import { ChannelOutboundSender } from "./outbound-sender.js";
7
7
  import { ChannelLifecycleSupervisor } from "./lifecycle-supervisor.js";
8
8
  //#region src/channels/manager.ts
@@ -1,8 +1,8 @@
1
1
  import { buildChannelCatalogForConfig } from "../../channels/catalog/channel-catalog-service.js";
2
2
  import { loadConfig, saveConfig } from "../../config/loader.js";
3
+ import { formatExamples, register } from "../registry.js";
3
4
  import { listChannelPairingState } from "../../channels/pairing/pairing-service.js";
4
5
  import { approveChannelPairingFromCli } from "../../channels/pairing/approve-cli.js";
5
- import { formatExamples, register } from "../registry.js";
6
6
  import { colors } from "../utils/colors.js";
7
7
  import { Command } from "commander";
8
8
  //#region src/cli/commands/channels.ts
@@ -1,8 +1,8 @@
1
1
  import { getStoreConnectorInstallPlan, installStoreConnector, listStoreConnectors } from "../../capabilities/store-connector.js";
2
2
  import { loadConfig, saveConfig } from "../../config/loader.js";
3
3
  import { register } from "../registry.js";
4
- import { confirm } from "@inquirer/prompts";
5
4
  import { Command } from "commander";
5
+ import { confirm } from "@inquirer/prompts";
6
6
  //#region src/cli/commands/connectors.ts
7
7
  function parsePairs(values, option) {
8
8
  const output = {};
@@ -53,7 +53,7 @@ async function checkDatabaseSchema(ctx) {
53
53
  id: "database-schema",
54
54
  label: "Database schema",
55
55
  status: "pass",
56
- message: `SQLite schema v${status.dbVersion} (current release v256).`,
56
+ message: `SQLite schema v${status.dbVersion} (current release v257).`,
57
57
  hints: []
58
58
  };
59
59
  }
@@ -1,24 +1,35 @@
1
+ import { getWorkspacePath } from "../../config/workspace-path-helpers.js";
2
+ import { pluginAuthorizations } from "../../extensions/agent-plugins/setup-contract.js";
3
+ import { PLUGIN_MANIFEST_PATHS } from "../../extensions/agent-plugins/formats.js";
4
+ import { pluginServerId } from "../../extensions/agent-plugins/validation.js";
5
+ import { isGitPluginSource } from "../../extensions/agent-plugins/source-catalog.js";
1
6
  import { AgentPluginStore } from "../../extensions/agent-plugins/store.js";
2
7
  import { loadConfig } from "../../config/loader.js";
3
8
  import { getContextWithOpts } from "../context.js";
4
9
  import { isAgentPluginArchive, withAgentPluginSource } from "../../extensions/agent-plugins/sources.js";
10
+ import { PluginSetupService } from "../../extensions/agent-plugins/setup.js";
5
11
  import { removePluginCredentials } from "../../extensions/agent-plugins/credentials.js";
6
12
  import { join, resolve } from "node:path";
7
13
  import { existsSync, readFileSync, statSync } from "node:fs";
14
+ import { readFile } from "node:fs/promises";
8
15
  import { confirm } from "@inquirer/prompts";
9
16
  //#region src/cli/commands/extension-agent-plugin.ts
10
17
  function isAgentPluginSource(source) {
11
- if (source.startsWith("https://")) return true;
18
+ if (source.startsWith("https://") || isGitPluginSource(source) || source.includes("#plugin=")) return true;
12
19
  const path = resolve(source);
13
20
  if (existsSync(join(path, "package.json"))) {
14
21
  if (JSON.parse(readFileSync(join(path, "package.json"), "utf8"))?.xopc?.extension) return false;
15
22
  }
16
- return existsSync(path) && (statSync(path).isFile() && /\.zip$/i.test(path) && statSync(path).size <= 50 * 1024 * 1024 && isAgentPluginArchive(readFileSync(path)) || existsSync(join(path, "plugin.json")) && !existsSync(join(path, "xopc.extension.json")));
23
+ return existsSync(path) && (statSync(path).isFile() && /\.zip$/i.test(path) && statSync(path).size <= 50 * 1024 * 1024 && isAgentPluginArchive(readFileSync(path)) || [
24
+ ...PLUGIN_MANIFEST_PATHS,
25
+ ".agents/plugins/marketplace.json",
26
+ ".claude-plugin/marketplace.json"
27
+ ].some((file) => existsSync(join(path, file))) && !existsSync(join(path, "xopc.extension.json")));
17
28
  }
18
29
  async function installAgentPluginFromCli(source, options) {
19
30
  const store = new AgentPluginStore();
20
31
  const cfg = loadConfig(getContextWithOpts().configPath);
21
- const plan = await withAgentPluginSource(source, cfg, (local) => store.inspect(local));
32
+ const plan = await withAgentPluginSource(source, cfg, (local, _p, _commit, importManifest) => store.inspect(local, source, importManifest));
22
33
  console.log(JSON.stringify({
23
34
  format: "agent-plugin",
24
35
  name: plan.manifest.name,
@@ -34,22 +45,96 @@ async function installAgentPluginFromCli(source, options) {
34
45
  default: false
35
46
  })) return;
36
47
  }
37
- const plugin = await withAgentPluginSource(source, cfg, (local, provenance) => store.install(local, {
48
+ const plugin = await withAgentPluginSource(source, cfg, (local, provenance, resolvedCommit, importManifest) => store.install(local, {
38
49
  reviewHash: plan.reviewHash,
39
50
  replace: options.force,
51
+ stage: options.force,
40
52
  expectedId: options.expectedId,
41
- sourceLabel: source.startsWith("https://") || source.startsWith("store:") ? source : resolve(source),
42
- provenance
53
+ sourceLabel: source,
54
+ provenance,
55
+ resolvedCommit,
56
+ importManifest
43
57
  }));
58
+ if (plugin.readiness !== "blocked") new PluginSetupService(store).create(plugin.id, "gateway-owner");
44
59
  console.log(`Installed plugin:${plugin.id} (${plugin.receipt.enabled ? "enabled" : "disabled"}).`);
60
+ if (plugin.readiness !== "blocked") console.log(`Continue with: xopc extensions setup plugin:${plugin.id} --prepare`);
45
61
  return plugin;
46
62
  }
47
63
  function addAgentPluginLifecycleCommands(command) {
64
+ command.command("setup").argument("<id>", "plugin:<id>").option("--prepare", "Prepare resources and check tools").option("--authorize <server>", "Authorize a plugin account or show native MCP sign-in instructions").option("--method <id>", "Choose one of the account authorization methods").option("--skip-auth", "Finish installation and authorize later in plugin details").option("--complete", "Finish setup and enable globally for all agents").option("--workspace <paths...>", "Restrict the plugin to these workspace paths").option("--config-file <path>", "Read typed user configuration from a JSON file").option("--allow-partial", "Enable available components after reviewing compatibility limits").option("--cancel", "Cancel preparation").action(async (raw, options) => {
65
+ const store = new AgentPluginStore(), setup = new PluginSetupService(store), id = raw.replace(/^plugin:/, "");
66
+ const cfg = loadConfig(getContextWithOpts().configPath), workspace = getWorkspacePath(cfg) || process.cwd(), owner = "gateway-owner";
67
+ let job = setup.create(id, owner);
68
+ const declaration = pluginAuthorizations((store.pending(id) ?? store.get(id)).manifest).find((value) => value.id === options.authorize);
69
+ const method = declaration?.methods.find((value) => value.id === (options.method ?? declaration.methods[0]?.id));
70
+ if (options.configFile) job = await setup.act(id, owner, {
71
+ action: "configure",
72
+ expectedRevision: job.revision,
73
+ values: JSON.parse(await readFile(options.configFile, "utf8")),
74
+ ...method?.type === "form" ? {
75
+ authorization: declaration.id,
76
+ method: method.id
77
+ } : {}
78
+ }, cfg, workspace);
79
+ if (options.prepare || declaration) job = await setup.act(id, owner, {
80
+ action: "prepare",
81
+ expectedRevision: job.revision
82
+ }, cfg, workspace);
83
+ if (options.authorize) if (declaration) {
84
+ if (!method) throw new Error("Unknown authorization method");
85
+ if (method.type !== "form") {
86
+ job = await setup.act(id, owner, {
87
+ action: "authorize",
88
+ expectedRevision: job.revision,
89
+ server: declaration.id,
90
+ method: method.id
91
+ }, cfg, workspace);
92
+ let lastUrl = "";
93
+ for (;;) {
94
+ const attempt = await setup.authorization(id, owner, declaration.id, cfg);
95
+ if (!attempt) throw new Error("Sign-in is unavailable. Retry authorization.");
96
+ const url = "challenge" in attempt ? attempt.challenge?.url : "authorizationUrl" in attempt ? attempt.authorizationUrl : void 0;
97
+ if (url && url !== lastUrl) {
98
+ console.log(`Complete sign-in: ${url}`);
99
+ lastUrl = url;
100
+ }
101
+ if (attempt.state === "connected") break;
102
+ if (["cancelled", "error"].includes(attempt.state)) throw new Error("Sign-in did not complete. Retry authorization.");
103
+ await new Promise((resolve) => setTimeout(resolve, 1e3));
104
+ }
105
+ job = await setup.act(id, owner, {
106
+ action: "prepare",
107
+ expectedRevision: job.revision
108
+ }, cfg, workspace);
109
+ } else if (!options.configFile) throw new Error("Provide credential fields with --config-file");
110
+ } else {
111
+ if (!job.connections.some((c) => c.name === options.authorize)) throw new Error("Unknown plugin MCP server");
112
+ console.log(`Sign in with: xopc mcp login ${pluginServerId(id, options.authorize)}`);
113
+ }
114
+ if (options.complete) job = await setup.act(id, owner, {
115
+ action: "complete",
116
+ expectedRevision: job.revision,
117
+ workspacePaths: options.workspace,
118
+ allowPartial: options.allowPartial === true
119
+ }, cfg, workspace);
120
+ if (options.skipAuth) job = await setup.act(id, owner, {
121
+ action: "defer",
122
+ expectedRevision: job.revision
123
+ }, cfg, workspace);
124
+ if (options.cancel) job = await setup.act(id, owner, {
125
+ action: "cancel",
126
+ expectedRevision: job.revision
127
+ }, cfg, workspace);
128
+ console.log(JSON.stringify(job, null, 2));
129
+ });
48
130
  command.command("rollback").argument("<id>", "plugin:<name>").action((raw) => {
49
131
  console.log(JSON.stringify(new AgentPluginStore().rollback(raw.replace(/^plugin:/, "")), null, 2));
50
132
  });
51
133
  for (const action of ["enable", "disable"]) command.command(action).argument("<id>", "plugin:<name>").action((raw) => {
52
- const plugin = new AgentPluginStore().setEnabled(raw.replace(/^plugin:/, ""), action === "enable");
134
+ const store = new AgentPluginStore(), id = raw.replace(/^plugin:/, "");
135
+ const job = new PluginSetupService(store).get(id, "gateway-owner");
136
+ if (action === "enable" && job && job.state !== "completed") throw new Error("Finish plugin setup before enabling");
137
+ const plugin = store.setEnabled(id, action === "enable");
53
138
  console.log(`${plugin.id}: ${action}d`);
54
139
  });
55
140
  command.command("remove").argument("<id>", "plugin:<name>").option("--remove-data", "Also remove persistent plugin data").option("--remove-credentials", "Also delete local credentials").action(async (raw, options) => {
@@ -16,8 +16,8 @@ import { existsSync, readFileSync, statSync } from "node:fs";
16
16
  import { execSync } from "node:child_process";
17
17
  import { createHash } from "node:crypto";
18
18
  import semver from "semver";
19
- import { confirm } from "@inquirer/prompts";
20
19
  import { Command } from "commander";
20
+ import { confirm } from "@inquirer/prompts";
21
21
  //#region src/cli/commands/extension-marketplace.ts
22
22
  init_paths();
23
23
  const MANIFEST = "xopc.extension.json";
@@ -224,7 +224,7 @@ async function installExtensionFromStoreWithLock(params) {
224
224
  }
225
225
  }
226
226
  function createExtensionInstallCommand() {
227
- return new Command("install").description("Install a native extension or portable Agent Plugin from an explicit source").argument("<target>", "store:<id>, npm:<package>, local directory, or Agent Plugin ZIP / HTTPS ZIP URL").option("-f, --force", "Replace an existing store or local extension with the same manifest id", false).option("-y, --yes", "Skip interactive install confirmation", false).action(async (target, opts) => {
227
+ return new Command("install").description("Install a native extension or Codex, Claude or portable Agent Plugin").argument("<target>", "store:<id>, npm:<package>, Git / marketplace source, directory or plugin ZIP").option("-f, --force", "Replace an existing store or local extension with the same manifest id", false).option("-y, --yes", "Skip interactive install confirmation", false).action(async (target, opts) => {
228
228
  if (isAgentPluginSource(target)) {
229
229
  await installAgentPluginFromCli(target, opts);
230
230
  return;
@@ -78,7 +78,7 @@ function createExtensionInspectCommand() {
78
78
  try {
79
79
  if (extensionId.startsWith("plugin:") || extensionId.startsWith("store:") || isAgentPluginSource(extensionId)) {
80
80
  const store = new AgentPluginStore();
81
- const result = extensionId.startsWith("plugin:") ? store.get(extensionId.slice(7)) : await withAgentPluginSource(extensionId, loadConfig(getContextWithOpts().configPath), (source) => store.inspect(source));
81
+ const result = extensionId.startsWith("plugin:") ? store.get(extensionId.slice(7)) : await withAgentPluginSource(extensionId, loadConfig(getContextWithOpts().configPath), (source, _p, _commit, importManifest) => store.inspect(source, extensionId, importManifest));
82
82
  if (!result) throw new Error("Plugin not installed");
83
83
  console.log(JSON.stringify(result, null, 2));
84
84
  return;
@@ -3,6 +3,7 @@ import { loadConfig } from "../../config/loader.js";
3
3
  import { register } from "../registry.js";
4
4
  import { createGatewayHttpClientFromConfig } from "../../mcp/gateway-http-client.js";
5
5
  import { createCapabilityMcpServer } from "../../mcp/capability-server.js";
6
+ import { resolveMcpSetupConfig } from "../../agent/mcp/effective-server.js";
6
7
  import { join } from "node:path";
7
8
  import { chmodSync, existsSync, readFileSync, writeFileSync } from "node:fs";
8
9
  import { main } from "@earendil-works/pi-coding-agent";
@@ -18,24 +19,25 @@ function createMcpCommand(ctx) {
18
19
  ]) {
19
20
  const native = command.command(action).description(`Use pi's native MCP ${action}`);
20
21
  if (action !== "list") native.argument("<server>", "Configured MCP server ID");
21
- if (action === "list") native.option("--json", "Print pi MCP diagnostics as JSON");
22
+ if (action === "list") native.option("--json", "Print pi MCP diagnostics as JSON").option("--agent <id>", "Include plugins bound to this agent");
22
23
  if (action === "login") native.option("--timeout <seconds>", "Browser sign-in timeout in seconds");
23
24
  native.action(async (serverOrOptions, loginOptions) => {
24
25
  const server = typeof serverOrOptions === "string" ? serverOrOptions : void 0;
25
26
  const options = typeof serverOrOptions === "string" ? loginOptions : serverOrOptions;
26
- const mcp = await prepareNativeMcpConfig(loadConfig(ctx.configPath), ctx.workspacePath || process.cwd());
27
+ const config = loadConfig(ctx.configPath);
28
+ const mcp = await prepareNativeMcpConfig(server ? resolveMcpSetupConfig(config, server) : config, ctx.workspacePath || process.cwd(), options?.agent);
27
29
  if (mcp.errors.length) throw new Error(mcp.errors.join("\n"));
28
30
  const path = join(getNativePiAgentDir(), "mcp.json");
29
31
  if (existsSync(path) && JSON.parse(readFileSync(path, "utf8")).xopcGenerated !== true) throw new Error("The pi directory contains a user-managed mcp.json. Use a dedicated PI_CODING_AGENT_DIR for xopc.");
30
32
  if (existsSync(path)) chmodSync(path, 384);
31
33
  writeFileSync(path, JSON.stringify({
32
34
  xopcGenerated: true,
33
- mcpServers: Object.fromEntries(mcp.servers.map((entry) => [entry.name, entry.config]))
35
+ mcpServers: Object.fromEntries(mcp.servers.filter((entry) => !server || entry.name === server).map((entry) => [mcp.credentialAliases?.[entry.name] ?? entry.name, entry.config]))
34
36
  }), { mode: 384 });
35
37
  await main([
36
38
  "mcp",
37
39
  action,
38
- ...server ? [server] : [],
40
+ ...server ? [mcp.credentialAliases?.[server] ?? server] : [],
39
41
  ...action === "list" && options?.json ? ["--json"] : [],
40
42
  ...action === "login" && loginOptions?.timeout ? ["--timeout", loginOptions.timeout] : []
41
43
  ]);
@@ -16,8 +16,8 @@ import { prepareUpdateGlobalDefaults } from "../../gateway/global-defaults-admin
16
16
  import { disconnectProvider } from "../../providers/provider-disconnect.js";
17
17
  import { colors } from "../utils/colors.js";
18
18
  import { runCliOAuthLogin } from "../utils/oauth-login.js";
19
- import { input } from "@inquirer/prompts";
20
19
  import { Command } from "commander";
20
+ import { input } from "@inquirer/prompts";
21
21
  //#region src/cli/commands/models.ts
22
22
  init_credentials();
23
23
  init_schema();
@@ -58,7 +58,7 @@ async function setupCloudCapabilities(config) {
58
58
  nextConfig = next;
59
59
  return { saved: true };
60
60
  }
61
- });
61
+ }, { enableAvailable: true });
62
62
  if (result.configured === false) throw new Error(result.error);
63
63
  return nextConfig;
64
64
  }
@@ -11,8 +11,8 @@ import { initWorkspace } from "../utils/init-workspace.js";
11
11
  import { setupModel } from "./onboard/model.js";
12
12
  import { getChannelConfigurators } from "./onboard/channels/registry.js";
13
13
  import { setupChannels } from "./onboard/channels/index.js";
14
- import { select } from "@inquirer/prompts";
15
14
  import { Command } from "commander";
15
+ import { select } from "@inquirer/prompts";
16
16
  //#region src/cli/commands/onboard.ts
17
17
  init_repository();
18
18
  init_schema();