@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 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
- command: z.ZodString;
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
- command: exports_external.string().min(1),
21370
- env: exports_external.record(exports_external.string(), exports_external.string()).optional()
21371
- }).strict();
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
- command: exports_external.string().min(1),
27443
- env: exports_external.record(exports_external.string(), exports_external.string()).optional()
27444
- }).strict();
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
- return {
28762
- ...route,
28763
- kind: "native-named-agent",
28764
- nativeAgentId: route.profileId,
28765
- runnerId
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
- return `- ${route.nodeId}: spawn_agent agent_type=${route.nativeAgentId} runner=${route.runnerId} needs=${needs}`;
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 `codex exec --json -C <repo-root> --sandbox ${codexSandbox(route.profile)} --skip-git-repo-check <node prompt>`;
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
- content: `${hashHeader("codex")}${stringify({
29083
- description: profile.description ?? id,
29084
- developer_instructions: [
29085
- profile.description ?? id,
29086
- instructionsPointer(profile),
29087
- "Configured grants:",
29088
- grants(profile)
29089
- ].join(`
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
- name: id,
29092
- sandbox_mode: profile.filesystem?.mode === "workspace-write" ? "workspace-write" : "read-only"
29093
- }).trimEnd()}
29151
+ model,
29152
+ name: id,
29153
+ sandbox_mode: profile.filesystem?.mode === "workspace-write" ? "workspace-write" : "read-only"
29154
+ }).trimEnd()}
29094
29155
  `,
29095
- host: "codex",
29096
- invocation: "$pipe <task description>",
29097
- path: `.codex/agents/${id}.toml`
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(toClaudeKimiMcpConfig(servers)),
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(toClaudeKimiMcpConfig(servers))];
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 toClaudeKimiMcpConfig(servers) {
37244
- return { mcpServers: servers };
37304
+ function isRemoteMcpServer(server) {
37305
+ return typeof server.url === "string";
37245
37306
  }
37246
- function toOpenCodeMcpConfig(servers) {
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
- mcp: Object.fromEntries(Object.entries(servers).map(([id, server]) => [
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
- command: [server.command, ...server.args ?? []],
37252
- enabled: true,
37253
- ...server.env ? { environment: server.env } : {},
37254
- type: "local"
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
- "--config",
37262
- `mcp_servers.${id}.command=${tomlValue(server.command)}`,
37263
- ...server.args ? ["--config", `mcp_servers.${id}.args=${tomlValue(server.args)}`] : [],
37264
- ...server.env ? ["--config", `mcp_servers.${id}.env=${tomlValue(server.env)}`] : []
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"}`
@@ -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
- command: exports_external.string().min(1),
28573
- env: exports_external.record(exports_external.string(), exports_external.string()).optional()
28574
- }).strict();
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(toClaudeKimiMcpConfig(servers)),
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(toClaudeKimiMcpConfig(servers))];
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 toClaudeKimiMcpConfig(servers) {
29728
- return { mcpServers: servers };
29775
+ function isRemoteMcpServer(server) {
29776
+ return typeof server.url === "string";
29729
29777
  }
29730
- function toOpenCodeMcpConfig(servers) {
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
- mcp: Object.fromEntries(Object.entries(servers).map(([id, server]) => [
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
- command: [server.command, ...server.args ?? []],
29736
- enabled: true,
29737
- ...server.env ? { environment: server.env } : {},
29738
- type: "local"
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
- "--config",
29746
- `mcp_servers.${id}.command=${tomlValue(server.command)}`,
29747
- ...server.args ? ["--config", `mcp_servers.${id}.args=${tomlValue(server.args)}`] : [],
29748
- ...server.env ? ["--config", `mcp_servers.${id}.env=${tomlValue(server.env)}`] : []
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(toClaudeKimiMcpConfig(servers)),
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(toClaudeKimiMcpConfig(servers))];
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 toClaudeKimiMcpConfig(servers) {
7574
- return { mcpServers: servers };
7571
+ function isRemoteMcpServer(server) {
7572
+ return typeof server.url === "string";
7575
7573
  }
7576
- function toOpenCodeMcpConfig(servers) {
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
- mcp: Object.fromEntries(Object.entries(servers).map(([id, server]) => [
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
- command: [server.command, ...server.args ?? []],
7582
- enabled: true,
7583
- ...server.env ? { environment: server.env } : {},
7584
- type: "local"
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
- "--config",
7592
- `mcp_servers.${id}.command=${tomlValue(server.command)}`,
7593
- ...server.args ? ["--config", `mcp_servers.${id}.args=${tomlValue(server.args)}`] : [],
7594
- ...server.env ? ["--config", `mcp_servers.${id}.env=${tomlValue(server.env)}`] : []
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 command definitions.
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:
package/package.json CHANGED
@@ -73,7 +73,7 @@
73
73
  "prepack": "bun run build:cli"
74
74
  },
75
75
  "type": "module",
76
- "version": "1.5.4",
76
+ "version": "1.5.6",
77
77
  "description": "",
78
78
  "main": "index.js",
79
79
  "keywords": [],