@oisincoveney/pipeline 1.5.4 → 1.5.6
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/README.md +1 -2
- package/dist/config.d.ts +4 -1
- package/dist/config.js +53 -3
- package/dist/index.js +210 -57
- package/dist/pipeline-runtime.js +168 -28
- package/dist/runner.js +104 -25
- package/docs/config-architecture.md +23 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -77,6 +77,7 @@ runners:
|
|
|
77
77
|
codex:
|
|
78
78
|
type: codex
|
|
79
79
|
command: codex
|
|
80
|
+
model: gpt-5.5
|
|
80
81
|
capabilities:
|
|
81
82
|
native_subagents: true
|
|
82
83
|
tools: [read, grep, bash, edit, write]
|
|
@@ -93,7 +94,6 @@ version: 1
|
|
|
93
94
|
profiles:
|
|
94
95
|
orchestrator:
|
|
95
96
|
runner: codex
|
|
96
|
-
model: gpt-5
|
|
97
97
|
instructions:
|
|
98
98
|
inline: Coordinate the workflow from this YAML file only.
|
|
99
99
|
tools: [read, grep, bash]
|
|
@@ -103,7 +103,6 @@ profiles:
|
|
|
103
103
|
mode: inherit
|
|
104
104
|
implementer:
|
|
105
105
|
runner: codex
|
|
106
|
-
model: gpt-5
|
|
107
106
|
instructions:
|
|
108
107
|
inline: Implement the requested change and return evidence.
|
|
109
108
|
tools: [read, grep, bash, edit, write]
|
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()
|
|
@@ -28728,6 +28778,9 @@ function canRunNatively(host, config2, profile) {
|
|
|
28728
28778
|
return false;
|
|
28729
28779
|
}
|
|
28730
28780
|
if (profile.runner === host) {
|
|
28781
|
+
if (host === "codex") {
|
|
28782
|
+
return resolvedHostModel(config2, host, profile) !== undefined;
|
|
28783
|
+
}
|
|
28731
28784
|
return true;
|
|
28732
28785
|
}
|
|
28733
28786
|
return host === "opencode" && isModelRunner(profile.runner) && resolvedHostModel(config2, host, profile) !== undefined;
|
|
@@ -28758,12 +28811,16 @@ function agentDispatchRoutes(host, config2) {
|
|
|
28758
28811
|
function dispatchRouteForAgent(host, config2, route) {
|
|
28759
28812
|
const runnerId = route.profile.runner;
|
|
28760
28813
|
if (host !== "pi" && runnerId === host) {
|
|
28761
|
-
|
|
28762
|
-
|
|
28763
|
-
|
|
28764
|
-
|
|
28765
|
-
|
|
28766
|
-
|
|
28814
|
+
const model = resolvedHostModel(config2, host, route.profile);
|
|
28815
|
+
if (host !== "codex" || model) {
|
|
28816
|
+
return {
|
|
28817
|
+
...route,
|
|
28818
|
+
kind: "native-named-agent",
|
|
28819
|
+
...model ? { model } : {},
|
|
28820
|
+
nativeAgentId: route.profileId,
|
|
28821
|
+
runnerId
|
|
28822
|
+
};
|
|
28823
|
+
}
|
|
28767
28824
|
}
|
|
28768
28825
|
if (host === "opencode" && isModelRunner(runnerId)) {
|
|
28769
28826
|
const model = resolvedHostModel(config2, host, route.profile);
|
|
@@ -28839,7 +28896,8 @@ function nativeDispatchBlock(host, routes) {
|
|
|
28839
28896
|
function nativeDispatchLine(host, route) {
|
|
28840
28897
|
const needs = needsSummary(route.needs);
|
|
28841
28898
|
if (host === "codex") {
|
|
28842
|
-
|
|
28899
|
+
const model = route.model ? ` model=${route.model}` : "";
|
|
28900
|
+
return `- ${route.nodeId}: spawn_agent agent_type=${route.nativeAgentId}${model} runner=${route.runnerId} needs=${needs}`;
|
|
28843
28901
|
}
|
|
28844
28902
|
if (host === "claude") {
|
|
28845
28903
|
return `- ${route.nodeId}: Agent tool subagent_type=${route.nativeAgentId} runner=${route.runnerId} needs=${needs}`;
|
|
@@ -28866,25 +28924,22 @@ function cliDispatchLine(route) {
|
|
|
28866
28924
|
}
|
|
28867
28925
|
function runnerCliCommand(route) {
|
|
28868
28926
|
if (route.runnerId === "codex") {
|
|
28869
|
-
return
|
|
28927
|
+
return "codex exec --json -C <repo-root> --dangerously-bypass-approvals-and-sandbox --skip-git-repo-check <node prompt>";
|
|
28870
28928
|
}
|
|
28871
28929
|
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>`;
|
|
28930
|
+
return `kimi --print --agent-file .kimi/agents/${route.profileId}.yaml --work-dir <repo-root> --yolo --final-message-only --prompt <node prompt>`;
|
|
28873
28931
|
}
|
|
28874
28932
|
if (route.runnerId === "opencode") {
|
|
28875
28933
|
return `opencode run --agent ${route.profileId} --format json --dir <repo-root> <node prompt>`;
|
|
28876
28934
|
}
|
|
28877
28935
|
if (route.runnerId === "claude") {
|
|
28878
|
-
return `claude --agent ${route.profileId} --print -p <node prompt>`;
|
|
28936
|
+
return `claude --agent ${route.profileId} --print --dangerously-skip-permissions -p <node prompt>`;
|
|
28879
28937
|
}
|
|
28880
28938
|
if (route.runnerId === "pi") {
|
|
28881
28939
|
return "pi --print --no-session <node prompt>";
|
|
28882
28940
|
}
|
|
28883
28941
|
return `${route.runnerId} <node prompt>`;
|
|
28884
28942
|
}
|
|
28885
|
-
function codexSandbox(profile) {
|
|
28886
|
-
return profile.filesystem?.mode === "workspace-write" ? "workspace-write" : "read-only";
|
|
28887
|
-
}
|
|
28888
28943
|
function nodePromptContract(workflowId, routes) {
|
|
28889
28944
|
const hasCliRoutes = routes.some((route) => route.kind === "cli");
|
|
28890
28945
|
const lead = hasCliRoutes ? "For each CLI node prompt include:" : "For each native node prompt include:";
|
|
@@ -29078,24 +29133,31 @@ function codexDefinitions(config2) {
|
|
|
29078
29133
|
invocation: "$pipe <task description>",
|
|
29079
29134
|
path: ".agents/skills/pipe/SKILL.md"
|
|
29080
29135
|
},
|
|
29081
|
-
...nativeProfileEntries("codex", config2).map(([id, profile]) =>
|
|
29082
|
-
|
|
29083
|
-
|
|
29084
|
-
|
|
29085
|
-
|
|
29086
|
-
|
|
29087
|
-
|
|
29088
|
-
|
|
29089
|
-
|
|
29136
|
+
...nativeProfileEntries("codex", config2).map(([id, profile]) => {
|
|
29137
|
+
const model = resolvedHostModel(config2, "codex", profile);
|
|
29138
|
+
if (!model) {
|
|
29139
|
+
throw new Error(`Codex native agent '${id}' requires a resolved model from profile.model or runner.model.`);
|
|
29140
|
+
}
|
|
29141
|
+
return {
|
|
29142
|
+
content: `${hashHeader("codex")}${stringify({
|
|
29143
|
+
description: profile.description ?? id,
|
|
29144
|
+
developer_instructions: [
|
|
29145
|
+
profile.description ?? id,
|
|
29146
|
+
instructionsPointer(profile),
|
|
29147
|
+
"Configured grants:",
|
|
29148
|
+
grants(profile)
|
|
29149
|
+
].join(`
|
|
29090
29150
|
`),
|
|
29091
|
-
|
|
29092
|
-
|
|
29093
|
-
|
|
29151
|
+
model,
|
|
29152
|
+
name: id,
|
|
29153
|
+
sandbox_mode: profile.filesystem?.mode === "workspace-write" ? "workspace-write" : "read-only"
|
|
29154
|
+
}).trimEnd()}
|
|
29094
29155
|
`,
|
|
29095
|
-
|
|
29096
|
-
|
|
29097
|
-
|
|
29098
|
-
|
|
29156
|
+
host: "codex",
|
|
29157
|
+
invocation: "$pipe <task description>",
|
|
29158
|
+
path: `.codex/agents/${id}.toml`
|
|
29159
|
+
};
|
|
29160
|
+
})
|
|
29099
29161
|
];
|
|
29100
29162
|
}
|
|
29101
29163
|
function kimiDefinitions(config2) {
|
|
@@ -29498,6 +29560,7 @@ runners:
|
|
|
29498
29560
|
codex:
|
|
29499
29561
|
type: codex
|
|
29500
29562
|
command: codex
|
|
29563
|
+
model: gpt-5.5
|
|
29501
29564
|
capabilities:
|
|
29502
29565
|
native_subagents: true
|
|
29503
29566
|
rules: true
|
|
@@ -36995,6 +37058,8 @@ import {
|
|
|
36995
37058
|
} from "node:fs";
|
|
36996
37059
|
import { tmpdir } from "node:os";
|
|
36997
37060
|
import { dirname as dirname3, join as join5 } from "node:path";
|
|
37061
|
+
var TOML_BARE_KEY_PATTERN = /^[A-Za-z0-9_-]+$/;
|
|
37062
|
+
|
|
36998
37063
|
class RunnerCapabilityError extends Error {
|
|
36999
37064
|
constructor(message) {
|
|
37000
37065
|
super(message);
|
|
@@ -37017,6 +37082,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
|
|
|
37017
37082
|
...claudeToolArgs(tools),
|
|
37018
37083
|
...mcpArgs,
|
|
37019
37084
|
...skillArgs,
|
|
37085
|
+
"--dangerously-skip-permissions",
|
|
37020
37086
|
"-p",
|
|
37021
37087
|
prompt
|
|
37022
37088
|
];
|
|
@@ -37029,10 +37095,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
|
|
|
37029
37095
|
...optionalModelArgs(harness, options2.runner, options2.actor),
|
|
37030
37096
|
...mcpArgs,
|
|
37031
37097
|
...skillArgs,
|
|
37032
|
-
"--sandbox",
|
|
37033
|
-
codexSandboxFor(options2.actor),
|
|
37034
|
-
"--config",
|
|
37035
|
-
'approval_policy="never"',
|
|
37098
|
+
"--dangerously-bypass-approvals-and-sandbox",
|
|
37036
37099
|
"--skip-git-repo-check",
|
|
37037
37100
|
prompt
|
|
37038
37101
|
];
|
|
@@ -37070,6 +37133,7 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
|
|
|
37070
37133
|
...optionalModelArgs(harness, options2.runner, options2.actor),
|
|
37071
37134
|
...mcpArgs,
|
|
37072
37135
|
...skillArgs,
|
|
37136
|
+
"--yolo",
|
|
37073
37137
|
"--final-message-only",
|
|
37074
37138
|
"--prompt",
|
|
37075
37139
|
prompt
|
|
@@ -37080,9 +37144,6 @@ function harnessArgv(harness, prompt, worktreePath, contextFile, options2 = {})
|
|
|
37080
37144
|
}
|
|
37081
37145
|
}
|
|
37082
37146
|
}
|
|
37083
|
-
function codexSandboxFor(actor) {
|
|
37084
|
-
return actor?.filesystem?.mode === "read-only" ? "read-only" : "workspace-write";
|
|
37085
|
-
}
|
|
37086
37147
|
function createRunnerLaunchPlan(config2, input) {
|
|
37087
37148
|
const profile = input.profileId ? config2.profiles[input.profileId] : undefined;
|
|
37088
37149
|
if (input.profileId && !profile) {
|
|
@@ -37215,12 +37276,12 @@ function mcpArgsFor(runnerType, config2, actor) {
|
|
|
37215
37276
|
if (runnerType === "claude") {
|
|
37216
37277
|
return [
|
|
37217
37278
|
"--mcp-config",
|
|
37218
|
-
JSON.stringify(
|
|
37279
|
+
JSON.stringify(toClaudeMcpConfig(servers)),
|
|
37219
37280
|
"--strict-mcp-config"
|
|
37220
37281
|
];
|
|
37221
37282
|
}
|
|
37222
37283
|
if (runnerType === "kimi") {
|
|
37223
|
-
return ["--mcp-config", JSON.stringify(
|
|
37284
|
+
return ["--mcp-config", JSON.stringify(toKimiMcpConfig(servers))];
|
|
37224
37285
|
}
|
|
37225
37286
|
if (runnerType === "codex") {
|
|
37226
37287
|
return codexMcpArgs(servers);
|
|
@@ -37240,39 +37301,120 @@ function runnerEnv(runnerType, config2, actor, worktreePath, nodeId) {
|
|
|
37240
37301
|
PIPELINE_WORKTREE: worktreePath
|
|
37241
37302
|
};
|
|
37242
37303
|
}
|
|
37243
|
-
function
|
|
37244
|
-
return
|
|
37304
|
+
function isRemoteMcpServer(server) {
|
|
37305
|
+
return typeof server.url === "string";
|
|
37245
37306
|
}
|
|
37246
|
-
function
|
|
37307
|
+
function headersWithBearerTokenEnv(server, renderTokenRef) {
|
|
37308
|
+
const headers = { ...server.headers ?? {} };
|
|
37309
|
+
if (server.bearer_token_env_var) {
|
|
37310
|
+
headers.Authorization = `Bearer ${renderTokenRef(server.bearer_token_env_var)}`;
|
|
37311
|
+
}
|
|
37312
|
+
return Object.keys(headers).length > 0 ? headers : undefined;
|
|
37313
|
+
}
|
|
37314
|
+
function toClaudeMcpConfig(servers) {
|
|
37247
37315
|
return {
|
|
37248
|
-
|
|
37316
|
+
mcpServers: Object.fromEntries(Object.entries(servers).map(([id, server]) => {
|
|
37317
|
+
if (isRemoteMcpServer(server)) {
|
|
37318
|
+
const headers = headersWithBearerTokenEnv(server, (envVar) => `\${${envVar}}`);
|
|
37319
|
+
return [
|
|
37320
|
+
id,
|
|
37321
|
+
{
|
|
37322
|
+
type: "http",
|
|
37323
|
+
url: server.url,
|
|
37324
|
+
...headers ? { headers } : {}
|
|
37325
|
+
}
|
|
37326
|
+
];
|
|
37327
|
+
}
|
|
37328
|
+
return [
|
|
37329
|
+
id,
|
|
37330
|
+
{
|
|
37331
|
+
command: server.command,
|
|
37332
|
+
...server.args ? { args: server.args } : {},
|
|
37333
|
+
...server.env ? { env: server.env } : {}
|
|
37334
|
+
}
|
|
37335
|
+
];
|
|
37336
|
+
}))
|
|
37337
|
+
};
|
|
37338
|
+
}
|
|
37339
|
+
function toKimiMcpConfig(servers) {
|
|
37340
|
+
return {
|
|
37341
|
+
mcpServers: Object.fromEntries(Object.entries(servers).map(([id, server]) => [
|
|
37249
37342
|
id,
|
|
37250
|
-
{
|
|
37251
|
-
|
|
37252
|
-
|
|
37253
|
-
...server.
|
|
37254
|
-
|
|
37343
|
+
isRemoteMcpServer(server) ? {
|
|
37344
|
+
url: server.url,
|
|
37345
|
+
...server.headers ? { headers: server.headers } : {},
|
|
37346
|
+
...server.bearer_token_env_var ? { bearerTokenEnvVar: server.bearer_token_env_var } : {}
|
|
37347
|
+
} : {
|
|
37348
|
+
command: server.command,
|
|
37349
|
+
...server.args ? { args: server.args } : {},
|
|
37350
|
+
...server.env ? { env: server.env } : {}
|
|
37255
37351
|
}
|
|
37256
37352
|
]))
|
|
37257
37353
|
};
|
|
37258
37354
|
}
|
|
37355
|
+
function toOpenCodeMcpConfig(servers) {
|
|
37356
|
+
return {
|
|
37357
|
+
mcp: Object.fromEntries(Object.entries(servers).map(([id, server]) => {
|
|
37358
|
+
if (isRemoteMcpServer(server)) {
|
|
37359
|
+
const headers = headersWithBearerTokenEnv(server, (envVar) => `{env:${envVar}}`);
|
|
37360
|
+
return [
|
|
37361
|
+
id,
|
|
37362
|
+
{
|
|
37363
|
+
enabled: true,
|
|
37364
|
+
...headers ? { headers } : {},
|
|
37365
|
+
type: "remote",
|
|
37366
|
+
url: server.url
|
|
37367
|
+
}
|
|
37368
|
+
];
|
|
37369
|
+
}
|
|
37370
|
+
return [
|
|
37371
|
+
id,
|
|
37372
|
+
{
|
|
37373
|
+
command: [server.command, ...server.args ?? []],
|
|
37374
|
+
enabled: true,
|
|
37375
|
+
...server.env ? { environment: server.env } : {},
|
|
37376
|
+
type: "local"
|
|
37377
|
+
}
|
|
37378
|
+
];
|
|
37379
|
+
}))
|
|
37380
|
+
};
|
|
37381
|
+
}
|
|
37259
37382
|
function codexMcpArgs(servers) {
|
|
37260
|
-
return Object.entries(servers).flatMap(([id, server]) =>
|
|
37261
|
-
|
|
37262
|
-
|
|
37263
|
-
|
|
37264
|
-
|
|
37265
|
-
|
|
37383
|
+
return Object.entries(servers).flatMap(([id, server]) => {
|
|
37384
|
+
if (isRemoteMcpServer(server)) {
|
|
37385
|
+
return [
|
|
37386
|
+
"--config",
|
|
37387
|
+
`mcp_servers.${id}.url=${tomlValue(server.url)}`,
|
|
37388
|
+
...server.headers ? [
|
|
37389
|
+
"--config",
|
|
37390
|
+
`mcp_servers.${id}.http_headers=${tomlValue(server.headers)}`
|
|
37391
|
+
] : [],
|
|
37392
|
+
...server.bearer_token_env_var ? [
|
|
37393
|
+
"--config",
|
|
37394
|
+
`mcp_servers.${id}.bearer_token_env_var=${tomlValue(server.bearer_token_env_var)}`
|
|
37395
|
+
] : []
|
|
37396
|
+
];
|
|
37397
|
+
}
|
|
37398
|
+
return [
|
|
37399
|
+
"--config",
|
|
37400
|
+
`mcp_servers.${id}.command=${tomlValue(server.command)}`,
|
|
37401
|
+
...server.args ? ["--config", `mcp_servers.${id}.args=${tomlValue(server.args)}`] : [],
|
|
37402
|
+
...server.env ? ["--config", `mcp_servers.${id}.env=${tomlValue(server.env)}`] : []
|
|
37403
|
+
];
|
|
37404
|
+
});
|
|
37266
37405
|
}
|
|
37267
37406
|
function tomlValue(value) {
|
|
37268
37407
|
if (Array.isArray(value)) {
|
|
37269
37408
|
return `[${value.map(tomlValue).join(", ")}]`;
|
|
37270
37409
|
}
|
|
37271
37410
|
if (value && typeof value === "object") {
|
|
37272
|
-
return `{ ${Object.entries(value).map(([key, item]) => `${key} = ${tomlValue(item)}`).join(", ")} }`;
|
|
37411
|
+
return `{ ${Object.entries(value).map(([key, item]) => `${tomlKey(key)} = ${tomlValue(item)}`).join(", ")} }`;
|
|
37273
37412
|
}
|
|
37274
37413
|
return JSON.stringify(value);
|
|
37275
37414
|
}
|
|
37415
|
+
function tomlKey(key) {
|
|
37416
|
+
return TOML_BARE_KEY_PATTERN.test(key) ? key : JSON.stringify(key);
|
|
37417
|
+
}
|
|
37276
37418
|
function nativeStrategy(config2, input, runnerId) {
|
|
37277
37419
|
const runner = config2.runners[runnerId];
|
|
37278
37420
|
const profile = input.profileId ? config2.profiles[input.profileId] : undefined;
|
|
@@ -37957,8 +38099,19 @@ function renderMcpReferences(ids, registry2) {
|
|
|
37957
38099
|
"Loaded MCP servers:",
|
|
37958
38100
|
...ids.map((id) => {
|
|
37959
38101
|
const server = registry2[id];
|
|
38102
|
+
if (server?.url) {
|
|
38103
|
+
return [
|
|
38104
|
+
`## ${id}`,
|
|
38105
|
+
"transport: http",
|
|
38106
|
+
`url: ${server.url}`,
|
|
38107
|
+
`headers: ${Object.keys(server.headers ?? {}).join(", ") || "none"}`,
|
|
38108
|
+
`bearer_token_env_var: ${server.bearer_token_env_var ?? "none"}`
|
|
38109
|
+
].join(`
|
|
38110
|
+
`);
|
|
38111
|
+
}
|
|
37960
38112
|
return [
|
|
37961
38113
|
`## ${id}`,
|
|
38114
|
+
"transport: stdio",
|
|
37962
38115
|
`command: ${server?.command ?? ""}`,
|
|
37963
38116
|
`args: ${(server?.args ?? []).join(" ") || "none"}`,
|
|
37964
38117
|
`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;
|
|
@@ -22,6 +22,7 @@ runners:
|
|
|
22
22
|
codex:
|
|
23
23
|
type: codex
|
|
24
24
|
command: codex
|
|
25
|
+
model: gpt-5.5
|
|
25
26
|
capabilities:
|
|
26
27
|
native_subagents: true
|
|
27
28
|
rules: true
|
|
@@ -108,12 +109,33 @@ receive explicit grants:
|
|
|
108
109
|
|
|
109
110
|
- `rules`: named markdown rule files.
|
|
110
111
|
- `skills`: named skill files.
|
|
111
|
-
- `mcp_servers`: named MCP
|
|
112
|
+
- `mcp_servers`: named MCP server definitions. Servers may be local stdio
|
|
113
|
+
commands or remote streamable HTTP endpoints.
|
|
112
114
|
- `tools`: allowed host tools only.
|
|
113
115
|
- `filesystem`: read-only or workspace-write plus allow/deny paths.
|
|
114
116
|
- `network`: inherited or disabled.
|
|
115
117
|
- `output`: text, JSON, JSONL, or JSON Schema output.
|
|
116
118
|
|
|
119
|
+
MCP servers support two strict shapes:
|
|
120
|
+
|
|
121
|
+
```yaml
|
|
122
|
+
mcp_servers:
|
|
123
|
+
docs:
|
|
124
|
+
command: npx
|
|
125
|
+
args: ["-y", "@example/docs-mcp"]
|
|
126
|
+
env:
|
|
127
|
+
DOCS_TOKEN: token
|
|
128
|
+
memory:
|
|
129
|
+
url: https://memory-mcp.momokaya.ee/mcp/
|
|
130
|
+
bearer_token_env_var: MEMORY_MCP_TOKEN
|
|
131
|
+
headers:
|
|
132
|
+
X-Memory-Region: eu
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Exactly one of `command` or `url` is required. `args` and `env` apply only to
|
|
136
|
+
command servers. `headers` and `bearer_token_env_var` apply only to URL
|
|
137
|
+
servers.
|
|
138
|
+
|
|
117
139
|
JSON Schema outputs are hard contracts. The runtime validates normalized agent
|
|
118
140
|
output before the node can pass. Schema outputs also get a bounded repair pass
|
|
119
141
|
by default:
|