@mmerterden/multi-agent-pipeline 15.10.0 → 15.10.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 CHANGED
@@ -16,6 +16,12 @@ Internal file-layout changes that don't affect the slash-command surface are sti
16
16
 
17
17
  ## [Unreleased]
18
18
 
19
+ ## [15.10.1] - 2026-08-21
20
+
21
+ ### Fixed
22
+ - **`uninstall --all-data` now removes the per-repo memory root.** `~/.claude/memory/multi-agent/` holds the learnings ledger and triage corpus: durable knowledge written in prose about the repos it was collected from, which on a corporate checkout is concrete information about the codebase. It survived even the full-cleanup mode, so "removes everything but your tokens" was not true in the one place a user is most likely to mean it. The default run still keeps it, alongside settings and logs, and both halves of that promise are now tested.
23
+ - **Offloaded tool payloads are reclaimable.** v15.10.0 added `offload-ref.sh` without a way to clean up after it. In worktree modes the payloads die with the worktree, but the `--local` modes write into the real checkout, and because `.multi-agent/refs/` is gitignored the files never appear in `git status` and nothing reclaims them. New `gc-refs.sh`, dispatched as a third phase of `/multi-agent:garbage-collect`, sweeps them with the same contract as the /tmp sweeper: dry-run until `--yes`, a root guard that refuses `/` and `$HOME`, a grace window so a sweep cannot pull a ref out from under a running phase, and node-id matching so a file the user put in that directory survives. `--all` sweeps every checkout under `$HOME`.
24
+
19
25
  ## [15.10.0] - 2026-08-21
20
26
 
21
27
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mmerterden/multi-agent-pipeline",
3
- "version": "15.10.0",
3
+ "version": "15.10.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",
@@ -1,6 +1,6 @@
1
1
  ---
2
- description: "Sweep leftover /tmp scratch (picker state, review diffs, channel payloads, analysis drafts) and worktree residue (orphan .worktrees dirs, gitlink index entries) from past runs. Dry-run first; confirms before deleting. Use when scratch files from earlier runs need clearing out."
3
- description-tr: "Geçmiş çalışmalardan kalan /tmp scratch'ini (picker durumu, review diff'leri, kanal payload'ları, analiz taslakları) ve worktree kalıntılarını (sahipsiz .worktrees klasörleri, gitlink index kayıtları) süpürür. Önce dry-run; silmeden önce onay alır."
2
+ description: "Sweep leftover /tmp scratch (picker state, review diffs, channel payloads, analysis drafts), worktree residue (orphan .worktrees dirs, gitlink index entries) and offloaded tool payloads under .multi-agent/refs/ from past runs. Dry-run first; confirms before deleting. Use when scratch files from earlier runs need clearing out."
3
+ description-tr: "Geçmiş çalışmalardan kalan /tmp scratch'ini (picker durumu, review diff'leri, kanal payload'ları, analiz taslakları), worktree kalıntılarını (sahipsiz .worktrees klasörleri, gitlink index kayıtları) ve .multi-agent/refs/ altındaki offload edilmiş araç çıktılarını süpürür. Önce dry-run; silmeden önce onay alır."
4
4
  argument-hint: "[--older-than=<minutes>] [--yes] - dry-run unless confirmed"
5
5
  ---
6
6
 
@@ -72,6 +72,31 @@ deletes nothing until you confirm.
72
72
  - On confirm, re-run with `--yes` and echo its summary line. If a gitlink
73
73
  was unstaged, remind the user the removal still needs a commit.
74
74
 
75
+ 7. **Offloaded payload sweep (third phase)** - when the current directory is a
76
+ git repo, also preview the offloaded tool payloads:
77
+
78
+ ```bash
79
+ bash $HOME/.claude/scripts/gc-refs.sh ${ARGUMENTS}
80
+ ```
81
+
82
+ `offload-ref.sh` parks build logs, diffs and test output under
83
+ `.multi-agent/refs/<node_id>.md`. In worktree modes that directory dies with
84
+ the worktree; in the `--local` modes it lands in the real checkout, and
85
+ because it is gitignored it never shows up in `git status`. Only files
86
+ matching the node-id shape are touched - anything else in that directory is
87
+ left alone, and files inside the grace window are spared so a sweep cannot
88
+ pull a ref out from under a running phase.
89
+
90
+ - Output says `nothing to do` -> skip silently, no question.
91
+ - Otherwise surface a third `AskUserQuestion` (in `outputLanguage`):
92
+ `question`: "Delete the listed offloaded payloads?" (include the count and
93
+ freed size), `header`: "Payloads", options `{ label: "Delete payloads" }` /
94
+ `{ label: "Cancel", description: "Keep everything, change nothing" }`.
95
+ - On confirm, re-run with `--yes` and echo its summary line.
96
+
97
+ Pass `--all` to sweep every checkout under `$HOME` rather than only the
98
+ current repo.
99
+
75
100
  ## Notes
76
101
 
77
102
  - An in-flight analysis keeps its drafts in `/tmp/analysis-<slug>-<timestamp>/`
@@ -79,6 +104,10 @@ deletes nothing until you confirm.
79
104
  `awaiting_output_decision`, pass `--older-than=<minutes>` so fresh drafts are
80
105
  spared, or finish the run first.
81
106
  - The /tmp phase only touches `/tmp` scratch; the worktree phase only touches
82
- the current repo's `.worktrees/` residue and index. Persistent per-task logs
107
+ the current repo's `.worktrees/` residue and index; the payload phase only
108
+ touches node-id files under `.multi-agent/refs/`. Persistent per-task logs
83
109
  live under `~/.claude/logs/multi-agent/` and are cleaned by
84
- `/multi-agent:prune-logs`.
110
+ `/multi-agent:prune-logs`. The per-repo memory stores under
111
+ `~/.claude/memory/multi-agent/` are durable knowledge, not scratch: they are
112
+ removed only by `/multi-agent:uninstall --all-data`, or one entry at a time
113
+ with `learnings-ledger.mjs forget`.
@@ -0,0 +1,187 @@
1
+ #!/usr/bin/env bash
2
+ # gc-refs.sh - remove offloaded tool payloads left behind in a repo checkout.
3
+ #
4
+ # `offload-ref.sh` parks build logs, diffs and test output under
5
+ # <root>/.multi-agent/refs/<node_id>.md so a phase prompt can carry a pointer
6
+ # instead of the whole log. In worktree modes that directory dies with the
7
+ # worktree. In the --local modes there is no worktree: the refs land in the
8
+ # real checkout and nothing ever removes them. They are gitignored, so they are
9
+ # invisible to `git status` and grow without bound.
10
+ #
11
+ # This sweeps them, with the same safety contract as gc-tmp.sh:
12
+ # - dry-run by default: lists what WOULD be removed and the space it frees,
13
+ # and deletes nothing until --yes
14
+ # - root guard: refuses a root that is not a directory, and refuses $HOME
15
+ # and / outright, so a stray GC_REFS_ROOT cannot sweep a home directory
16
+ # - fresh-payload grace: files touched in the last GC_REFS_GRACE_MIN minutes
17
+ # (default 10) are spared, so a sweep during an in-flight run cannot pull a
18
+ # ref out from under the agent that is about to read it
19
+ #
20
+ # Only files matching the node-id shape are touched; anything else a user put
21
+ # in that directory is left alone.
22
+ #
23
+ # Usage:
24
+ # gc-refs.sh # dry-run over the current repo
25
+ # gc-refs.sh --yes # actually delete
26
+ # gc-refs.sh --older-than=1440 # only payloads older than a day
27
+ # gc-refs.sh --all # every repo under GC_REFS_SEARCH (default $HOME)
28
+ #
29
+ # Env:
30
+ # GC_REFS_ROOT override the repo root (default: git toplevel, else $PWD)
31
+ # GC_REFS_SEARCH where --all looks for checkouts (default $HOME)
32
+ # GC_REFS_GRACE_MIN grace window in minutes (default 10, 0 = off)
33
+ #
34
+ # Exit: 0 on success or nothing to do, 2 on usage error or a refused root.
35
+
36
+ set -uo pipefail
37
+
38
+ GRACE_MIN="${GC_REFS_GRACE_MIN:-10}"
39
+ SEARCH_ROOT="${GC_REFS_SEARCH:-$HOME}"
40
+ DELETE=0
41
+ OLDER_MIN=0
42
+ ALL=0
43
+
44
+ usage() {
45
+ grep -E '^#( |$)' "$0" | sed -E 's/^# ?//'
46
+ }
47
+
48
+ for arg in "$@"; do
49
+ case "$arg" in
50
+ --yes | --force) DELETE=1 ;;
51
+ --all) ALL=1 ;;
52
+ --older-than=*)
53
+ OLDER_MIN="${arg#*=}"
54
+ if ! printf '%s' "$OLDER_MIN" | grep -qE '^[0-9]+$'; then
55
+ echo "gc-refs: --older-than needs a whole number of minutes, got: $OLDER_MIN" >&2
56
+ exit 2
57
+ fi
58
+ ;;
59
+ -h | --help)
60
+ usage
61
+ exit 0
62
+ ;;
63
+ *)
64
+ echo "gc-refs: unknown argument: $arg" >&2
65
+ exit 2
66
+ ;;
67
+ esac
68
+ done
69
+
70
+ if ! printf '%s' "$GRACE_MIN" | grep -qE '^[0-9]+$'; then
71
+ echo "gc-refs: GC_REFS_GRACE_MIN needs a whole number of minutes, got: $GRACE_MIN" >&2
72
+ exit 2
73
+ fi
74
+
75
+ # Collect the refs directories to consider.
76
+ REFS_DIRS=""
77
+ if [ "$ALL" -eq 1 ]; then
78
+ if [ ! -d "$SEARCH_ROOT" ]; then
79
+ echo "gc-refs: no search root at $SEARCH_ROOT - nothing to do"
80
+ exit 0
81
+ fi
82
+ # Prune the trees that are large and never hold a pipeline checkout, so a
83
+ # home-wide sweep stays seconds rather than minutes.
84
+ REFS_DIRS=$(find "$SEARCH_ROOT" \
85
+ \( -name node_modules -o -name Pods -o -name .build -o -name DerivedData -o -name .next \) -prune \
86
+ -o -type d -path "*/.multi-agent/refs" -print 2>/dev/null)
87
+ else
88
+ ROOT="${GC_REFS_ROOT:-}"
89
+ if [ -z "$ROOT" ]; then
90
+ ROOT=$(git rev-parse --show-toplevel 2>/dev/null || true)
91
+ [ -n "$ROOT" ] || ROOT="$PWD"
92
+ fi
93
+ # Root guard: never accept a root that resolves to / or $HOME. A sweep is
94
+ # recursive and a mistyped override should not be able to reach a home dir.
95
+ case "$ROOT" in
96
+ / | "$HOME")
97
+ echo "gc-refs: refusing to sweep '$ROOT' - point GC_REFS_ROOT at a repo checkout" >&2
98
+ exit 2
99
+ ;;
100
+ esac
101
+ [ -d "$ROOT" ] || {
102
+ echo "gc-refs: no directory at $ROOT - nothing to do"
103
+ exit 0
104
+ }
105
+ [ -d "$ROOT/.multi-agent/refs" ] && REFS_DIRS="$ROOT/.multi-agent/refs"
106
+ fi
107
+
108
+ if [ -z "$REFS_DIRS" ]; then
109
+ echo "gc-refs: no offloaded payloads found - nothing to do"
110
+ exit 0
111
+ fi
112
+
113
+ # Match the node-id shape offload-ref.sh writes (p<phase>-<slug>-<8 hex>.md).
114
+ # Anything else in that directory belongs to someone else.
115
+ NODE_GLOB='p*-*-*.md'
116
+
117
+ MATCHES=""
118
+ while IFS= read -r dir; do
119
+ [ -n "$dir" ] || continue
120
+ # `-mmin +0` is not a no-op: it means "older than a minute" and would drop a
121
+ # file written seconds ago. The age filter is applied only when one was asked
122
+ # for; the grace window below is what protects an in-flight payload.
123
+ if [ "$OLDER_MIN" -gt 0 ]; then
124
+ found=$(find "$dir" -maxdepth 1 -type f -name "$NODE_GLOB" -mmin +"$OLDER_MIN" 2>/dev/null)
125
+ else
126
+ found=$(find "$dir" -maxdepth 1 -type f -name "$NODE_GLOB" 2>/dev/null)
127
+ fi
128
+ [ -n "$found" ] || continue
129
+ while IFS= read -r f; do
130
+ [ -n "$f" ] || continue
131
+ # Grace: skip anything touched inside the window.
132
+ if [ "$GRACE_MIN" -gt 0 ] && [ -n "$(find "$f" -mmin -"$GRACE_MIN" 2>/dev/null)" ]; then
133
+ continue
134
+ fi
135
+ MATCHES="$MATCHES$f
136
+ "
137
+ done <<EOF
138
+ $found
139
+ EOF
140
+ done <<EOF
141
+ $REFS_DIRS
142
+ EOF
143
+
144
+ MATCHES=$(printf '%s' "$MATCHES" | grep -v '^$' || true)
145
+ if [ -z "$MATCHES" ]; then
146
+ echo "gc-refs: no offloaded payloads outside the grace window - nothing to do"
147
+ exit 0
148
+ fi
149
+
150
+ COUNT=$(printf '%s\n' "$MATCHES" | grep -c .)
151
+ BYTES=0
152
+ while IFS= read -r f; do
153
+ [ -n "$f" ] || continue
154
+ sz=$(wc -c < "$f" 2>/dev/null | tr -d ' ')
155
+ BYTES=$((BYTES + ${sz:-0}))
156
+ done <<EOF
157
+ $MATCHES
158
+ EOF
159
+ KB=$(((BYTES + 1023) / 1024))
160
+
161
+ if [ "$DELETE" -eq 0 ]; then
162
+ echo "gc-refs: would remove $COUNT offloaded payload(s), freeing ${KB} KB"
163
+ printf '%s\n' "$MATCHES" | sed 's/^/ /'
164
+ echo ""
165
+ echo "Nothing deleted. Re-run with --yes to remove them."
166
+ exit 0
167
+ fi
168
+
169
+ removed=0
170
+ while IFS= read -r f; do
171
+ [ -n "$f" ] || continue
172
+ rm -f "$f" && removed=$((removed + 1))
173
+ done <<EOF
174
+ $MATCHES
175
+ EOF
176
+
177
+ # Drop a refs directory that is now empty; leave one that still holds
178
+ # something we did not put there.
179
+ while IFS= read -r dir; do
180
+ [ -n "$dir" ] || continue
181
+ rmdir "$dir" 2>/dev/null || true
182
+ done <<EOF
183
+ $REFS_DIRS
184
+ EOF
185
+
186
+ echo "gc-refs: removed $removed offloaded payload(s), freed ${KB} KB"
187
+ exit 0
@@ -31,6 +31,7 @@
31
31
  * Preserved by default, removed with --all-data:
32
32
  * - $HOME/.claude/multi-agent-preferences.json (pipeline settings)
33
33
  * - $HOME/.claude/logs/multi-agent/ (task logs, state, metrics, audit trail)
34
+ * - $HOME/.claude/memory/multi-agent/ (per-repo learnings ledger + triage corpus)
34
35
  *
35
36
  * @module pipeline/scripts/runtime/uninstall
36
37
  */
@@ -635,6 +636,7 @@ export async function main() {
635
636
  console.log(" FULL CLEANUP (--all-data) also removes:");
636
637
  console.log(" - ~/.claude/multi-agent-preferences.json (pipeline settings)");
637
638
  console.log(" - ~/.claude/logs/multi-agent/ (task logs, state, metrics, audit trail)");
639
+ console.log(" - ~/.claude/memory/multi-agent/ (per-repo learnings ledger + triage corpus)");
638
640
  console.log("");
639
641
  }
640
642
  console.log(" PRESERVED (never touched):");
@@ -733,14 +735,22 @@ export async function main() {
733
735
  stripManagedBlock(join(COP, "copilot-instructions.md"));
734
736
  }
735
737
 
736
- // Full cleanup: pipeline settings + the multi-agent log root. Both are
737
- // pipeline-generated data (not user-authored like CLAUDE.md / rules), so
738
- // --all-data removes them; the default run leaves them in place.
738
+ // Full cleanup: pipeline settings, the log root, and the per-repo memory
739
+ // stores. All three are pipeline-generated data (not user-authored like
740
+ // CLAUDE.md / rules), so --all-data removes them; the default run leaves them
741
+ // in place.
742
+ //
743
+ // The memory root was missing here, and it is the one a user is most likely
744
+ // to mean by "remove everything": the learnings ledger and triage corpus hold
745
+ // architectural facts and past review findings written in prose about the
746
+ // repos they were collected from. On a corporate checkout that is concrete
747
+ // information about the codebase, and it survived even --all-data.
739
748
  if (allData && HOME) {
740
749
  console.log("");
741
- console.log(" [Full cleanup] Removing pipeline settings + logs...");
750
+ console.log(" [Full cleanup] Removing pipeline settings, logs + memory...");
742
751
  rmIfExists(join(HOME, ".claude", "multi-agent-preferences.json"));
743
752
  rmIfExists(join(HOME, ".claude", "logs", "multi-agent"));
753
+ rmIfExists(join(HOME, ".claude", "memory", "multi-agent"));
744
754
  }
745
755
 
746
756
  // Legacy adapter-file cleanup (adapters removed in v10.7.0). These blocks
@@ -818,7 +828,7 @@ export async function main() {
818
828
  if (!allData) {
819
829
  console.log("");
820
830
  console.log(
821
- " Kept your pipeline settings + logs. To remove those too, re-run with --all-data.",
831
+ " Kept your pipeline settings, logs + per-repo memory. To remove those too, re-run with --all-data.",
822
832
  );
823
833
  } else {
824
834
  console.log("");