@oisincoveney/pipeline 1.8.0 → 1.9.0

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
@@ -37,11 +37,17 @@ Momokaya remote endpoint
37
37
 
38
38
  The default GitHub MCP registration uses GitHub's official container in
39
39
  read-only mode and reads `GITHUB_PERSONAL_ACCESS_TOKEN` from the environment.
40
- The Momokaya Qdrant endpoint is protected by Traefik HTTP Basic auth. Set either
41
- `MOMOKAYA_MCP_AUTHORIZATION` to the complete Authorization header value
42
- (`Basic <base64-user-colon-password>`) or `MEMORY_MCP_BASIC_AUTH` to only the
43
- base64 payload. `pipe init` resolves that value before registering the remote
44
- server with MCPM.
40
+ The Momokaya Qdrant endpoint is protected by Traefik HTTP Basic auth. Set
41
+ `MEMORY_MCP_BASIC_AUTH` to the base64 `user:password` payload before running
42
+ `pipe init` if you want init to register that remote server with MCPM:
43
+
44
+ ```shell
45
+ export MEMORY_MCP_BASIC_AUTH="$(printf '%s' 'user:password' | base64)"
46
+ ```
47
+
48
+ When `MEMORY_MCP_BASIC_AUTH` is not set, `pipe init` still writes the default
49
+ scaffold and keeps the generated `qdrant` MCP entry, but skips immediate MCPM
50
+ registration for that private endpoint.
45
51
 
46
52
  Check local prerequisites and config health:
47
53
 
@@ -90,7 +96,7 @@ pipe epic PIPE-31
90
96
 
91
97
  The `epic` entrypoint routes an epic's child tickets into fixed specialist
92
98
  tracks, runs those tracks in parallel, merges passing branches, and then runs a
93
- hardened review.
99
+ thermo-nuclear code quality review.
94
100
 
95
101
  The `pipe` binary also accepts the task directly:
96
102
 
@@ -201,11 +207,11 @@ The built-in `epic` entrypoint uses those primitives:
201
207
  entrypoints:
202
208
  epic:
203
209
  workflow: epic-drain
204
- description: Route an epic's tickets into specialist tracks, run them in parallel, then hardened-review.
210
+ description: Route an epic's tickets into specialist tracks, run them in parallel, then thermo-nuclear review.
205
211
 
206
212
  workflows:
207
213
  epic-drain:
208
- description: Research, route, parallel-implement tracks in isolated worktrees, integrate, hardened-review.
214
+ description: Research, route, parallel-implement tracks in isolated worktrees, integrate, thermo-nuclear review.
209
215
  nodes:
210
216
  - id: research
211
217
  kind: agent
@@ -240,7 +246,7 @@ workflows:
240
246
  needs: [implement]
241
247
  - id: review
242
248
  kind: agent
243
- profile: pipeline-hardened-reviewer
249
+ profile: pipeline-thermo-nuclear-reviewer
244
250
  needs: [merge]
245
251
  gates:
246
252
  - { id: review-verdict, kind: verdict, target: stdout }
@@ -253,10 +259,9 @@ branches share a base SHA, and merges passing branches into an integration
253
259
  branch in declaration order. It reports merge conflicts; it does not resolve
254
260
  them automatically.
255
261
 
256
- The `hardened-review` skill is an external/local skill registered at
257
- `.agents/skills/hardened-review/SKILL.md`. When that file is absent, normal
258
- validation reports a `missing-file-reference` warning and continues; `--strict`
259
- promotes that warning to a failure.
262
+ The `thermo-nuclear-code-quality-review` skill is installed from
263
+ `cursor/plugins` and registered at
264
+ `.agents/skills/thermo-nuclear-code-quality-review/SKILL.md`.
260
265
 
261
266
  ## Generated Host Resources
262
267
 
@@ -30,6 +30,10 @@
30
30
  "deprecation-and-migration"
31
31
  ]
32
32
  },
33
+ {
34
+ "source": "cursor/plugins",
35
+ "skills": ["thermo-nuclear-code-quality-review"]
36
+ },
33
37
  {
34
38
  "source": "trailofbits/skills",
35
39
  "skills": ["semgrep", "supply-chain-risk-auditor"]
@@ -78,12 +82,10 @@
78
82
  "name": "oisin-pipeline-qdrant",
79
83
  "transport": "remote",
80
84
  "url": "https://memory-mcp.momokaya.ee/mcp/",
85
+ "optionalRegistration": true,
81
86
  "headers": {
82
87
  "Authorization": {
83
- "sources": [
84
- { "env": "MOMOKAYA_MCP_AUTHORIZATION" },
85
- { "env": "MEMORY_MCP_BASIC_AUTH", "prefix": "Basic " }
86
- ]
88
+ "sources": [{ "env": "MEMORY_MCP_BASIC_AUTH", "prefix": "Basic " }]
87
89
  }
88
90
  }
89
91
  },
@@ -29,6 +29,18 @@ var PipelineMcpInstallError = class extends Error {
29
29
  this.name = "PipelineMcpInstallError";
30
30
  }
31
31
  };
32
+ var PipelineMcpMissingCredentialError = class extends PipelineMcpInstallError {
33
+ headerName;
34
+ missingEnv;
35
+ serverName;
36
+ constructor(serverName, headerName, missingEnv) {
37
+ super([`MCP server ${serverName} requires ${headerName} credentials before it can be registered.`, `Set ${missingEnv.join(" or ")} and re-run pipeline init.`].join("\n"));
38
+ this.name = "PipelineMcpMissingCredentialError";
39
+ this.serverName = serverName;
40
+ this.headerName = headerName;
41
+ this.missingEnv = missingEnv;
42
+ }
43
+ };
32
44
  var PipelineDefaultManifestError = class extends Error {
33
45
  constructor(message) {
34
46
  super(message);
@@ -58,6 +70,7 @@ const pipelineMcpInstallSpecSchema = z.object({
58
70
  env: z.record(z.string(), z.string()).optional(),
59
71
  headers: z.record(z.string(), pipelineMcpHeaderValueSchema).optional(),
60
72
  name: z.string().min(1),
73
+ optionalRegistration: z.boolean().optional(),
61
74
  transport: z.enum(["remote", "stdio"]),
62
75
  url: z.string().url().optional()
63
76
  }).strict().superRefine((spec, ctx) => {
@@ -125,6 +138,9 @@ entrypoints:
125
138
  inspect:
126
139
  workflow: inspect
127
140
  description: Read-only repository inspection
141
+ epic:
142
+ workflow: epic-drain
143
+ description: Route an epic's tickets into specialist tracks, run them in parallel, then thermo-nuclear review.
128
144
 
129
145
  orchestrator:
130
146
  profile: orchestrator
@@ -234,6 +250,121 @@ workflows:
234
250
  kind: agent
235
251
  profile: pipeline-learner
236
252
  needs: [verify]
253
+ infra:
254
+ description: Default-shaped stub workflow for infrastructure specialization.
255
+ nodes:
256
+ - id: research
257
+ kind: agent
258
+ profile: pipeline-researcher
259
+ - id: red
260
+ kind: agent
261
+ profile: pipeline-test-writer
262
+ needs: [research]
263
+ gates:
264
+ - id: red-test-file-policy
265
+ kind: changed_files
266
+ changed_files:
267
+ allow:
268
+ [
269
+ "**/*.test.*",
270
+ "**/*.spec.*",
271
+ "**/*_test.*",
272
+ "**/__tests__/**",
273
+ "test/**",
274
+ "tests/**",
275
+ "**/*.snap",
276
+ ]
277
+ require_any:
278
+ [
279
+ "**/*.test.*",
280
+ "**/*.spec.*",
281
+ "**/*_test.*",
282
+ "**/__tests__/**",
283
+ "test/**",
284
+ "tests/**",
285
+ ]
286
+ - id: green
287
+ kind: agent
288
+ profile: pipeline-code-writer
289
+ needs: [red]
290
+ - id: acceptance
291
+ kind: agent
292
+ profile: pipeline-acceptance-reviewer
293
+ needs: [green]
294
+ gates:
295
+ - id: acceptance-coverage
296
+ kind: acceptance
297
+ target: stdout
298
+ required: false
299
+ - id: acceptance-verdict
300
+ kind: verdict
301
+ target: stdout
302
+ - id: verify
303
+ kind: agent
304
+ profile: pipeline-verifier
305
+ needs: [acceptance]
306
+ gates:
307
+ - id: verify-typecheck
308
+ kind: builtin
309
+ builtin: typecheck
310
+ - id: verify-tests
311
+ kind: builtin
312
+ builtin: test
313
+ - id: verify-semgrep
314
+ kind: builtin
315
+ builtin: semgrep
316
+ - id: verify-duplication
317
+ kind: builtin
318
+ builtin: duplication
319
+ - id: verify-verdict
320
+ kind: verdict
321
+ target: stdout
322
+ - id: learn
323
+ kind: agent
324
+ profile: pipeline-learner
325
+ needs: [verify]
326
+ epic-drain:
327
+ description: Research, route, parallel-implement tracks in isolated worktrees, integrate, thermo-nuclear review.
328
+ nodes:
329
+ - id: research
330
+ kind: agent
331
+ profile: pipeline-researcher
332
+ - id: plan
333
+ kind: agent
334
+ profile: pipeline-epic-router
335
+ needs: [research]
336
+ - id: implement
337
+ kind: parallel
338
+ needs: [plan]
339
+ nodes:
340
+ - id: test
341
+ kind: workflow
342
+ workflow: default
343
+ worktree_root: .pipeline/runs/\${runId}/test
344
+ - id: frontend
345
+ kind: workflow
346
+ workflow: default
347
+ worktree_root: .pipeline/runs/\${runId}/frontend
348
+ - id: backend
349
+ kind: workflow
350
+ workflow: default
351
+ worktree_root: .pipeline/runs/\${runId}/backend
352
+ - id: k8s
353
+ kind: workflow
354
+ workflow: infra
355
+ worktree_root: .pipeline/runs/\${runId}/k8s
356
+ - id: merge
357
+ kind: builtin
358
+ builtin: drain-merge
359
+ needs: [implement]
360
+ - id: review
361
+ kind: agent
362
+ profile: pipeline-thermo-nuclear-reviewer
363
+ needs: [merge]
364
+ gates:
365
+ - id: review-verdict
366
+ kind: verdict
367
+ target: stdout
237
368
  `;
238
369
  const DEFAULT_RUNNERS_YAML = `version: 1
239
370
 
@@ -364,6 +495,8 @@ skills:
364
495
  path: .agents/skills/incremental-implementation/SKILL.md
365
496
  debugging-and-error-recovery:
366
497
  path: .agents/skills/debugging-and-error-recovery/SKILL.md
498
+ thermo-nuclear-code-quality-review:
499
+ path: .agents/skills/thermo-nuclear-code-quality-review/SKILL.md
367
500
  code-review-and-quality:
368
501
  path: .agents/skills/code-review-and-quality/SKILL.md
369
502
  doubt-driven-development:
@@ -489,6 +622,25 @@ profiles:
489
622
  mode: inherit
490
623
  output:
491
624
  format: text
625
+ pipeline-epic-router:
626
+ runner: codex
627
+ description: Route epic sub-tickets into fixed implementation tracks.
628
+ instructions:
629
+ path: .pipeline/prompts/epic-router.md
630
+ mcp_servers: [backlog, github-readonly]
631
+ tools: [read, list, grep, glob, bash]
632
+ filesystem:
633
+ mode: read-only
634
+ allow: ["**/*"]
635
+ deny: ["node_modules/**", "dist/**", ".git/**"]
636
+ network:
637
+ mode: inherit
638
+ output:
639
+ format: json_schema
640
+ schema_path: .pipeline/schemas/epic-plan.schema.json
641
+ repair:
642
+ enabled: true
643
+ max_attempts: 1
492
644
  pipeline-code-writer:
493
645
  runner: codex
494
646
  description: Implement production code until the failing tests pass.
@@ -539,6 +691,26 @@ profiles:
539
691
  repair:
540
692
  enabled: true
541
693
  max_attempts: 1
694
+ pipeline-thermo-nuclear-reviewer:
695
+ runner: codex
696
+ description: Perform the final thermo-nuclear code quality review of the integration branch.
697
+ instructions:
698
+ path: .agents/skills/thermo-nuclear-code-quality-review/SKILL.md
699
+ skills: [thermo-nuclear-code-quality-review]
700
+ mcp_servers: [serena, semgrep, github-readonly]
701
+ tools: [read, list, grep, glob, bash]
702
+ filesystem:
703
+ mode: read-only
704
+ allow: ["**/*"]
705
+ deny: ["node_modules/**", "dist/**", ".git/**"]
706
+ network:
707
+ mode: inherit
708
+ output:
709
+ format: json_schema
710
+ schema_path: .pipeline/schemas/review.schema.json
711
+ repair:
712
+ enabled: true
713
+ max_attempts: 1
542
714
  pipeline-verifier:
543
715
  runner: codex
544
716
  description: Verify checks, implementation fit, and final evidence.
@@ -696,6 +868,109 @@ const ACCEPTANCE_SCHEMA = JSON.stringify({
696
868
  ],
697
869
  type: "object"
698
870
  }, null, 2);
871
+ const EPIC_PLAN_SCHEMA = JSON.stringify({
872
+ additionalProperties: false,
873
+ properties: {
874
+ backend: {
875
+ items: {
876
+ additionalProperties: false,
877
+ properties: {
878
+ id: { type: "string" },
879
+ rationale: { type: "string" },
880
+ title: { type: "string" }
881
+ },
882
+ required: ["id"],
883
+ type: "object"
884
+ },
885
+ type: "array"
886
+ },
887
+ frontend: {
888
+ items: {
889
+ additionalProperties: false,
890
+ properties: {
891
+ id: { type: "string" },
892
+ rationale: { type: "string" },
893
+ title: { type: "string" }
894
+ },
895
+ required: ["id"],
896
+ type: "object"
897
+ },
898
+ type: "array"
899
+ },
900
+ k8s: {
901
+ items: {
902
+ additionalProperties: false,
903
+ properties: {
904
+ id: { type: "string" },
905
+ rationale: { type: "string" },
906
+ title: { type: "string" }
907
+ },
908
+ required: ["id"],
909
+ type: "object"
910
+ },
911
+ type: "array"
912
+ },
913
+ rationale: { type: "string" },
914
+ test: {
915
+ items: {
916
+ additionalProperties: false,
917
+ properties: {
918
+ id: { type: "string" },
919
+ rationale: { type: "string" },
920
+ title: { type: "string" }
921
+ },
922
+ required: ["id"],
923
+ type: "object"
924
+ },
925
+ type: "array"
926
+ }
927
+ },
928
+ required: [
929
+ "test",
930
+ "frontend",
931
+ "backend",
932
+ "k8s"
933
+ ],
934
+ type: "object"
935
+ }, null, 2);
936
+ const REVIEW_SCHEMA = JSON.stringify({
937
+ additionalProperties: false,
938
+ properties: {
939
+ findings: {
940
+ items: {
941
+ additionalProperties: false,
942
+ properties: {
943
+ file: { type: "string" },
944
+ line: {
945
+ minimum: 1,
946
+ type: "integer"
947
+ },
948
+ message: { type: "string" },
949
+ rule: { type: "string" },
950
+ severity: {
951
+ enum: [
952
+ "info",
953
+ "warn",
954
+ "error",
955
+ "critical"
956
+ ],
957
+ type: "string"
958
+ }
959
+ },
960
+ required: ["severity", "message"],
961
+ type: "object"
962
+ },
963
+ type: "array"
964
+ },
965
+ summary: { type: "string" },
966
+ verdict: {
967
+ enum: ["PASS", "FAIL"],
968
+ type: "string"
969
+ }
970
+ },
971
+ required: ["verdict", "findings"],
972
+ type: "object"
973
+ }, null, 2);
699
974
  const SCAFFOLD_FILES = {
700
975
  [PIPELINE_CONFIG_PATH]: DEFAULT_PIPELINE_YAML,
701
976
  [PROFILES_CONFIG_PATH]: DEFAULT_PROFILES_YAML,
@@ -733,6 +1008,36 @@ const SCAFFOLD_FILES = {
733
1008
  "Return concrete failing-test evidence.",
734
1009
  ""
735
1010
  ].join("\n"),
1011
+ ".pipeline/prompts/epic-router.md": [
1012
+ "# Epic router",
1013
+ "",
1014
+ "You read an epic ticket and its sub-tickets via the Backlog MCP server, then route each sub-ticket into exactly one of four named tracks: test, frontend, backend, k8s. You output a JSON document matching `.pipeline/schemas/epic-plan.schema.json`.",
1015
+ "",
1016
+ "## Inputs",
1017
+ "",
1018
+ "- The user's task is an epic id (or a description that names one). Use the Backlog MCP `task_view` and `task_search` tools to find the epic and enumerate its sub-tickets.",
1019
+ "- For each sub-ticket, read its title, description, labels, and any referenced files.",
1020
+ "",
1021
+ "## Routing rules",
1022
+ "",
1023
+ "Pick the single best-fit track per ticket. Heuristics, in priority order:",
1024
+ "",
1025
+ "1. **k8s** - anything touching deployment, Kubernetes manifests, Helm charts, infra YAML, CI/CD pipelines, Docker, ingress, RBAC, cluster config.",
1026
+ "2. **backend** - server-side APIs, services, database schema, server-side data flows, MCP servers, non-UI integrations.",
1027
+ "3. **frontend** - UI components, client-side state, styling, browser interactions, accessibility, Figma-referenced work.",
1028
+ "4. **test** - work that is *primarily* writing or restructuring tests (e.g. coverage uplift, harness changes). Don't route a feature ticket here just because it mentions tests - features go to their domain track and write their own tests there.",
1029
+ "",
1030
+ "Ties: prefer **backend > frontend > test > k8s** unless a strong signal flips it.",
1031
+ "",
1032
+ "A track may be empty (`[]`).",
1033
+ "",
1034
+ "## Output",
1035
+ "",
1036
+ "Emit a single JSON document conforming to the schema. Include a short `rationale` string explaining notable routing decisions.",
1037
+ "",
1038
+ "Do not modify any files. Do not invoke other agents.",
1039
+ ""
1040
+ ].join("\n"),
736
1041
  ".pipeline/prompts/code-writer.md": [
737
1042
  "You are the GREEN/code-write phase for the pipeline.",
738
1043
  "Implement the smallest production change that satisfies the failing tests.",
@@ -785,7 +1090,9 @@ const SCAFFOLD_FILES = {
785
1090
  ].join("\n"),
786
1091
  ".pipeline/schemas/research.schema.json": `${RESEARCH_SCHEMA}\n`,
787
1092
  ".pipeline/schemas/acceptance.schema.json": `${ACCEPTANCE_SCHEMA}\n`,
1093
+ ".pipeline/schemas/epic-plan.schema.json": `${EPIC_PLAN_SCHEMA}\n`,
788
1094
  ".pipeline/schemas/verify.schema.json": `${VERIFY_SCHEMA}\n`,
1095
+ ".pipeline/schemas/review.schema.json": `${REVIEW_SCHEMA}\n`,
789
1096
  ".pipeline/schemas/learn.schema.json": `${LEARN_SCHEMA}\n`,
790
1097
  ".pipeline/host-resources/claude.md": hostResourceInput("Claude Code"),
791
1098
  ".pipeline/host-resources/codex.md": hostResourceInput("Codex"),
@@ -824,8 +1131,13 @@ async function installDefaultSkillsWithCli(specs, cwd) {
824
1131
  }
825
1132
  }
826
1133
  async function installDefaultMcpsWithCli(specs, cwd) {
1134
+ const skipped = [];
827
1135
  for (const spec of specs) {
828
1136
  const install = mcpInstallArgs(spec);
1137
+ if ("skipped" in install) {
1138
+ skipped.push(install.skipped);
1139
+ continue;
1140
+ }
829
1141
  try {
830
1142
  await execa("uvx", [...DEFAULT_MCPM_ARGS, ...install.args], {
831
1143
  cwd,
@@ -848,6 +1160,7 @@ async function installDefaultMcpsWithCli(specs, cwd) {
848
1160
  ].filter(Boolean).join("\n"));
849
1161
  }
850
1162
  }
1163
+ return { skipped };
851
1164
  }
852
1165
  function mcpInstallArgs(spec) {
853
1166
  if (spec.catalog) return {
@@ -870,19 +1183,29 @@ function mcpInstallArgs(spec) {
870
1183
  if (spec.transport === "remote") {
871
1184
  if (!spec.url) throw new PipelineMcpInstallError(`MCP server ${spec.name} is remote but has no url.`);
872
1185
  const redactions = [];
873
- return {
874
- args: [
875
- ...args,
876
- "--url",
877
- spec.url,
878
- ...Object.entries(spec.headers ?? {}).flatMap(([key, value]) => {
879
- const headerValue = resolveMcpHeaderValue(spec.name, key, value);
880
- redactions.push(headerValue);
881
- return ["--headers", `${key}=${headerValue}`];
882
- })
883
- ],
884
- redactions
885
- };
1186
+ try {
1187
+ const headers = Object.entries(spec.headers ?? {}).flatMap(([key, value]) => {
1188
+ const headerValue = resolveMcpHeaderValue(spec.name, key, value);
1189
+ redactions.push(headerValue);
1190
+ return ["--headers", `${key}=${headerValue}`];
1191
+ });
1192
+ return {
1193
+ args: [
1194
+ ...args,
1195
+ "--url",
1196
+ spec.url,
1197
+ ...headers
1198
+ ],
1199
+ redactions
1200
+ };
1201
+ } catch (err) {
1202
+ if (spec.optionalRegistration && err instanceof PipelineMcpMissingCredentialError) return { skipped: {
1203
+ missingEnv: err.missingEnv,
1204
+ name: spec.name,
1205
+ reason: `missing ${err.headerName} credentials`
1206
+ } };
1207
+ throw err;
1208
+ }
886
1209
  }
887
1210
  if (!spec.command) throw new PipelineMcpInstallError(`MCP server ${spec.name} is stdio but has no command.`);
888
1211
  return {
@@ -914,8 +1237,7 @@ function resolveMcpHeaderValue(serverName, headerName, header) {
914
1237
  const rawValue = process.env[source.env];
915
1238
  if (rawValue && rawValue.trim().length > 0) return `${source.prefix ?? ""}${rawValue}${source.suffix ?? ""}`;
916
1239
  }
917
- const envNames = header.sources.map((source) => source.env).join(" or ");
918
- throw new PipelineMcpInstallError([`MCP server ${serverName} requires ${headerName} credentials before it can be registered.`, `Set ${envNames} and re-run pipeline init.`].join("\n"));
1240
+ throw new PipelineMcpMissingCredentialError(serverName, headerName, header.sources.map((source) => source.env));
919
1241
  }
920
1242
  function assertDefaultSkillsInstalled(cwd) {
921
1243
  const paths = defaultSkillPaths();
@@ -935,7 +1257,7 @@ async function initPipelineProject(options = {}) {
935
1257
  const paths = Object.keys(files);
936
1258
  const conflicts = paths.filter((path) => existsSync(join(cwd, path)));
937
1259
  if (conflicts.length > 0 && !options.overwrite) throw new PipelineInitError(conflicts);
938
- await (options.mcpInstaller ?? installDefaultMcpsWithCli)(DEFAULT_MCP_INSTALLS, cwd);
1260
+ const mcpInstallResult = await (options.mcpInstaller ?? installDefaultMcpsWithCli)(DEFAULT_MCP_INSTALLS, cwd);
939
1261
  await (options.skillInstaller ?? installDefaultSkillsWithCli)(DEFAULT_SKILL_INSTALLS, cwd);
940
1262
  const skillPaths = assertDefaultSkillsInstalled(cwd);
941
1263
  for (const [path, content] of Object.entries(files)) {
@@ -949,10 +1271,18 @@ async function initPipelineProject(options = {}) {
949
1271
  ...existsSync(join(cwd, "skills-lock.json")) ? ["skills-lock.json"] : []
950
1272
  ];
951
1273
  loadPipelineConfig(cwd);
952
- return { files: generatedPaths };
1274
+ return {
1275
+ files: generatedPaths,
1276
+ skippedMcps: mcpInstallResult?.skipped ?? []
1277
+ };
953
1278
  }
954
1279
  function formatPipelineInitResult(result) {
955
- return ["Initialized pipeline scaffold:", ...result.files.map((path) => `create ${path}`)].join("\n");
1280
+ const skippedMcps = result.skippedMcps ?? [];
1281
+ return [
1282
+ "Initialized pipeline scaffold:",
1283
+ ...result.files.map((path) => `create ${path}`),
1284
+ ...skippedMcps.flatMap((skip) => [`Skipped MCPM registration for ${skip.name}: ${skip.reason}.`, `Set ${skip.missingEnv.join(" or ")} before retrying MCPM registration. The generated MCP entry remains in .mcp.json.`])
1285
+ ].join("\n");
956
1286
  }
957
1287
  function hostResourceInput(host) {
958
1288
  return [
package/package.json CHANGED
@@ -82,7 +82,7 @@
82
82
  "prepack": "bun run build:cli"
83
83
  },
84
84
  "type": "module",
85
- "version": "1.8.0",
85
+ "version": "1.9.0",
86
86
  "description": "Config-driven multi-agent pipeline runner for repository work",
87
87
  "main": "./dist/index.js",
88
88
  "types": "./dist/index.d.ts",