@mmerterden/multi-agent-pipeline 14.1.0 → 14.1.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/CHANGELOG.md +57 -1
- package/README.md +4 -4
- package/docs/adr/0008-installer-modularization-and-secret-leak-defense.md +1 -1
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/dev/SKILL.md +5 -1
- package/pipeline/commands/multi-agent/sync/SKILL.md +7 -2
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +6 -3
- package/pipeline/schemas/token-budget.json +2 -2
- package/pipeline/scripts/build-stack-plugins.mjs +21 -0
- package/pipeline/scripts/migrate-prefs.mjs +30 -0
- package/pipeline/skills/.skills-index.json +9 -9
- package/pipeline/skills/skills-index.md +1 -1
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,62 @@ Internal file-layout changes that don't affect the slash-command surface are sti
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [14.1.1] - 2026-07-30
|
|
20
|
+
|
|
21
|
+
Three defects that all shared one shape: a name written in one place and read in
|
|
22
|
+
another, so the mechanism looked implemented, ran without error, and did nothing.
|
|
23
|
+
|
|
24
|
+
- **Phase 0 wrote the base-ref field its own exit gate does not read.** `/multi-agent:dev`
|
|
25
|
+
recorded `"baseRefFreshness"` while `phase0-exit-gate.mjs` requires `baseFetchStatus`
|
|
26
|
+
with one of `fresh | cached-stale | local-branch | aborted`. The value vocabulary was
|
|
27
|
+
already correct - only the field name differed - so every dev-mode run failed its own
|
|
28
|
+
exit gate with `baseFetchStatus="<unset>"` even when all four Phase 0 pickers had
|
|
29
|
+
actually run. A gate that always fails is as useless as one that never fails. The
|
|
30
|
+
canonical name appeared in five places and the wrong one in exactly one: the dev
|
|
31
|
+
command's own doc. `smoke-phase-0-multi-repo.sh` now asserts that the name the exit
|
|
32
|
+
gate reads equals the name the phase doc documents, and that no shipped file names an
|
|
33
|
+
alternative, with a planted-line probe proving the detector can fire.
|
|
34
|
+
- **Branch memory never populated.** Phase 0 Step 3 read
|
|
35
|
+
`prefs.global.recentBranches[{projectKey}]` while its own step 7 wrote the legacy
|
|
36
|
+
`prefs.projects[].branches`, which `prefs.schema.json` marks pre-v2.1.0. Both spots
|
|
37
|
+
also described a `{name, lastUsed}` entry the schema rejects (`branch` is required and
|
|
38
|
+
`additionalProperties` is false), so a literal implementation would have failed prefs
|
|
39
|
+
validation and the dedup - which keys on `branch` - would have accumulated a duplicate
|
|
40
|
+
every run. The "reused from last run" picker option could therefore never appear.
|
|
41
|
+
`migrate-prefs.mjs` carries stranded legacy entries into the canonical LRU, stamped
|
|
42
|
+
with the migration time because the legacy field never recorded a real one and an epoch
|
|
43
|
+
stamp would be pruned by the TTL on first read; `count: 0` marks them seeded rather
|
|
44
|
+
than observed.
|
|
45
|
+
- **The sync skill hardcoded the author's git identity.** `git config user.name`,
|
|
46
|
+
`user.email` and `gh auth switch --user` carried literal values in the plugin-publish
|
|
47
|
+
block, while the same file's other two publish blocks used `{identity.name}` and
|
|
48
|
+
`{owner}`. Since the file ships to every installation, a downstream user's
|
|
49
|
+
plugins-repo commits would have been attributed to someone else and their `gh` account
|
|
50
|
+
switched under them - and it contradicted the pipeline's own rule that the git author
|
|
51
|
+
is always the user's identity.
|
|
52
|
+
|
|
53
|
+
Leak-gate coverage, which is why the third defect had gone unnoticed:
|
|
54
|
+
|
|
55
|
+
- `smoke-personal-data.sh` only ever scanned `pipeline/`, but the package also publishes
|
|
56
|
+
`install/`, `docs/`, `index.js`, `install.js`, `README.md` and `CHANGELOG.md`, and every
|
|
57
|
+
tracked file is public regardless of what npm ships. `CHANGELOG.md` was additionally in
|
|
58
|
+
the `--exclude` list. A second pass now scans every tracked file outside `pipeline/`,
|
|
59
|
+
driven by `git ls-files` so the covered set stays exactly "what is public" with no
|
|
60
|
+
second list to maintain. `LICENSE`, `package.json` and `CODE_OF_CONDUCT.md` are exempt,
|
|
61
|
+
because a package must name its author and a code of conduct must give a real contact.
|
|
62
|
+
- Added patterns for the author's own name, personal email and `gh auth switch` account -
|
|
63
|
+
none were checked before, which is precisely how a literal identity survived in a
|
|
64
|
+
shipped command - plus the employer's abbreviation where it is used as a symbol or
|
|
65
|
+
workspace prefix, bounded so ordinary words that merely contain those letters
|
|
66
|
+
(`HEALTHY`, `RHYTHM`) do not match.
|
|
67
|
+
- `--exclude-dir` for `.git`, `node_modules`, `.worktrees`, `.next` and `DerivedData`.
|
|
68
|
+
Without it, `--root` mode scanned `.git/logs`, so auditing any checkout was guaranteed
|
|
69
|
+
to "fail" on commit metadata no consumer receives, burying the real findings.
|
|
70
|
+
- Five leaks removed from public files: a real corporate email in `CHANGELOG-archive.md`,
|
|
71
|
+
a corporate toolkit name in both changelogs, the author's website in `docs/adr/0008`
|
|
72
|
+
and `docs/internal/`, and corporate symbol/repo/task literals in `docs/internal/`.
|
|
73
|
+
These are gone from HEAD; git history still contains them.
|
|
74
|
+
|
|
19
75
|
## [14.1.0] - 2026-07-29
|
|
20
76
|
|
|
21
77
|
Two things the pipeline was supposed to do and did not: use the skills a project's
|
|
@@ -2650,7 +2706,7 @@ Analysis open-question resolver + repo hygiene hardening.
|
|
|
2650
2706
|
blockquotes), humanizer punctuation policy, no Figma access (Locked 30 - design-gap
|
|
2651
2707
|
rows get only Defer + a re-run recommendation), no auto-commit. Command inventory
|
|
2652
2708
|
33 -> 34; `/multi-agent:analysis` Phase 5 report now suggests the resolver when
|
|
2653
|
-
Section 20 has open rows. Pattern ported from
|
|
2709
|
+
Section 20 has open rows. Pattern ported from a private stack toolkit's resolver skills.
|
|
2654
2710
|
- **Dead references removed.** `analysis.md` Reusable refs no longer points at a
|
|
2655
2711
|
non-existent `fetch-wiki.sh` (the wiki fetch chain is inline: clone -> gh api ->
|
|
2656
2712
|
WebFetch); `refs/features/external-context-injection.md` figma row routed to the real
|
package/README.md
CHANGED
|
@@ -62,11 +62,11 @@ The discipline behind all of this - bounded loops, evidence gates, token-budgete
|
|
|
62
62
|
| Autopilot | `/multi-agent:autopilot "task"` | All 8 phases, no confirmations |
|
|
63
63
|
| Dev | `/multi-agent:dev "task"` | Init → Dev → Review → Test → Commit → Report |
|
|
64
64
|
| Local | `/multi-agent:local "task"` | Full pipeline, current branch (no worktree) |
|
|
65
|
-
|
|
|
65
|
+
| Ship | `/multi-agent:ship` | Run the review→test→commit→report tail over local work |
|
|
66
66
|
| Audit | `/multi-agent:design-check` | Mock-mode vs Figma conformance, local-only |
|
|
67
67
|
| Audit | `/multi-agent:testflight-validation` | Pre-submission gates for a TestFlight build: static archive audit → Apple's `altool --validate-app` → Review-Guidelines check. Validates only, never uploads |
|
|
68
68
|
|
|
69
|
-
Helpers: `setup`, `status`, `resume #N`, `review`, `test`, `channels`, `stack`, `update`, `sync`, `refactor`, `jira`, `issue`, `analysis`, `create-jira`, `save`, `routines`, `forget`.
|
|
69
|
+
Helpers: `setup`, `status`, `resume #N`, `review`, `test`, `channels`, `stack`, `update`, `sync`, `refactor`, `jira`, `issue`, `analysis`, `create-jira`, `save`, `routines`, `forget`. 44 commands in all - full list: `/multi-agent:help`.
|
|
70
70
|
|
|
71
71
|
## Stacks
|
|
72
72
|
|
|
@@ -80,12 +80,12 @@ This enables the matching plugin (+ the shared `ai-common` plugin) in the repo's
|
|
|
80
80
|
|
|
81
81
|
## Tool support
|
|
82
82
|
|
|
83
|
-
The pipeline runs natively on **Claude Code**, **Copilot CLI** and **Codex CLI** - all three install from the same `pipeline/` source and get the same
|
|
83
|
+
The pipeline runs natively on **Claude Code**, **Copilot CLI** and **Codex CLI** - all three install from the same `pipeline/` source and get the same 44 commands.
|
|
84
84
|
|
|
85
85
|
| Tool | Flag | What it installs |
|
|
86
86
|
|---|---|---|
|
|
87
87
|
| Claude Code | `--claude` (default) | slash commands + skills + agents + `PreToolUse` secret-scan hook |
|
|
88
|
-
| Copilot CLI | `--copilot` | instructions +
|
|
88
|
+
| Copilot CLI | `--copilot` | instructions + 44 sub-command skills + scripts |
|
|
89
89
|
| Codex CLI | `--codex` | one router skill + 43 specs as refs + 8 agent TOML + `AGENTS.md` block + `codex mcp add` |
|
|
90
90
|
|
|
91
91
|
Filter skills by stack with `--platform=ios\|android\|all`.
|
|
@@ -10,7 +10,7 @@ Two pressures collided during the v7.x line:
|
|
|
10
10
|
|
|
11
11
|
1. **Installer monolith.** `install.js` reached 1246 LOC by v7.9.1. It mixed flag parsing, three platform installers (Claude / Copilot / six third-party adapters), telemetry, a dev-only file exclusion list, and a 200-line static generator for `copilot-instructions.md`. Reasoning about install behaviour required holding the whole file in your head; reviewers asked for documentation we could not produce because every change touched untyped, intertwined sections.
|
|
12
12
|
|
|
13
|
-
2. **Secret leaks at deploy time.** During the v7.9.1 production deploy of
|
|
13
|
+
2. **Secret leaks at deploy time.** During the v7.9.1 production deploy of the project website, a `vercel deploy --token=vcp_...` invocation failed. The Vercel CLI printed the failed argv verbatim in its retry hint. That leaked the deploy token into the conversation transcript and forced a token rotation. A second incident in the same release window - `git -c user.email=...` overriding the repo-local config - pushed seven commits with the wrong author identity, which Vercel's contributor gate then blocked. Both classes of failure share a root cause: privileged values flowed through argv when the codebase had no audited boundary between provider tools and the orchestration layer.
|
|
14
14
|
|
|
15
15
|
We needed an architectural answer that prevented both classes of failure from recurring without expanding scope into "rewrite everything as TypeScript" - the project's zero-dependency philosophy (ADR-4) is a hard constraint.
|
|
16
16
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "14.1.
|
|
3
|
+
"version": "14.1.1",
|
|
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",
|
|
@@ -91,9 +91,13 @@ The agent CANNOT make these Phase 0 decisions automatically; it suggests, then w
|
|
|
91
91
|
3. Cancel
|
|
92
92
|
Confirm? [1/2/3]
|
|
93
93
|
```
|
|
94
|
-
- User picks `2` → log warning + record `"
|
|
94
|
+
- User picks `2` → log warning + record `"baseFetchStatus": "cached-stale"` in
|
|
95
95
|
`agent-state.json`, proceed from local ref. Phase 6 push needs network anyway,
|
|
96
96
|
so re-prompt there if still unreachable.
|
|
97
|
+
- Option `1` (fetch succeeded) records `"fresh"`; a local-branch base records
|
|
98
|
+
`"local-branch"`; option `3` records `"aborted"`. The field name and this
|
|
99
|
+
four-value vocabulary are what `phase0-exit-gate.mjs` reads, so a run that writes
|
|
100
|
+
anything else cannot close Phase 0.
|
|
97
101
|
|
|
98
102
|
Always show what was **observed** next to what was **classified**. The previous
|
|
99
103
|
wording asserted `Detected: <host> unreachable (VPN/DNS)` for every failure mode,
|
|
@@ -245,10 +245,15 @@ node "$HOME/multi-agent-pipeline/pipeline/scripts/build-stack-plugins.mjs"
|
|
|
245
245
|
```bash
|
|
246
246
|
cd "$PLUGINS_REPO"
|
|
247
247
|
if ! git diff --quiet; then
|
|
248
|
-
|
|
248
|
+
# Identity resolves from prefs.global.identities[] routed by platformIdentityRouting,
|
|
249
|
+
# exactly as Phase 6 does. Never hardcode a name, email or gh account here: this file
|
|
250
|
+
# ships to every installation, so a literal identity attributes a downstream user's
|
|
251
|
+
# plugins-repo commits to someone else and switches their gh account out from under them.
|
|
252
|
+
git config user.name "{identity.name}"
|
|
253
|
+
git config user.email "{identity.email}"
|
|
249
254
|
git add -A
|
|
250
255
|
git commit -m "chore: rebuild stack plugins from pipeline shared/external"
|
|
251
|
-
gh auth switch --user
|
|
256
|
+
gh auth switch --user {owner} 2>/dev/null || true
|
|
252
257
|
git push origin main
|
|
253
258
|
fi
|
|
254
259
|
```
|
|
@@ -73,7 +73,7 @@ Used for: input parsing, branch naming, commit messages.
|
|
|
73
73
|
|---|---|---|---|
|
|
74
74
|
| Project picked (Step 2) | `global.recentProjects` | `[{path, label, count, lastUsed}]` | 20 |
|
|
75
75
|
| Multi-repo group picked or saved (Step 2) | `global.recentGroups` | `[{label?, repos[], count, lastUsed}]` | 10 |
|
|
76
|
-
| Branch picked (Step 3) | `global.recentBranches[{projectKey}]` | `[{
|
|
76
|
+
| Branch picked (Step 3) | `global.recentBranches[{projectKey}]` | `[{branch, lastUsed, count?}]` (TTL `settings.branchTtlDays`, default 15d) | 10 (TTL also prunes) |
|
|
77
77
|
| Service ping (any external API call) | `global.serviceStatus[{service}]` | `{ok, checkedAt, reason?}` (TTL `settings.serviceStatusCacheSeconds`, default 300s) | n/a |
|
|
78
78
|
| Git identity routed (Step 6a) | `projects[{name}].lastIdentity` | int (index into `global.identities`) | n/a |
|
|
79
79
|
|
|
@@ -261,7 +261,10 @@ Scan `$HOME` (maxdepth 2) for project markers (`.xcodeproj`, `Package.swift`, `b
|
|
|
261
261
|
header: "Base branch"
|
|
262
262
|
options: origin/develop (Recommended, reused from last run) | origin/main | release/8.4.0 | Other
|
|
263
263
|
```
|
|
264
|
-
7. User picks → store as `baseBranch
|
|
264
|
+
7. User picks → store as `baseBranch`, and append `{branch, lastUsed, count?}` to
|
|
265
|
+
`prefs.global.recentBranches[{projectKey}]` (dedup by `branch`, cap 10) - what the TTL
|
|
266
|
+
filter below reads. Key is `branch`, not `name`. Never the legacy
|
|
267
|
+
`projects[{project}].branches`.
|
|
265
268
|
|
|
266
269
|
**MUST: this step is not skippable (BLOCKING).** The only legitimate skip is rule 4
|
|
267
270
|
above - `baseBranch` already supplied in the input. Everything else asks. A run once
|
|
@@ -277,7 +280,7 @@ which still writes the fields - it does not leave them unset.
|
|
|
277
280
|
|
|
278
281
|
**TTL filter for recent branches**:
|
|
279
282
|
|
|
280
|
-
- `prefs.global.recentBranches[{projectKey}][]` carries `{
|
|
283
|
+
- `prefs.global.recentBranches[{projectKey}][]` carries `{branch, lastUsed, count?}`. Filter to those whose `lastUsed` is within `settings.branchTtlDays` (default 15).
|
|
281
284
|
- Stale entries (>TTL) are pruned in-place during the read - keeps the picker uncluttered without a separate cleanup pass.
|
|
282
285
|
- The filtered "Recent" list precedes the fresh `git branch -r` list; cap at 5 visible recent entries.
|
|
283
286
|
|
|
@@ -36,6 +36,6 @@
|
|
|
36
36
|
"warn_tokens": 5600
|
|
37
37
|
}
|
|
38
38
|
},
|
|
39
|
-
"total_max_tokens":
|
|
40
|
-
"note": "Token estimate = ceil(chars / 4). Per-phase budget rule: warn = current+10% (rounded to nearest 50), max = current+25%. Gives ~6 edit cycles of headroom before warn trips - intentionally quiet under normal maintenance, loud when a phase grows unusually. Only the active phase is loaded (lazy). Recalibrated at v10.0.0 after the validator/consistency/simplifier/lesson gate contracts landed in phases 1-4. Recalibrated again at v10.9.0 after the verify-by-test (Phase 4 Step 3.7), update-check (Phase 0 Step 0.6), immutable-test (Phase 3 GREEN) and redTests re-entry contracts landed - Step 3.7 prose was compressed to a pointer into refs/features/verify-by-test.md before the recalibration. Total bumped 50000 -> 51000 at v12.5.0 after the worktree residue/traversal-prune contract (Phase 0 + Phase 5 heal) and the Reflexion causal-diagnosis contract (Phase 4 lesson memory) landed; the prose was compressed first (161 tokens reclaimed) and every per-phase max still passes - only the aggregate needed room. Recalibrated again at v13.6.0 after the install-relative path correction: an instruction that names `pipeline/scripts/x` resolves only from a repo checkout, and a run happens in the user's worktree, so 157 references across these docs moved to `$HOME/.claude/...` at +5 bytes each - 196 tokens of pure correctness cost. Same discipline as before: prose was compressed FIRST (149 tokens reclaimed, by pointing Phase 1's Figma tier table at the Phase 0 probe that already resolved it and Phase 4's Codex constraints at the always-loaded AGENTS.md block), and only then were the budgets moved. Five warn lines had been permanently amber, which makes the amber tier useless as a signal, so every warn was reset to the documented current+10% and the four maxes that the new warn would have collided with were reset to current+25%. Aggregate 51000 -> 51500. Total bumped 51500 -> 52200 at v14.0.0 after Phase 4 Review entered the four --dev mode phase sets and the criteria-resolution contract (Step 1.78) landed. Same discipline as every prior bump: prose was compressed FIRST, 820 tokens reclaimed, before the number moved. Two of those compressions are structural rather than cosmetic - the hardcoded SwiftUI interaction list in Step 1.5 and the SwiftUI convention paragraph in Step 2.8 were transcriptions of rules that now live in a scoped registry, so keeping them here would have re-created the drift this release exists to remove, and the third moved the Step 1.78 full contract into refs/features/skill-conformance.md leaving a pointer. What remains is contract text that cannot be inferred: the manifest's four consumer-visible parts, the conformance checklist the reviewers must return, and the fail-closed semantics. Every per-phase max still passes (phase-4 12405/14750); only the aggregate needed room. Total bumped 52200 -> 52700 at v14.1.0 after two more contracts landed: stack skill routing (Phase 3 pre-flight step 9) and worktree finalize (Phase 6 step 9). Compression came first, as always, and twice: 224 tokens out of Phase 3 by pointing its criteria-ledger and routing steps at their feature files instead of restating them, and 190 out of Phase 6 by moving the finalize contract into refs/features/worktree-finalize.md and leaving the invocation plus the exit-3 semantics. Both new contracts follow the pattern the earlier ones set: the phase doc carries the call and the decision, the feature file carries the reasoning, and the feature files are outside this budget because it loops only the eight phase-N-* keys. Every per-phase max still passes (phase-3 7677/8950, phase-6 5223/6150 and both under warn); only the aggregate needed room."
|
|
39
|
+
"total_max_tokens": 52750,
|
|
40
|
+
"note": "Token estimate = ceil(chars / 4). Per-phase budget rule: warn = current+10% (rounded to nearest 50), max = current+25%. Gives ~6 edit cycles of headroom before warn trips - intentionally quiet under normal maintenance, loud when a phase grows unusually. Only the active phase is loaded (lazy). Recalibrated at v10.0.0 after the validator/consistency/simplifier/lesson gate contracts landed in phases 1-4. Recalibrated again at v10.9.0 after the verify-by-test (Phase 4 Step 3.7), update-check (Phase 0 Step 0.6), immutable-test (Phase 3 GREEN) and redTests re-entry contracts landed - Step 3.7 prose was compressed to a pointer into refs/features/verify-by-test.md before the recalibration. Total bumped 50000 -> 51000 at v12.5.0 after the worktree residue/traversal-prune contract (Phase 0 + Phase 5 heal) and the Reflexion causal-diagnosis contract (Phase 4 lesson memory) landed; the prose was compressed first (161 tokens reclaimed) and every per-phase max still passes - only the aggregate needed room. Recalibrated again at v13.6.0 after the install-relative path correction: an instruction that names `pipeline/scripts/x` resolves only from a repo checkout, and a run happens in the user's worktree, so 157 references across these docs moved to `$HOME/.claude/...` at +5 bytes each - 196 tokens of pure correctness cost. Same discipline as before: prose was compressed FIRST (149 tokens reclaimed, by pointing Phase 1's Figma tier table at the Phase 0 probe that already resolved it and Phase 4's Codex constraints at the always-loaded AGENTS.md block), and only then were the budgets moved. Five warn lines had been permanently amber, which makes the amber tier useless as a signal, so every warn was reset to the documented current+10% and the four maxes that the new warn would have collided with were reset to current+25%. Aggregate 51000 -> 51500. Total bumped 51500 -> 52200 at v14.0.0 after Phase 4 Review entered the four --dev mode phase sets and the criteria-resolution contract (Step 1.78) landed. Same discipline as every prior bump: prose was compressed FIRST, 820 tokens reclaimed, before the number moved. Two of those compressions are structural rather than cosmetic - the hardcoded SwiftUI interaction list in Step 1.5 and the SwiftUI convention paragraph in Step 2.8 were transcriptions of rules that now live in a scoped registry, so keeping them here would have re-created the drift this release exists to remove, and the third moved the Step 1.78 full contract into refs/features/skill-conformance.md leaving a pointer. What remains is contract text that cannot be inferred: the manifest's four consumer-visible parts, the conformance checklist the reviewers must return, and the fail-closed semantics. Every per-phase max still passes (phase-4 12405/14750); only the aggregate needed room. Total bumped 52200 -> 52700 at v14.1.0 after two more contracts landed: stack skill routing (Phase 3 pre-flight step 9) and worktree finalize (Phase 6 step 9). Compression came first, as always, and twice: 224 tokens out of Phase 3 by pointing its criteria-ledger and routing steps at their feature files instead of restating them, and 190 out of Phase 6 by moving the finalize contract into refs/features/worktree-finalize.md and leaving the invocation plus the exit-3 semantics. Both new contracts follow the pattern the earlier ones set: the phase doc carries the call and the decision, the feature file carries the reasoning, and the feature files are outside this budget because it loops only the eight phase-N-* keys. Every per-phase max still passes (phase-3 7677/8950, phase-6 5223/6150 and both under warn); only the aggregate needed room. Total bumped 52700 -> 52750 for the Phase 0 Step 3 branch-persistence correction: the step wrote the legacy `projects[].branches` while the TTL filter two sections below read `global.recentBranches`, and both spots named a `{name, lastUsed}` shape the schema rejects (`branch` required, `additionalProperties: false`), so the recent-branch picker option could never populate and a literal implementation would have failed prefs validation. Naming the right target, the right key and the legacy field to avoid costs 41 tokens over the one line it replaces. Compression came first and was applied three times to the replacement text itself, from 120 tokens down to 66, by moving the rationale out of the phase doc entirely: the reasoning now lives where it is enforced, in the migrate-prefs carry-forward comment and the smoke-pref-migration f7 block, leaving the phase doc with only the instruction. 50 was the smallest step that clears it; phase-0-init sits at 10893/12400, far under its own max, so this is purely an aggregate ceiling."
|
|
41
41
|
}
|
|
@@ -33,6 +33,7 @@ import {
|
|
|
33
33
|
statSync,
|
|
34
34
|
} from "node:fs";
|
|
35
35
|
import { join } from "node:path";
|
|
36
|
+
import { spawnSync } from "node:child_process";
|
|
36
37
|
|
|
37
38
|
const args = process.argv.slice(2);
|
|
38
39
|
// Accepts both `--key value` and `--key=value`. The `=` form used to fall through to
|
|
@@ -251,6 +252,26 @@ for (const [plugin, want] of Object.entries(desired)) {
|
|
|
251
252
|
pj.skills = newSkills;
|
|
252
253
|
pj.version = newV;
|
|
253
254
|
writeFileSync(pjPath, `${JSON.stringify(pj, null, 2)}\n`);
|
|
255
|
+
|
|
256
|
+
// The marketplace README carries a per-plugin table of version + skill count,
|
|
257
|
+
// and that table is what a human reads to know what is published. Bumping
|
|
258
|
+
// plugin.json without it drifted five of the five rows, silently, because the
|
|
259
|
+
// drift is only visible if someone runs the checker. `tools/bump.py` owns the
|
|
260
|
+
// table's format, so call it rather than reproducing the row layout here - a
|
|
261
|
+
// second formatter would be the one that rots.
|
|
262
|
+
const bumpTool = join(PLUGINS_REPO, "tools", "bump.py");
|
|
263
|
+
if (existsSync(bumpTool)) {
|
|
264
|
+
const r = spawnSync("python3", [bumpTool, plugin, "--set", newV], {
|
|
265
|
+
cwd: PLUGINS_REPO,
|
|
266
|
+
encoding: "utf8",
|
|
267
|
+
});
|
|
268
|
+
if (r.status !== 0) {
|
|
269
|
+
console.warn(
|
|
270
|
+
` WARN ${plugin}: plugin.json is ${newV} but the README table was not synced ` +
|
|
271
|
+
`(bump.py exit ${r.status ?? "n/a"}). Run \`tools/bump.py --check\` in ${PLUGINS_REPO}.`,
|
|
272
|
+
);
|
|
273
|
+
}
|
|
274
|
+
}
|
|
254
275
|
}
|
|
255
276
|
report.push({
|
|
256
277
|
plugin,
|
|
@@ -270,6 +270,36 @@ function migrate(prefs) {
|
|
|
270
270
|
out.global.recentBranches = {};
|
|
271
271
|
changes.push("added empty recentBranches");
|
|
272
272
|
}
|
|
273
|
+
// Carry the legacy per-project branch list into the canonical LRU. Phase 0 Step 3
|
|
274
|
+
// read global.recentBranches while its own step 7 wrote projects[].branches, so
|
|
275
|
+
// every branch a user ever picked landed in the field nothing reads and the
|
|
276
|
+
// "reused from last run" picker option stayed empty. Seeding here makes that
|
|
277
|
+
// history usable instead of stranding it. Idempotent: an existing entry for the
|
|
278
|
+
// same branch is never duplicated or overwritten.
|
|
279
|
+
//
|
|
280
|
+
// `lastUsed` is stamped with the migration time, not the real pick time, which the
|
|
281
|
+
// legacy field never recorded. Stamping the true unknown (epoch) would put every
|
|
282
|
+
// seeded entry outside settings.branchTtlDays and the TTL filter would prune it on
|
|
283
|
+
// the first read, making this carry-forward a no-op. `count: 0` marks the entry as
|
|
284
|
+
// seeded rather than observed, and the normal TTL retires anything the user does not
|
|
285
|
+
// actually pick again within the window.
|
|
286
|
+
const seededAt = new Date().toISOString();
|
|
287
|
+
for (const [projectKey, project] of Object.entries(out.projects ?? {})) {
|
|
288
|
+
if (!Array.isArray(project?.branches) || project.branches.length === 0) continue;
|
|
289
|
+
const lru = (out.global.recentBranches[projectKey] ??= []);
|
|
290
|
+
const known = new Set(lru.map((e) => e?.branch));
|
|
291
|
+
let seeded = 0;
|
|
292
|
+
for (const branch of project.branches) {
|
|
293
|
+
if (typeof branch !== "string" || !branch || known.has(branch)) continue;
|
|
294
|
+
if (lru.length >= 10) break;
|
|
295
|
+
lru.push({ branch, lastUsed: seededAt, count: 0 });
|
|
296
|
+
known.add(branch);
|
|
297
|
+
seeded += 1;
|
|
298
|
+
}
|
|
299
|
+
if (seeded > 0) {
|
|
300
|
+
changes.push(`seeded ${seeded} recentBranches entr${seeded === 1 ? "y" : "ies"} for ${projectKey} from legacy projects[].branches`);
|
|
301
|
+
}
|
|
302
|
+
}
|
|
273
303
|
if (!Array.isArray(out.global.recentGroups)) {
|
|
274
304
|
out.global.recentGroups = [];
|
|
275
305
|
changes.push("added empty recentGroups");
|
|
@@ -857,15 +857,6 @@
|
|
|
857
857
|
"triggerPaths": [],
|
|
858
858
|
"relativePath": "shared/core/multi-agent-diff-explain/SKILL.md"
|
|
859
859
|
},
|
|
860
|
-
{
|
|
861
|
-
"name": "multi-agent-ship",
|
|
862
|
-
"description": "Continue already-done LOCAL work through the pipeline tail: Review → Build+Test → Commit/PR → Report (technical analysis + Jira test-scenario comment). No dev phase. Use when local work is already done and only review, build, commit and reporting remain.",
|
|
863
|
-
"platform": null,
|
|
864
|
-
"group": "core",
|
|
865
|
-
"triggerKeywords": [],
|
|
866
|
-
"triggerPaths": [],
|
|
867
|
-
"relativePath": "shared/core/multi-agent-ship/SKILL.md"
|
|
868
|
-
},
|
|
869
860
|
{
|
|
870
861
|
"name": "multi-agent-forget",
|
|
871
862
|
"description": "Remove a saved /multi-agent routine (created by /multi-agent:save): deletes its local-only command and its registry entry. Asks which one and confirms. Use when a saved routine is no longer wanted and should be removed.",
|
|
@@ -1082,6 +1073,15 @@
|
|
|
1082
1073
|
"triggerPaths": [],
|
|
1083
1074
|
"relativePath": "shared/core/multi-agent-setup/SKILL.md"
|
|
1084
1075
|
},
|
|
1076
|
+
{
|
|
1077
|
+
"name": "multi-agent-ship",
|
|
1078
|
+
"description": "Continue already-done LOCAL work through the pipeline tail: Review → Build+Test → Commit/PR → Report (technical analysis + Jira test-scenario comment). No dev phase. Use when local work is already done and only review, build, commit and reporting remain.",
|
|
1079
|
+
"platform": null,
|
|
1080
|
+
"group": "core",
|
|
1081
|
+
"triggerKeywords": [],
|
|
1082
|
+
"triggerPaths": [],
|
|
1083
|
+
"relativePath": "shared/core/multi-agent-ship/SKILL.md"
|
|
1084
|
+
},
|
|
1085
1085
|
{
|
|
1086
1086
|
"name": "multi-agent-stack",
|
|
1087
1087
|
"description": "Select the active stack for this repo by enabling the matching marketplace plugin(s) in .claude/settings.json (ios/android/mobile/backend/frontend/fullstack/all). Use when a repo's stack changed or the wrong plugins are enabled for it.",
|
|
@@ -102,7 +102,6 @@
|
|
|
102
102
|
| core | `multi-agent-dev-local` | - | Fast mode + local - Init → Dev(Opus) → Review → Commit → Report, no worktree. Use when a change should be developed and reviewed on the cu |
|
|
103
103
|
| core | `multi-agent-dev-local-autopilot` | - | Fastest + local - Dev(Opus) + autopilot, no worktree, zero interaction. Use when a change should be developed on the current branch with n |
|
|
104
104
|
| core | `multi-agent-diff-explain` | - | Map Phase 4 triage findings to branch diff lines. Read-only post-hoc command, used after review to answer 'which finding lines up with which |
|
|
105
|
-
| core | `multi-agent-ship` | - | Continue already-done LOCAL work through the pipeline tail: Review → Build+Test → Commit/PR → Report (technical analysis + Jira test-scenari |
|
|
106
105
|
| core | `multi-agent-forget` | - | Remove a saved /multi-agent routine (created by /multi-agent:save): deletes its local-only command and its registry entry. Asks which one an |
|
|
107
106
|
| core | `multi-agent-garbage-collect` | - | Sweep leftover /tmp scratch (picker state, review diffs, channel payloads, analysis drafts) from past runs. Dry-run first; confirms before d |
|
|
108
107
|
| core | `multi-agent-help` | - | Multi-agent pipeline usage guide - renders in EN or TR per prefs.global.outputLanguage (falls back to promptLanguage for backward compatib |
|
|
@@ -127,6 +126,7 @@
|
|
|
127
126
|
| core | `multi-agent-scan` | - | Skill security scan: walks local skill directories against a tiered pattern catalog. Use when local skill directories need checking for unsa |
|
|
128
127
|
| core | `multi-agent-search` | - | Log search across every agent-log.md with smart ranking and filters. Optional --semantic flag queries the per-repo triage corpus. Use when s |
|
|
129
128
|
| core | `multi-agent-setup` | - | First-run setup wizard: keychain token discovery, Git Identity onboarding, and pipeline preparation. Use when the pipeline is being set up f |
|
|
129
|
+
| core | `multi-agent-ship` | - | Continue already-done LOCAL work through the pipeline tail: Review → Build+Test → Commit/PR → Report (technical analysis + Jira test-scenari |
|
|
130
130
|
| core | `multi-agent-stack` | - | Select the active stack for this repo by enabling the matching marketplace plugin(s) in .claude/settings.json (ios/android/mobile/backend/fr |
|
|
131
131
|
| core | `multi-agent-status` | - | Show every multi-agent task's ID, phase, branch, and status. Use when asked what is running, or for an overview of every task. |
|
|
132
132
|
| core | `multi-agent-sync` | - | One-shot sync of the entire multi-agent ecosystem: Claude Code, Copilot CLI, pipeline repo, website, and the dev-toolkit MCP server. Use whe |
|