@mmerterden/multi-agent-pipeline 16.1.1 → 16.1.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/CHANGELOG.md CHANGED
@@ -16,6 +16,19 @@ Internal file-layout changes that don't affect the slash-command surface are sti
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [16.1.2] - 2026-08-23
20
+
21
+ The rule reached all three hosts in 16.1.1. It only WORKED on one.
22
+
23
+ ### Fixed
24
+
25
+ - **Rules were installed with a byte copy, so every path in them dangled on two hosts.** Each CLI keeps its trees under its own root, and both installers carry a path-rewrite table that names `rules` explicitly - but `installRules` (Copilot) and `installTree` (Codex) used a plain `copyDir`, so the rewrite never ran on that tree. Result: all 13 rules told a Copilot or Codex session to run `~/.claude/lib/credential-store.sh`, a tree those installs never create. This is the same dangling-path class the Copilot rewrite was written to eliminate for skills; rules were named in the doctrine and left out of the code. It bites hardest on the one rule whose entire job is resolving that path. Both installers route rules through `copyTreeRewritten` now: `~/.copilot/lib/...` on Copilot, `~/.codex/lib/...` on Codex, unchanged on Claude Code. Twelve pre-existing rules were fixed along with the new one.
26
+ - `outside-the-pipeline.md` says what to do when the refs tree is absent. Copilot installs no `multi-agent-refs/` by design - the doctrine routes those references to `~/.claude` when Claude Code shares the machine - so a Copilot-only install was being sent to a file that is not there with no explanation. The rule now states that the summary it carries IS the contract in that case.
27
+
28
+ ### Changed
29
+
30
+ - `smoke-context-budget.sh` asserts both installers put rules through the rewriter. Verified by reverting the Copilot fix and watching it go red. Shipping a rule to a host is not the same as shipping a rule that works there, and only the second one is worth the bytes it costs every session.
31
+
19
32
  ## [16.1.1] - 2026-08-23
20
33
 
21
34
  Found by reviewing 16.1.0 after it shipped, and by the `/mcp` reconnect confirming the fix worked.
package/install/codex.mjs CHANGED
@@ -493,6 +493,14 @@ function installScripts(pipelineSrc, dest, useSymlinks) {
493
493
  * Copy a pipeline tree verbatim (lib / schemas). These are executed, not read
494
494
  * as prose, and they resolve their own paths at runtime.
495
495
  */
496
+ // Trees whose text references `$HOME/.claude/...` and therefore have to be
497
+ // retargeted on the way in. The rewrite table already carries rules -> .codex
498
+ // rules, but `rules` was installed with a byte copy, so every rule naming
499
+ // `~/.claude/lib/credential-store.sh` pointed at a tree a Codex-only install
500
+ // never creates. `lib` and `schemas` are data the pipeline reads by absolute
501
+ // path from the caller's side, so they stay byte-identical.
502
+ const REWRITTEN_TREES = new Set(["rules"]);
503
+
496
504
  function installTree(name, pipelineSrc, dest, useSymlinks) {
497
505
  const src = join(pipelineSrc, name);
498
506
  if (!existsSync(src)) return;
@@ -501,6 +509,11 @@ function installTree(name, pipelineSrc, dest, useSymlinks) {
501
509
  ensureDir(dest);
502
510
  }
503
511
  wipeDir(dest);
512
+ if (!useSymlinks && REWRITTEN_TREES.has(name)) {
513
+ const n = copyTreeRewritten(src, dest);
514
+ console.log(` -> ${n} ${name} file(s) copied to ${dest} (paths retargeted)`);
515
+ return;
516
+ }
504
517
  copyDir(src, dest, { useSymlinks });
505
518
  console.log(` -> ${countFiles(src)} ${name} file(s) copied to ${dest}`);
506
519
  }
@@ -283,8 +283,20 @@ function installRules(pipelineSrc, dest, useSymlinks) {
283
283
  if (!existsSync(rulesSrc)) return;
284
284
  if (!useSymlinks) ensureRealDir(dest);
285
285
  wipeDir(dest);
286
- copyDir(rulesSrc, dest, { useSymlinks });
287
- console.log(` -> ${countFiles(rulesSrc)} files copied to ${dest}`);
286
+ if (useSymlinks) {
287
+ copyDir(rulesSrc, dest, { useSymlinks });
288
+ console.log(` -> ${countFiles(rulesSrc)} files linked to ${dest}`);
289
+ return;
290
+ }
291
+ // Rewritten, not copied. COPILOT_PATH_REWRITES lists `rules` among the trees
292
+ // Copilot owns, but this function used plain copyDir - so every rule shipped
293
+ // here naming `~/.claude/lib/credential-store.sh` pointed at a tree a
294
+ // Copilot-only install never creates. The same dangling-path class the
295
+ // rewrite was introduced to kill for skills, still live in rules because
296
+ // rules never went through it. It matters most for the one rule whose whole
297
+ // job is resolving that path.
298
+ const n = copyTreeRewritten(rulesSrc, dest);
299
+ console.log(` -> ${n} files copied to ${dest} (paths retargeted)`);
288
300
  }
289
301
 
290
302
  function installSkills(opts) {
@@ -379,7 +391,8 @@ function installSkills(opts) {
379
391
  let prevDelivered = null;
380
392
  try {
381
393
  const parsed = JSON.parse(readFileSync(join(dest, EXTERNAL_SKILLS_MANIFEST), "utf-8"));
382
- if (Array.isArray(parsed)) prevDelivered = new Set(parsed.filter((n) => typeof n === "string"));
394
+ if (Array.isArray(parsed))
395
+ prevDelivered = new Set(parsed.filter((n) => typeof n === "string"));
383
396
  } catch {
384
397
  prevDelivered = null;
385
398
  }
@@ -421,7 +434,9 @@ function installSkills(opts) {
421
434
  }
422
435
  }
423
436
  writeExternalSkillsManifest(dest, keep);
424
- console.log(` -> stack filter (${selectionSource}): ${keep.length} kept, ${skipped.length} skipped`);
437
+ console.log(
438
+ ` -> stack filter (${selectionSource}): ${keep.length} kept, ${skipped.length} skipped`,
439
+ );
425
440
  if (keptForeign > 0) {
426
441
  console.log(
427
442
  ` note: ${keptForeign} skipped-stack dir(s) kept - not delivered by this pipeline (no manifest entry, differs from catalog)`,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "16.1.1",
3
+ "version": "16.1.2",
4
4
  "description": "8-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI and Codex CLI. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Fable triage, default-FAIL evidence gates, secret + intent guards, per-phase cost ledger, persistent learnings memory, wiki generation, commit automation. Token-preserving uninstall.",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -3,7 +3,8 @@
3
3
  `/multi-agent` is not the only way to use what the install set up. Reach for
4
4
  these when the work calls for it - not eagerly, and not by starting an 8-phase
5
5
  run to read one ticket. Detail, commands and the safety contract:
6
- `$HOME/.claude/multi-agent-refs/outside-the-pipeline.md`.
6
+ `$HOME/.claude/multi-agent-refs/outside-the-pipeline.md` - absent on a host that
7
+ installs no refs tree, in which case the summary below is the contract.
7
8
 
8
9
  **Services.** Tokens onboarded by `/multi-agent:setup` are readable now. Logical
9
10
  name in `prefs.global.keychainMapping`, value via