@skaile/workspaces 0.23.0 → 0.25.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.
- package/CHANGELOG.md +83 -0
- package/dist/{asset-feeds-WKIKSZ6Z.js → asset-feeds-77KLWCBP.js} +9 -9
- package/dist/{asset-feeds-WKIKSZ6Z.js.map → asset-feeds-77KLWCBP.js.map} +1 -1
- package/dist/asset-manager/index.js +7 -7
- package/dist/asset-manager/installer.js +6 -6
- package/dist/base-assets/connectors/deploy.js +7 -7
- package/dist/base-assets/connectors/devserver.js +7 -7
- package/dist/base-assets/connectors/flow/adapter.js +7 -7
- package/dist/base-assets/connectors/flow/run-flow.js +8 -8
- package/dist/base-assets/connectors/flow.js +7 -7
- package/dist/base-assets/connectors/git.js +7 -7
- package/dist/base-assets/connectors/gmail.js +7 -7
- package/dist/base-assets/connectors/googledrive/driver.d.ts.map +1 -1
- package/dist/base-assets/connectors/googledrive.js +7 -7
- package/dist/base-assets/connectors/local.js +7 -7
- package/dist/base-assets/connectors/mattermost.js +7 -7
- package/dist/base-assets/connectors/memory.js +7 -7
- package/dist/base-assets/connectors/minio.js +7 -7
- package/dist/base-assets/connectors/postgres.js +7 -7
- package/dist/base-assets/connectors/s3.js +7 -7
- package/dist/base-assets/connectors/sharepoint/driver.d.ts.map +1 -1
- package/dist/base-assets/connectors/sharepoint.js +7 -7
- package/dist/base-assets/connectors/sqlite.js +7 -7
- package/dist/base-assets/connectors/static-server.js +7 -7
- package/dist/base-assets/connectors/tunnel.js +7 -7
- package/dist/base-assets/connectors/webdav/driver.d.ts.map +1 -1
- package/dist/base-assets/connectors/webdav.js +7 -7
- package/dist/base-assets/connectors/xstate-store/adapter.d.ts +1 -1
- package/dist/base-assets/connectors/xstate-store/adapter.d.ts.map +1 -1
- package/dist/base-assets/connectors/xstate-store.js +7 -7
- package/dist/base-assets/connectors/xstate.js +7 -7
- package/dist/{chunk-542K7SR6.js → chunk-3QTZWPGH.js} +36 -7
- package/dist/chunk-3QTZWPGH.js.map +1 -0
- package/dist/{chunk-46COM7M5.js → chunk-4FADEVBN.js} +4 -4
- package/dist/{chunk-46COM7M5.js.map → chunk-4FADEVBN.js.map} +1 -1
- package/dist/{chunk-AFLH7B64.js → chunk-4FJE6BI6.js} +3 -3
- package/dist/{chunk-AFLH7B64.js.map → chunk-4FJE6BI6.js.map} +1 -1
- package/dist/{chunk-OVQZ5OKL.js → chunk-4QVFQEY2.js} +2 -2
- package/dist/{chunk-OVQZ5OKL.js.map → chunk-4QVFQEY2.js.map} +1 -1
- package/dist/{chunk-BTAC2VYT.js → chunk-B4ZXBH57.js} +7 -7
- package/dist/{chunk-BTAC2VYT.js.map → chunk-B4ZXBH57.js.map} +1 -1
- package/dist/{chunk-DZCFFTAX.js → chunk-BJWUSHC4.js} +336 -113
- package/dist/chunk-BJWUSHC4.js.map +1 -0
- package/dist/{chunk-2F3RUZXC.js → chunk-DCAWIRD6.js} +15 -6
- package/dist/chunk-DCAWIRD6.js.map +1 -0
- package/dist/{chunk-QTWA6BZK.js → chunk-FJFHJBGS.js} +5 -5
- package/dist/{chunk-QTWA6BZK.js.map → chunk-FJFHJBGS.js.map} +1 -1
- package/dist/{chunk-DH4N5AW4.js → chunk-GL45UNVS.js} +3 -3
- package/dist/{chunk-DH4N5AW4.js.map → chunk-GL45UNVS.js.map} +1 -1
- package/dist/{chunk-LJ52ZKIU.js → chunk-KT3CK26V.js} +3 -3
- package/dist/{chunk-LJ52ZKIU.js.map → chunk-KT3CK26V.js.map} +1 -1
- package/dist/{chunk-2RFOFHSM.js → chunk-QXC62DOF.js} +4 -4
- package/dist/{chunk-2RFOFHSM.js.map → chunk-QXC62DOF.js.map} +1 -1
- package/dist/{chunk-ODPII24X.js → chunk-SETTLPBD.js} +3 -3
- package/dist/{chunk-ODPII24X.js.map → chunk-SETTLPBD.js.map} +1 -1
- package/dist/{chunk-5ESCS2OS.js → chunk-UD4ZLXGS.js} +4 -4
- package/dist/{chunk-5ESCS2OS.js.map → chunk-UD4ZLXGS.js.map} +1 -1
- package/dist/{chunk-YX3UWPJ5.js → chunk-WIAHJOMG.js} +19 -49
- package/dist/chunk-WIAHJOMG.js.map +1 -0
- package/dist/{chunk-E4UJ7CVK.js → chunk-XMP6XTMF.js} +213 -57
- package/dist/chunk-XMP6XTMF.js.map +1 -0
- package/dist/{chunk-Z3M5K67G.js → chunk-XVL22AWE.js} +3 -3
- package/dist/{chunk-Z3M5K67G.js.map → chunk-XVL22AWE.js.map} +1 -1
- package/dist/cli/index.js +160 -46
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/src/commands/project.d.ts.map +1 -1
- package/dist/cli/src/commands/validate.d.ts.map +1 -1
- package/dist/connectors/config.js +6 -6
- package/dist/connectors/index.js +7 -7
- package/dist/connectors/src/connector-manager.d.ts +49 -0
- package/dist/connectors/src/connector-manager.d.ts.map +1 -1
- package/dist/connectors/src/connector-types.d.ts +16 -0
- package/dist/connectors/src/connector-types.d.ts.map +1 -1
- package/dist/core/index.js +5 -5
- package/dist/core/manifest.js +2 -2
- package/dist/core/models.js +1 -1
- package/dist/core/runtime-assets.js +4 -4
- package/dist/core/src/index.d.ts +2 -2
- package/dist/core/src/index.d.ts.map +1 -1
- package/dist/core/src/models.d.ts +10 -3
- package/dist/core/src/models.d.ts.map +1 -1
- package/dist/core/src/workspace-config.d.ts +21 -0
- package/dist/core/src/workspace-config.d.ts.map +1 -1
- package/dist/core/workspace-config.js +3 -3
- package/dist/deploy/index.js +5 -5
- package/dist/discovery/index.js +3 -3
- package/dist/{ensure-sources-OJUBGX6Z.js → ensure-sources-7MOOKY3K.js} +9 -9
- package/dist/{ensure-sources-OJUBGX6Z.js.map → ensure-sources-7MOOKY3K.js.map} +1 -1
- package/dist/library/index.js +12 -4
- package/dist/library/src/install/install-from-manifest.d.ts.map +1 -1
- package/dist/open-library-GW7DWWNZ.js +21 -0
- package/dist/{open-library-67FSSQWE.js.map → open-library-GW7DWWNZ.js.map} +1 -1
- package/dist/{plugin-store-IZ5SCRAV.js → plugin-store-R32NH7JE.js} +7 -7
- package/dist/{plugin-store-IZ5SCRAV.js.map → plugin-store-R32NH7JE.js.map} +1 -1
- package/dist/runner/index.js +9 -9
- package/dist/runner/src/external-mcp.d.ts +112 -0
- package/dist/runner/src/external-mcp.d.ts.map +1 -0
- package/dist/runner/src/resources.d.ts +22 -1
- package/dist/runner/src/resources.d.ts.map +1 -1
- package/dist/runner/src/serve.d.ts.map +1 -1
- package/dist/runner/src/session-builder.d.ts +19 -0
- package/dist/runner/src/session-builder.d.ts.map +1 -1
- package/dist/sdk/asset-manager.js +7 -7
- package/dist/sdk/core.js +5 -5
- package/dist/sdk/index.js +9 -9
- package/dist/sdk/runner.js +9 -9
- package/dist/{setup-J7CYEQOF.js → setup-SRPBQOHY.js} +7 -7
- package/dist/{setup-J7CYEQOF.js.map → setup-SRPBQOHY.js.map} +1 -1
- package/dist/store-client-INZD2RYD.js +14 -0
- package/dist/{store-client-AEI6Y3KD.js.map → store-client-INZD2RYD.js.map} +1 -1
- package/dist/tui/index.js +9 -9
- package/dist/types/src/install-manifest.d.ts +1 -1
- package/dist/types/src/install-manifest.d.ts.map +1 -1
- package/dist/workspace-plugin/index.js +1 -1
- package/package.json +1 -1
- package/dist/chunk-2F3RUZXC.js.map +0 -1
- package/dist/chunk-542K7SR6.js.map +0 -1
- package/dist/chunk-DZCFFTAX.js.map +0 -1
- package/dist/chunk-E4UJ7CVK.js.map +0 -1
- package/dist/chunk-YX3UWPJ5.js.map +0 -1
- package/dist/open-library-67FSSQWE.js +0 -13
- package/dist/store-client-AEI6Y3KD.js +0 -14
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { WorkspacePlugin } from './chunk-
|
|
1
|
+
import { WorkspacePlugin } from './chunk-4QVFQEY2.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';
|
|
@@ -6,13 +6,14 @@ import { EventNormalizer } from './chunk-M5TE6YI5.js';
|
|
|
6
6
|
import { classifyClaudeSdkError } from './chunk-DQWREFRQ.js';
|
|
7
7
|
import { createDriver } from './chunk-6VTG73UY.js';
|
|
8
8
|
import { deployCatalogEntry, undeployCatalogEntry } from './chunk-LV2HPH3C.js';
|
|
9
|
-
import { registerBuiltinConnectors, findMissingPackages, installNpmPackages, ConnectorManager, ConnectorStartupError, buildConnectorPromptSection, buildSdkConnectorTools } from './chunk-
|
|
10
|
-
import { loadConnectorDeclarations, PreMintedSecretProvider, InMemorySecretProvider } from './chunk-
|
|
9
|
+
import { registerBuiltinConnectors, findMissingPackages, installNpmPackages, ConnectorManager, ConnectorStartupError, buildConnectorPromptSection, buildSdkConnectorTools } from './chunk-XMP6XTMF.js';
|
|
10
|
+
import { loadConnectorDeclarations, PreMintedSecretProvider, InMemorySecretProvider } from './chunk-SETTLPBD.js';
|
|
11
11
|
import { renderStimulusPrompt, buildOrchestratorPrompt } from './chunk-GZWJGNNN.js';
|
|
12
|
-
import { resolveSettings, resolveApiKey, providerEnvKey } from './chunk-
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
12
|
+
import { resolveSettings, resolveApiKey, providerEnvKey } from './chunk-XVL22AWE.js';
|
|
13
|
+
import { resolveDriverPaths } from './chunk-K5GBV4SA.js';
|
|
14
|
+
import { resolveRuntimeAssets } from './chunk-UD4ZLXGS.js';
|
|
15
|
+
import { resolveSkWorkspaceConfig, resolveAgentDir, stageMaterializedSkills, loadMcpServerDeclarations, COMPACTION_DEFAULTS, validateAssetRecipeAttr } from './chunk-3QTZWPGH.js';
|
|
16
|
+
import { parseAssetRef } from './chunk-WIAHJOMG.js';
|
|
16
17
|
import { getLogStore, resolveLogStoreConfig, createLogStoreFromConfig, OnLogBridgeSink, WsLogSink, registerLogStore, resetLogStore, createLogger } from './chunk-24UIWON4.js';
|
|
17
18
|
import { __require } from './chunk-NSBPE2FW.js';
|
|
18
19
|
import pc from 'picocolors';
|
|
@@ -28,6 +29,10 @@ import { createHash, randomUUID } from 'crypto';
|
|
|
28
29
|
import { execFile, spawnSync } from 'child_process';
|
|
29
30
|
import { promisify } from 'util';
|
|
30
31
|
import { parse } from 'yaml';
|
|
32
|
+
import { Client } from '@modelcontextprotocol/sdk/client/index.js';
|
|
33
|
+
import { SSEClientTransport } from '@modelcontextprotocol/sdk/client/sse.js';
|
|
34
|
+
import { getDefaultEnvironment, StdioClientTransport } from '@modelcontextprotocol/sdk/client/stdio.js';
|
|
35
|
+
import { StreamableHTTPClientTransport } from '@modelcontextprotocol/sdk/client/streamableHttp.js';
|
|
31
36
|
import mime from 'mime';
|
|
32
37
|
|
|
33
38
|
// runner/src/logging-bootstrap.ts
|
|
@@ -850,8 +855,262 @@ function validateSubstitutedPaths(command, args) {
|
|
|
850
855
|
return missing;
|
|
851
856
|
}
|
|
852
857
|
|
|
858
|
+
// runner/src/external-mcp.ts
|
|
859
|
+
function resolveRecordSecrets(record, secrets) {
|
|
860
|
+
if (!secrets) return record;
|
|
861
|
+
const resolved = {};
|
|
862
|
+
for (const [k, v] of Object.entries(record)) {
|
|
863
|
+
resolved[k] = secrets.resolve(v) ?? v;
|
|
864
|
+
}
|
|
865
|
+
return resolved;
|
|
866
|
+
}
|
|
867
|
+
var RESERVED_MCP_SERVER_IDS = /* @__PURE__ */ new Set([
|
|
868
|
+
"skaile-connectors",
|
|
869
|
+
"skaile-workspace",
|
|
870
|
+
"skaile-capabilities"
|
|
871
|
+
]);
|
|
872
|
+
function resolveExternalMcpDeclarations(projectDir, sessionId) {
|
|
873
|
+
const mcpLog = createLogger({
|
|
874
|
+
kind: "mcp",
|
|
875
|
+
subkind: "wiring",
|
|
876
|
+
instance: sessionId ?? "no-session"
|
|
877
|
+
});
|
|
878
|
+
const mcpDeclarations = loadMcpServerDeclarations(projectDir);
|
|
879
|
+
mcpLog.debug("loaded MCP declarations", { count: mcpDeclarations.length });
|
|
880
|
+
const recipeCache = createRecipeCache();
|
|
881
|
+
const nixFlakeRef = process.env.SKAILE_NIX_FLAKE_REF ?? "/etc/skaile/flake";
|
|
882
|
+
const resolved = [];
|
|
883
|
+
for (const decl of mcpDeclarations) {
|
|
884
|
+
if (RESERVED_MCP_SERVER_IDS.has(decl.id)) {
|
|
885
|
+
mcpLog.warn("MCP server skipped: reserved id", { id: decl.id });
|
|
886
|
+
continue;
|
|
887
|
+
}
|
|
888
|
+
let resolvedDecl = decl;
|
|
889
|
+
if (decl.recipe) {
|
|
890
|
+
const recipeLogKey = decl.recipe.flake ? { flake: decl.recipe.flake } : { attr: decl.recipe.attr };
|
|
891
|
+
try {
|
|
892
|
+
const recipeKey = decl.recipe.flake ? `mcps.${decl.id}` : decl.recipe.attr ?? `mcps.${decl.id}`;
|
|
893
|
+
const outPath = resolveRecipePath(nixFlakeRef, recipeKey, recipeCache);
|
|
894
|
+
const outPaths = /* @__PURE__ */ new Map([[decl.id, outPath]]);
|
|
895
|
+
const resolvedCommand = decl.command ? substituteRecipeTemplating(decl.command, outPaths) : decl.command;
|
|
896
|
+
const resolvedArgs = decl.args?.map((a) => substituteRecipeTemplating(a, outPaths));
|
|
897
|
+
const resolvedEnv = substituteRecipeMap(decl.env, outPaths);
|
|
898
|
+
resolvedDecl = {
|
|
899
|
+
...decl,
|
|
900
|
+
command: resolvedCommand,
|
|
901
|
+
args: resolvedArgs,
|
|
902
|
+
env: resolvedEnv
|
|
903
|
+
};
|
|
904
|
+
const recipeLog = createLogger({
|
|
905
|
+
kind: "mcp",
|
|
906
|
+
subkind: decl.id,
|
|
907
|
+
instance: "recipe-resolve"
|
|
908
|
+
});
|
|
909
|
+
const allResolved = [
|
|
910
|
+
resolvedCommand ?? "",
|
|
911
|
+
...resolvedArgs ?? [],
|
|
912
|
+
...Object.values(resolvedEnv ?? {})
|
|
913
|
+
];
|
|
914
|
+
for (const v of allResolved) {
|
|
915
|
+
if (v.includes("${recipe:")) {
|
|
916
|
+
recipeLog.warn("unresolved recipe marker after substitution", {
|
|
917
|
+
value: v,
|
|
918
|
+
declId: decl.id
|
|
919
|
+
});
|
|
920
|
+
}
|
|
921
|
+
}
|
|
922
|
+
const missingPaths = validateSubstitutedPaths(resolvedCommand, resolvedArgs);
|
|
923
|
+
if (missingPaths.length > 0) {
|
|
924
|
+
recipeLog.error("MCP server skipped: substituted path does not exist", void 0, {
|
|
925
|
+
id: decl.id,
|
|
926
|
+
...recipeLogKey,
|
|
927
|
+
missing: missingPaths
|
|
928
|
+
});
|
|
929
|
+
continue;
|
|
930
|
+
}
|
|
931
|
+
recipeLog.info("recipe substitution complete", { ...recipeLogKey, outPath });
|
|
932
|
+
} catch (err) {
|
|
933
|
+
createLogger({ kind: "mcp", subkind: decl.id, instance: "recipe-resolve" }).error(
|
|
934
|
+
"MCP server skipped: recipe resolution failed",
|
|
935
|
+
err,
|
|
936
|
+
{ id: decl.id, ...recipeLogKey, flakeRef: nixFlakeRef }
|
|
937
|
+
);
|
|
938
|
+
continue;
|
|
939
|
+
}
|
|
940
|
+
}
|
|
941
|
+
resolved.push(resolvedDecl);
|
|
942
|
+
}
|
|
943
|
+
return resolved;
|
|
944
|
+
}
|
|
945
|
+
var PASSTHROUGH_INPUT_ZOD = {
|
|
946
|
+
parse: (v) => v
|
|
947
|
+
};
|
|
948
|
+
function buildTransport(decl, secrets) {
|
|
949
|
+
const transport = decl.transport ?? "stdio";
|
|
950
|
+
if (transport === "stdio") {
|
|
951
|
+
if (!decl.command) {
|
|
952
|
+
throw new Error(`stdio MCP server '${decl.id}' is missing 'command'`);
|
|
953
|
+
}
|
|
954
|
+
const env = {
|
|
955
|
+
...getDefaultEnvironment(),
|
|
956
|
+
...resolveRecordSecrets(decl.env ?? {}, secrets)
|
|
957
|
+
};
|
|
958
|
+
return new StdioClientTransport({
|
|
959
|
+
command: decl.command,
|
|
960
|
+
args: decl.args ?? [],
|
|
961
|
+
env,
|
|
962
|
+
stderr: "pipe"
|
|
963
|
+
});
|
|
964
|
+
}
|
|
965
|
+
if (transport === "sse") {
|
|
966
|
+
if (!decl.url) throw new Error(`sse MCP server '${decl.id}' is missing 'url'`);
|
|
967
|
+
const headers = resolveRecordSecrets(decl.headers ?? {}, secrets);
|
|
968
|
+
return new SSEClientTransport(new URL(decl.url), { requestInit: { headers } });
|
|
969
|
+
}
|
|
970
|
+
if (transport === "http") {
|
|
971
|
+
if (!decl.url) throw new Error(`http MCP server '${decl.id}' is missing 'url'`);
|
|
972
|
+
const headers = resolveRecordSecrets(decl.headers ?? {}, secrets);
|
|
973
|
+
return new StreamableHTTPClientTransport(new URL(decl.url), { requestInit: { headers } });
|
|
974
|
+
}
|
|
975
|
+
throw new Error(`Unknown MCP transport '${transport}' for server '${decl.id}'`);
|
|
976
|
+
}
|
|
977
|
+
function defaultMcpClientConnector(secrets) {
|
|
978
|
+
return async (decl) => {
|
|
979
|
+
const transport = buildTransport(decl, secrets);
|
|
980
|
+
const client = new Client({ name: "skaile-runner", version: "1.0.0" }, { capabilities: {} });
|
|
981
|
+
await client.connect(transport);
|
|
982
|
+
return client;
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
var ExternalMcpManager = class {
|
|
986
|
+
/**
|
|
987
|
+
* @param registry Session capability registry to register MCP tools into.
|
|
988
|
+
* @param secrets Secret provider for resolving `env:` / `forge:` refs in the
|
|
989
|
+
* stdio subprocess env and sse/http headers.
|
|
990
|
+
* @param sessionId Used for the logger instance slice.
|
|
991
|
+
* @param connect Optional connector override (tests inject a fake client so
|
|
992
|
+
* no live subprocess is spawned). Defaults to the real SDK
|
|
993
|
+
* client + transport.
|
|
994
|
+
*/
|
|
995
|
+
constructor(registry, secrets, sessionId, connect) {
|
|
996
|
+
this.registry = registry;
|
|
997
|
+
this.connect = connect ?? defaultMcpClientConnector(secrets);
|
|
998
|
+
this.log = createLogger({
|
|
999
|
+
kind: "mcp",
|
|
1000
|
+
subkind: "runner-managed",
|
|
1001
|
+
instance: sessionId ?? "no-session"
|
|
1002
|
+
});
|
|
1003
|
+
}
|
|
1004
|
+
registry;
|
|
1005
|
+
servers = [];
|
|
1006
|
+
log;
|
|
1007
|
+
connect;
|
|
1008
|
+
/** True when at least one external server connected and registered tools. */
|
|
1009
|
+
hasServers() {
|
|
1010
|
+
return this.servers.length > 0;
|
|
1011
|
+
}
|
|
1012
|
+
/**
|
|
1013
|
+
* Connect every declaration and register its tools. Per-server failures are
|
|
1014
|
+
* logged and skipped so a single bad server never blocks the session.
|
|
1015
|
+
*/
|
|
1016
|
+
async start(declarations) {
|
|
1017
|
+
for (const decl of declarations) {
|
|
1018
|
+
try {
|
|
1019
|
+
await this.startServer(decl);
|
|
1020
|
+
} catch (err) {
|
|
1021
|
+
this.log.error("MCP server spawn failed; skipping", err, {
|
|
1022
|
+
id: decl.id,
|
|
1023
|
+
transport: decl.transport ?? "stdio"
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
async startServer(decl) {
|
|
1029
|
+
const client = await this.connect(decl);
|
|
1030
|
+
const toolNames = [];
|
|
1031
|
+
try {
|
|
1032
|
+
const { tools } = await client.listTools();
|
|
1033
|
+
for (const tool of tools) {
|
|
1034
|
+
const cap = this.buildToolCapability(decl.id, tool, client);
|
|
1035
|
+
this.registry.register(cap, "agent");
|
|
1036
|
+
toolNames.push(cap.name);
|
|
1037
|
+
}
|
|
1038
|
+
} catch (err) {
|
|
1039
|
+
for (const name of toolNames) this.registry.deregister(name);
|
|
1040
|
+
try {
|
|
1041
|
+
await client.close();
|
|
1042
|
+
} catch {
|
|
1043
|
+
}
|
|
1044
|
+
throw err;
|
|
1045
|
+
}
|
|
1046
|
+
this.servers.push({ id: decl.id, client, toolNames });
|
|
1047
|
+
this.log.info("MCP server registered (runner-managed)", {
|
|
1048
|
+
id: decl.id,
|
|
1049
|
+
transport: decl.transport ?? "stdio",
|
|
1050
|
+
toolCount: toolNames.length,
|
|
1051
|
+
tools: toolNames
|
|
1052
|
+
});
|
|
1053
|
+
}
|
|
1054
|
+
/**
|
|
1055
|
+
* Wrap a single MCP tool as a {@link DefinedCapability}. The capability name
|
|
1056
|
+
* is `mcp__<server>__<tool>` (the naming claude-sdk wildcards and prompts
|
|
1057
|
+
* depend on). The handler proxies the call to the live MCP client; a tool
|
|
1058
|
+
* error (`isError`) is rethrown so the capability dispatch path surfaces it
|
|
1059
|
+
* to the LLM as a tool failure.
|
|
1060
|
+
*/
|
|
1061
|
+
buildToolCapability(serverId, tool, client) {
|
|
1062
|
+
const name = `mcp__${serverId}__${tool.name}`;
|
|
1063
|
+
const inputSchema = tool.inputSchema && typeof tool.inputSchema === "object" ? tool.inputSchema : { type: "object" };
|
|
1064
|
+
return {
|
|
1065
|
+
name,
|
|
1066
|
+
description: tool.description ?? `MCP tool ${tool.name} from server ${serverId}`,
|
|
1067
|
+
inputSchema,
|
|
1068
|
+
side: "agent",
|
|
1069
|
+
origin: { kind: "mcp", serverId },
|
|
1070
|
+
scope: "session",
|
|
1071
|
+
kind: "effect",
|
|
1072
|
+
// LLM-only — these are agent tools, not user command-palette actions.
|
|
1073
|
+
audience: ["llm"],
|
|
1074
|
+
inputZod: PASSTHROUGH_INPUT_ZOD,
|
|
1075
|
+
handler: async (input, ctx) => {
|
|
1076
|
+
const result = await client.callTool({
|
|
1077
|
+
name: tool.name,
|
|
1078
|
+
arguments: input ?? {}
|
|
1079
|
+
});
|
|
1080
|
+
const content = result.content ?? [];
|
|
1081
|
+
const text = content.filter((c) => c.type === "text" && typeof c.text === "string").map((c) => c.text).join("\n");
|
|
1082
|
+
if (result.isError) {
|
|
1083
|
+
throw new Error(text || `MCP tool ${name} returned an error`);
|
|
1084
|
+
}
|
|
1085
|
+
ctx.log.debug("mcp tool ok", { tool: name, hasText: text.length > 0 });
|
|
1086
|
+
return text.length > 0 ? text : content;
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
}
|
|
1090
|
+
/**
|
|
1091
|
+
* Deregister every tool and close every client (kills the subprocesses).
|
|
1092
|
+
* Best-effort: a failed close on one server does not prevent the rest.
|
|
1093
|
+
*/
|
|
1094
|
+
async dispose() {
|
|
1095
|
+
for (const server of this.servers) {
|
|
1096
|
+
for (const toolName of server.toolNames) {
|
|
1097
|
+
this.registry.deregister(toolName);
|
|
1098
|
+
}
|
|
1099
|
+
try {
|
|
1100
|
+
await server.client.close();
|
|
1101
|
+
} catch (err) {
|
|
1102
|
+
this.log.warn("MCP server close failed", {
|
|
1103
|
+
id: server.id,
|
|
1104
|
+
error: err instanceof Error ? err.message : String(err)
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
}
|
|
1108
|
+
this.servers.length = 0;
|
|
1109
|
+
}
|
|
1110
|
+
};
|
|
1111
|
+
|
|
853
1112
|
// runner/src/resources.ts
|
|
854
|
-
async function buildAgentResources(projectDir, driverType, _onLog, watch, secretProvider, sessionMeta, tokenMediator, preMintedSecrets) {
|
|
1113
|
+
async function buildAgentResources(projectDir, driverType, _onLog, watch, secretProvider, sessionMeta, tokenMediator, preMintedSecrets, deferFilesystemMounts, capabilityRegistry) {
|
|
855
1114
|
const resLog = createLogger({
|
|
856
1115
|
kind: "runner",
|
|
857
1116
|
subkind: "resources",
|
|
@@ -891,11 +1150,13 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
891
1150
|
secrets: secretProvider,
|
|
892
1151
|
catalogEntries: runtimeAssets.catalogEntries,
|
|
893
1152
|
tokenMediator,
|
|
894
|
-
preMintedSecrets
|
|
1153
|
+
preMintedSecrets,
|
|
1154
|
+
onStatusChange: watch?.onConnectorStatus
|
|
895
1155
|
});
|
|
896
1156
|
try {
|
|
897
1157
|
const report = await resourceManager.connectAll(connectorDeclarations, {
|
|
898
|
-
failOnReadWriteError: true
|
|
1158
|
+
failOnReadWriteError: true,
|
|
1159
|
+
deferMounts: deferFilesystemMounts
|
|
899
1160
|
});
|
|
900
1161
|
for (const r of report.results) {
|
|
901
1162
|
if (r.connected) {
|
|
@@ -918,13 +1179,9 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
918
1179
|
}
|
|
919
1180
|
}
|
|
920
1181
|
const resourcePromptSection = resourceManager ? buildConnectorPromptSection(resourceManager) : "";
|
|
921
|
-
const mcpLog = createLogger({
|
|
922
|
-
kind: "mcp",
|
|
923
|
-
subkind: "wiring",
|
|
924
|
-
instance: sessionMeta?.sessionId ?? "no-session"
|
|
925
|
-
});
|
|
926
1182
|
let mcpServers;
|
|
927
1183
|
let workspacePluginToShutdown = null;
|
|
1184
|
+
let externalMcpManager = null;
|
|
928
1185
|
if (driverType === "claude-sdk") {
|
|
929
1186
|
if (resourceManager) {
|
|
930
1187
|
const connectorsLog = createLogger({ kind: "mcp", subkind: "skaile-connectors" });
|
|
@@ -955,96 +1212,34 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
955
1212
|
mcpServers = { ...mcpServers ?? {}, "skaile-workspace": wsServer };
|
|
956
1213
|
}
|
|
957
1214
|
workspacePluginToShutdown = workspacePlugin;
|
|
958
|
-
|
|
959
|
-
|
|
960
|
-
const
|
|
961
|
-
|
|
962
|
-
|
|
963
|
-
|
|
964
|
-
|
|
965
|
-
|
|
966
|
-
|
|
967
|
-
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
|
|
973
|
-
|
|
974
|
-
|
|
975
|
-
|
|
976
|
-
|
|
977
|
-
resolvedDecl = {
|
|
978
|
-
...decl,
|
|
979
|
-
command: resolvedCommand,
|
|
980
|
-
args: resolvedArgs,
|
|
981
|
-
env: resolvedEnv
|
|
982
|
-
};
|
|
983
|
-
const allResolved = [
|
|
984
|
-
resolvedCommand ?? "",
|
|
985
|
-
...resolvedArgs ?? [],
|
|
986
|
-
...Object.values(resolvedEnv ?? {})
|
|
987
|
-
];
|
|
988
|
-
for (const v of allResolved) {
|
|
989
|
-
if (v.includes("${recipe:")) {
|
|
990
|
-
const recipeLog2 = createLogger({
|
|
991
|
-
kind: "mcp",
|
|
992
|
-
subkind: decl.id,
|
|
993
|
-
instance: "recipe-resolve"
|
|
994
|
-
});
|
|
995
|
-
recipeLog2.warn("unresolved recipe marker after substitution", {
|
|
996
|
-
value: v,
|
|
997
|
-
declId: decl.id
|
|
998
|
-
});
|
|
999
|
-
}
|
|
1000
|
-
}
|
|
1001
|
-
const missingPaths = validateSubstitutedPaths(resolvedCommand, resolvedArgs);
|
|
1002
|
-
if (missingPaths.length > 0) {
|
|
1003
|
-
const recipeLog2 = createLogger({
|
|
1004
|
-
kind: "mcp",
|
|
1005
|
-
subkind: decl.id,
|
|
1006
|
-
instance: "recipe-resolve"
|
|
1007
|
-
});
|
|
1008
|
-
recipeLog2.error("MCP server skipped: substituted path does not exist", void 0, {
|
|
1009
|
-
id: decl.id,
|
|
1010
|
-
...recipeLogKey,
|
|
1011
|
-
missing: missingPaths
|
|
1012
|
-
});
|
|
1013
|
-
continue;
|
|
1014
|
-
}
|
|
1015
|
-
const recipeLog = createLogger({
|
|
1016
|
-
kind: "mcp",
|
|
1017
|
-
subkind: decl.id,
|
|
1018
|
-
instance: "recipe-resolve"
|
|
1019
|
-
});
|
|
1020
|
-
recipeLog.info("recipe substitution complete", {
|
|
1021
|
-
...recipeLogKey,
|
|
1022
|
-
outPath
|
|
1023
|
-
});
|
|
1024
|
-
} catch (err) {
|
|
1025
|
-
const recipeLog = createLogger({
|
|
1026
|
-
kind: "mcp",
|
|
1027
|
-
subkind: decl.id,
|
|
1028
|
-
instance: "recipe-resolve"
|
|
1029
|
-
});
|
|
1030
|
-
recipeLog.error("MCP server skipped: recipe resolution failed", err, {
|
|
1031
|
-
id: decl.id,
|
|
1032
|
-
...recipeLogKey,
|
|
1033
|
-
flakeRef: nixFlakeRef
|
|
1034
|
-
});
|
|
1035
|
-
continue;
|
|
1036
|
-
}
|
|
1037
|
-
}
|
|
1215
|
+
}
|
|
1216
|
+
if (capabilityRegistry) {
|
|
1217
|
+
const resolvedDecls = resolveExternalMcpDeclarations(projectDir, sessionMeta?.sessionId);
|
|
1218
|
+
if (resolvedDecls.length > 0) {
|
|
1219
|
+
externalMcpManager = new ExternalMcpManager(
|
|
1220
|
+
capabilityRegistry,
|
|
1221
|
+
secretProvider,
|
|
1222
|
+
sessionMeta?.sessionId
|
|
1223
|
+
);
|
|
1224
|
+
await externalMcpManager.start(resolvedDecls);
|
|
1225
|
+
}
|
|
1226
|
+
} else if (driverType === "claude-sdk") {
|
|
1227
|
+
const mcpLog = createLogger({
|
|
1228
|
+
kind: "mcp",
|
|
1229
|
+
subkind: "wiring",
|
|
1230
|
+
instance: sessionMeta?.sessionId ?? "no-session"
|
|
1231
|
+
});
|
|
1232
|
+
const resolvedDecls = resolveExternalMcpDeclarations(projectDir, sessionMeta?.sessionId);
|
|
1233
|
+
for (const decl of resolvedDecls) {
|
|
1038
1234
|
const serverConfig = toSdkMcpServerConfig(
|
|
1039
|
-
|
|
1235
|
+
decl,
|
|
1040
1236
|
secretProvider
|
|
1041
1237
|
);
|
|
1042
1238
|
if (serverConfig) {
|
|
1043
1239
|
mcpServers = { ...mcpServers ?? {}, [decl.id]: serverConfig };
|
|
1044
|
-
|
|
1045
|
-
declLog.info("MCP server registered", {
|
|
1240
|
+
createLogger({ kind: "mcp", subkind: decl.id }).info("MCP server registered", {
|
|
1046
1241
|
transport: decl.transport ?? "stdio",
|
|
1047
|
-
...decl.transport === "stdio" || !decl.transport ? { command:
|
|
1242
|
+
...decl.transport === "stdio" || !decl.transport ? { command: decl.command, args: decl.args } : { url: decl.url }
|
|
1048
1243
|
});
|
|
1049
1244
|
} else {
|
|
1050
1245
|
mcpLog.error("MCP server config invalid (translation returned null)", void 0, {
|
|
@@ -1054,7 +1249,8 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
1054
1249
|
}
|
|
1055
1250
|
}
|
|
1056
1251
|
}
|
|
1057
|
-
if (!resourceManager && driverType !== "claude-sdk"
|
|
1252
|
+
if (!resourceManager && driverType !== "claude-sdk" && !externalMcpManager?.hasServers())
|
|
1253
|
+
return noopResult;
|
|
1058
1254
|
const startWatching = () => {
|
|
1059
1255
|
if (resourceManager && watch?.onFileChanged) {
|
|
1060
1256
|
const dedupTtlMs = watch.dedupTtlMs ?? 500;
|
|
@@ -1075,6 +1271,10 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
1075
1271
|
}
|
|
1076
1272
|
};
|
|
1077
1273
|
const dispose = async () => {
|
|
1274
|
+
try {
|
|
1275
|
+
await externalMcpManager?.dispose();
|
|
1276
|
+
} catch {
|
|
1277
|
+
}
|
|
1078
1278
|
if (workspacePluginToShutdown) {
|
|
1079
1279
|
try {
|
|
1080
1280
|
await workspacePluginToShutdown.shutdown();
|
|
@@ -1098,15 +1298,6 @@ async function buildAgentResources(projectDir, driverType, _onLog, watch, secret
|
|
|
1098
1298
|
return noopResult;
|
|
1099
1299
|
}
|
|
1100
1300
|
}
|
|
1101
|
-
var RESERVED_MCP_SERVER_IDS = /* @__PURE__ */ new Set(["skaile-connectors", "skaile-workspace"]);
|
|
1102
|
-
function resolveRecordSecrets(record, secrets) {
|
|
1103
|
-
if (!secrets) return record;
|
|
1104
|
-
const resolved = {};
|
|
1105
|
-
for (const [k, v] of Object.entries(record)) {
|
|
1106
|
-
resolved[k] = secrets.resolve(v) ?? v;
|
|
1107
|
-
}
|
|
1108
|
-
return resolved;
|
|
1109
|
-
}
|
|
1110
1301
|
function toSdkMcpServerConfig(decl, secrets) {
|
|
1111
1302
|
const transport = decl.transport ?? "stdio";
|
|
1112
1303
|
if (transport === "stdio") {
|
|
@@ -1184,7 +1375,9 @@ async function createAgentSession(config) {
|
|
|
1184
1375
|
sessionId
|
|
1185
1376
|
},
|
|
1186
1377
|
config.tokenMediator,
|
|
1187
|
-
config.preMintedSecrets
|
|
1378
|
+
config.preMintedSecrets,
|
|
1379
|
+
config.deferFilesystemMounts,
|
|
1380
|
+
config.capabilityRegistry
|
|
1188
1381
|
);
|
|
1189
1382
|
const wsConfig = wsConfigOverride ?? resolveSkWorkspaceConfig(projectDir);
|
|
1190
1383
|
const contextSection = buildContextSection(wsConfig.agent?.context);
|
|
@@ -2743,7 +2936,10 @@ function splitConnectorsForWire(manager) {
|
|
|
2743
2936
|
driver: c.driver,
|
|
2744
2937
|
access: c.access,
|
|
2745
2938
|
mountPath: c.mountPath,
|
|
2746
|
-
|
|
2939
|
+
// A deferred (background) mount is pre-registered with its path but
|
|
2940
|
+
// status "connecting" — report it as not-yet-mounted; the platform
|
|
2941
|
+
// flips it on the subsequent connector_status "connected" event.
|
|
2942
|
+
mounted: c.status === "connected",
|
|
2747
2943
|
source
|
|
2748
2944
|
});
|
|
2749
2945
|
} else {
|
|
@@ -3026,10 +3222,25 @@ async function startAgentServer(opts) {
|
|
|
3026
3222
|
action: event.action,
|
|
3027
3223
|
mountId: connectorId
|
|
3028
3224
|
});
|
|
3225
|
+
},
|
|
3226
|
+
// Forward connector lifecycle transitions to the platform. This is the
|
|
3227
|
+
// channel deferred (rclone-backed) filesystem mounts report progress on
|
|
3228
|
+
// after session_init_ack — a wedged remote shows as "still syncing".
|
|
3229
|
+
onConnectorStatus: (event) => {
|
|
3230
|
+
sendEvent(event);
|
|
3029
3231
|
}
|
|
3030
3232
|
},
|
|
3233
|
+
// Bring rclone-backed filesystem mounts up in the background so a slow
|
|
3234
|
+
// remote can't blow the platform's session_init_ack deadline and trigger
|
|
3235
|
+
// the container restart loop.
|
|
3236
|
+
deferFilesystemMounts: true,
|
|
3031
3237
|
onLog: (line) => log(`[serve] ${line}`),
|
|
3032
3238
|
capabilities: buildCapabilityHooks(),
|
|
3239
|
+
// Hand the registry to the session builder so external (declarative /
|
|
3240
|
+
// recipe-backed) MCP servers are spawned by the RUNNER and their tools
|
|
3241
|
+
// registered as `mcp`-origin capabilities — works on every driver, no
|
|
3242
|
+
// dependence on the claude-agent-sdk `mcpServers` query option.
|
|
3243
|
+
capabilityRegistry,
|
|
3033
3244
|
// v3: pre-minted credentials replace the tokenMediator for initial mints.
|
|
3034
3245
|
// Refresh routes through `host.refresh_credential` (invoked from the
|
|
3035
3246
|
// bridge driver's onAuthError callback). The legacy `tokenMediator`
|
|
@@ -3049,6 +3260,18 @@ async function startAgentServer(opts) {
|
|
|
3049
3260
|
let secretProvider;
|
|
3050
3261
|
let runtimeIdentity;
|
|
3051
3262
|
let preMintedSecrets;
|
|
3263
|
+
try {
|
|
3264
|
+
const { skillsDir } = resolveDriverPaths({
|
|
3265
|
+
driver: opts.driver ?? wsConfig.agent_config?.default?.driver ?? "claude-sdk"
|
|
3266
|
+
});
|
|
3267
|
+
const stagedSkills = stageMaterializedSkills(opts.projectDir, skillsDir);
|
|
3268
|
+
if (stagedSkills.length > 0) {
|
|
3269
|
+
log(
|
|
3270
|
+
`[serve] staged ${stagedSkills.length} materialized skill(s): ${stagedSkills.join(", ")}`
|
|
3271
|
+
);
|
|
3272
|
+
}
|
|
3273
|
+
} catch {
|
|
3274
|
+
}
|
|
3052
3275
|
if (secretsMode === "provisioned") {
|
|
3053
3276
|
log("[serve] secrets mode: provisioned \u2014 waiting for provision_secrets command");
|
|
3054
3277
|
} else {
|
|
@@ -4287,5 +4510,5 @@ function touchSession(state) {
|
|
|
4287
4510
|
}
|
|
4288
4511
|
|
|
4289
4512
|
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, 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 };
|
|
4290
|
-
//# sourceMappingURL=chunk-
|
|
4291
|
-
//# sourceMappingURL=chunk-
|
|
4513
|
+
//# sourceMappingURL=chunk-BJWUSHC4.js.map
|
|
4514
|
+
//# sourceMappingURL=chunk-BJWUSHC4.js.map
|