@skaile/workspaces 0.35.0 → 0.37.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 (146) hide show
  1. package/CHANGELOG.md +18 -0
  2. package/dist/{asset-feeds-PCLTE2W5.js → asset-feeds-W6JNAGNQ.js} +7 -7
  3. package/dist/{asset-feeds-PCLTE2W5.js.map → asset-feeds-W6JNAGNQ.js.map} +1 -1
  4. package/dist/asset-manager/index.js +5 -5
  5. package/dist/asset-manager/installer.js +4 -4
  6. package/dist/bridge/drivers/claude-sdk.js +9 -5
  7. package/dist/bridge/drivers/claude-sdk.js.map +1 -1
  8. package/dist/bridge/drivers/codex.js +2 -2
  9. package/dist/bridge/drivers/continue.js +3 -3
  10. package/dist/bridge/drivers/echo.js +1 -1
  11. package/dist/bridge/drivers/gemini.js +4 -4
  12. package/dist/bridge/drivers/goose.js +3 -3
  13. package/dist/bridge/drivers/omp.js +2 -2
  14. package/dist/bridge/drivers/opencode.js +3 -3
  15. package/dist/bridge/drivers/qwen.js +4 -4
  16. package/dist/bridge/index.js +3 -3
  17. package/dist/bridge/src/drivers/claude-sdk.d.ts.map +1 -1
  18. package/dist/bridge/src/error-classifier.d.ts +22 -0
  19. package/dist/bridge/src/error-classifier.d.ts.map +1 -1
  20. package/dist/bridge/src/index.d.ts +1 -1
  21. package/dist/bridge/src/index.d.ts.map +1 -1
  22. package/dist/bridge/src/types.d.ts +1 -1
  23. package/dist/bridge/src/types.d.ts.map +1 -1
  24. package/dist/{chunk-NAMD4AIK.js → chunk-3HR6IN5B.js} +4 -4
  25. package/dist/{chunk-NAMD4AIK.js.map → chunk-3HR6IN5B.js.map} +1 -1
  26. package/dist/{chunk-WEQN6EWW.js → chunk-4A2LAEX6.js} +4 -4
  27. package/dist/{chunk-WEQN6EWW.js.map → chunk-4A2LAEX6.js.map} +1 -1
  28. package/dist/{chunk-TV2OU2EZ.js → chunk-4ZACMAT3.js} +4 -4
  29. package/dist/{chunk-TV2OU2EZ.js.map → chunk-4ZACMAT3.js.map} +1 -1
  30. package/dist/{chunk-NSVAJWWQ.js → chunk-5IXCNMMU.js} +4 -4
  31. package/dist/{chunk-NSVAJWWQ.js.map → chunk-5IXCNMMU.js.map} +1 -1
  32. package/dist/{chunk-O2OHGE4S.js → chunk-6KKNROBU.js} +2 -2
  33. package/dist/{chunk-O2OHGE4S.js.map → chunk-6KKNROBU.js.map} +1 -1
  34. package/dist/{chunk-XOBPOVFT.js → chunk-C54IAYEU.js} +3 -3
  35. package/dist/{chunk-XOBPOVFT.js.map → chunk-C54IAYEU.js.map} +1 -1
  36. package/dist/{chunk-EOCKR5TN.js → chunk-CBXZB3G5.js} +3 -3
  37. package/dist/{chunk-EOCKR5TN.js.map → chunk-CBXZB3G5.js.map} +1 -1
  38. package/dist/{chunk-52HINMW4.js → chunk-CC5ZHSHJ.js} +22 -10
  39. package/dist/chunk-CC5ZHSHJ.js.map +1 -0
  40. package/dist/{chunk-ZGJE4ZDP.js → chunk-CCQ3EMJT.js} +2 -2
  41. package/dist/{chunk-ZGJE4ZDP.js.map → chunk-CCQ3EMJT.js.map} +1 -1
  42. package/dist/{chunk-5DPQ766L.js → chunk-CFCSDZYF.js} +3 -3
  43. package/dist/{chunk-5DPQ766L.js.map → chunk-CFCSDZYF.js.map} +1 -1
  44. package/dist/{chunk-SKVUDDHE.js → chunk-DAEYSPOC.js} +333 -106
  45. package/dist/chunk-DAEYSPOC.js.map +1 -0
  46. package/dist/{chunk-2Q6OY3SU.js → chunk-FBIQ4QPF.js} +3 -3
  47. package/dist/{chunk-2Q6OY3SU.js.map → chunk-FBIQ4QPF.js.map} +1 -1
  48. package/dist/{chunk-NGJ6E344.js → chunk-GAH4YRCI.js} +20 -3
  49. package/dist/chunk-GAH4YRCI.js.map +1 -0
  50. package/dist/{chunk-I3TERDTR.js → chunk-HAXQAC6D.js} +2 -2
  51. package/dist/{chunk-I3TERDTR.js.map → chunk-HAXQAC6D.js.map} +1 -1
  52. package/dist/{chunk-56YT6CWS.js → chunk-HL66R2P2.js} +23 -18
  53. package/dist/chunk-HL66R2P2.js.map +1 -0
  54. package/dist/{chunk-CIFTUSBV.js → chunk-KM6DCR7A.js} +2 -2
  55. package/dist/{chunk-CIFTUSBV.js.map → chunk-KM6DCR7A.js.map} +1 -1
  56. package/dist/{chunk-7B3CL5JT.js → chunk-RNFNWOKZ.js} +6 -6
  57. package/dist/{chunk-7B3CL5JT.js.map → chunk-RNFNWOKZ.js.map} +1 -1
  58. package/dist/{chunk-67AXL4OK.js → chunk-U3TV7SRR.js} +4 -4
  59. package/dist/{chunk-67AXL4OK.js.map → chunk-U3TV7SRR.js.map} +1 -1
  60. package/dist/{chunk-6422UOMQ.js → chunk-ZSFWJAFD.js} +5 -5
  61. package/dist/{chunk-6422UOMQ.js.map → chunk-ZSFWJAFD.js.map} +1 -1
  62. package/dist/cli/index.js +31 -31
  63. package/dist/connectors/config.js +4 -4
  64. package/dist/connectors/index.js +5 -5
  65. package/dist/connectors/src/secrets.d.ts +14 -14
  66. package/dist/connectors/src/secrets.d.ts.map +1 -1
  67. package/dist/core/index.js +3 -3
  68. package/dist/core/runtime-assets.js +2 -2
  69. package/dist/core/src/index.d.ts +1 -1
  70. package/dist/core/src/index.d.ts.map +1 -1
  71. package/dist/core/src/workspace-config.d.ts +6 -0
  72. package/dist/core/src/workspace-config.d.ts.map +1 -1
  73. package/dist/core/workspace-config.js +1 -1
  74. package/dist/deploy/index.js +3 -3
  75. package/dist/{ensure-sources-HMMEQEZC.js → ensure-sources-AGORTKJC.js} +5 -5
  76. package/dist/{ensure-sources-HMMEQEZC.js.map → ensure-sources-AGORTKJC.js.map} +1 -1
  77. package/dist/factory-assets/connectors/deploy.js +5 -5
  78. package/dist/factory-assets/connectors/devserver.js +5 -5
  79. package/dist/factory-assets/connectors/flow/adapter.js +5 -5
  80. package/dist/factory-assets/connectors/flow/engine.js +3 -3
  81. package/dist/factory-assets/connectors/flow/run-flow.js +6 -6
  82. package/dist/factory-assets/connectors/flow.js +5 -5
  83. package/dist/factory-assets/connectors/git.js +5 -5
  84. package/dist/factory-assets/connectors/gmail.js +5 -5
  85. package/dist/factory-assets/connectors/googledrive.js +5 -5
  86. package/dist/factory-assets/connectors/local.js +5 -5
  87. package/dist/factory-assets/connectors/mattermost.js +5 -5
  88. package/dist/factory-assets/connectors/memory.js +5 -5
  89. package/dist/factory-assets/connectors/minio.js +5 -5
  90. package/dist/factory-assets/connectors/postgres.js +5 -5
  91. package/dist/factory-assets/connectors/s3.js +5 -5
  92. package/dist/factory-assets/connectors/sharepoint.js +5 -5
  93. package/dist/factory-assets/connectors/sqlite.js +5 -5
  94. package/dist/factory-assets/connectors/static-server.js +5 -5
  95. package/dist/factory-assets/connectors/tunnel.js +5 -5
  96. package/dist/factory-assets/connectors/webdav.js +5 -5
  97. package/dist/factory-assets/connectors/xstate-store.js +5 -5
  98. package/dist/factory-assets/connectors/xstate.js +5 -5
  99. package/dist/{flows-O7OXGFIY.js → flows-BOJMGLRI.js} +3 -3
  100. package/dist/{flows-O7OXGFIY.js.map → flows-BOJMGLRI.js.map} +1 -1
  101. package/dist/library/index.js +3 -3
  102. package/dist/library/install.js +3 -3
  103. package/dist/{open-library-5WWTBHQD.js → open-library-WTN7QLN7.js} +6 -6
  104. package/dist/{open-library-5WWTBHQD.js.map → open-library-WTN7QLN7.js.map} +1 -1
  105. package/dist/{paths-UC3ZHLKC.js → paths-66ZDGXK3.js} +6 -6
  106. package/dist/{paths-UC3ZHLKC.js.map → paths-66ZDGXK3.js.map} +1 -1
  107. package/dist/{plugin-store-R2WLXRT3.js → plugin-store-BOQXW3XV.js} +5 -5
  108. package/dist/{plugin-store-R2WLXRT3.js.map → plugin-store-BOQXW3XV.js.map} +1 -1
  109. package/dist/runner/index.js +10 -10
  110. package/dist/runner/src/external-mcp.d.ts +29 -1
  111. package/dist/runner/src/external-mcp.d.ts.map +1 -1
  112. package/dist/runner/src/mcp-runtime-handlers.d.ts +58 -0
  113. package/dist/runner/src/mcp-runtime-handlers.d.ts.map +1 -0
  114. package/dist/runner/src/resources.d.ts +12 -0
  115. package/dist/runner/src/resources.d.ts.map +1 -1
  116. package/dist/runner/src/runner-capabilities.d.ts +59 -0
  117. package/dist/runner/src/runner-capabilities.d.ts.map +1 -1
  118. package/dist/runner/src/serve.d.ts +18 -1
  119. package/dist/runner/src/serve.d.ts.map +1 -1
  120. package/dist/runner/src/session-builder.d.ts +8 -0
  121. package/dist/runner/src/session-builder.d.ts.map +1 -1
  122. package/dist/runner/src/session-resource-handlers.d.ts +5 -1
  123. package/dist/runner/src/session-resource-handlers.d.ts.map +1 -1
  124. package/dist/sdk/asset-manager.js +5 -5
  125. package/dist/sdk/bridge.js +3 -3
  126. package/dist/sdk/core.js +3 -3
  127. package/dist/sdk/flow.js +3 -3
  128. package/dist/sdk/index.js +10 -10
  129. package/dist/sdk/runner.js +10 -10
  130. package/dist/{setup-BSDHVMR6.js → setup-JIGNL3O4.js} +8 -8
  131. package/dist/{setup-BSDHVMR6.js.map → setup-JIGNL3O4.js.map} +1 -1
  132. package/dist/{store-client-4GKV4LOD.js → store-client-ODJJK5XS.js} +6 -6
  133. package/dist/{store-client-4GKV4LOD.js.map → store-client-ODJJK5XS.js.map} +1 -1
  134. package/dist/tui/index.js +10 -10
  135. package/dist/types/src/events.d.ts +22 -4
  136. package/dist/types/src/events.d.ts.map +1 -1
  137. package/dist/types/src/index.d.ts +1 -1
  138. package/dist/types/src/index.d.ts.map +1 -1
  139. package/dist/workspace-plugin/adapters/mcp.js +1 -1
  140. package/dist/workspace-plugin/adapters/omp.js +3 -3
  141. package/dist/workspace-plugin/index.js +1 -1
  142. package/package.json +1 -1
  143. package/dist/chunk-52HINMW4.js.map +0 -1
  144. package/dist/chunk-56YT6CWS.js.map +0 -1
  145. package/dist/chunk-NGJ6E344.js.map +0 -1
  146. package/dist/chunk-SKVUDDHE.js.map +0 -1
@@ -1,17 +1,17 @@
1
- import { WorkspacePlugin } from './chunk-ZGJE4ZDP.js';
1
+ import { WorkspacePlugin } from './chunk-CCQ3EMJT.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-3HR6IN5B.js';
10
+ import { loadConnectorDeclarations, SecretProviderChain, PreMintedSecretProvider, InMemorySecretProvider } from './chunk-CC5ZHSHJ.js';
11
11
  import { renderStimulusPrompt, buildOrchestratorPrompt } from './chunk-DEYYRFQU.js';
12
- import { resolveSettings, resolveApiKey, providerEnvKey } from './chunk-2Q6OY3SU.js';
13
- import { resolveRuntimeAssets } from './chunk-5DPQ766L.js';
14
- import { resolveSkWorkspaceConfig, resolveAgentDir, stageMaterializedSkills, loadMcpServerDeclarations, COMPACTION_DEFAULTS, validateAssetRecipeAttr } from './chunk-56YT6CWS.js';
12
+ import { resolveSettings, resolveApiKey, providerEnvKey } from './chunk-FBIQ4QPF.js';
13
+ import { resolveRuntimeAssets } from './chunk-CFCSDZYF.js';
14
+ import { resolveSkWorkspaceConfig, resolveAgentDir, stageMaterializedSkills, loadMcpServerDeclarations, COMPACTION_DEFAULTS, validateAssetRecipeAttr, deriveSingleMaterializedMcpDeclaration } from './chunk-HL66R2P2.js';
15
15
  import { parseAssetRef } from './chunk-BM7XANVN.js';
16
16
  import { resolveDriverPaths } from './chunk-K5GBV4SA.js';
17
17
  import { getLogStore, resolveLogStoreConfig, createLogStoreFromConfig, OnLogBridgeSink, WsLogSink, registerLogStore, resetLogStore, createLogger } from './chunk-JB35MVBN.js';
@@ -882,6 +882,14 @@ function validateSubstitutedPaths(command, args) {
882
882
  }
883
883
 
884
884
  // runner/src/external-mcp.ts
885
+ var McpServerAlreadyRegisteredError = class extends Error {
886
+ constructor(id) {
887
+ super(`MCP server '${id}' is already registered`);
888
+ this.id = id;
889
+ this.name = "McpServerAlreadyRegisteredError";
890
+ }
891
+ id;
892
+ };
885
893
  function resolveRecordSecrets(record, secrets) {
886
894
  if (!secrets) return record;
887
895
  const resolved = {};
@@ -1070,7 +1078,7 @@ var ExternalMcpManager = class {
1070
1078
  async start(declarations) {
1071
1079
  for (const decl of declarations) {
1072
1080
  try {
1073
- await this.startServer(decl);
1081
+ await this.addServer(decl);
1074
1082
  } catch (err) {
1075
1083
  this.log.error("MCP server spawn failed; skipping", err, {
1076
1084
  id: decl.id,
@@ -1079,7 +1087,15 @@ var ExternalMcpManager = class {
1079
1087
  }
1080
1088
  }
1081
1089
  }
1082
- async startServer(decl) {
1090
+ /**
1091
+ * Connect one MCP server and register its tools into the capability registry.
1092
+ * Returns the server id and the registered tool capability names.
1093
+ * Throws if the id is already registered or if connect/listTools fails.
1094
+ */
1095
+ async addServer(decl) {
1096
+ if (this.servers.some((s) => s.id === decl.id)) {
1097
+ throw new McpServerAlreadyRegisteredError(decl.id);
1098
+ }
1083
1099
  const client = await this.connectWithReauth(decl);
1084
1100
  const server = { id: decl.id, decl, client, toolNames: [] };
1085
1101
  const toolNames = [];
@@ -1106,6 +1122,39 @@ var ExternalMcpManager = class {
1106
1122
  toolCount: toolNames.length,
1107
1123
  tools: toolNames
1108
1124
  });
1125
+ return { id: decl.id, toolNames };
1126
+ }
1127
+ /**
1128
+ * Deregister a running MCP server's tools and close its client.
1129
+ * No-op when the id is not found.
1130
+ *
1131
+ * Drains any in-flight reauth first: a doReauthAndReconnect resolving after
1132
+ * splice would swap server.client to a freshly-connected client that nothing
1133
+ * then closes, leaking the transport/subprocess.
1134
+ */
1135
+ async removeServer(id) {
1136
+ const idx = this.servers.findIndex((s) => s.id === id);
1137
+ if (idx === -1) return;
1138
+ const server = this.servers[idx];
1139
+ if (server.reauthInFlight) await server.reauthInFlight.catch(() => {
1140
+ });
1141
+ this.servers.splice(idx, 1);
1142
+ for (const name of server.toolNames) {
1143
+ this.registry.deregister(name);
1144
+ }
1145
+ try {
1146
+ await server.client.close();
1147
+ } catch {
1148
+ }
1149
+ this.log.info("MCP server removed (runner-managed)", { id });
1150
+ }
1151
+ /** Summary of every currently-connected MCP server. */
1152
+ listServers() {
1153
+ return this.servers.map((s) => ({
1154
+ id: s.id,
1155
+ transport: s.decl.transport ?? "stdio",
1156
+ toolCount: s.toolNames.length
1157
+ }));
1109
1158
  }
1110
1159
  /**
1111
1160
  * Connect, re-minting once on an initial-connect 401: the provisioned bearer
@@ -1252,7 +1301,11 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1252
1301
  dispose: async () => {
1253
1302
  },
1254
1303
  startWatching: () => {
1255
- }
1304
+ },
1305
+ getOrCreateExternalMcpManager: () => {
1306
+ throw new Error("external MCP manager unavailable \u2014 no capability registry (CLI/flow mode)");
1307
+ },
1308
+ getExternalMcpManager: () => null
1256
1309
  };
1257
1310
  try {
1258
1311
  registerBuiltinConnectors();
@@ -1280,6 +1333,26 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1280
1333
  let mcpServers;
1281
1334
  let workspacePluginToShutdown = null;
1282
1335
  let externalMcpManager = null;
1336
+ const mcpSecretChain = preMintedSecrets ? new SecretProviderChain(
1337
+ [preMintedSecrets, secretProvider].filter(
1338
+ Boolean
1339
+ )
1340
+ ) : secretProvider;
1341
+ const getOrCreateExternalMcpManager = () => {
1342
+ if (!capabilityRegistry) {
1343
+ throw new Error(
1344
+ "external MCP manager unavailable \u2014 no capability registry (CLI/flow mode)"
1345
+ );
1346
+ }
1347
+ if (!externalMcpManager) {
1348
+ externalMcpManager = createExternalMcpManager(
1349
+ capabilityRegistry,
1350
+ mcpSecretChain,
1351
+ sessionMeta
1352
+ );
1353
+ }
1354
+ return externalMcpManager;
1355
+ };
1283
1356
  if (driverType === "claude-sdk") {
1284
1357
  const inProcess = await buildInProcessMcpServers(
1285
1358
  resourceManager,
@@ -1294,7 +1367,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1294
1367
  externalMcpManager = await startExternalMcpServers(
1295
1368
  capabilityRegistry,
1296
1369
  projectDir,
1297
- secretProvider,
1370
+ mcpSecretChain,
1298
1371
  sessionMeta
1299
1372
  );
1300
1373
  } else if (driverType === "claude-sdk") {
@@ -1305,7 +1378,7 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1305
1378
  sessionMeta
1306
1379
  );
1307
1380
  }
1308
- if (!resourceManager && driverType !== "claude-sdk" && !externalMcpManager?.hasServers())
1381
+ if (!resourceManager && driverType !== "claude-sdk" && !externalMcpManager?.hasServers() && !capabilityRegistry)
1309
1382
  return noopResult;
1310
1383
  const startWatching = () => {
1311
1384
  if (resourceManager && watch?.onFileChanged) {
@@ -1348,7 +1421,9 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
1348
1421
  mcpServers,
1349
1422
  runtimeAssets,
1350
1423
  dispose,
1351
- startWatching
1424
+ startWatching,
1425
+ getOrCreateExternalMcpManager,
1426
+ getExternalMcpManager: () => externalMcpManager
1352
1427
  };
1353
1428
  } catch {
1354
1429
  return noopResult;
@@ -1433,15 +1508,18 @@ async function buildInProcessMcpServers(resourceManager, projectDir, driverType,
1433
1508
  async function startExternalMcpServers(capabilityRegistry, projectDir, secretProvider, sessionMeta) {
1434
1509
  const resolvedDecls = resolveExternalMcpDeclarations(projectDir, sessionMeta?.sessionId);
1435
1510
  if (resolvedDecls.length === 0) return null;
1436
- const externalMcpManager = new ExternalMcpManager(
1511
+ const mgr = createExternalMcpManager(capabilityRegistry, secretProvider, sessionMeta);
1512
+ await mgr.start(resolvedDecls);
1513
+ return mgr;
1514
+ }
1515
+ function createExternalMcpManager(capabilityRegistry, secretProvider, sessionMeta) {
1516
+ return new ExternalMcpManager(
1437
1517
  capabilityRegistry,
1438
1518
  secretProvider,
1439
1519
  sessionMeta?.sessionId,
1440
1520
  void 0,
1441
1521
  buildMcpReauthorizer(capabilityRegistry, secretProvider, sessionMeta?.sessionId)
1442
1522
  );
1443
- await externalMcpManager.start(resolvedDecls);
1444
- return externalMcpManager;
1445
1523
  }
1446
1524
  function mcpAuthSecretKey(id) {
1447
1525
  return `MCP__${id.replace(/[^A-Za-z0-9_]/g, "_")}__AUTH`;
@@ -1563,7 +1641,9 @@ async function createAgentSession(config) {
1563
1641
  mcpServers,
1564
1642
  runtimeAssets,
1565
1643
  dispose,
1566
- startWatching
1644
+ startWatching,
1645
+ getOrCreateExternalMcpManager,
1646
+ getExternalMcpManager
1567
1647
  } = await buildAgentResources(
1568
1648
  projectDir,
1569
1649
  driverType,
@@ -1650,6 +1730,8 @@ async function createAgentSession(config) {
1650
1730
  model,
1651
1731
  dispose,
1652
1732
  startWatching,
1733
+ getOrCreateExternalMcpManager,
1734
+ getExternalMcpManager,
1653
1735
  telemetry,
1654
1736
  systemPromptSections
1655
1737
  };
@@ -2867,6 +2949,161 @@ function buildLifecycleHandler(deps) {
2867
2949
  return { ok: true };
2868
2950
  };
2869
2951
  }
2952
+
2953
+ // runner/src/session-resource-handlers.ts
2954
+ function asDeclaration(declaration) {
2955
+ if (declaration !== null && typeof declaration === "object" && typeof declaration.id === "string" && typeof declaration.driver === "string") {
2956
+ return declaration;
2957
+ }
2958
+ return null;
2959
+ }
2960
+ function toPreMinted(token) {
2961
+ return { ok: true, token: token.token, expiresAt: token.expiresAt ?? null };
2962
+ }
2963
+ function buildSessionResourceHandlers(deps) {
2964
+ const { getResourceManager, getPreMintedSecrets, emitResourcesAvailable, log } = deps;
2965
+ async function add(kind, input) {
2966
+ const rm = getResourceManager();
2967
+ if (!rm) return { ok: false, code: "no_session", message: "session resources not ready" };
2968
+ const decl = asDeclaration(input.declaration);
2969
+ if (!decl) {
2970
+ return { ok: false, code: "invalid_declaration", message: "declaration missing id/driver" };
2971
+ }
2972
+ if (input.preMintedToken) {
2973
+ getPreMintedSecrets()?.set(kind, decl.id, toPreMinted(input.preMintedToken));
2974
+ }
2975
+ try {
2976
+ await rm.connect(decl);
2977
+ } catch (err) {
2978
+ const message = err instanceof Error ? err.message : String(err);
2979
+ log(`[session-resource] runner.add_${kind} failed for ${decl.id}: ${message}`);
2980
+ return { ok: false, code: "connect_failed", message };
2981
+ }
2982
+ emitResourcesAvailable();
2983
+ log(`[session-resource] runner.add_${kind} connected ${decl.id}`);
2984
+ return { ok: true, id: decl.id };
2985
+ }
2986
+ return {
2987
+ addConnector: (input) => add("connector", input),
2988
+ addMount: (input) => add("mount", input),
2989
+ removeResource: async (input) => {
2990
+ const rm = getResourceManager();
2991
+ if (!rm) return { ok: false, code: "no_session", message: "session resources not ready" };
2992
+ if (!rm.has(input.id)) {
2993
+ return { ok: false, code: "not_found", message: `no resource with id ${input.id}` };
2994
+ }
2995
+ try {
2996
+ await rm.disconnect(input.id);
2997
+ } catch (err) {
2998
+ const message = err instanceof Error ? err.message : String(err);
2999
+ log(`[session-resource] runner.remove_resource failed for ${input.id}: ${message}`);
3000
+ return { ok: false, code: "disconnect_failed", message };
3001
+ }
3002
+ const ps = getPreMintedSecrets();
3003
+ ps?.unset("connector", input.id);
3004
+ ps?.unset("mount", input.id);
3005
+ emitResourcesAvailable();
3006
+ log(`[session-resource] runner.remove_resource removed ${input.id}`);
3007
+ return { ok: true };
3008
+ },
3009
+ updateCredential: async (input) => {
3010
+ const ps = getPreMintedSecrets();
3011
+ if (!ps) return { ok: false, code: "no_session", message: "session resources not ready" };
3012
+ const rm = getResourceManager();
3013
+ if (rm && !rm.has(input.id)) {
3014
+ return { ok: false, code: "not_found", message: `no resource with id ${input.id}` };
3015
+ }
3016
+ ps.set(input.kind, input.id, input.mint);
3017
+ log(`[session-resource] runner.update_credential staged ${input.kind}:${input.id}`);
3018
+ return { ok: true };
3019
+ }
3020
+ };
3021
+ }
3022
+
3023
+ // runner/src/mcp-runtime-handlers.ts
3024
+ function buildMcpRuntimeHandlers(deps) {
3025
+ return {
3026
+ addMcpServer: async (input) => {
3027
+ const decl = input.declaration;
3028
+ if (!decl?.id) {
3029
+ return { ok: false, code: "invalid_declaration", message: "declaration.id is required" };
3030
+ }
3031
+ const mgr = deps.getOrCreateMcpManager();
3032
+ if (!mgr) return { ok: false, code: "no_session", message: "session resources not ready" };
3033
+ if (input.preMintedToken) {
3034
+ deps.getPreMintedSecrets()?.set("mcp", decl.id, toPreMinted(input.preMintedToken));
3035
+ }
3036
+ try {
3037
+ const { toolNames } = await mgr.addServer(decl);
3038
+ deps.emitResourcesAvailable();
3039
+ deps.log(
3040
+ `[mcp-runtime] runner.add_mcp_server connected ${decl.id} (${toolNames.length} tools)`
3041
+ );
3042
+ return {
3043
+ ok: true,
3044
+ id: decl.id,
3045
+ live: deps.driverPicksUpToolsLive(),
3046
+ toolCount: toolNames.length
3047
+ };
3048
+ } catch (err) {
3049
+ deps.getPreMintedSecrets()?.unset("mcp", decl.id);
3050
+ const message = err instanceof Error ? err.message : String(err);
3051
+ const code = err instanceof McpServerAlreadyRegisteredError ? "mcp_already_registered" : "mcp_connect_failed";
3052
+ return { ok: false, code, message };
3053
+ }
3054
+ },
3055
+ attachInstance: async (input) => {
3056
+ if (input.kind !== "mcp-server") {
3057
+ return {
3058
+ ok: false,
3059
+ code: "unsupported_kind",
3060
+ message: `attach_instance supports mcp-server only; '${input.kind}' is not yet supported`
3061
+ };
3062
+ }
3063
+ if (!input.name) {
3064
+ return { ok: false, code: "invalid_input", message: "name is required" };
3065
+ }
3066
+ if (input.name.includes("/") || input.name.includes("\\") || input.name.includes("..")) {
3067
+ return {
3068
+ ok: false,
3069
+ code: "invalid_input",
3070
+ message: "name must not contain path separators or traversal segments"
3071
+ };
3072
+ }
3073
+ if (!deps.getProjectDir) {
3074
+ return { ok: false, code: "no_project_dir", message: "getProjectDir not configured" };
3075
+ }
3076
+ const subDir = join(deps.getProjectDir(), ".skaile/assets/mcp-server", input.name);
3077
+ const decl = deriveSingleMaterializedMcpDeclaration(subDir, input.name);
3078
+ if (!decl) {
3079
+ return {
3080
+ ok: false,
3081
+ code: "not_materialized",
3082
+ message: `no materialized mcp-server at ${subDir}`
3083
+ };
3084
+ }
3085
+ const mgr = deps.getOrCreateMcpManager();
3086
+ if (!mgr) return { ok: false, code: "no_session", message: "session resources not ready" };
3087
+ try {
3088
+ const { toolNames } = await mgr.addServer(decl);
3089
+ deps.emitResourcesAvailable();
3090
+ deps.log(
3091
+ `[mcp-runtime] runner.attach_instance connected ${decl.id} (${toolNames.length} tools)`
3092
+ );
3093
+ return {
3094
+ ok: true,
3095
+ id: decl.id,
3096
+ live: deps.driverPicksUpToolsLive(),
3097
+ toolCount: toolNames.length
3098
+ };
3099
+ } catch (err) {
3100
+ const message = err instanceof Error ? err.message : String(err);
3101
+ const code = err instanceof McpServerAlreadyRegisteredError ? "mcp_already_registered" : "mcp_connect_failed";
3102
+ return { ok: false, code, message };
3103
+ }
3104
+ }
3105
+ };
3106
+ }
2870
3107
  function parseFleetHealthBody(body) {
2871
3108
  return body.trim().toLowerCase() === "healthy" ? "healthy" : "error";
2872
3109
  }
@@ -2958,6 +3195,14 @@ var connectorDeclarationInput = z5.strictObject({
2958
3195
  declaration: requiredUnknown,
2959
3196
  preMintedToken: preMintedTokenSchema
2960
3197
  });
3198
+ var addMcpServerInputSchema = z5.strictObject({
3199
+ declaration: requiredUnknown,
3200
+ preMintedToken: preMintedTokenSchema
3201
+ });
3202
+ var attachInstanceInputSchema = z5.strictObject({
3203
+ kind: z5.string(),
3204
+ name: z5.string()
3205
+ });
2961
3206
  var removeResourceInput = z5.strictObject({
2962
3207
  id: z5.string()
2963
3208
  });
@@ -3018,6 +3263,38 @@ function buildRunnerCapabilities(handlers) {
3018
3263
  });
3019
3264
  }
3020
3265
  }),
3266
+ // TODO(mcp-detach): no runner.remove_mcp_server yet — live MCP detach + mcp: credential cleanup deferred with the attach-by-ref rework.
3267
+ defineCapability({
3268
+ name: "runner.add_mcp_server",
3269
+ displayName: "Add MCP server",
3270
+ description: "Live-attach a remote MCP server to the running session. Used by the platform to connect additional MCP tool servers mid-session.",
3271
+ side: "agent",
3272
+ origin: RUNNER_CAP_ORIGIN,
3273
+ audience: ["runtime"],
3274
+ kind: "effect",
3275
+ input: addMcpServerInputSchema,
3276
+ handler: async (input) => {
3277
+ if (!handlers.addMcpServer) return notImplemented("runner.add_mcp_server");
3278
+ return handlers.addMcpServer({
3279
+ declaration: input.declaration,
3280
+ preMintedToken: input.preMintedToken
3281
+ });
3282
+ }
3283
+ }),
3284
+ defineCapability({
3285
+ name: "runner.attach_instance",
3286
+ displayName: "Attach instance",
3287
+ description: "Materialize-then-attach-by-ref: the platform writes the asset to .skaile/assets/ then invokes this cap; the runner self-derives the declaration from disk and attaches it live.",
3288
+ side: "agent",
3289
+ origin: RUNNER_CAP_ORIGIN,
3290
+ audience: ["runtime"],
3291
+ kind: "effect",
3292
+ input: attachInstanceInputSchema,
3293
+ handler: async (input) => {
3294
+ if (!handlers.attachInstance) return notImplemented("runner.attach_instance");
3295
+ return handlers.attachInstance({ kind: input.kind, name: input.name });
3296
+ }
3297
+ }),
3021
3298
  defineCapability({
3022
3299
  name: "runner.remove_resource",
3023
3300
  displayName: "Remove resource",
@@ -3157,76 +3434,6 @@ function extractClaudeAiOauthExpiresAt(json) {
3157
3434
  return null;
3158
3435
  }
3159
3436
 
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
3437
  // runner/src/session-stimulus.ts
3231
3438
  var DEFAULT_COALESCE_MS = 50;
3232
3439
  function createSessionStimulusBus(opts) {
@@ -3371,6 +3578,11 @@ function splitConnectorsForWire(manager) {
3371
3578
  }
3372
3579
  return { mounts, connectors };
3373
3580
  }
3581
+ function buildResourcesAvailablePayload(manager, mcpManager, driverLive) {
3582
+ const { mounts, connectors } = splitConnectorsForWire(manager);
3583
+ const mcp_servers = (mcpManager?.listServers() ?? []).map((s) => ({ ...s, live: driverLive }));
3584
+ return { type: "resources_available", mounts, connectors, mcp_servers };
3585
+ }
3374
3586
  function findAiAssetsRoot(startDir) {
3375
3587
  let dir = startDir;
3376
3588
  for (let i = 0; i < 6; i++) {
@@ -4137,10 +4349,15 @@ async function startAgentServer(opts) {
4137
4349
  driver = agentSession.driver;
4138
4350
  rebuildCompactionOrchestrator();
4139
4351
  registerSessionComposition(agentSession);
4140
- sendEvent({
4141
- type: "resources_available",
4142
- ...splitConnectorsForWire(resourceManager)
4143
- });
4352
+ const driverPicksUpToolsLive = () => agentSession?.driverType !== "claude-sdk";
4353
+ const emitResourcesAvailable = () => sendEvent(
4354
+ buildResourcesAvailablePayload(
4355
+ resourceManager,
4356
+ agentSession?.getExternalMcpManager(),
4357
+ driverPicksUpToolsLive()
4358
+ )
4359
+ );
4360
+ emitResourcesAvailable();
4144
4361
  agentSession.startWatching();
4145
4362
  capabilityRegistry.setRemoteInvoker(remoteCapabilityInvoker);
4146
4363
  const runnerCaps = buildRunnerCapabilities({
@@ -4150,14 +4367,19 @@ async function startAgentServer(opts) {
4150
4367
  ...buildSessionResourceHandlers({
4151
4368
  getResourceManager: () => resourceManager,
4152
4369
  getPreMintedSecrets: () => preMintedSecrets,
4153
- emitResourcesAvailable: () => {
4154
- sendEvent({
4155
- type: "resources_available",
4156
- ...splitConnectorsForWire(resourceManager)
4157
- });
4158
- },
4370
+ emitResourcesAvailable,
4159
4371
  log
4160
4372
  }),
4373
+ // runner.add_mcp_server + runner.attach_instance — wired to the live
4374
+ // session's lazily-created ExternalMcpManager + PreMintedSecretProvider.
4375
+ ...buildMcpRuntimeHandlers({
4376
+ getOrCreateMcpManager: () => agentSession?.getOrCreateExternalMcpManager() ?? null,
4377
+ getPreMintedSecrets: () => preMintedSecrets ?? null,
4378
+ driverPicksUpToolsLive,
4379
+ emitResourcesAvailable,
4380
+ log,
4381
+ getProjectDir: () => opts.projectDir
4382
+ }),
4161
4383
  // setLogLevel left undefined (the cap self-falls-back to getLogStore);
4162
4384
  // setState remains a stub (not resource hot-plug).
4163
4385
  lifecycle: buildLifecycleHandler({
@@ -4856,12 +5078,17 @@ async function startAgentServer(opts) {
4856
5078
  agentSession.startWatching();
4857
5079
  }
4858
5080
  function emitAvailabilityOnConnect() {
4859
- if (resourceManager) {
4860
- const wire = splitConnectorsForWire(resourceManager);
5081
+ if (resourceManager || agentSession?.getExternalMcpManager()) {
5082
+ const driverLive = agentSession?.driverType !== "claude-sdk";
5083
+ const payload = buildResourcesAvailablePayload(
5084
+ resourceManager,
5085
+ agentSession?.getExternalMcpManager() ?? null,
5086
+ driverLive
5087
+ );
4861
5088
  log(
4862
- `[serve] emitting resources_available: ${wire.mounts.length} mount(s), ${wire.connectors.length} connector(s)`
5089
+ `[serve] emitting resources_available: ${payload.mounts.length} mount(s), ${payload.connectors.length} connector(s)`
4863
5090
  );
4864
- sendEvent({ type: "resources_available", ...wire });
5091
+ sendEvent(payload);
4865
5092
  }
4866
5093
  const commands = driver?.getSlashCommands?.() ?? [];
4867
5094
  if (commands.length > 0) {
@@ -5044,6 +5271,6 @@ function touchSession(state) {
5044
5271
  return { ...state, updatedAt: (/* @__PURE__ */ new Date()).toISOString() };
5045
5272
  }
5046
5273
 
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
5274
+ 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 };
5275
+ //# sourceMappingURL=chunk-DAEYSPOC.js.map
5276
+ //# sourceMappingURL=chunk-DAEYSPOC.js.map