@skaile/workspaces 0.35.0 → 0.36.0

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 (99) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/asset-manager/index.js +1 -1
  3. package/dist/bridge/drivers/claude-sdk.js +9 -5
  4. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  5. package/dist/bridge/drivers/codex.js +2 -2
  6. package/dist/bridge/drivers/continue.js +3 -3
  7. package/dist/bridge/drivers/echo.js +1 -1
  8. package/dist/bridge/drivers/gemini.js +4 -4
  9. package/dist/bridge/drivers/goose.js +3 -3
  10. package/dist/bridge/drivers/omp.js +2 -2
  11. package/dist/bridge/drivers/opencode.js +3 -3
  12. package/dist/bridge/drivers/qwen.js +4 -4
  13. package/dist/bridge/index.js +3 -3
  14. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  15. package/dist/bridge/src/error-classifier.d.ts +22 -0
  16. package/dist/bridge/src/error-classifier.d.ts.map +1 -1
  17. package/dist/bridge/src/index.d.ts +1 -1
  18. package/dist/bridge/src/index.d.ts.map +1 -1
  19. package/dist/bridge/src/types.d.ts +1 -1
  20. package/dist/bridge/src/types.d.ts.map +1 -1
  21. package/dist/{chunk-TV2OU2EZ.js → chunk-4ZACMAT3.js} +4 -4
  22. package/dist/{chunk-TV2OU2EZ.js.map → chunk-4ZACMAT3.js.map} +1 -1
  23. package/dist/{chunk-NSVAJWWQ.js → chunk-5IXCNMMU.js} +4 -4
  24. package/dist/{chunk-NSVAJWWQ.js.map → chunk-5IXCNMMU.js.map} +1 -1
  25. package/dist/{chunk-SKVUDDHE.js → chunk-FDLVPYSN.js} +253 -103
  26. package/dist/chunk-FDLVPYSN.js.map +1 -0
  27. package/dist/{chunk-NGJ6E344.js → chunk-GAH4YRCI.js} +20 -3
  28. package/dist/chunk-GAH4YRCI.js.map +1 -0
  29. package/dist/{chunk-NAMD4AIK.js → chunk-JNH6TTIO.js} +3 -3
  30. package/dist/{chunk-NAMD4AIK.js.map → chunk-JNH6TTIO.js.map} +1 -1
  31. package/dist/{chunk-CIFTUSBV.js → chunk-KM6DCR7A.js} +2 -2
  32. package/dist/{chunk-CIFTUSBV.js.map → chunk-KM6DCR7A.js.map} +1 -1
  33. package/dist/{chunk-6422UOMQ.js → chunk-LY5O73Q2.js} +3 -3
  34. package/dist/{chunk-6422UOMQ.js.map → chunk-LY5O73Q2.js.map} +1 -1
  35. package/dist/{chunk-52HINMW4.js → chunk-MCQ4TJ3P.js} +21 -9
  36. package/dist/chunk-MCQ4TJ3P.js.map +1 -0
  37. package/dist/{chunk-67AXL4OK.js → chunk-U3TV7SRR.js} +4 -4
  38. package/dist/{chunk-67AXL4OK.js.map → chunk-U3TV7SRR.js.map} +1 -1
  39. package/dist/{chunk-ZGJE4ZDP.js → chunk-YPRW2ROJ.js} +2 -2
  40. package/dist/{chunk-ZGJE4ZDP.js.map → chunk-YPRW2ROJ.js.map} +1 -1
  41. package/dist/{chunk-7B3CL5JT.js → chunk-ZE5WYJVU.js} +2 -2
  42. package/dist/{chunk-7B3CL5JT.js.map → chunk-ZE5WYJVU.js.map} +1 -1
  43. package/dist/cli/index.js +10 -10
  44. package/dist/connectors/config.js +1 -1
  45. package/dist/connectors/index.js +2 -2
  46. package/dist/connectors/src/secrets.d.ts +14 -14
  47. package/dist/connectors/src/secrets.d.ts.map +1 -1
  48. package/dist/factory-assets/connectors/deploy.js +2 -2
  49. package/dist/factory-assets/connectors/devserver.js +2 -2
  50. package/dist/factory-assets/connectors/flow/adapter.js +2 -2
  51. package/dist/factory-assets/connectors/flow/run-flow.js +3 -3
  52. package/dist/factory-assets/connectors/flow.js +2 -2
  53. package/dist/factory-assets/connectors/git.js +2 -2
  54. package/dist/factory-assets/connectors/gmail.js +2 -2
  55. package/dist/factory-assets/connectors/googledrive.js +2 -2
  56. package/dist/factory-assets/connectors/local.js +2 -2
  57. package/dist/factory-assets/connectors/mattermost.js +2 -2
  58. package/dist/factory-assets/connectors/memory.js +2 -2
  59. package/dist/factory-assets/connectors/minio.js +2 -2
  60. package/dist/factory-assets/connectors/postgres.js +2 -2
  61. package/dist/factory-assets/connectors/s3.js +2 -2
  62. package/dist/factory-assets/connectors/sharepoint.js +2 -2
  63. package/dist/factory-assets/connectors/sqlite.js +2 -2
  64. package/dist/factory-assets/connectors/static-server.js +2 -2
  65. package/dist/factory-assets/connectors/tunnel.js +2 -2
  66. package/dist/factory-assets/connectors/webdav.js +2 -2
  67. package/dist/factory-assets/connectors/xstate-store.js +2 -2
  68. package/dist/factory-assets/connectors/xstate.js +2 -2
  69. package/dist/runner/index.js +7 -7
  70. package/dist/runner/src/external-mcp.d.ts +24 -1
  71. package/dist/runner/src/external-mcp.d.ts.map +1 -1
  72. package/dist/runner/src/mcp-runtime-handlers.d.ts +42 -0
  73. package/dist/runner/src/mcp-runtime-handlers.d.ts.map +1 -0
  74. package/dist/runner/src/resources.d.ts +12 -0
  75. package/dist/runner/src/resources.d.ts.map +1 -1
  76. package/dist/runner/src/runner-capabilities.d.ts +33 -0
  77. package/dist/runner/src/runner-capabilities.d.ts.map +1 -1
  78. package/dist/runner/src/serve.d.ts +18 -1
  79. package/dist/runner/src/serve.d.ts.map +1 -1
  80. package/dist/runner/src/session-builder.d.ts +8 -0
  81. package/dist/runner/src/session-builder.d.ts.map +1 -1
  82. package/dist/runner/src/session-resource-handlers.d.ts +5 -1
  83. package/dist/runner/src/session-resource-handlers.d.ts.map +1 -1
  84. package/dist/sdk/asset-manager.js +1 -1
  85. package/dist/sdk/bridge.js +3 -3
  86. package/dist/sdk/index.js +7 -7
  87. package/dist/sdk/runner.js +7 -7
  88. package/dist/{setup-BSDHVMR6.js → setup-QQ3SNNWP.js} +5 -5
  89. package/dist/{setup-BSDHVMR6.js.map → setup-QQ3SNNWP.js.map} +1 -1
  90. package/dist/tui/index.js +7 -7
  91. package/dist/types/src/events.d.ts +22 -4
  92. package/dist/types/src/events.d.ts.map +1 -1
  93. package/dist/types/src/index.d.ts +1 -1
  94. package/dist/types/src/index.d.ts.map +1 -1
  95. package/dist/workspace-plugin/index.js +1 -1
  96. package/package.json +1 -1
  97. package/dist/chunk-52HINMW4.js.map +0 -1
  98. package/dist/chunk-NGJ6E344.js.map +0 -1
  99. package/dist/chunk-SKVUDDHE.js.map +0 -1
@@ -1,13 +1,13 @@
1
- import { WorkspacePlugin } from './chunk-ZGJE4ZDP.js';
1
+ import { WorkspacePlugin } from './chunk-YPRW2ROJ.js';
2
2
  import { WebSocketServerTransport } from './chunk-WQ7DE5UC.js';
3
3
  import { assembleSystemPrompt, buildCapabilitiesPromptSection } from './chunk-W3UDISS2.js';
4
4
  import { PROTOCOL_VERSION } from './chunk-TDSRLMDB.js';
5
- import { EventNormalizer } from './chunk-NSVAJWWQ.js';
6
- import { classifyClaudeSdkError } from './chunk-NGJ6E344.js';
7
- import { createDriver } from './chunk-CIFTUSBV.js';
5
+ import { EventNormalizer } from './chunk-5IXCNMMU.js';
6
+ import { classifyClaudeSdkError } from './chunk-GAH4YRCI.js';
7
+ import { createDriver } from './chunk-KM6DCR7A.js';
8
8
  import { deployCatalogEntry, undeployCatalogEntry } from './chunk-LV2HPH3C.js';
9
- import { registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, ConnectorStartupError, buildSdkConnectorTools } from './chunk-NAMD4AIK.js';
10
- import { loadConnectorDeclarations, PreMintedSecretProvider, InMemorySecretProvider } from './chunk-52HINMW4.js';
9
+ import { registerBuiltinConnectors, buildConnectorPromptSection, findMissingPackages, installNpmPackages, ConnectorManager, ConnectorStartupError, buildSdkConnectorTools } from './chunk-JNH6TTIO.js';
10
+ import { loadConnectorDeclarations, SecretProviderChain, PreMintedSecretProvider, InMemorySecretProvider } from './chunk-MCQ4TJ3P.js';
11
11
  import { renderStimulusPrompt, buildOrchestratorPrompt } from './chunk-DEYYRFQU.js';
12
12
  import { resolveSettings, resolveApiKey, providerEnvKey } from './chunk-2Q6OY3SU.js';
13
13
  import { resolveRuntimeAssets } from './chunk-5DPQ766L.js';
@@ -1070,7 +1070,7 @@ var ExternalMcpManager = class {
1070
1070
  async start(declarations) {
1071
1071
  for (const decl of declarations) {
1072
1072
  try {
1073
- await this.startServer(decl);
1073
+ await this.addServer(decl);
1074
1074
  } catch (err) {
1075
1075
  this.log.error("MCP server spawn failed; skipping", err, {
1076
1076
  id: decl.id,
@@ -1079,7 +1079,15 @@ var ExternalMcpManager = class {
1079
1079
  }
1080
1080
  }
1081
1081
  }
1082
- async startServer(decl) {
1082
+ /**
1083
+ * Connect one MCP server and register its tools into the capability registry.
1084
+ * Returns the server id and the registered tool capability names.
1085
+ * Throws if the id is already registered or if connect/listTools fails.
1086
+ */
1087
+ async addServer(decl) {
1088
+ if (this.servers.some((s) => s.id === decl.id)) {
1089
+ throw new Error(`MCP server '${decl.id}' is already registered`);
1090
+ }
1083
1091
  const client = await this.connectWithReauth(decl);
1084
1092
  const server = { id: decl.id, decl, client, toolNames: [] };
1085
1093
  const toolNames = [];
@@ -1106,6 +1114,39 @@ var ExternalMcpManager = class {
1106
1114
  toolCount: toolNames.length,
1107
1115
  tools: toolNames
1108
1116
  });
1117
+ return { id: decl.id, toolNames };
1118
+ }
1119
+ /**
1120
+ * Deregister a running MCP server's tools and close its client.
1121
+ * No-op when the id is not found.
1122
+ *
1123
+ * Drains any in-flight reauth first: a doReauthAndReconnect resolving after
1124
+ * splice would swap server.client to a freshly-connected client that nothing
1125
+ * then closes, leaking the transport/subprocess.
1126
+ */
1127
+ async removeServer(id) {
1128
+ const idx = this.servers.findIndex((s) => s.id === id);
1129
+ if (idx === -1) return;
1130
+ const server = this.servers[idx];
1131
+ if (server.reauthInFlight) await server.reauthInFlight.catch(() => {
1132
+ });
1133
+ this.servers.splice(idx, 1);
1134
+ for (const name of server.toolNames) {
1135
+ this.registry.deregister(name);
1136
+ }
1137
+ try {
1138
+ await server.client.close();
1139
+ } catch {
1140
+ }
1141
+ this.log.info("MCP server removed (runner-managed)", { id });
1142
+ }
1143
+ /** Summary of every currently-connected MCP server. */
1144
+ listServers() {
1145
+ return this.servers.map((s) => ({
1146
+ id: s.id,
1147
+ transport: s.decl.transport ?? "stdio",
1148
+ toolCount: s.toolNames.length
1149
+ }));
1109
1150
  }
1110
1151
  /**
1111
1152
  * Connect, re-minting once on an initial-connect 401: the provisioned bearer
@@ -1252,7 +1293,11 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1252
1293
  dispose: async () => {
1253
1294
  },
1254
1295
  startWatching: () => {
1255
- }
1296
+ },
1297
+ getOrCreateExternalMcpManager: () => {
1298
+ throw new Error("external MCP manager unavailable \u2014 no capability registry (CLI/flow mode)");
1299
+ },
1300
+ getExternalMcpManager: () => null
1256
1301
  };
1257
1302
  try {
1258
1303
  registerBuiltinConnectors();
@@ -1280,6 +1325,26 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1280
1325
  let mcpServers;
1281
1326
  let workspacePluginToShutdown = null;
1282
1327
  let externalMcpManager = null;
1328
+ const mcpSecretChain = preMintedSecrets ? new SecretProviderChain(
1329
+ [preMintedSecrets, secretProvider].filter(
1330
+ Boolean
1331
+ )
1332
+ ) : secretProvider;
1333
+ const getOrCreateExternalMcpManager = () => {
1334
+ if (!capabilityRegistry) {
1335
+ throw new Error(
1336
+ "external MCP manager unavailable \u2014 no capability registry (CLI/flow mode)"
1337
+ );
1338
+ }
1339
+ if (!externalMcpManager) {
1340
+ externalMcpManager = createExternalMcpManager(
1341
+ capabilityRegistry,
1342
+ mcpSecretChain,
1343
+ sessionMeta
1344
+ );
1345
+ }
1346
+ return externalMcpManager;
1347
+ };
1283
1348
  if (driverType === "claude-sdk") {
1284
1349
  const inProcess = await buildInProcessMcpServers(
1285
1350
  resourceManager,
@@ -1294,7 +1359,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1294
1359
  externalMcpManager = await startExternalMcpServers(
1295
1360
  capabilityRegistry,
1296
1361
  projectDir,
1297
- secretProvider,
1362
+ mcpSecretChain,
1298
1363
  sessionMeta
1299
1364
  );
1300
1365
  } else if (driverType === "claude-sdk") {
@@ -1305,7 +1370,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1305
1370
  sessionMeta
1306
1371
  );
1307
1372
  }
1308
- if (!resourceManager && driverType !== "claude-sdk" && !externalMcpManager?.hasServers())
1373
+ if (!resourceManager && driverType !== "claude-sdk" && !externalMcpManager?.hasServers() && !capabilityRegistry)
1309
1374
  return noopResult;
1310
1375
  const startWatching = () => {
1311
1376
  if (resourceManager && watch?.onFileChanged) {
@@ -1348,7 +1413,9 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1348
1413
  mcpServers,
1349
1414
  runtimeAssets,
1350
1415
  dispose,
1351
- startWatching
1416
+ startWatching,
1417
+ getOrCreateExternalMcpManager,
1418
+ getExternalMcpManager: () => externalMcpManager
1352
1419
  };
1353
1420
  } catch {
1354
1421
  return noopResult;
@@ -1433,15 +1500,18 @@ async function buildInProcessMcpServers(resourceManager, projectDir, driverType,
1433
1500
  async function startExternalMcpServers(capabilityRegistry, projectDir, secretProvider, sessionMeta) {
1434
1501
  const resolvedDecls = resolveExternalMcpDeclarations(projectDir, sessionMeta?.sessionId);
1435
1502
  if (resolvedDecls.length === 0) return null;
1436
- const externalMcpManager = new ExternalMcpManager(
1503
+ const mgr = createExternalMcpManager(capabilityRegistry, secretProvider, sessionMeta);
1504
+ await mgr.start(resolvedDecls);
1505
+ return mgr;
1506
+ }
1507
+ function createExternalMcpManager(capabilityRegistry, secretProvider, sessionMeta) {
1508
+ return new ExternalMcpManager(
1437
1509
  capabilityRegistry,
1438
1510
  secretProvider,
1439
1511
  sessionMeta?.sessionId,
1440
1512
  void 0,
1441
1513
  buildMcpReauthorizer(capabilityRegistry, secretProvider, sessionMeta?.sessionId)
1442
1514
  );
1443
- await externalMcpManager.start(resolvedDecls);
1444
- return externalMcpManager;
1445
1515
  }
1446
1516
  function mcpAuthSecretKey(id) {
1447
1517
  return `MCP__${id.replace(/[^A-Za-z0-9_]/g, "_")}__AUTH`;
@@ -1563,7 +1633,9 @@ async function createAgentSession(config) {
1563
1633
  mcpServers,
1564
1634
  runtimeAssets,
1565
1635
  dispose,
1566
- startWatching
1636
+ startWatching,
1637
+ getOrCreateExternalMcpManager,
1638
+ getExternalMcpManager
1567
1639
  } = await buildAgentResources(
1568
1640
  projectDir,
1569
1641
  driverType,
@@ -1650,6 +1722,8 @@ async function createAgentSession(config) {
1650
1722
  model,
1651
1723
  dispose,
1652
1724
  startWatching,
1725
+ getOrCreateExternalMcpManager,
1726
+ getExternalMcpManager,
1653
1727
  telemetry,
1654
1728
  systemPromptSections
1655
1729
  };
@@ -2867,6 +2941,111 @@ function buildLifecycleHandler(deps) {
2867
2941
  return { ok: true };
2868
2942
  };
2869
2943
  }
2944
+
2945
+ // runner/src/session-resource-handlers.ts
2946
+ function asDeclaration(declaration) {
2947
+ if (declaration !== null && typeof declaration === "object" && typeof declaration.id === "string" && typeof declaration.driver === "string") {
2948
+ return declaration;
2949
+ }
2950
+ return null;
2951
+ }
2952
+ function toPreMinted(token) {
2953
+ return { ok: true, token: token.token, expiresAt: token.expiresAt ?? null };
2954
+ }
2955
+ function buildSessionResourceHandlers(deps) {
2956
+ const { getResourceManager, getPreMintedSecrets, emitResourcesAvailable, log } = deps;
2957
+ async function add(kind, input) {
2958
+ const rm = getResourceManager();
2959
+ if (!rm) return { ok: false, code: "no_session", message: "session resources not ready" };
2960
+ const decl = asDeclaration(input.declaration);
2961
+ if (!decl) {
2962
+ return { ok: false, code: "invalid_declaration", message: "declaration missing id/driver" };
2963
+ }
2964
+ if (input.preMintedToken) {
2965
+ getPreMintedSecrets()?.set(kind, decl.id, toPreMinted(input.preMintedToken));
2966
+ }
2967
+ try {
2968
+ await rm.connect(decl);
2969
+ } catch (err) {
2970
+ const message = err instanceof Error ? err.message : String(err);
2971
+ log(`[session-resource] runner.add_${kind} failed for ${decl.id}: ${message}`);
2972
+ return { ok: false, code: "connect_failed", message };
2973
+ }
2974
+ emitResourcesAvailable();
2975
+ log(`[session-resource] runner.add_${kind} connected ${decl.id}`);
2976
+ return { ok: true, id: decl.id };
2977
+ }
2978
+ return {
2979
+ addConnector: (input) => add("connector", input),
2980
+ addMount: (input) => add("mount", input),
2981
+ removeResource: async (input) => {
2982
+ const rm = getResourceManager();
2983
+ if (!rm) return { ok: false, code: "no_session", message: "session resources not ready" };
2984
+ if (!rm.has(input.id)) {
2985
+ return { ok: false, code: "not_found", message: `no resource with id ${input.id}` };
2986
+ }
2987
+ try {
2988
+ await rm.disconnect(input.id);
2989
+ } catch (err) {
2990
+ const message = err instanceof Error ? err.message : String(err);
2991
+ log(`[session-resource] runner.remove_resource failed for ${input.id}: ${message}`);
2992
+ return { ok: false, code: "disconnect_failed", message };
2993
+ }
2994
+ const ps = getPreMintedSecrets();
2995
+ ps?.unset("connector", input.id);
2996
+ ps?.unset("mount", input.id);
2997
+ emitResourcesAvailable();
2998
+ log(`[session-resource] runner.remove_resource removed ${input.id}`);
2999
+ return { ok: true };
3000
+ },
3001
+ updateCredential: async (input) => {
3002
+ const ps = getPreMintedSecrets();
3003
+ if (!ps) return { ok: false, code: "no_session", message: "session resources not ready" };
3004
+ const rm = getResourceManager();
3005
+ if (rm && !rm.has(input.id)) {
3006
+ return { ok: false, code: "not_found", message: `no resource with id ${input.id}` };
3007
+ }
3008
+ ps.set(input.kind, input.id, input.mint);
3009
+ log(`[session-resource] runner.update_credential staged ${input.kind}:${input.id}`);
3010
+ return { ok: true };
3011
+ }
3012
+ };
3013
+ }
3014
+
3015
+ // runner/src/mcp-runtime-handlers.ts
3016
+ function buildMcpRuntimeHandlers(deps) {
3017
+ return {
3018
+ addMcpServer: async (input) => {
3019
+ const decl = input.declaration;
3020
+ if (!decl?.id) {
3021
+ return { ok: false, code: "invalid_declaration", message: "declaration.id is required" };
3022
+ }
3023
+ const mgr = deps.getOrCreateMcpManager();
3024
+ if (!mgr) return { ok: false, code: "no_session", message: "session resources not ready" };
3025
+ if (input.preMintedToken) {
3026
+ deps.getPreMintedSecrets()?.set("mcp", decl.id, toPreMinted(input.preMintedToken));
3027
+ }
3028
+ try {
3029
+ const { toolNames } = await mgr.addServer(decl);
3030
+ deps.emitResourcesAvailable();
3031
+ deps.log(
3032
+ `[mcp-runtime] runner.add_mcp_server connected ${decl.id} (${toolNames.length} tools)`
3033
+ );
3034
+ return {
3035
+ ok: true,
3036
+ id: decl.id,
3037
+ live: deps.driverPicksUpToolsLive(),
3038
+ toolCount: toolNames.length
3039
+ };
3040
+ } catch (err) {
3041
+ deps.getPreMintedSecrets()?.unset("mcp", decl.id);
3042
+ const message = err instanceof Error ? err.message : String(err);
3043
+ const code = message.includes("already registered") ? "mcp_already_registered" : "mcp_connect_failed";
3044
+ return { ok: false, code, message };
3045
+ }
3046
+ }
3047
+ };
3048
+ }
2870
3049
  function parseFleetHealthBody(body) {
2871
3050
  return body.trim().toLowerCase() === "healthy" ? "healthy" : "error";
2872
3051
  }
@@ -2958,6 +3137,10 @@ var connectorDeclarationInput = z5.strictObject({
2958
3137
  declaration: requiredUnknown,
2959
3138
  preMintedToken: preMintedTokenSchema
2960
3139
  });
3140
+ var addMcpServerInputSchema = z5.strictObject({
3141
+ declaration: requiredUnknown,
3142
+ preMintedToken: preMintedTokenSchema
3143
+ });
2961
3144
  var removeResourceInput = z5.strictObject({
2962
3145
  id: z5.string()
2963
3146
  });
@@ -3018,6 +3201,24 @@ function buildRunnerCapabilities(handlers) {
3018
3201
  });
3019
3202
  }
3020
3203
  }),
3204
+ // TODO(mcp-detach): no runner.remove_mcp_server yet — live MCP detach + mcp: credential cleanup deferred with the attach-by-ref rework.
3205
+ defineCapability({
3206
+ name: "runner.add_mcp_server",
3207
+ displayName: "Add MCP server",
3208
+ description: "Live-attach a remote MCP server to the running session. Used by the platform to connect additional MCP tool servers mid-session.",
3209
+ side: "agent",
3210
+ origin: RUNNER_CAP_ORIGIN,
3211
+ audience: ["runtime"],
3212
+ kind: "effect",
3213
+ input: addMcpServerInputSchema,
3214
+ handler: async (input) => {
3215
+ if (!handlers.addMcpServer) return notImplemented("runner.add_mcp_server");
3216
+ return handlers.addMcpServer({
3217
+ declaration: input.declaration,
3218
+ preMintedToken: input.preMintedToken
3219
+ });
3220
+ }
3221
+ }),
3021
3222
  defineCapability({
3022
3223
  name: "runner.remove_resource",
3023
3224
  displayName: "Remove resource",
@@ -3157,76 +3358,6 @@ function extractClaudeAiOauthExpiresAt(json) {
3157
3358
  return null;
3158
3359
  }
3159
3360
 
3160
- // runner/src/session-resource-handlers.ts
3161
- function asDeclaration(declaration) {
3162
- if (declaration !== null && typeof declaration === "object" && typeof declaration.id === "string" && typeof declaration.driver === "string") {
3163
- return declaration;
3164
- }
3165
- return null;
3166
- }
3167
- function toPreMinted(token) {
3168
- return { ok: true, token: token.token, expiresAt: token.expiresAt ?? null };
3169
- }
3170
- function buildSessionResourceHandlers(deps) {
3171
- const { getResourceManager, getPreMintedSecrets, emitResourcesAvailable, log } = deps;
3172
- async function add(kind, input) {
3173
- const rm = getResourceManager();
3174
- if (!rm) return { ok: false, code: "no_session", message: "session resources not ready" };
3175
- const decl = asDeclaration(input.declaration);
3176
- if (!decl) {
3177
- return { ok: false, code: "invalid_declaration", message: "declaration missing id/driver" };
3178
- }
3179
- if (input.preMintedToken) {
3180
- getPreMintedSecrets()?.set(kind, decl.id, toPreMinted(input.preMintedToken));
3181
- }
3182
- try {
3183
- await rm.connect(decl);
3184
- } catch (err) {
3185
- const message = err instanceof Error ? err.message : String(err);
3186
- log(`[session-resource] runner.add_${kind} failed for ${decl.id}: ${message}`);
3187
- return { ok: false, code: "connect_failed", message };
3188
- }
3189
- emitResourcesAvailable();
3190
- log(`[session-resource] runner.add_${kind} connected ${decl.id}`);
3191
- return { ok: true, id: decl.id };
3192
- }
3193
- return {
3194
- addConnector: (input) => add("connector", input),
3195
- addMount: (input) => add("mount", input),
3196
- removeResource: async (input) => {
3197
- const rm = getResourceManager();
3198
- if (!rm) return { ok: false, code: "no_session", message: "session resources not ready" };
3199
- if (!rm.has(input.id)) {
3200
- return { ok: false, code: "not_found", message: `no resource with id ${input.id}` };
3201
- }
3202
- try {
3203
- await rm.disconnect(input.id);
3204
- } catch (err) {
3205
- const message = err instanceof Error ? err.message : String(err);
3206
- log(`[session-resource] runner.remove_resource failed for ${input.id}: ${message}`);
3207
- return { ok: false, code: "disconnect_failed", message };
3208
- }
3209
- const ps = getPreMintedSecrets();
3210
- ps?.unset("connector", input.id);
3211
- ps?.unset("mount", input.id);
3212
- emitResourcesAvailable();
3213
- log(`[session-resource] runner.remove_resource removed ${input.id}`);
3214
- return { ok: true };
3215
- },
3216
- updateCredential: async (input) => {
3217
- const ps = getPreMintedSecrets();
3218
- if (!ps) return { ok: false, code: "no_session", message: "session resources not ready" };
3219
- const rm = getResourceManager();
3220
- if (rm && !rm.has(input.id)) {
3221
- return { ok: false, code: "not_found", message: `no resource with id ${input.id}` };
3222
- }
3223
- ps.set(input.kind, input.id, input.mint);
3224
- log(`[session-resource] runner.update_credential staged ${input.kind}:${input.id}`);
3225
- return { ok: true };
3226
- }
3227
- };
3228
- }
3229
-
3230
3361
  // runner/src/session-stimulus.ts
3231
3362
  var DEFAULT_COALESCE_MS = 50;
3232
3363
  function createSessionStimulusBus(opts) {
@@ -3371,6 +3502,11 @@ function splitConnectorsForWire(manager) {
3371
3502
  }
3372
3503
  return { mounts, connectors };
3373
3504
  }
3505
+ function buildResourcesAvailablePayload(manager, mcpManager, driverLive) {
3506
+ const { mounts, connectors } = splitConnectorsForWire(manager);
3507
+ const mcp_servers = (mcpManager?.listServers() ?? []).map((s) => ({ ...s, live: driverLive }));
3508
+ return { type: "resources_available", mounts, connectors, mcp_servers };
3509
+ }
3374
3510
  function findAiAssetsRoot(startDir) {
3375
3511
  let dir = startDir;
3376
3512
  for (let i = 0; i < 6; i++) {
@@ -4137,10 +4273,15 @@ async function startAgentServer(opts) {
4137
4273
  driver = agentSession.driver;
4138
4274
  rebuildCompactionOrchestrator();
4139
4275
  registerSessionComposition(agentSession);
4140
- sendEvent({
4141
- type: "resources_available",
4142
- ...splitConnectorsForWire(resourceManager)
4143
- });
4276
+ const driverPicksUpToolsLive = () => agentSession?.driverType !== "claude-sdk";
4277
+ const emitResourcesAvailable = () => sendEvent(
4278
+ buildResourcesAvailablePayload(
4279
+ resourceManager,
4280
+ agentSession?.getExternalMcpManager(),
4281
+ driverPicksUpToolsLive()
4282
+ )
4283
+ );
4284
+ emitResourcesAvailable();
4144
4285
  agentSession.startWatching();
4145
4286
  capabilityRegistry.setRemoteInvoker(remoteCapabilityInvoker);
4146
4287
  const runnerCaps = buildRunnerCapabilities({
@@ -4150,12 +4291,16 @@ async function startAgentServer(opts) {
4150
4291
  ...buildSessionResourceHandlers({
4151
4292
  getResourceManager: () => resourceManager,
4152
4293
  getPreMintedSecrets: () => preMintedSecrets,
4153
- emitResourcesAvailable: () => {
4154
- sendEvent({
4155
- type: "resources_available",
4156
- ...splitConnectorsForWire(resourceManager)
4157
- });
4158
- },
4294
+ emitResourcesAvailable,
4295
+ log
4296
+ }),
4297
+ // runner.add_mcp_server — wired to the live session's lazily-created
4298
+ // ExternalMcpManager + PreMintedSecretProvider.
4299
+ ...buildMcpRuntimeHandlers({
4300
+ getOrCreateMcpManager: () => agentSession?.getOrCreateExternalMcpManager() ?? null,
4301
+ getPreMintedSecrets: () => preMintedSecrets ?? null,
4302
+ driverPicksUpToolsLive,
4303
+ emitResourcesAvailable,
4159
4304
  log
4160
4305
  }),
4161
4306
  // setLogLevel left undefined (the cap self-falls-back to getLogStore);
@@ -4856,12 +5001,17 @@ async function startAgentServer(opts) {
4856
5001
  agentSession.startWatching();
4857
5002
  }
4858
5003
  function emitAvailabilityOnConnect() {
4859
- if (resourceManager) {
4860
- const wire = splitConnectorsForWire(resourceManager);
5004
+ if (resourceManager || agentSession?.getExternalMcpManager()) {
5005
+ const driverLive = agentSession?.driverType !== "claude-sdk";
5006
+ const payload = buildResourcesAvailablePayload(
5007
+ resourceManager,
5008
+ agentSession?.getExternalMcpManager() ?? null,
5009
+ driverLive
5010
+ );
4861
5011
  log(
4862
- `[serve] emitting resources_available: ${wire.mounts.length} mount(s), ${wire.connectors.length} connector(s)`
5012
+ `[serve] emitting resources_available: ${payload.mounts.length} mount(s), ${payload.connectors.length} connector(s)`
4863
5013
  );
4864
- sendEvent({ type: "resources_available", ...wire });
5014
+ sendEvent(payload);
4865
5015
  }
4866
5016
  const commands = driver?.getSlashCommands?.() ?? [];
4867
5017
  if (commands.length > 0) {
@@ -5044,6 +5194,6 @@ function touchSession(state) {
5044
5194
  return { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
5045
5195
  }
5046
5196
 
5047
- export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, MarkdownStreamer, PreInitRingSink, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildContextSection, buildEnvironmentSection, builtinCapabilities, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, createAgentSession, createSessionStimulusBus, defineCapability, deleteSession, dispatchRunnerCapabilityInvocation, emitSystemPromptComposed, ensureGitConfigInclude, extractClaudeAiOauthExpiresAt, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, installPreInitRingSink, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadSession, loadSessionById, newSession, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityCallTimeoutMs, resolveCapabilityResult, resolveComposition, resolveMixin, runAgentChat, saveSession, setCurrentSession, startAgentServer, touchSession, writeClaudeCodeCredentialsFile };
5048
- //# sourceMappingURL=chunk-SKVUDDHE.js.map
5049
- //# sourceMappingURL=chunk-SKVUDDHE.js.map
5197
+ export { CLAUDE_CODE_CREDENTIALS_KEY, COMPILE_MANIFEST_FILENAME, CapabilityRegistry, DEFAULT_CAPABILITY_CALL_TIMEOUT_MS, DEFAULT_COALESCE_MS, MarkdownStreamer, PreInitRingSink, agentDefinitionExists, bootstrapCapabilityRegistry, bootstrapRunnerLogStore, buildAgentResources, buildClientCapabilityHandler, buildContextSection, buildEnvironmentSection, buildResourcesAvailablePayload, builtinCapabilities, clearPreInitRingSink, clearSession, compileComposition, computeCapabilitySignature, createAgentSession, createSessionStimulusBus, defineCapability, deleteSession, dispatchRunnerCapabilityInvocation, emitSystemPromptComposed, ensureGitConfigInclude, extractClaudeAiOauthExpiresAt, getPreInitRingSink, handleMountResourceRequest, handleResourceRequest, installPreInitRingSink, listSessions, loadAgentManifest, loadCompileManifest, loadCompileManifestFromDir, loadSession, loadSessionById, mcpAuthSecretKey, newSession, registerCompositionCapabilities, rejectCapabilityOnApprovalDeny, resetRunnerLogStore, resolveAgentComposition, resolveAgentMixins, resolveBinding, resolveCapabilityCallTimeoutMs, resolveCapabilityResult, resolveComposition, resolveMixin, runAgentChat, saveSession, setCurrentSession, startAgentServer, touchSession, writeClaudeCodeCredentialsFile };
5198
+ //# sourceMappingURL=chunk-FDLVPYSN.js.map
5199
+ //# sourceMappingURL=chunk-FDLVPYSN.js.map