@oisincoveney/pipeline 1.15.3 → 1.16.1
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 +7 -1
- package/dist/config.js +2 -0
- package/dist/index.js +1 -1
- package/dist/install-commands.js +0 -3
- package/dist/mcp/gateway.js +6 -4
- package/dist/mcp/launch-plan.js +1 -1
- package/dist/pipeline-init.js +5 -1
- package/dist/schedule-planner.js +26 -19
- package/docs/mcp-gateway.md +3 -1
- package/docs/operator-guide.md +9 -4
- package/package.json +1 -1
- package/dist/mcp/native-config.js +0 -21
package/dist/config.d.ts
CHANGED
|
@@ -9,6 +9,7 @@ declare const NODE_KINDS: readonly ["agent", "command", "builtin", "group", "par
|
|
|
9
9
|
declare const HOOK_EVENTS: readonly ["workflow.start", "workflow.success", "workflow.failure", "workflow.complete", "node.start", "node.success", "node.error", "node.finish", "gate.failure"];
|
|
10
10
|
declare const GATE_KINDS: readonly ["acceptance", "artifact", "builtin", "changed_files", "command", "json_schema", "verdict"];
|
|
11
11
|
declare const SCHEDULE_BASELINES: readonly ["epic", "pipe"];
|
|
12
|
+
declare const SCHEDULING_ROLES: readonly ["coverage", "implementation"];
|
|
12
13
|
type PipelineConfigErrorCode = "PIPELINE_CONFIG_LEGACY_UNSUPPORTED" | "PIPELINE_CONFIG_MISSING" | "PIPELINE_CONFIG_PARSE_ERROR" | "PIPELINE_CONFIG_VALIDATION_ERROR";
|
|
13
14
|
interface PipelineConfigIssue {
|
|
14
15
|
message: string;
|
|
@@ -291,6 +292,10 @@ declare const configSchema: z.ZodObject<{
|
|
|
291
292
|
}, z.core.$strict>>;
|
|
292
293
|
rules: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
293
294
|
runner: z.ZodString;
|
|
295
|
+
scheduling_roles: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
296
|
+
coverage: "coverage";
|
|
297
|
+
implementation: "implementation";
|
|
298
|
+
}>>>;
|
|
294
299
|
skills: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
295
300
|
tools: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
296
301
|
read: "read";
|
|
@@ -379,6 +384,7 @@ type WorkflowNodeKind = (typeof NODE_KINDS)[number];
|
|
|
379
384
|
type HookEvent = (typeof HOOK_EVENTS)[number];
|
|
380
385
|
type GateKind = (typeof GATE_KINDS)[number];
|
|
381
386
|
type ScheduleBaseline = (typeof SCHEDULE_BASELINES)[number];
|
|
387
|
+
type SchedulingRole = (typeof SCHEDULING_ROLES)[number];
|
|
382
388
|
interface PipelineConfigParts {
|
|
383
389
|
pipeline: string;
|
|
384
390
|
profiles: string;
|
|
@@ -393,4 +399,4 @@ declare function parsePipelineConfigYaml(source: string, sourcePath?: string, pr
|
|
|
393
399
|
declare function parsePipelineConfigParts(sources: PipelineConfigParts, projectRoot?: string, sourcePaths?: PipelineConfigParts, options?: PipelineConfigValidationOptions): PipelineConfig;
|
|
394
400
|
declare function validatePipelineConfig(rawConfig: PipelineConfig, projectRoot?: string, options?: PipelineConfigValidationOptions): PipelineConfig;
|
|
395
401
|
//#endregion
|
|
396
|
-
export { GateKind, HookEvent, PIPELINE_CONFIG_PATH, PROFILES_CONFIG_PATH, PipelineConfig, PipelineConfigError, PipelineConfigErrorCode, PipelineConfigIssue, PipelineConfigParts, PipelineConfigValidationOptions, RUNNERS_CONFIG_PATH, RunnerType, ScheduleBaseline, WorkflowNodeKind, loadPipelineConfig, parsePipelineConfigParts, parsePipelineConfigYaml, tryLoadPipelineConfig, validatePipelineConfig, workflowSchema };
|
|
402
|
+
export { GateKind, HookEvent, PIPELINE_CONFIG_PATH, PROFILES_CONFIG_PATH, PipelineConfig, PipelineConfigError, PipelineConfigErrorCode, PipelineConfigIssue, PipelineConfigParts, PipelineConfigValidationOptions, RUNNERS_CONFIG_PATH, RunnerType, ScheduleBaseline, SchedulingRole, WorkflowNodeKind, loadPipelineConfig, parsePipelineConfigParts, parsePipelineConfigYaml, tryLoadPipelineConfig, validatePipelineConfig, workflowSchema };
|
package/dist/config.js
CHANGED
|
@@ -55,6 +55,7 @@ const RETRY_REASONS = [
|
|
|
55
55
|
"timeout"
|
|
56
56
|
];
|
|
57
57
|
const SCHEDULE_BASELINES = ["epic", "pipe"];
|
|
58
|
+
const SCHEDULING_ROLES = ["coverage", "implementation"];
|
|
58
59
|
const PIPELINE_GATEWAY_SERVER_ID = "pipeline-gateway";
|
|
59
60
|
var PipelineConfigError = class extends Error {
|
|
60
61
|
code;
|
|
@@ -227,6 +228,7 @@ const profileSchema = z.object({
|
|
|
227
228
|
output: outputSchema.optional(),
|
|
228
229
|
rules: z.array(z.string()).optional(),
|
|
229
230
|
runner: z.string(),
|
|
231
|
+
scheduling_roles: z.array(z.enum(SCHEDULING_ROLES)).optional(),
|
|
230
232
|
skills: z.array(z.string()).optional(),
|
|
231
233
|
tools: z.array(z.enum(TOOL_NAMES)).optional()
|
|
232
234
|
}).strict();
|
package/dist/index.js
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { PipelineConfigError, loadPipelineConfig, tryLoadPipelineConfig } from "./config.js";
|
|
3
|
-
import { configureGatewayHosts, localGatewayStatus, renderGatewayConfig, runGatewayDoctor, startLocalGateway } from "./mcp/gateway.js";
|
|
4
3
|
import { compileWorkflowPlan } from "./workflow-planner.js";
|
|
5
4
|
import { formatInstallCommandsResult, installCommands, parseCommandHost } from "./install-commands.js";
|
|
5
|
+
import { configureGatewayHosts, localGatewayStatus, renderGatewayConfig, runGatewayDoctor, startLocalGateway } from "./mcp/gateway.js";
|
|
6
6
|
import { createOrchestratorLaunchPlan, createRunnerLaunchPlan } from "./runner.js";
|
|
7
7
|
import { formatConfigError, runPipelineFromConfig } from "./pipeline-runtime.js";
|
|
8
8
|
import { runKubernetesRunnerJob } from "./kubernetes-runner.js";
|
package/dist/install-commands.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { resolveFileReference } from "./path-refs.js";
|
|
2
2
|
import { loadPipelineConfig } from "./config.js";
|
|
3
|
-
import { codexNativeMcpConfig } from "./mcp/native-config.js";
|
|
4
3
|
import { compileWorkflowPlan } from "./workflow-planner.js";
|
|
5
4
|
import { existsSync, readFileSync } from "node:fs";
|
|
6
5
|
import { basename, dirname, join, relative } from "node:path";
|
|
@@ -407,7 +406,6 @@ function codexTomlAgentDefinition(config, cwd, id, profile) {
|
|
|
407
406
|
};
|
|
408
407
|
const skillConfig = codexSkillConfig(config, cwd, profile);
|
|
409
408
|
const agentConfig = {
|
|
410
|
-
name: id,
|
|
411
409
|
description: profile.description ?? id,
|
|
412
410
|
...profileWithResolvedModel.model ? { model: profileWithResolvedModel.model } : {},
|
|
413
411
|
...profile.filesystem?.mode ? { sandbox_mode: profile.filesystem.mode } : {},
|
|
@@ -424,7 +422,6 @@ function codexTomlAgentDefinition(config, cwd, id, profile) {
|
|
|
424
422
|
"",
|
|
425
423
|
codexAgentInstructions(cwd, profile)
|
|
426
424
|
].join("\n"),
|
|
427
|
-
...codexNativeMcpConfig(config, profile),
|
|
428
425
|
skills: { config: skillConfig }
|
|
429
426
|
};
|
|
430
427
|
const mcpConfig = "mcp_servers" in agentConfig ? agentConfig : {
|
package/dist/mcp/gateway.js
CHANGED
|
@@ -5,7 +5,7 @@ import { execa } from "execa";
|
|
|
5
5
|
//#region src/mcp/gateway.ts
|
|
6
6
|
const PIPELINE_GATEWAY_SERVER_ID = "pipeline-gateway";
|
|
7
7
|
const DEFAULT_LOCAL_GATEWAY_URL = "http://127.0.0.1:4483/mcp";
|
|
8
|
-
const LEGACY_CODEX_MCP_RE = /\[mcp_servers
|
|
8
|
+
const LEGACY_CODEX_MCP_RE = /\[mcp_servers\./;
|
|
9
9
|
const LEGACY_OPENCODE_MCP_RE = /"mcp"\s*:\s*{(?!\s*"pipeline-gateway")/s;
|
|
10
10
|
const LEGACY_PIPELINE_MCP_RE = /path:\s*\.mcp\.json|uvx\s+mcpm|mcpm\s+run/;
|
|
11
11
|
var PipelineMcpGatewayError = class extends Error {
|
|
@@ -53,9 +53,11 @@ function renderGatewayConfig(config) {
|
|
|
53
53
|
function renderCodexGatewayConfig(config) {
|
|
54
54
|
const gateway = configuredGateway(config);
|
|
55
55
|
return [
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
"# Generated by @oisincoveney/pipeline.",
|
|
57
|
+
"# Codex pipeline runs receive MCP gateway config through runtime launch args.",
|
|
58
|
+
"# Persistent Codex MCP config is intentionally left empty to avoid startup-time MCP fan-out.",
|
|
59
|
+
`# gateway_url = ${JSON.stringify(gatewayUrl(gateway))}`,
|
|
60
|
+
`# token_env = ${JSON.stringify(gateway.token_env)}`,
|
|
59
61
|
""
|
|
60
62
|
].join("\n");
|
|
61
63
|
}
|
package/dist/mcp/launch-plan.js
CHANGED
package/dist/pipeline-init.js
CHANGED
|
@@ -462,6 +462,7 @@ profiles:
|
|
|
462
462
|
max_attempts: 1
|
|
463
463
|
pipeline-code-writer:
|
|
464
464
|
runner: codex
|
|
465
|
+
scheduling_roles: [implementation]
|
|
465
466
|
description: Implement production code until the failing tests pass.
|
|
466
467
|
instructions:
|
|
467
468
|
path: .pipeline/prompts/code-writer.md
|
|
@@ -479,6 +480,7 @@ profiles:
|
|
|
479
480
|
format: text
|
|
480
481
|
pipeline-acceptance-reviewer:
|
|
481
482
|
runner: codex
|
|
483
|
+
scheduling_roles: [coverage]
|
|
482
484
|
description: Audit the finished change against every acceptance criterion.
|
|
483
485
|
instructions:
|
|
484
486
|
path: .pipeline/prompts/acceptance-reviewer.md
|
|
@@ -500,6 +502,7 @@ profiles:
|
|
|
500
502
|
max_attempts: 1
|
|
501
503
|
pipeline-thermo-nuclear-reviewer:
|
|
502
504
|
runner: codex
|
|
505
|
+
scheduling_roles: [coverage]
|
|
503
506
|
description: Perform the final thermo-nuclear code quality review of the integration branch.
|
|
504
507
|
instructions:
|
|
505
508
|
path: .agents/skills/critique/SKILL.md
|
|
@@ -520,6 +523,7 @@ profiles:
|
|
|
520
523
|
max_attempts: 1
|
|
521
524
|
pipeline-verifier:
|
|
522
525
|
runner: codex
|
|
526
|
+
scheduling_roles: [coverage]
|
|
523
527
|
description: Verify checks, implementation fit, and final evidence.
|
|
524
528
|
instructions:
|
|
525
529
|
path: .pipeline/prompts/verifier.md
|
|
@@ -720,7 +724,7 @@ const SCAFFOLD_FILES = {
|
|
|
720
724
|
"",
|
|
721
725
|
"Generate exactly one workflow named `root`. Do not embed `default`, `epic-drain`, `infra`, `track`, or other configured workflow copies. Use explicit generated agent, builtin, command, parallel, or group nodes. Do not use `kind: workflow`.",
|
|
722
726
|
"",
|
|
723
|
-
"Use the provided backlog work units as the source of truth when present. Assign each work unit to explicit generated agent nodes with only its `task_context.id`, use only allowed configured profiles, and ensure implementation
|
|
727
|
+
"Use the provided backlog work units as the source of truth when present. Assign each work unit to explicit generated agent nodes with only its `task_context.id`, use only allowed configured profiles, and ensure profiles with the `implementation` scheduling role have downstream profiles with the `coverage` scheduling role. Do not invent profiles or node-level skill overrides.",
|
|
724
728
|
"Do not copy backlog descriptions or acceptance criteria into output; the scheduler hydrates them from the assigned `task_context.id` after parsing.",
|
|
725
729
|
"Preserve Backlog dependency ids as schedule needs edges. A node assigned a dependent work unit must depend on the nodes assigned its prerequisite work units, directly or through an explicit path.",
|
|
726
730
|
"",
|
package/dist/schedule-planner.js
CHANGED
|
@@ -376,7 +376,7 @@ function plannerPrompt(entrypointId, task, baseline, config, planningContext) {
|
|
|
376
376
|
"Every agent node must declare one configured profile id. Do not invent profile ids or node-level skill overrides.",
|
|
377
377
|
"Assign each backlog work unit to explicit generated agent nodes with task_context.id. The scheduler hydrates title, description, and acceptance_criteria after parsing.",
|
|
378
378
|
"Do not copy backlog descriptions or acceptance criteria into task_context output.",
|
|
379
|
-
"
|
|
379
|
+
"Profiles with the implementation scheduling role must have downstream profiles with the coverage scheduling role in the generated DAG.",
|
|
380
380
|
"Preserve Backlog dependency ids as schedule needs edges. A node assigned a dependent work unit must depend on the nodes assigned its prerequisite work units, directly or through an explicit path.",
|
|
381
381
|
"Shape the graph by intent, not by ticket count. Do not create a full RED/GREEN/ACCEPTANCE/VERIFY chain for each backlog ticket unless each step needs ticket-specific evidence.",
|
|
382
382
|
"Only add needs edges for real dependencies, shared constraints, or verification/review fan-in.",
|
|
@@ -385,7 +385,7 @@ function plannerPrompt(entrypointId, task, baseline, config, planningContext) {
|
|
|
385
385
|
"Only serialize ticket nodes when the backlog, a shared migration/schema/API dependency, or implementation risk requires it.",
|
|
386
386
|
"",
|
|
387
387
|
"Allowed profiles:",
|
|
388
|
-
...Object.keys(config.profiles).sort().map((id) =>
|
|
388
|
+
...Object.keys(config.profiles).sort().map((id) => allowedProfilePromptLine(config, id)),
|
|
389
389
|
"",
|
|
390
390
|
"Gate recipes:",
|
|
391
391
|
"- Prefer preserving valid gates from the baseline workflows instead of recreating them.",
|
|
@@ -403,6 +403,13 @@ function plannerPrompt(entrypointId, task, baseline, config, planningContext) {
|
|
|
403
403
|
stringify(baseline)
|
|
404
404
|
].join("\n");
|
|
405
405
|
}
|
|
406
|
+
function allowedProfilePromptLine(config, id) {
|
|
407
|
+
const roles = effectiveSchedulingRoles(config, id);
|
|
408
|
+
return roles.length > 0 ? `- ${id} (scheduling_roles: ${roles.join(", ")})` : `- ${id}`;
|
|
409
|
+
}
|
|
410
|
+
function effectiveSchedulingRoles(config, profileId) {
|
|
411
|
+
return [...new Set(config.profiles[profileId]?.scheduling_roles ?? [])].sort();
|
|
412
|
+
}
|
|
406
413
|
function canonicalizeGeneratedScheduleIds(artifact) {
|
|
407
414
|
return {
|
|
408
415
|
...artifact,
|
|
@@ -451,9 +458,9 @@ function validateScheduleArtifact(config, artifact, planningContext) {
|
|
|
451
458
|
...workflowReferenceNodeIssues(artifact),
|
|
452
459
|
...workflowAssignedWorkUnitIssues(artifact, planningContext.workUnits),
|
|
453
460
|
...missingAssignedWorkUnitIssues(artifact, planningContext.workUnits),
|
|
454
|
-
...workUnitDependencyIssues(artifact, planningContext.workUnits),
|
|
461
|
+
...workUnitDependencyIssues(config, artifact, planningContext.workUnits),
|
|
455
462
|
...invalidWorkflowPrimitiveIssues(config, artifact),
|
|
456
|
-
...implementationCoverageIssues(artifact)
|
|
463
|
+
...implementationCoverageIssues(config, artifact)
|
|
457
464
|
];
|
|
458
465
|
if (issues.length > 0) throw new ScheduleArtifactError(["Invalid generated schedule:", ...issues.map((issue) => `- ${issue}`)].join("\n"));
|
|
459
466
|
}
|
|
@@ -514,7 +521,7 @@ function missingAssignedWorkUnitIssues(artifact, workUnits) {
|
|
|
514
521
|
const missing = workUnits.map((unit) => unit.id).filter((id) => !assigned.has(id));
|
|
515
522
|
return missing.length > 0 ? [`missing assigned backlog work units: ${missing.join(", ")}`] : [];
|
|
516
523
|
}
|
|
517
|
-
function workUnitDependencyIssues(artifact, workUnits) {
|
|
524
|
+
function workUnitDependencyIssues(config, artifact, workUnits) {
|
|
518
525
|
if (workUnits.length === 0) return [];
|
|
519
526
|
const workUnitIds = new Set(workUnits.map((unit) => unit.id));
|
|
520
527
|
const dependenciesByUnit = new Map(workUnits.map((unit) => [unit.id, (unit.dependencies ?? []).filter((id) => workUnitIds.has(id))]));
|
|
@@ -522,7 +529,7 @@ function workUnitDependencyIssues(artifact, workUnits) {
|
|
|
522
529
|
const nodes = workflow.nodes.flatMap(flattenWorkflowNode);
|
|
523
530
|
const dependentsByNeed = workflowDependentsByNeed(nodes);
|
|
524
531
|
const nodesByWorkUnit = nodesByAssignedWorkUnit(nodes);
|
|
525
|
-
return nodes.filter(isImplementationNode).flatMap((node) => {
|
|
532
|
+
return nodes.filter((node) => isImplementationNode(config, node)).flatMap((node) => {
|
|
526
533
|
const dependentId = node.task_context?.id;
|
|
527
534
|
if (!dependentId) return [];
|
|
528
535
|
return (dependenciesByUnit.get(dependentId) ?? []).flatMap((prerequisiteId) => {
|
|
@@ -564,14 +571,15 @@ function invalidWorkflowPrimitiveIssues(config, artifact) {
|
|
|
564
571
|
return [];
|
|
565
572
|
});
|
|
566
573
|
}
|
|
567
|
-
function implementationCoverageIssues(artifact) {
|
|
574
|
+
function implementationCoverageIssues(config, artifact) {
|
|
568
575
|
return Object.entries(artifact.workflows).flatMap(([workflowId, workflow]) => {
|
|
569
|
-
const
|
|
570
|
-
|
|
576
|
+
const nodes = workflow.nodes.flatMap(flattenWorkflowNode);
|
|
577
|
+
const dependentsByNeed = workflowDependentsByNeed(nodes);
|
|
578
|
+
return nodes.filter((node) => isImplementationNode(config, node)).filter((node) => !hasDownstreamCoverage(config, node.id, dependentsByNeed)).map((node) => `implementation node '${workflowId}.${node.id}' is without downstream verification or review`);
|
|
571
579
|
});
|
|
572
580
|
}
|
|
573
|
-
function isImplementationNode(node) {
|
|
574
|
-
return
|
|
581
|
+
function isImplementationNode(config, node) {
|
|
582
|
+
return hasSchedulingRole(config, node, "implementation");
|
|
575
583
|
}
|
|
576
584
|
function workflowDependentsByNeed(nodes) {
|
|
577
585
|
const dependentsByNeed = /* @__PURE__ */ new Map();
|
|
@@ -582,25 +590,24 @@ function workflowDependentsByNeed(nodes) {
|
|
|
582
590
|
}
|
|
583
591
|
return dependentsByNeed;
|
|
584
592
|
}
|
|
585
|
-
function hasDownstreamCoverage(nodeId, dependentsByNeed) {
|
|
593
|
+
function hasDownstreamCoverage(config, nodeId, dependentsByNeed) {
|
|
586
594
|
const queue = [...dependentsByNeed.get(nodeId) ?? []];
|
|
587
595
|
const seen = /* @__PURE__ */ new Set();
|
|
588
596
|
while (queue.length > 0) {
|
|
589
597
|
const node = queue.shift();
|
|
590
598
|
if (!node || seen.has(node.id)) continue;
|
|
591
599
|
seen.add(node.id);
|
|
592
|
-
if (isCoverageNode(node)) return true;
|
|
600
|
+
if (isCoverageNode(config, node)) return true;
|
|
593
601
|
queue.push(...dependentsByNeed.get(node.id) ?? []);
|
|
594
602
|
}
|
|
595
603
|
return false;
|
|
596
604
|
}
|
|
597
|
-
function isCoverageNode(node) {
|
|
605
|
+
function isCoverageNode(config, node) {
|
|
606
|
+
return hasSchedulingRole(config, node, "coverage");
|
|
607
|
+
}
|
|
608
|
+
function hasSchedulingRole(config, node, role) {
|
|
598
609
|
if (node.kind !== "agent") return false;
|
|
599
|
-
return [
|
|
600
|
-
"pipeline-acceptance-reviewer",
|
|
601
|
-
"pipeline-thermo-nuclear-reviewer",
|
|
602
|
-
"pipeline-verifier"
|
|
603
|
-
].includes(node.profile);
|
|
610
|
+
return config.profiles[node.profile]?.scheduling_roles?.includes(role) ?? false;
|
|
604
611
|
}
|
|
605
612
|
function allWorkflowNodes(workflows) {
|
|
606
613
|
return Object.values(workflows).flatMap((workflow) => workflow.nodes.flatMap(flattenWorkflowNode));
|
package/docs/mcp-gateway.md
CHANGED
|
@@ -86,4 +86,6 @@ Use an off-the-shelf aggregator when possible:
|
|
|
86
86
|
Use `pipe mcp gateway doctor` to check required environment variables, gateway
|
|
87
87
|
health, local ToolHive availability for local mode, and legacy direct MCP
|
|
88
88
|
entries. Use `pipe mcp gateway configure-host` to rewrite project or global
|
|
89
|
-
|
|
89
|
+
host config with a backup. For Codex, this removes persistent MCP entries and
|
|
90
|
+
leaves gateway metadata as comments because the runtime injects the gateway
|
|
91
|
+
with `--config` only for pipeline-launched agents.
|
package/docs/operator-guide.md
CHANGED
|
@@ -412,12 +412,17 @@ pipe mcp gateway local-status
|
|
|
412
412
|
pipe mcp gateway local-start
|
|
413
413
|
```
|
|
414
414
|
|
|
415
|
-
`configure-host`
|
|
415
|
+
`configure-host` removes persistent Codex MCP config and records the gateway
|
|
416
|
+
metadata as comments. Codex pipeline runs receive the gateway through runtime
|
|
417
|
+
launch arguments so ordinary Codex sessions do not start pipeline MCP clients at
|
|
418
|
+
startup:
|
|
416
419
|
|
|
417
420
|
```toml
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
+
# Generated by @oisincoveney/pipeline.
|
|
422
|
+
# Codex pipeline runs receive MCP gateway config through runtime launch args.
|
|
423
|
+
# Persistent Codex MCP config is intentionally left empty to avoid startup-time MCP fan-out.
|
|
424
|
+
# gateway_url = "https://gateway.example/mcp"
|
|
425
|
+
# token_env = "PIPELINE_MCP_GATEWAY_TOKEN"
|
|
421
426
|
```
|
|
422
427
|
|
|
423
428
|
OpenCode receives:
|
package/package.json
CHANGED
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"prepack": "bun run build:cli"
|
|
100
100
|
},
|
|
101
101
|
"type": "module",
|
|
102
|
-
"version": "1.
|
|
102
|
+
"version": "1.16.1",
|
|
103
103
|
"description": "Config-driven multi-agent pipeline runner for repository work",
|
|
104
104
|
"main": "./dist/index.js",
|
|
105
105
|
"types": "./dist/index.d.ts",
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
import { gatewayServerForProfile } from "./gateway.js";
|
|
2
|
-
import { isRemoteMcpServer } from "./launch-plan.js";
|
|
3
|
-
//#region src/mcp/native-config.ts
|
|
4
|
-
function codexNativeMcpConfig(config, profile) {
|
|
5
|
-
const mcpServers = Object.fromEntries(Object.entries(gatewayServerForProfile(config, profile)).map(([id, server]) => [id, codexNativeMcpServerConfig(server)]));
|
|
6
|
-
return Object.keys(mcpServers).length > 0 ? { mcp_servers: mcpServers } : {};
|
|
7
|
-
}
|
|
8
|
-
function codexNativeMcpServerConfig(server) {
|
|
9
|
-
if (isRemoteMcpServer(server)) return {
|
|
10
|
-
...server.bearer_token_env_var ? { bearer_token_env_var: server.bearer_token_env_var } : {},
|
|
11
|
-
...server.headers ? { http_headers: server.headers } : {},
|
|
12
|
-
url: server.url
|
|
13
|
-
};
|
|
14
|
-
return {
|
|
15
|
-
...server.args ? { args: server.args } : {},
|
|
16
|
-
command: server.command,
|
|
17
|
-
...server.env ? { env: server.env } : {}
|
|
18
|
-
};
|
|
19
|
-
}
|
|
20
|
-
//#endregion
|
|
21
|
-
export { codexNativeMcpConfig };
|