@oisincoveney/pipeline 1.5.4 → 1.5.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +4 -1
- package/dist/config.js +53 -3
- package/dist/index.js +171 -34
- package/dist/pipeline-runtime.js +168 -28
- package/dist/runner.js +104 -25
- package/docs/config-architecture.md +22 -1
- package/package.json +1 -1
package/dist/config.d.ts
CHANGED
|
@@ -57,8 +57,11 @@ declare const configSchema: z.ZodObject<{
|
|
|
57
57
|
}, z.core.$strict>>>;
|
|
58
58
|
mcp_servers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
59
59
|
args: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
60
|
-
|
|
60
|
+
bearer_token_env_var: z.ZodOptional<z.ZodString>;
|
|
61
|
+
command: z.ZodOptional<z.ZodString>;
|
|
61
62
|
env: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
63
|
+
headers: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
64
|
+
url: z.ZodOptional<z.ZodString>;
|
|
62
65
|
}, z.core.$strict>>>;
|
|
63
66
|
orchestrator: z.ZodObject<{
|
|
64
67
|
hooks: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
package/dist/config.js
CHANGED
|
@@ -21366,9 +21366,59 @@ var pathRefSchema = exports_external.object({
|
|
|
21366
21366
|
}).strict();
|
|
21367
21367
|
var mcpServerSchema = exports_external.object({
|
|
21368
21368
|
args: exports_external.array(exports_external.string()).optional(),
|
|
21369
|
-
|
|
21370
|
-
|
|
21371
|
-
|
|
21369
|
+
bearer_token_env_var: exports_external.string().min(1).optional(),
|
|
21370
|
+
command: exports_external.string().min(1).optional(),
|
|
21371
|
+
env: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
21372
|
+
headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
21373
|
+
url: exports_external.string().url().refine((value) => ["http:", "https:"].includes(new URL(value).protocol), {
|
|
21374
|
+
message: "MCP server url must use http or https"
|
|
21375
|
+
}).optional()
|
|
21376
|
+
}).strict().superRefine((server, ctx) => {
|
|
21377
|
+
const hasCommand = Boolean(server.command);
|
|
21378
|
+
const hasUrl = Boolean(server.url);
|
|
21379
|
+
if (hasCommand === hasUrl) {
|
|
21380
|
+
ctx.addIssue({
|
|
21381
|
+
code: "custom",
|
|
21382
|
+
message: "MCP server must declare exactly one of command or url",
|
|
21383
|
+
path: hasCommand ? ["url"] : ["command"]
|
|
21384
|
+
});
|
|
21385
|
+
}
|
|
21386
|
+
if (hasUrl && server.args) {
|
|
21387
|
+
ctx.addIssue({
|
|
21388
|
+
code: "custom",
|
|
21389
|
+
message: "args are only valid for command MCP servers",
|
|
21390
|
+
path: ["args"]
|
|
21391
|
+
});
|
|
21392
|
+
}
|
|
21393
|
+
if (hasUrl && server.env) {
|
|
21394
|
+
ctx.addIssue({
|
|
21395
|
+
code: "custom",
|
|
21396
|
+
message: "env is only valid for command MCP servers",
|
|
21397
|
+
path: ["env"]
|
|
21398
|
+
});
|
|
21399
|
+
}
|
|
21400
|
+
if (hasCommand && server.headers) {
|
|
21401
|
+
ctx.addIssue({
|
|
21402
|
+
code: "custom",
|
|
21403
|
+
message: "headers are only valid for url MCP servers",
|
|
21404
|
+
path: ["headers"]
|
|
21405
|
+
});
|
|
21406
|
+
}
|
|
21407
|
+
if (hasCommand && server.bearer_token_env_var) {
|
|
21408
|
+
ctx.addIssue({
|
|
21409
|
+
code: "custom",
|
|
21410
|
+
message: "bearer_token_env_var is only valid for url MCP servers",
|
|
21411
|
+
path: ["bearer_token_env_var"]
|
|
21412
|
+
});
|
|
21413
|
+
}
|
|
21414
|
+
if (hasUrl && server.bearer_token_env_var && Object.keys(server.headers ?? {}).some((key) => key.toLowerCase() === "authorization")) {
|
|
21415
|
+
ctx.addIssue({
|
|
21416
|
+
code: "custom",
|
|
21417
|
+
message: "headers.Authorization cannot be combined with bearer_token_env_var",
|
|
21418
|
+
path: ["bearer_token_env_var"]
|
|
21419
|
+
});
|
|
21420
|
+
}
|
|
21421
|
+
});
|
|
21372
21422
|
var instructionsSchema = exports_external.object({
|
|
21373
21423
|
inline: exports_external.string().min(1).optional(),
|
|
21374
21424
|
path: exports_external.string().min(1).optional()
|
package/dist/index.js
CHANGED
|
@@ -27439,9 +27439,59 @@ var pathRefSchema = exports_external.object({
|
|
|
27439
27439
|
}).strict();
|
|
27440
27440
|
var mcpServerSchema = exports_external.object({
|
|
27441
27441
|
args: exports_external.array(exports_external.string()).optional(),
|
|
27442
|
-
|
|
27443
|
-
|
|
27444
|
-
|
|
27442
|
+
bearer_token_env_var: exports_external.string().min(1).optional(),
|
|
27443
|
+
command: exports_external.string().min(1).optional(),
|
|
27444
|
+
env: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
27445
|
+
headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
27446
|
+
url: exports_external.string().url().refine((value) => ["http:", "https:"].includes(new URL(value).protocol), {
|
|
27447
|
+
message: "MCP server url must use http or https"
|
|
27448
|
+
}).optional()
|
|
27449
|
+
}).strict().superRefine((server, ctx) => {
|
|
27450
|
+
const hasCommand = Boolean(server.command);
|
|
27451
|
+
const hasUrl = Boolean(server.url);
|
|
27452
|
+
if (hasCommand === hasUrl) {
|
|
27453
|
+
ctx.addIssue({
|
|
27454
|
+
code: "custom",
|
|
27455
|
+
message: "MCP server must declare exactly one of command or url",
|
|
27456
|
+
path: hasCommand ? ["url"] : ["command"]
|
|
27457
|
+
});
|
|
27458
|
+
}
|
|
27459
|
+
if (hasUrl && server.args) {
|
|
27460
|
+
ctx.addIssue({
|
|
27461
|
+
code: "custom",
|
|
27462
|
+
message: "args are only valid for command MCP servers",
|
|
27463
|
+
path: ["args"]
|
|
27464
|
+
});
|
|
27465
|
+
}
|
|
27466
|
+
if (hasUrl && server.env) {
|
|
27467
|
+
ctx.addIssue({
|
|
27468
|
+
code: "custom",
|
|
27469
|
+
message: "env is only valid for command MCP servers",
|
|
27470
|
+
path: ["env"]
|
|
27471
|
+
});
|
|
27472
|
+
}
|
|
27473
|
+
if (hasCommand && server.headers) {
|
|
27474
|
+
ctx.addIssue({
|
|
27475
|
+
code: "custom",
|
|
27476
|
+
message: "headers are only valid for url MCP servers",
|
|
27477
|
+
path: ["headers"]
|
|
27478
|
+
});
|
|
27479
|
+
}
|
|
27480
|
+
if (hasCommand && server.bearer_token_env_var) {
|
|
27481
|
+
ctx.addIssue({
|
|
27482
|
+
code: "custom",
|
|
27483
|
+
message: "bearer_token_env_var is only valid for url MCP servers",
|
|
27484
|
+
path: ["bearer_token_env_var"]
|
|
27485
|
+
});
|
|
27486
|
+
}
|
|
27487
|
+
if (hasUrl && server.bearer_token_env_var && Object.keys(server.headers ?? {}).some((key) => key.toLowerCase() === "authorization")) {
|
|
27488
|
+
ctx.addIssue({
|
|
27489
|
+
code: "custom",
|
|
27490
|
+
message: "headers.Authorization cannot be combined with bearer_token_env_var",
|
|
27491
|
+
path: ["bearer_token_env_var"]
|
|
27492
|
+
});
|
|
27493
|
+
}
|
|
27494
|
+
});
|
|
27445
27495
|
var instructionsSchema = exports_external.object({
|
|
27446
27496
|
inline: exports_external.string().min(1).optional(),
|
|
27447
27497
|
path: exports_external.string().min(1).optional()
|
|
@@ -28866,25 +28916,22 @@ function cliDispatchLine(route) {
|
|
|
28866
28916
|
}
|
|
28867
28917
|
function runnerCliCommand(route) {
|
|
28868
28918
|
if (route.runnerId === "codex") {
|
|
28869
|
-
return
|
|
28919
|
+
return "codex exec --json -C <repo-root> --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check <node prompt>";
|
|
28870
28920
|
}
|
|
28871
28921
|
if (route.runnerId === "kimi") {
|
|
28872
|
-
return `kimi --print --agent-file .kimi/agents/${route.profileId}.yaml --work-dir <repo-root> --final-message-only --prompt <node prompt>`;
|
|
28922
|
+
return `kimi --print --agent-file .kimi/agents/${route.profileId}.yaml --work-dir <repo-root> --yolo --final-message-only --prompt <node prompt>`;
|
|
28873
28923
|
}
|
|
28874
28924
|
if (route.runnerId === "opencode") {
|
|
28875
28925
|
return `opencode run --agent ${route.profileId} --format json --dir <repo-root> <node prompt>`;
|
|
28876
28926
|
}
|
|
28877
28927
|
if (route.runnerId === "claude") {
|
|
28878
|
-
return `claude --agent ${route.profileId} --print -p <node prompt>`;
|
|
28928
|
+
return `claude --agent ${route.profileId} --print --dangerously-skip-permissions -p <node prompt>`;
|
|
28879
28929
|
}
|
|
28880
28930
|
if (route.runnerId === "pi") {
|
|
28881
28931
|
return "pi --print --no-session <node prompt>";
|
|
28882
28932
|
}
|
|
28883
28933
|
return `${route.runnerId} <node prompt>`;
|
|
28884
28934
|
}
|
|
28885
|
-
function codexSandbox(profile) {
|
|
28886
|
-
return profile.filesystem?.mode === "workspace-write" ? "workspace-write" : "read-only";
|
|
28887
|
-
}
|
|
28888
28935
|
function nodePromptContract(workflowId, routes) {
|
|
28889
28936
|
const hasCliRoutes = routes.some((route) => route.kind === "cli");
|
|
28890
28937
|
const lead = hasCliRoutes ? "For each CLI node prompt include:" : "For each native node prompt include:";
|
|
@@ -36995,6 +37042,8 @@ import {
|
|
|
36995
37042
|
} from "node:fs";
|
|
36996
37043
|
import { tmpdir } from "node:os";
|
|
36997
37044
|
import { dirname as dirname3, join as join5 } from "node:path";
|
|
37045
|
+
var TOML_BARE_KEY_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
37046
|
+
|
|
36998
37047
|
class RunnerCapabilityError extends Error {
|
|
36999
37048
|
constructor(message) {
|
|
37000
37049
|
super(message);
|
|
@@ -37017,6 +37066,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
|
|
|
37017
37066
|
...claudeToolArgs(tools),
|
|
37018
37067
|
...mcpArgs,
|
|
37019
37068
|
...skillArgs,
|
|
37069
|
+
"--dangerously-skip-permissions",
|
|
37020
37070
|
"-p",
|
|
37021
37071
|
prompt
|
|
37022
37072
|
];
|
|
@@ -37029,10 +37079,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
|
|
|
37029
37079
|
...optionalModelArgs(harness, options2.runner, options2.actor),
|
|
37030
37080
|
...mcpArgs,
|
|
37031
37081
|
...skillArgs,
|
|
37032
|
-
"--sandbox",
|
|
37033
|
-
codexSandboxFor(options2.actor),
|
|
37034
|
-
"--config",
|
|
37035
|
-
'approval_policy="never"',
|
|
37082
|
+
"--dangerously-bypass-approvals-and-sandbox",
|
|
37036
37083
|
"--skip-git-repo-check",
|
|
37037
37084
|
prompt
|
|
37038
37085
|
];
|
|
@@ -37070,6 +37117,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
|
|
|
37070
37117
|
...optionalModelArgs(harness, options2.runner, options2.actor),
|
|
37071
37118
|
...mcpArgs,
|
|
37072
37119
|
...skillArgs,
|
|
37120
|
+
"--yolo",
|
|
37073
37121
|
"--final-message-only",
|
|
37074
37122
|
"--prompt",
|
|
37075
37123
|
prompt
|
|
@@ -37080,9 +37128,6 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
|
|
|
37080
37128
|
}
|
|
37081
37129
|
}
|
|
37082
37130
|
}
|
|
37083
|
-
function codexSandboxFor(actor) {
|
|
37084
|
-
return actor?.filesystem?.mode === "read-only" ? "read-only" : "workspace-write";
|
|
37085
|
-
}
|
|
37086
37131
|
function createRunnerLaunchPlan(config2, input) {
|
|
37087
37132
|
const profile = input.profileId ? config2.profiles[input.profileId] : undefined;
|
|
37088
37133
|
if (input.profileId && !profile) {
|
|
@@ -37215,12 +37260,12 @@ function mcpArgsFor(runnerType, config2, actor) {
|
|
|
37215
37260
|
if (runnerType === "claude") {
|
|
37216
37261
|
return [
|
|
37217
37262
|
"--mcp-config",
|
|
37218
|
-
JSON.stringify(
|
|
37263
|
+
JSON.stringify(toClaudeMcpConfig(servers)),
|
|
37219
37264
|
"--strict-mcp-config"
|
|
37220
37265
|
];
|
|
37221
37266
|
}
|
|
37222
37267
|
if (runnerType === "kimi") {
|
|
37223
|
-
return ["--mcp-config", JSON.stringify(
|
|
37268
|
+
return ["--mcp-config", JSON.stringify(toKimiMcpConfig(servers))];
|
|
37224
37269
|
}
|
|
37225
37270
|
if (runnerType === "codex") {
|
|
37226
37271
|
return codexMcpArgs(servers);
|
|
@@ -37240,39 +37285,120 @@ function runnerEnv(runnerType, config2, actor, worktreePath, nodeId) {
|
|
|
37240
37285
|
PIPELINE_WORKTREE: worktreePath
|
|
37241
37286
|
};
|
|
37242
37287
|
}
|
|
37243
|
-
function
|
|
37244
|
-
return
|
|
37288
|
+
function isRemoteMcpServer(server) {
|
|
37289
|
+
return typeof server.url === "string";
|
|
37245
37290
|
}
|
|
37246
|
-
function
|
|
37291
|
+
function headersWithBearerTokenEnv(server, renderTokenRef) {
|
|
37292
|
+
const headers = { ...server.headers ?? {} };
|
|
37293
|
+
if (server.bearer_token_env_var) {
|
|
37294
|
+
headers.Authorization = `Bearer ${renderTokenRef(server.bearer_token_env_var)}`;
|
|
37295
|
+
}
|
|
37296
|
+
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
37297
|
+
}
|
|
37298
|
+
function toClaudeMcpConfig(servers) {
|
|
37299
|
+
return {
|
|
37300
|
+
mcpServers: Object.fromEntries(Object.entries(servers).map(([id, server]) => {
|
|
37301
|
+
if (isRemoteMcpServer(server)) {
|
|
37302
|
+
const headers = headersWithBearerTokenEnv(server, (envVar) => `\${${envVar}}`);
|
|
37303
|
+
return [
|
|
37304
|
+
id,
|
|
37305
|
+
{
|
|
37306
|
+
type: "http",
|
|
37307
|
+
url: server.url,
|
|
37308
|
+
...headers ? { headers } : {}
|
|
37309
|
+
}
|
|
37310
|
+
];
|
|
37311
|
+
}
|
|
37312
|
+
return [
|
|
37313
|
+
id,
|
|
37314
|
+
{
|
|
37315
|
+
command: server.command,
|
|
37316
|
+
...server.args ? { args: server.args } : {},
|
|
37317
|
+
...server.env ? { env: server.env } : {}
|
|
37318
|
+
}
|
|
37319
|
+
];
|
|
37320
|
+
}))
|
|
37321
|
+
};
|
|
37322
|
+
}
|
|
37323
|
+
function toKimiMcpConfig(servers) {
|
|
37247
37324
|
return {
|
|
37248
|
-
|
|
37325
|
+
mcpServers: Object.fromEntries(Object.entries(servers).map(([id, server]) => [
|
|
37249
37326
|
id,
|
|
37250
|
-
{
|
|
37251
|
-
|
|
37252
|
-
|
|
37253
|
-
...server.
|
|
37254
|
-
|
|
37327
|
+
isRemoteMcpServer(server) ? {
|
|
37328
|
+
url: server.url,
|
|
37329
|
+
...server.headers ? { headers: server.headers } : {},
|
|
37330
|
+
...server.bearer_token_env_var ? { bearerTokenEnvVar: server.bearer_token_env_var } : {}
|
|
37331
|
+
} : {
|
|
37332
|
+
command: server.command,
|
|
37333
|
+
...server.args ? { args: server.args } : {},
|
|
37334
|
+
...server.env ? { env: server.env } : {}
|
|
37255
37335
|
}
|
|
37256
37336
|
]))
|
|
37257
37337
|
};
|
|
37258
37338
|
}
|
|
37339
|
+
function toOpenCodeMcpConfig(servers) {
|
|
37340
|
+
return {
|
|
37341
|
+
mcp: Object.fromEntries(Object.entries(servers).map(([id, server]) => {
|
|
37342
|
+
if (isRemoteMcpServer(server)) {
|
|
37343
|
+
const headers = headersWithBearerTokenEnv(server, (envVar) => `{env:${envVar}}`);
|
|
37344
|
+
return [
|
|
37345
|
+
id,
|
|
37346
|
+
{
|
|
37347
|
+
enabled: true,
|
|
37348
|
+
...headers ? { headers } : {},
|
|
37349
|
+
type: "remote",
|
|
37350
|
+
url: server.url
|
|
37351
|
+
}
|
|
37352
|
+
];
|
|
37353
|
+
}
|
|
37354
|
+
return [
|
|
37355
|
+
id,
|
|
37356
|
+
{
|
|
37357
|
+
command: [server.command, ...server.args ?? []],
|
|
37358
|
+
enabled: true,
|
|
37359
|
+
...server.env ? { environment: server.env } : {},
|
|
37360
|
+
type: "local"
|
|
37361
|
+
}
|
|
37362
|
+
];
|
|
37363
|
+
}))
|
|
37364
|
+
};
|
|
37365
|
+
}
|
|
37259
37366
|
function codexMcpArgs(servers) {
|
|
37260
|
-
return Object.entries(servers).flatMap(([id, server]) =>
|
|
37261
|
-
|
|
37262
|
-
|
|
37263
|
-
|
|
37264
|
-
|
|
37265
|
-
|
|
37367
|
+
return Object.entries(servers).flatMap(([id, server]) => {
|
|
37368
|
+
if (isRemoteMcpServer(server)) {
|
|
37369
|
+
return [
|
|
37370
|
+
"--config",
|
|
37371
|
+
`mcp_servers.${id}.url=${tomlValue(server.url)}`,
|
|
37372
|
+
...server.headers ? [
|
|
37373
|
+
"--config",
|
|
37374
|
+
`mcp_servers.${id}.http_headers=${tomlValue(server.headers)}`
|
|
37375
|
+
] : [],
|
|
37376
|
+
...server.bearer_token_env_var ? [
|
|
37377
|
+
"--config",
|
|
37378
|
+
`mcp_servers.${id}.bearer_token_env_var=${tomlValue(server.bearer_token_env_var)}`
|
|
37379
|
+
] : []
|
|
37380
|
+
];
|
|
37381
|
+
}
|
|
37382
|
+
return [
|
|
37383
|
+
"--config",
|
|
37384
|
+
`mcp_servers.${id}.command=${tomlValue(server.command)}`,
|
|
37385
|
+
...server.args ? ["--config", `mcp_servers.${id}.args=${tomlValue(server.args)}`] : [],
|
|
37386
|
+
...server.env ? ["--config", `mcp_servers.${id}.env=${tomlValue(server.env)}`] : []
|
|
37387
|
+
];
|
|
37388
|
+
});
|
|
37266
37389
|
}
|
|
37267
37390
|
function tomlValue(value) {
|
|
37268
37391
|
if (Array.isArray(value)) {
|
|
37269
37392
|
return `[${value.map(tomlValue).join(", ")}]`;
|
|
37270
37393
|
}
|
|
37271
37394
|
if (value && typeof value === "object") {
|
|
37272
|
-
return `{ ${Object.entries(value).map(([key, item]) => `${key} = ${tomlValue(item)}`).join(", ")} }`;
|
|
37395
|
+
return `{ ${Object.entries(value).map(([key, item]) => `${tomlKey(key)} = ${tomlValue(item)}`).join(", ")} }`;
|
|
37273
37396
|
}
|
|
37274
37397
|
return JSON.stringify(value);
|
|
37275
37398
|
}
|
|
37399
|
+
function tomlKey(key) {
|
|
37400
|
+
return TOML_BARE_KEY_PATTERN.test(key) ? key : JSON.stringify(key);
|
|
37401
|
+
}
|
|
37276
37402
|
function nativeStrategy(config2, input, runnerId) {
|
|
37277
37403
|
const runner = config2.runners[runnerId];
|
|
37278
37404
|
const profile = input.profileId ? config2.profiles[input.profileId] : undefined;
|
|
@@ -37957,8 +38083,19 @@ function renderMcpReferences(ids, registry2) {
|
|
|
37957
38083
|
"Loaded MCP servers:",
|
|
37958
38084
|
...ids.map((id) => {
|
|
37959
38085
|
const server = registry2[id];
|
|
38086
|
+
if (server?.url) {
|
|
38087
|
+
return [
|
|
38088
|
+
`## ${id}`,
|
|
38089
|
+
"transport: http",
|
|
38090
|
+
`url: ${server.url}`,
|
|
38091
|
+
`headers: ${Object.keys(server.headers ?? {}).join(", ") || "none"}`,
|
|
38092
|
+
`bearer_token_env_var: ${server.bearer_token_env_var ?? "none"}`
|
|
38093
|
+
].join(`
|
|
38094
|
+
`);
|
|
38095
|
+
}
|
|
37960
38096
|
return [
|
|
37961
38097
|
`## ${id}`,
|
|
38098
|
+
"transport: stdio",
|
|
37962
38099
|
`command: ${server?.command ?? ""}`,
|
|
37963
38100
|
`args: ${(server?.args ?? []).join(" ") || "none"}`,
|
|
37964
38101
|
`env: ${Object.keys(server?.env ?? {}).join(", ") || "none"}`
|
package/dist/pipeline-runtime.js
CHANGED
|
@@ -28569,9 +28569,59 @@ var pathRefSchema = exports_external.object({
|
|
|
28569
28569
|
}).strict();
|
|
28570
28570
|
var mcpServerSchema = exports_external.object({
|
|
28571
28571
|
args: exports_external.array(exports_external.string()).optional(),
|
|
28572
|
-
|
|
28573
|
-
|
|
28574
|
-
|
|
28572
|
+
bearer_token_env_var: exports_external.string().min(1).optional(),
|
|
28573
|
+
command: exports_external.string().min(1).optional(),
|
|
28574
|
+
env: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
28575
|
+
headers: exports_external.record(exports_external.string(), exports_external.string()).optional(),
|
|
28576
|
+
url: exports_external.string().url().refine((value) => ["http:", "https:"].includes(new URL(value).protocol), {
|
|
28577
|
+
message: "MCP server url must use http or https"
|
|
28578
|
+
}).optional()
|
|
28579
|
+
}).strict().superRefine((server, ctx) => {
|
|
28580
|
+
const hasCommand = Boolean(server.command);
|
|
28581
|
+
const hasUrl = Boolean(server.url);
|
|
28582
|
+
if (hasCommand === hasUrl) {
|
|
28583
|
+
ctx.addIssue({
|
|
28584
|
+
code: "custom",
|
|
28585
|
+
message: "MCP server must declare exactly one of command or url",
|
|
28586
|
+
path: hasCommand ? ["url"] : ["command"]
|
|
28587
|
+
});
|
|
28588
|
+
}
|
|
28589
|
+
if (hasUrl && server.args) {
|
|
28590
|
+
ctx.addIssue({
|
|
28591
|
+
code: "custom",
|
|
28592
|
+
message: "args are only valid for command MCP servers",
|
|
28593
|
+
path: ["args"]
|
|
28594
|
+
});
|
|
28595
|
+
}
|
|
28596
|
+
if (hasUrl && server.env) {
|
|
28597
|
+
ctx.addIssue({
|
|
28598
|
+
code: "custom",
|
|
28599
|
+
message: "env is only valid for command MCP servers",
|
|
28600
|
+
path: ["env"]
|
|
28601
|
+
});
|
|
28602
|
+
}
|
|
28603
|
+
if (hasCommand && server.headers) {
|
|
28604
|
+
ctx.addIssue({
|
|
28605
|
+
code: "custom",
|
|
28606
|
+
message: "headers are only valid for url MCP servers",
|
|
28607
|
+
path: ["headers"]
|
|
28608
|
+
});
|
|
28609
|
+
}
|
|
28610
|
+
if (hasCommand && server.bearer_token_env_var) {
|
|
28611
|
+
ctx.addIssue({
|
|
28612
|
+
code: "custom",
|
|
28613
|
+
message: "bearer_token_env_var is only valid for url MCP servers",
|
|
28614
|
+
path: ["bearer_token_env_var"]
|
|
28615
|
+
});
|
|
28616
|
+
}
|
|
28617
|
+
if (hasUrl && server.bearer_token_env_var && Object.keys(server.headers ?? {}).some((key) => key.toLowerCase() === "authorization")) {
|
|
28618
|
+
ctx.addIssue({
|
|
28619
|
+
code: "custom",
|
|
28620
|
+
message: "headers.Authorization cannot be combined with bearer_token_env_var",
|
|
28621
|
+
path: ["bearer_token_env_var"]
|
|
28622
|
+
});
|
|
28623
|
+
}
|
|
28624
|
+
});
|
|
28575
28625
|
var instructionsSchema = exports_external.object({
|
|
28576
28626
|
inline: exports_external.string().min(1).optional(),
|
|
28577
28627
|
path: exports_external.string().min(1).optional()
|
|
@@ -29485,6 +29535,8 @@ import {
|
|
|
29485
29535
|
} from "node:fs";
|
|
29486
29536
|
import { tmpdir } from "node:os";
|
|
29487
29537
|
import { dirname, join as join3 } from "node:path";
|
|
29538
|
+
var TOML_BARE_KEY_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
29539
|
+
|
|
29488
29540
|
class RunnerCapabilityError extends Error {
|
|
29489
29541
|
constructor(message) {
|
|
29490
29542
|
super(message);
|
|
@@ -29507,6 +29559,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
|
|
|
29507
29559
|
...claudeToolArgs(tools),
|
|
29508
29560
|
...mcpArgs,
|
|
29509
29561
|
...skillArgs,
|
|
29562
|
+
"--dangerously-skip-permissions",
|
|
29510
29563
|
"-p",
|
|
29511
29564
|
prompt
|
|
29512
29565
|
];
|
|
@@ -29519,10 +29572,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
|
|
|
29519
29572
|
...optionalModelArgs(harness, options.runner, options.actor),
|
|
29520
29573
|
...mcpArgs,
|
|
29521
29574
|
...skillArgs,
|
|
29522
|
-
"--sandbox",
|
|
29523
|
-
codexSandboxFor(options.actor),
|
|
29524
|
-
"--config",
|
|
29525
|
-
'approval_policy="never"',
|
|
29575
|
+
"--dangerously-bypass-approvals-and-sandbox",
|
|
29526
29576
|
"--skip-git-repo-check",
|
|
29527
29577
|
prompt
|
|
29528
29578
|
];
|
|
@@ -29560,6 +29610,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
|
|
|
29560
29610
|
...optionalModelArgs(harness, options.runner, options.actor),
|
|
29561
29611
|
...mcpArgs,
|
|
29562
29612
|
...skillArgs,
|
|
29613
|
+
"--yolo",
|
|
29563
29614
|
"--final-message-only",
|
|
29564
29615
|
"--prompt",
|
|
29565
29616
|
prompt
|
|
@@ -29570,9 +29621,6 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
|
|
|
29570
29621
|
}
|
|
29571
29622
|
}
|
|
29572
29623
|
}
|
|
29573
|
-
function codexSandboxFor(actor) {
|
|
29574
|
-
return actor?.filesystem?.mode === "read-only" ? "read-only" : "workspace-write";
|
|
29575
|
-
}
|
|
29576
29624
|
function createRunnerLaunchPlan(config2, input) {
|
|
29577
29625
|
const profile = input.profileId ? config2.profiles[input.profileId] : undefined;
|
|
29578
29626
|
if (input.profileId && !profile) {
|
|
@@ -29699,12 +29747,12 @@ function mcpArgsFor(runnerType, config2, actor) {
|
|
|
29699
29747
|
if (runnerType === "claude") {
|
|
29700
29748
|
return [
|
|
29701
29749
|
"--mcp-config",
|
|
29702
|
-
JSON.stringify(
|
|
29750
|
+
JSON.stringify(toClaudeMcpConfig(servers)),
|
|
29703
29751
|
"--strict-mcp-config"
|
|
29704
29752
|
];
|
|
29705
29753
|
}
|
|
29706
29754
|
if (runnerType === "kimi") {
|
|
29707
|
-
return ["--mcp-config", JSON.stringify(
|
|
29755
|
+
return ["--mcp-config", JSON.stringify(toKimiMcpConfig(servers))];
|
|
29708
29756
|
}
|
|
29709
29757
|
if (runnerType === "codex") {
|
|
29710
29758
|
return codexMcpArgs(servers);
|
|
@@ -29724,39 +29772,120 @@ function runnerEnv(runnerType, config2, actor, worktreePath, nodeId) {
|
|
|
29724
29772
|
PIPELINE_WORKTREE: worktreePath
|
|
29725
29773
|
};
|
|
29726
29774
|
}
|
|
29727
|
-
function
|
|
29728
|
-
return
|
|
29775
|
+
function isRemoteMcpServer(server) {
|
|
29776
|
+
return typeof server.url === "string";
|
|
29729
29777
|
}
|
|
29730
|
-
function
|
|
29778
|
+
function headersWithBearerTokenEnv(server, renderTokenRef) {
|
|
29779
|
+
const headers = { ...server.headers ?? {} };
|
|
29780
|
+
if (server.bearer_token_env_var) {
|
|
29781
|
+
headers.Authorization = `Bearer ${renderTokenRef(server.bearer_token_env_var)}`;
|
|
29782
|
+
}
|
|
29783
|
+
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
29784
|
+
}
|
|
29785
|
+
function toClaudeMcpConfig(servers) {
|
|
29731
29786
|
return {
|
|
29732
|
-
|
|
29787
|
+
mcpServers: Object.fromEntries(Object.entries(servers).map(([id, server]) => {
|
|
29788
|
+
if (isRemoteMcpServer(server)) {
|
|
29789
|
+
const headers = headersWithBearerTokenEnv(server, (envVar) => `\${${envVar}}`);
|
|
29790
|
+
return [
|
|
29791
|
+
id,
|
|
29792
|
+
{
|
|
29793
|
+
type: "http",
|
|
29794
|
+
url: server.url,
|
|
29795
|
+
...headers ? { headers } : {}
|
|
29796
|
+
}
|
|
29797
|
+
];
|
|
29798
|
+
}
|
|
29799
|
+
return [
|
|
29800
|
+
id,
|
|
29801
|
+
{
|
|
29802
|
+
command: server.command,
|
|
29803
|
+
...server.args ? { args: server.args } : {},
|
|
29804
|
+
...server.env ? { env: server.env } : {}
|
|
29805
|
+
}
|
|
29806
|
+
];
|
|
29807
|
+
}))
|
|
29808
|
+
};
|
|
29809
|
+
}
|
|
29810
|
+
function toKimiMcpConfig(servers) {
|
|
29811
|
+
return {
|
|
29812
|
+
mcpServers: Object.fromEntries(Object.entries(servers).map(([id, server]) => [
|
|
29733
29813
|
id,
|
|
29734
|
-
{
|
|
29735
|
-
|
|
29736
|
-
|
|
29737
|
-
...server.
|
|
29738
|
-
|
|
29814
|
+
isRemoteMcpServer(server) ? {
|
|
29815
|
+
url: server.url,
|
|
29816
|
+
...server.headers ? { headers: server.headers } : {},
|
|
29817
|
+
...server.bearer_token_env_var ? { bearerTokenEnvVar: server.bearer_token_env_var } : {}
|
|
29818
|
+
} : {
|
|
29819
|
+
command: server.command,
|
|
29820
|
+
...server.args ? { args: server.args } : {},
|
|
29821
|
+
...server.env ? { env: server.env } : {}
|
|
29739
29822
|
}
|
|
29740
29823
|
]))
|
|
29741
29824
|
};
|
|
29742
29825
|
}
|
|
29826
|
+
function toOpenCodeMcpConfig(servers) {
|
|
29827
|
+
return {
|
|
29828
|
+
mcp: Object.fromEntries(Object.entries(servers).map(([id, server]) => {
|
|
29829
|
+
if (isRemoteMcpServer(server)) {
|
|
29830
|
+
const headers = headersWithBearerTokenEnv(server, (envVar) => `{env:${envVar}}`);
|
|
29831
|
+
return [
|
|
29832
|
+
id,
|
|
29833
|
+
{
|
|
29834
|
+
enabled: true,
|
|
29835
|
+
...headers ? { headers } : {},
|
|
29836
|
+
type: "remote",
|
|
29837
|
+
url: server.url
|
|
29838
|
+
}
|
|
29839
|
+
];
|
|
29840
|
+
}
|
|
29841
|
+
return [
|
|
29842
|
+
id,
|
|
29843
|
+
{
|
|
29844
|
+
command: [server.command, ...server.args ?? []],
|
|
29845
|
+
enabled: true,
|
|
29846
|
+
...server.env ? { environment: server.env } : {},
|
|
29847
|
+
type: "local"
|
|
29848
|
+
}
|
|
29849
|
+
];
|
|
29850
|
+
}))
|
|
29851
|
+
};
|
|
29852
|
+
}
|
|
29743
29853
|
function codexMcpArgs(servers) {
|
|
29744
|
-
return Object.entries(servers).flatMap(([id, server]) =>
|
|
29745
|
-
|
|
29746
|
-
|
|
29747
|
-
|
|
29748
|
-
|
|
29749
|
-
|
|
29854
|
+
return Object.entries(servers).flatMap(([id, server]) => {
|
|
29855
|
+
if (isRemoteMcpServer(server)) {
|
|
29856
|
+
return [
|
|
29857
|
+
"--config",
|
|
29858
|
+
`mcp_servers.${id}.url=${tomlValue(server.url)}`,
|
|
29859
|
+
...server.headers ? [
|
|
29860
|
+
"--config",
|
|
29861
|
+
`mcp_servers.${id}.http_headers=${tomlValue(server.headers)}`
|
|
29862
|
+
] : [],
|
|
29863
|
+
...server.bearer_token_env_var ? [
|
|
29864
|
+
"--config",
|
|
29865
|
+
`mcp_servers.${id}.bearer_token_env_var=${tomlValue(server.bearer_token_env_var)}`
|
|
29866
|
+
] : []
|
|
29867
|
+
];
|
|
29868
|
+
}
|
|
29869
|
+
return [
|
|
29870
|
+
"--config",
|
|
29871
|
+
`mcp_servers.${id}.command=${tomlValue(server.command)}`,
|
|
29872
|
+
...server.args ? ["--config", `mcp_servers.${id}.args=${tomlValue(server.args)}`] : [],
|
|
29873
|
+
...server.env ? ["--config", `mcp_servers.${id}.env=${tomlValue(server.env)}`] : []
|
|
29874
|
+
];
|
|
29875
|
+
});
|
|
29750
29876
|
}
|
|
29751
29877
|
function tomlValue(value) {
|
|
29752
29878
|
if (Array.isArray(value)) {
|
|
29753
29879
|
return `[${value.map(tomlValue).join(", ")}]`;
|
|
29754
29880
|
}
|
|
29755
29881
|
if (value && typeof value === "object") {
|
|
29756
|
-
return `{ ${Object.entries(value).map(([key, item]) => `${key} = ${tomlValue(item)}`).join(", ")} }`;
|
|
29882
|
+
return `{ ${Object.entries(value).map(([key, item]) => `${tomlKey(key)} = ${tomlValue(item)}`).join(", ")} }`;
|
|
29757
29883
|
}
|
|
29758
29884
|
return JSON.stringify(value);
|
|
29759
29885
|
}
|
|
29886
|
+
function tomlKey(key) {
|
|
29887
|
+
return TOML_BARE_KEY_PATTERN.test(key) ? key : JSON.stringify(key);
|
|
29888
|
+
}
|
|
29760
29889
|
function nativeStrategy(config2, input, runnerId) {
|
|
29761
29890
|
const runner = config2.runners[runnerId];
|
|
29762
29891
|
const profile = input.profileId ? config2.profiles[input.profileId] : undefined;
|
|
@@ -30663,8 +30792,19 @@ function renderMcpReferences(ids, registry2) {
|
|
|
30663
30792
|
"Loaded MCP servers:",
|
|
30664
30793
|
...ids.map((id) => {
|
|
30665
30794
|
const server = registry2[id];
|
|
30795
|
+
if (server?.url) {
|
|
30796
|
+
return [
|
|
30797
|
+
`## ${id}`,
|
|
30798
|
+
"transport: http",
|
|
30799
|
+
`url: ${server.url}`,
|
|
30800
|
+
`headers: ${Object.keys(server.headers ?? {}).join(", ") || "none"}`,
|
|
30801
|
+
`bearer_token_env_var: ${server.bearer_token_env_var ?? "none"}`
|
|
30802
|
+
].join(`
|
|
30803
|
+
`);
|
|
30804
|
+
}
|
|
30666
30805
|
return [
|
|
30667
30806
|
`## ${id}`,
|
|
30807
|
+
"transport: stdio",
|
|
30668
30808
|
`command: ${server?.command ?? ""}`,
|
|
30669
30809
|
`args: ${(server?.args ?? []).join(" ") || "none"}`,
|
|
30670
30810
|
`env: ${Object.keys(server?.env ?? {}).join(", ") || "none"}`
|
package/dist/runner.js
CHANGED
|
@@ -7215,6 +7215,8 @@ var {
|
|
|
7215
7215
|
} = getIpcExport();
|
|
7216
7216
|
|
|
7217
7217
|
// src/runner.ts
|
|
7218
|
+
var TOML_BARE_KEY_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
7219
|
+
|
|
7218
7220
|
class RunnerCapabilityError extends Error {
|
|
7219
7221
|
constructor(message) {
|
|
7220
7222
|
super(message);
|
|
@@ -7270,6 +7272,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
|
|
|
7270
7272
|
...claudeToolArgs(tools),
|
|
7271
7273
|
...mcpArgs,
|
|
7272
7274
|
...skillArgs,
|
|
7275
|
+
"--dangerously-skip-permissions",
|
|
7273
7276
|
"-p",
|
|
7274
7277
|
prompt
|
|
7275
7278
|
];
|
|
@@ -7282,10 +7285,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
|
|
|
7282
7285
|
...optionalModelArgs(harness, options.runner, options.actor),
|
|
7283
7286
|
...mcpArgs,
|
|
7284
7287
|
...skillArgs,
|
|
7285
|
-
"--sandbox",
|
|
7286
|
-
codexSandboxFor(options.actor),
|
|
7287
|
-
"--config",
|
|
7288
|
-
'approval_policy="never"',
|
|
7288
|
+
"--dangerously-bypass-approvals-and-sandbox",
|
|
7289
7289
|
"--skip-git-repo-check",
|
|
7290
7290
|
prompt
|
|
7291
7291
|
];
|
|
@@ -7323,6 +7323,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
|
|
|
7323
7323
|
...optionalModelArgs(harness, options.runner, options.actor),
|
|
7324
7324
|
...mcpArgs,
|
|
7325
7325
|
...skillArgs,
|
|
7326
|
+
"--yolo",
|
|
7326
7327
|
"--final-message-only",
|
|
7327
7328
|
"--prompt",
|
|
7328
7329
|
prompt
|
|
@@ -7333,9 +7334,6 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options = {}) {
|
|
|
7333
7334
|
}
|
|
7334
7335
|
}
|
|
7335
7336
|
}
|
|
7336
|
-
function codexSandboxFor(actor) {
|
|
7337
|
-
return actor?.filesystem?.mode === "read-only" ? "read-only" : "workspace-write";
|
|
7338
|
-
}
|
|
7339
7337
|
async function execaHarness(harness, prompt, contextFile, worktreePath) {
|
|
7340
7338
|
if (harness === "pi") {
|
|
7341
7339
|
return execaHarnessPi(prompt, contextFile, worktreePath);
|
|
@@ -7545,12 +7543,12 @@ function mcpArgsFor(runnerType, config, actor) {
|
|
|
7545
7543
|
if (runnerType === "claude") {
|
|
7546
7544
|
return [
|
|
7547
7545
|
"--mcp-config",
|
|
7548
|
-
JSON.stringify(
|
|
7546
|
+
JSON.stringify(toClaudeMcpConfig(servers)),
|
|
7549
7547
|
"--strict-mcp-config"
|
|
7550
7548
|
];
|
|
7551
7549
|
}
|
|
7552
7550
|
if (runnerType === "kimi") {
|
|
7553
|
-
return ["--mcp-config", JSON.stringify(
|
|
7551
|
+
return ["--mcp-config", JSON.stringify(toKimiMcpConfig(servers))];
|
|
7554
7552
|
}
|
|
7555
7553
|
if (runnerType === "codex") {
|
|
7556
7554
|
return codexMcpArgs(servers);
|
|
@@ -7570,39 +7568,120 @@ function runnerEnv(runnerType, config, actor, worktreePath, nodeId) {
|
|
|
7570
7568
|
PIPELINE_WORKTREE: worktreePath
|
|
7571
7569
|
};
|
|
7572
7570
|
}
|
|
7573
|
-
function
|
|
7574
|
-
return
|
|
7571
|
+
function isRemoteMcpServer(server) {
|
|
7572
|
+
return typeof server.url === "string";
|
|
7575
7573
|
}
|
|
7576
|
-
function
|
|
7574
|
+
function headersWithBearerTokenEnv(server, renderTokenRef) {
|
|
7575
|
+
const headers = { ...server.headers ?? {} };
|
|
7576
|
+
if (server.bearer_token_env_var) {
|
|
7577
|
+
headers.Authorization = `Bearer ${renderTokenRef(server.bearer_token_env_var)}`;
|
|
7578
|
+
}
|
|
7579
|
+
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
7580
|
+
}
|
|
7581
|
+
function toClaudeMcpConfig(servers) {
|
|
7577
7582
|
return {
|
|
7578
|
-
|
|
7583
|
+
mcpServers: Object.fromEntries(Object.entries(servers).map(([id, server]) => {
|
|
7584
|
+
if (isRemoteMcpServer(server)) {
|
|
7585
|
+
const headers = headersWithBearerTokenEnv(server, (envVar) => `\${${envVar}}`);
|
|
7586
|
+
return [
|
|
7587
|
+
id,
|
|
7588
|
+
{
|
|
7589
|
+
type: "http",
|
|
7590
|
+
url: server.url,
|
|
7591
|
+
...headers ? { headers } : {}
|
|
7592
|
+
}
|
|
7593
|
+
];
|
|
7594
|
+
}
|
|
7595
|
+
return [
|
|
7596
|
+
id,
|
|
7597
|
+
{
|
|
7598
|
+
command: server.command,
|
|
7599
|
+
...server.args ? { args: server.args } : {},
|
|
7600
|
+
...server.env ? { env: server.env } : {}
|
|
7601
|
+
}
|
|
7602
|
+
];
|
|
7603
|
+
}))
|
|
7604
|
+
};
|
|
7605
|
+
}
|
|
7606
|
+
function toKimiMcpConfig(servers) {
|
|
7607
|
+
return {
|
|
7608
|
+
mcpServers: Object.fromEntries(Object.entries(servers).map(([id, server]) => [
|
|
7579
7609
|
id,
|
|
7580
|
-
{
|
|
7581
|
-
|
|
7582
|
-
|
|
7583
|
-
...server.
|
|
7584
|
-
|
|
7610
|
+
isRemoteMcpServer(server) ? {
|
|
7611
|
+
url: server.url,
|
|
7612
|
+
...server.headers ? { headers: server.headers } : {},
|
|
7613
|
+
...server.bearer_token_env_var ? { bearerTokenEnvVar: server.bearer_token_env_var } : {}
|
|
7614
|
+
} : {
|
|
7615
|
+
command: server.command,
|
|
7616
|
+
...server.args ? { args: server.args } : {},
|
|
7617
|
+
...server.env ? { env: server.env } : {}
|
|
7585
7618
|
}
|
|
7586
7619
|
]))
|
|
7587
7620
|
};
|
|
7588
7621
|
}
|
|
7622
|
+
function toOpenCodeMcpConfig(servers) {
|
|
7623
|
+
return {
|
|
7624
|
+
mcp: Object.fromEntries(Object.entries(servers).map(([id, server]) => {
|
|
7625
|
+
if (isRemoteMcpServer(server)) {
|
|
7626
|
+
const headers = headersWithBearerTokenEnv(server, (envVar) => `{env:${envVar}}`);
|
|
7627
|
+
return [
|
|
7628
|
+
id,
|
|
7629
|
+
{
|
|
7630
|
+
enabled: true,
|
|
7631
|
+
...headers ? { headers } : {},
|
|
7632
|
+
type: "remote",
|
|
7633
|
+
url: server.url
|
|
7634
|
+
}
|
|
7635
|
+
];
|
|
7636
|
+
}
|
|
7637
|
+
return [
|
|
7638
|
+
id,
|
|
7639
|
+
{
|
|
7640
|
+
command: [server.command, ...server.args ?? []],
|
|
7641
|
+
enabled: true,
|
|
7642
|
+
...server.env ? { environment: server.env } : {},
|
|
7643
|
+
type: "local"
|
|
7644
|
+
}
|
|
7645
|
+
];
|
|
7646
|
+
}))
|
|
7647
|
+
};
|
|
7648
|
+
}
|
|
7589
7649
|
function codexMcpArgs(servers) {
|
|
7590
|
-
return Object.entries(servers).flatMap(([id, server]) =>
|
|
7591
|
-
|
|
7592
|
-
|
|
7593
|
-
|
|
7594
|
-
|
|
7595
|
-
|
|
7650
|
+
return Object.entries(servers).flatMap(([id, server]) => {
|
|
7651
|
+
if (isRemoteMcpServer(server)) {
|
|
7652
|
+
return [
|
|
7653
|
+
"--config",
|
|
7654
|
+
`mcp_servers.${id}.url=${tomlValue(server.url)}`,
|
|
7655
|
+
...server.headers ? [
|
|
7656
|
+
"--config",
|
|
7657
|
+
`mcp_servers.${id}.http_headers=${tomlValue(server.headers)}`
|
|
7658
|
+
] : [],
|
|
7659
|
+
...server.bearer_token_env_var ? [
|
|
7660
|
+
"--config",
|
|
7661
|
+
`mcp_servers.${id}.bearer_token_env_var=${tomlValue(server.bearer_token_env_var)}`
|
|
7662
|
+
] : []
|
|
7663
|
+
];
|
|
7664
|
+
}
|
|
7665
|
+
return [
|
|
7666
|
+
"--config",
|
|
7667
|
+
`mcp_servers.${id}.command=${tomlValue(server.command)}`,
|
|
7668
|
+
...server.args ? ["--config", `mcp_servers.${id}.args=${tomlValue(server.args)}`] : [],
|
|
7669
|
+
...server.env ? ["--config", `mcp_servers.${id}.env=${tomlValue(server.env)}`] : []
|
|
7670
|
+
];
|
|
7671
|
+
});
|
|
7596
7672
|
}
|
|
7597
7673
|
function tomlValue(value) {
|
|
7598
7674
|
if (Array.isArray(value)) {
|
|
7599
7675
|
return `[${value.map(tomlValue).join(", ")}]`;
|
|
7600
7676
|
}
|
|
7601
7677
|
if (value && typeof value === "object") {
|
|
7602
|
-
return `{ ${Object.entries(value).map(([key, item]) => `${key} = ${tomlValue(item)}`).join(", ")} }`;
|
|
7678
|
+
return `{ ${Object.entries(value).map(([key, item]) => `${tomlKey(key)} = ${tomlValue(item)}`).join(", ")} }`;
|
|
7603
7679
|
}
|
|
7604
7680
|
return JSON.stringify(value);
|
|
7605
7681
|
}
|
|
7682
|
+
function tomlKey(key) {
|
|
7683
|
+
return TOML_BARE_KEY_PATTERN.test(key) ? key : JSON.stringify(key);
|
|
7684
|
+
}
|
|
7606
7685
|
function nativeStrategy(config, input, runnerId) {
|
|
7607
7686
|
const runner = config.runners[runnerId];
|
|
7608
7687
|
const profile = input.profileId ? config.profiles[input.profileId] : undefined;
|
|
@@ -108,12 +108,33 @@ receive explicit grants:
|
|
|
108
108
|
|
|
109
109
|
- `rules`: named markdown rule files.
|
|
110
110
|
- `skills`: named skill files.
|
|
111
|
-
- `mcp_servers`: named MCP
|
|
111
|
+
- `mcp_servers`: named MCP server definitions. Servers may be local stdio
|
|
112
|
+
commands or remote streamable HTTP endpoints.
|
|
112
113
|
- `tools`: allowed host tools only.
|
|
113
114
|
- `filesystem`: read-only or workspace-write plus allow/deny paths.
|
|
114
115
|
- `network`: inherited or disabled.
|
|
115
116
|
- `output`: text, JSON, JSONL, or JSON Schema output.
|
|
116
117
|
|
|
118
|
+
MCP servers support two strict shapes:
|
|
119
|
+
|
|
120
|
+
```yaml
|
|
121
|
+
mcp_servers:
|
|
122
|
+
docs:
|
|
123
|
+
command: npx
|
|
124
|
+
args: ["-y", "@example/docs-mcp"]
|
|
125
|
+
env:
|
|
126
|
+
DOCS_TOKEN: token
|
|
127
|
+
memory:
|
|
128
|
+
url: https://memory-mcp.momokaya.ee/mcp/
|
|
129
|
+
bearer_token_env_var: MEMORY_MCP_TOKEN
|
|
130
|
+
headers:
|
|
131
|
+
X-Memory-Region: eu
|
|
132
|
+
```
|
|
133
|
+
|
|
134
|
+
Exactly one of `command` or `url` is required. `args` and `env` apply only to
|
|
135
|
+
command servers. `headers` and `bearer_token_env_var` apply only to URL
|
|
136
|
+
servers.
|
|
137
|
+
|
|
117
138
|
JSON Schema outputs are hard contracts. The runtime validates normalized agent
|
|
118
139
|
output before the node can pass. Schema outputs also get a bounded repair pass
|
|
119
140
|
by default:
|