@oisincoveney/pipeline 1.16.0 → 1.16.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/config.d.ts +4 -3
- package/dist/config.js +2 -1
- package/dist/index.js +1 -1
- package/dist/install-commands.js +0 -3
- package/dist/mcp/gateway.js +25 -8
- package/dist/mcp/launch-plan.js +6 -3
- package/dist/pipeline-init.js +1 -1
- package/docs/config-architecture.md +2 -1
- package/docs/mcp-gateway.md +5 -2
- package/docs/operator-guide.md +13 -6
- package/package.json +1 -1
- package/dist/mcp/native-config.js +0 -21
package/dist/config.d.ts
CHANGED
|
@@ -223,8 +223,8 @@ declare const configSchema: z.ZodObject<{
|
|
|
223
223
|
policy: z.ZodOptional<z.ZodObject<{
|
|
224
224
|
commands: z.ZodOptional<z.ZodEnum<{
|
|
225
225
|
allow: "allow";
|
|
226
|
-
"trusted-only": "trusted-only";
|
|
227
226
|
deny: "deny";
|
|
227
|
+
"trusted-only": "trusted-only";
|
|
228
228
|
}>>;
|
|
229
229
|
modules: z.ZodOptional<z.ZodEnum<{
|
|
230
230
|
allow: "allow";
|
|
@@ -240,6 +240,7 @@ declare const configSchema: z.ZodObject<{
|
|
|
240
240
|
}>;
|
|
241
241
|
provider: z.ZodLiteral<"toolhive">;
|
|
242
242
|
token_env: z.ZodDefault<z.ZodString>;
|
|
243
|
+
url: z.ZodOptional<z.ZodString>;
|
|
243
244
|
url_env: z.ZodDefault<z.ZodString>;
|
|
244
245
|
}, z.core.$strict>>;
|
|
245
246
|
mcp_servers: z.ZodDefault<z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
@@ -278,10 +279,10 @@ declare const configSchema: z.ZodObject<{
|
|
|
278
279
|
}, z.core.$strict>>;
|
|
279
280
|
output: z.ZodOptional<z.ZodObject<{
|
|
280
281
|
format: z.ZodEnum<{
|
|
282
|
+
json_schema: "json_schema";
|
|
281
283
|
text: "text";
|
|
282
284
|
json: "json";
|
|
283
285
|
jsonl: "jsonl";
|
|
284
|
-
json_schema: "json_schema";
|
|
285
286
|
}>;
|
|
286
287
|
repair: z.ZodOptional<z.ZodObject<{
|
|
287
288
|
enabled: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -325,10 +326,10 @@ declare const configSchema: z.ZodObject<{
|
|
|
325
326
|
disabled: "disabled";
|
|
326
327
|
}>>>;
|
|
327
328
|
output_formats: z.ZodOptional<z.ZodArray<z.ZodEnum<{
|
|
329
|
+
json_schema: "json_schema";
|
|
328
330
|
text: "text";
|
|
329
331
|
json: "json";
|
|
330
332
|
jsonl: "jsonl";
|
|
331
|
-
json_schema: "json_schema";
|
|
332
333
|
}>>>;
|
|
333
334
|
rules: z.ZodOptional<z.ZodBoolean>;
|
|
334
335
|
skills: z.ZodOptional<z.ZodBoolean>;
|
package/dist/config.js
CHANGED
|
@@ -132,7 +132,8 @@ const mcpGatewaySchema = z.object({
|
|
|
132
132
|
default_profile: z.string().min(1).optional(),
|
|
133
133
|
mode: z.enum(["hosted", "local"]),
|
|
134
134
|
provider: z.literal("toolhive"),
|
|
135
|
-
token_env: z.string().min(1).default("
|
|
135
|
+
token_env: z.string().min(1).default("MEMORY_MCP_BASIC_AUTH"),
|
|
136
|
+
url: z.string().url().refine((value) => ["http:", "https:"].includes(new URL(value).protocol), { message: "MCP gateway url must use http or https" }).optional(),
|
|
136
137
|
url_env: z.string().min(1).default("PIPELINE_MCP_GATEWAY_URL")
|
|
137
138
|
}).strict();
|
|
138
139
|
const instructionsSchema = z.object({
|
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,8 @@ 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
|
|
8
|
+
const AUTHORIZATION_ENV_RE = /\{env:([A-Za-z_][A-Za-z0-9_]*)\}/g;
|
|
9
|
+
const LEGACY_CODEX_MCP_RE = /\[mcp_servers\./;
|
|
9
10
|
const LEGACY_OPENCODE_MCP_RE = /"mcp"\s*:\s*{(?!\s*"pipeline-gateway")/s;
|
|
10
11
|
const LEGACY_PIPELINE_MCP_RE = /path:\s*\.mcp\.json|uvx\s+mcpm|mcpm\s+run/;
|
|
11
12
|
var PipelineMcpGatewayError = class extends Error {
|
|
@@ -25,7 +26,7 @@ function gatewayServer(config, env = process.env) {
|
|
|
25
26
|
const gateway = configuredGateway(config);
|
|
26
27
|
const url = gatewayUrl(gateway, env);
|
|
27
28
|
return {
|
|
28
|
-
|
|
29
|
+
headers: { Authorization: gatewayAuthorizationHeader(gateway) },
|
|
29
30
|
url
|
|
30
31
|
};
|
|
31
32
|
}
|
|
@@ -36,6 +37,7 @@ function configuredGateway(config) {
|
|
|
36
37
|
function gatewayUrl(gateway, env = process.env) {
|
|
37
38
|
const url = env[gateway.url_env];
|
|
38
39
|
if (url) return url;
|
|
40
|
+
if (gateway.url) return gateway.url;
|
|
39
41
|
if (gateway.mode === "local") return DEFAULT_LOCAL_GATEWAY_URL;
|
|
40
42
|
throw new PipelineMcpGatewayError(`MCP gateway URL is required. Set ${gateway.url_env}.`);
|
|
41
43
|
}
|
|
@@ -44,6 +46,7 @@ function renderGatewayConfig(config) {
|
|
|
44
46
|
return [
|
|
45
47
|
`provider: ${gateway.provider}`,
|
|
46
48
|
`mode: ${gateway.mode}`,
|
|
49
|
+
gateway.url ? `url: ${gateway.url}` : "",
|
|
47
50
|
`url_env: ${gateway.url_env}`,
|
|
48
51
|
`token_env: ${gateway.token_env}`,
|
|
49
52
|
gateway.default_profile ? `default_profile: ${gateway.default_profile}` : "",
|
|
@@ -53,9 +56,11 @@ function renderGatewayConfig(config) {
|
|
|
53
56
|
function renderCodexGatewayConfig(config) {
|
|
54
57
|
const gateway = configuredGateway(config);
|
|
55
58
|
return [
|
|
56
|
-
"
|
|
57
|
-
|
|
58
|
-
|
|
59
|
+
"# Generated by @oisincoveney/pipeline.",
|
|
60
|
+
"# Codex pipeline runs receive MCP gateway config through runtime launch args.",
|
|
61
|
+
"# Persistent Codex MCP config is intentionally left empty to avoid startup-time MCP fan-out.",
|
|
62
|
+
`# gateway_url = ${JSON.stringify(gatewayUrl(gateway))}`,
|
|
63
|
+
`# token_env = ${JSON.stringify(gateway.token_env)}`,
|
|
59
64
|
""
|
|
60
65
|
].join("\n");
|
|
61
66
|
}
|
|
@@ -65,7 +70,7 @@ function renderOpenCodeGatewayConfig(config) {
|
|
|
65
70
|
$schema: "https://opencode.ai/config.json",
|
|
66
71
|
mcp: { [PIPELINE_GATEWAY_SERVER_ID]: {
|
|
67
72
|
enabled: true,
|
|
68
|
-
headers:
|
|
73
|
+
headers: gatewayOpenCodeHeaders(gateway),
|
|
69
74
|
type: "remote",
|
|
70
75
|
url: gatewayUrl(gateway)
|
|
71
76
|
} }
|
|
@@ -169,6 +174,17 @@ function checkGatewayToken(gateway) {
|
|
|
169
174
|
passed: false
|
|
170
175
|
};
|
|
171
176
|
}
|
|
177
|
+
function gatewayAuthorizationHeader(gateway) {
|
|
178
|
+
return `Basic {env:${gateway.token_env}}`;
|
|
179
|
+
}
|
|
180
|
+
function resolveHeaderEnvPlaceholders(value, env = process.env) {
|
|
181
|
+
return value.replace(AUTHORIZATION_ENV_RE, (_match, envVar) => {
|
|
182
|
+
return env[envVar] || `{env:${envVar}}`;
|
|
183
|
+
});
|
|
184
|
+
}
|
|
185
|
+
function gatewayOpenCodeHeaders(gateway) {
|
|
186
|
+
return { Authorization: gatewayAuthorizationHeader(gateway) };
|
|
187
|
+
}
|
|
172
188
|
async function checkThv(cwd) {
|
|
173
189
|
try {
|
|
174
190
|
await execa("thv", ["version"], {
|
|
@@ -238,11 +254,12 @@ async function checkGatewayHealth(gateway) {
|
|
|
238
254
|
}
|
|
239
255
|
}
|
|
240
256
|
async function firstHealthyGatewayResponse(url, gateway) {
|
|
257
|
+
const authorization = process.env[gateway.token_env] ? `Basic ${process.env[gateway.token_env]}` : void 0;
|
|
241
258
|
for (const healthUrl of gatewayHealthUrls(url)) {
|
|
242
259
|
const response = await fetch(healthUrl, {
|
|
243
260
|
headers: {
|
|
244
261
|
Accept: "application/json, text/event-stream",
|
|
245
|
-
...
|
|
262
|
+
...authorization ? { Authorization: authorization } : {}
|
|
246
263
|
},
|
|
247
264
|
method: "GET"
|
|
248
265
|
});
|
|
@@ -285,4 +302,4 @@ function legacyContentHit(cwd, path, pattern) {
|
|
|
285
302
|
return pattern.test(readFileSync(fullPath, "utf8")) ? path : void 0;
|
|
286
303
|
}
|
|
287
304
|
//#endregion
|
|
288
|
-
export { configureGatewayHosts, gatewayServerForProfile, localGatewayStatus, renderGatewayConfig, runGatewayDoctor, startLocalGateway };
|
|
305
|
+
export { configureGatewayHosts, gatewayServerForProfile, localGatewayStatus, renderGatewayConfig, resolveHeaderEnvPlaceholders, runGatewayDoctor, startLocalGateway };
|
package/dist/mcp/launch-plan.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { gatewayServerForProfile } from "./gateway.js";
|
|
1
|
+
import { gatewayServerForProfile, resolveHeaderEnvPlaceholders } from "./gateway.js";
|
|
2
2
|
import { mkdtempSync } from "node:fs";
|
|
3
3
|
import { join } from "node:path";
|
|
4
4
|
import { tmpdir } from "node:os";
|
|
@@ -74,7 +74,7 @@ function codexMcpArgs(servers) {
|
|
|
74
74
|
if (isRemoteMcpServer(server)) return [
|
|
75
75
|
"--config",
|
|
76
76
|
`mcp_servers.${id}.url=${tomlValue(server.url)}`,
|
|
77
|
-
...server.headers ? ["--config", `mcp_servers.${id}.http_headers=${tomlValue(server.headers)}`] : [],
|
|
77
|
+
...server.headers ? ["--config", `mcp_servers.${id}.http_headers=${tomlValue(codexHttpHeaders(server.headers))}`] : [],
|
|
78
78
|
...server.bearer_token_env_var ? ["--config", `mcp_servers.${id}.bearer_token_env_var=${tomlValue(server.bearer_token_env_var)}`] : []
|
|
79
79
|
];
|
|
80
80
|
return [
|
|
@@ -85,6 +85,9 @@ function codexMcpArgs(servers) {
|
|
|
85
85
|
];
|
|
86
86
|
});
|
|
87
87
|
}
|
|
88
|
+
function codexHttpHeaders(headers) {
|
|
89
|
+
return Object.fromEntries(Object.entries(headers).map(([key, value]) => [key, resolveHeaderEnvPlaceholders(value)]));
|
|
90
|
+
}
|
|
88
91
|
function tomlValue(value) {
|
|
89
92
|
if (Array.isArray(value)) return `[${value.map(tomlValue).join(", ")}]`;
|
|
90
93
|
if (value && typeof value === "object") return `{ ${Object.entries(value).map(([key, item]) => `${tomlKey(key)} = ${tomlValue(item)}`).join(", ")} }`;
|
|
@@ -94,4 +97,4 @@ function tomlKey(key) {
|
|
|
94
97
|
return TOML_BARE_KEY_PATTERN.test(key) ? key : JSON.stringify(key);
|
|
95
98
|
}
|
|
96
99
|
//#endregion
|
|
97
|
-
export { buildMcpLaunchPlan,
|
|
100
|
+
export { buildMcpLaunchPlan, tomlValue };
|
package/dist/pipeline-init.js
CHANGED
|
@@ -150,8 +150,9 @@ MCP-enabled profiles use one gateway grant:
|
|
|
150
150
|
mcp_gateway:
|
|
151
151
|
provider: toolhive
|
|
152
152
|
mode: hosted
|
|
153
|
+
url: https://pipeline-mcp.momokaya.ee/mcp/
|
|
153
154
|
url_env: PIPELINE_MCP_GATEWAY_URL
|
|
154
|
-
token_env:
|
|
155
|
+
token_env: MEMORY_MCP_BASIC_AUTH
|
|
155
156
|
default_profile: default
|
|
156
157
|
|
|
157
158
|
profiles:
|
package/docs/mcp-gateway.md
CHANGED
|
@@ -52,8 +52,9 @@ Example profile config:
|
|
|
52
52
|
mcp_gateway:
|
|
53
53
|
provider: toolhive
|
|
54
54
|
mode: hosted
|
|
55
|
+
url: https://pipeline-mcp.momokaya.ee/mcp/
|
|
55
56
|
url_env: PIPELINE_MCP_GATEWAY_URL
|
|
56
|
-
token_env:
|
|
57
|
+
token_env: MEMORY_MCP_BASIC_AUTH
|
|
57
58
|
default_profile: default
|
|
58
59
|
|
|
59
60
|
profiles:
|
|
@@ -86,4 +87,6 @@ Use an off-the-shelf aggregator when possible:
|
|
|
86
87
|
Use `pipe mcp gateway doctor` to check required environment variables, gateway
|
|
87
88
|
health, local ToolHive availability for local mode, and legacy direct MCP
|
|
88
89
|
entries. Use `pipe mcp gateway configure-host` to rewrite project or global
|
|
89
|
-
|
|
90
|
+
host config with a backup. For Codex, this removes persistent MCP entries and
|
|
91
|
+
leaves gateway metadata as comments because the runtime injects the gateway
|
|
92
|
+
with `--config` only for pipeline-launched agents.
|
package/docs/operator-guide.md
CHANGED
|
@@ -378,8 +378,9 @@ Use the same client config shape for hosted and local gateways:
|
|
|
378
378
|
mcp_gateway:
|
|
379
379
|
provider: toolhive
|
|
380
380
|
mode: hosted
|
|
381
|
+
url: https://pipeline-mcp.momokaya.ee/mcp/
|
|
381
382
|
url_env: PIPELINE_MCP_GATEWAY_URL
|
|
382
|
-
token_env:
|
|
383
|
+
token_env: MEMORY_MCP_BASIC_AUTH
|
|
383
384
|
default_profile: default
|
|
384
385
|
```
|
|
385
386
|
|
|
@@ -412,12 +413,17 @@ pipe mcp gateway local-status
|
|
|
412
413
|
pipe mcp gateway local-start
|
|
413
414
|
```
|
|
414
415
|
|
|
415
|
-
`configure-host`
|
|
416
|
+
`configure-host` removes persistent Codex MCP config and records the gateway
|
|
417
|
+
metadata as comments. Codex pipeline runs receive the gateway through runtime
|
|
418
|
+
launch arguments so ordinary Codex sessions do not start pipeline MCP clients at
|
|
419
|
+
startup:
|
|
416
420
|
|
|
417
421
|
```toml
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
422
|
+
# Generated by @oisincoveney/pipeline.
|
|
423
|
+
# Codex pipeline runs receive MCP gateway config through runtime launch args.
|
|
424
|
+
# Persistent Codex MCP config is intentionally left empty to avoid startup-time MCP fan-out.
|
|
425
|
+
# gateway_url = "https://gateway.example/mcp"
|
|
426
|
+
# token_env = "MEMORY_MCP_BASIC_AUTH"
|
|
421
427
|
```
|
|
422
428
|
|
|
423
429
|
OpenCode receives:
|
|
@@ -521,8 +527,9 @@ singleton gateway server to profiles that need MCP.
|
|
|
521
527
|
mcp_gateway:
|
|
522
528
|
provider: toolhive
|
|
523
529
|
mode: hosted
|
|
530
|
+
url: https://pipeline-mcp.momokaya.ee/mcp/
|
|
524
531
|
url_env: PIPELINE_MCP_GATEWAY_URL
|
|
525
|
-
token_env:
|
|
532
|
+
token_env: MEMORY_MCP_BASIC_AUTH
|
|
526
533
|
|
|
527
534
|
profiles:
|
|
528
535
|
pipeline-router:
|
package/package.json
CHANGED
|
@@ -99,7 +99,7 @@
|
|
|
99
99
|
"prepack": "bun run build:cli"
|
|
100
100
|
},
|
|
101
101
|
"type": "module",
|
|
102
|
-
"version": "1.16.
|
|
102
|
+
"version": "1.16.2",
|
|
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 };
|