@mmerterden/multi-agent-pipeline 15.1.0 → 15.3.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/CHANGELOG.md +33 -0
- package/package.json +1 -1
- package/pipeline/commands/multi-agent/setup/SKILL.md +34 -0
- package/pipeline/commands/multi-agent/update/SKILL.md +27 -0
- package/pipeline/preferences-template.json +1 -0
- package/pipeline/schemas/prefs.schema.json +7 -0
- package/pipeline/scripts/usage-report.mjs +32 -1
package/CHANGELOG.md
CHANGED
|
@@ -16,6 +16,39 @@ Internal file-layout changes that don't affect the slash-command surface are sti
|
|
|
16
16
|
|
|
17
17
|
## [Unreleased]
|
|
18
18
|
|
|
19
|
+
## [15.3.0] - 2026-08-15
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **`/multi-agent:setup` onboards the usage-dashboard token (opt-in, one-time).**
|
|
24
|
+
When a team runs the private dashboard and the admin issued this user a personal
|
|
25
|
+
ingest token, setup stores it in the OS credential store ONLY (never a file,
|
|
26
|
+
prefs value, git, or synced tree), maps `keychainMapping.usage_ingest`, and
|
|
27
|
+
turns logging on. After that single paste, `/multi-agent:update` keeps it active
|
|
28
|
+
and every run reports itself - no further steps. The token is write-only,
|
|
29
|
+
per-user (independently revocable), and read at runtime from the credential
|
|
30
|
+
store, transmitted only over TLS. Skipping the prompt leaves logging fully off.
|
|
31
|
+
True zero-touch is deliberately not offered: a machine that authenticates with
|
|
32
|
+
no prior onboarding would require an embeddable secret, which is the attack
|
|
33
|
+
vector - one-time onboarding is the security floor.
|
|
34
|
+
|
|
35
|
+
## [15.2.0] - 2026-08-15
|
|
36
|
+
|
|
37
|
+
### Added
|
|
38
|
+
|
|
39
|
+
- **`/multi-agent:update` auto-enables usage logging when a token is onboarded.**
|
|
40
|
+
The private dashboard stays opt-in and off by default, but once the shared
|
|
41
|
+
ingest token exists on a machine, an update flips `usageLog.enabled` on so the
|
|
42
|
+
admin's trusted group does not each have to toggle it by hand. It NEVER
|
|
43
|
+
fabricates or ships a secret: it activates only when a token resolves from
|
|
44
|
+
`MULTI_AGENT_USAGE_TOKEN`, `usageLog.token`, or the Keychain item named by the
|
|
45
|
+
new generic `keychainMapping.usage_ingest` slot - a machine that was never
|
|
46
|
+
given the token stays silent.
|
|
47
|
+
- **`usage-report.mjs` reads the ingest token from the Keychain** (via
|
|
48
|
+
`credential-store.sh`, resolved through `keychainMapping.usage_ingest`) as a
|
|
49
|
+
fallback after env and `usageLog.token`, so the secret never has to live in a
|
|
50
|
+
synced or plaintext file for logging to work.
|
|
51
|
+
|
|
19
52
|
## [15.1.0] - 2026-08-14
|
|
20
53
|
|
|
21
54
|
Opt-in run telemetry to a private dashboard, and a refactor band that mines it.
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "15.
|
|
3
|
+
"version": "15.3.0",
|
|
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",
|
|
@@ -206,6 +206,40 @@ Save the resolved mapping to preferences:
|
|
|
206
206
|
|
|
207
207
|
`null` = not mapped (missing or skipped). Pipeline phases read this mapping to retrieve tokens dynamically - never hardcoded key names.
|
|
208
208
|
|
|
209
|
+
### Step 2.7 - Usage dashboard token (optional, opt-in)
|
|
210
|
+
|
|
211
|
+
Only relevant when the team runs a private usage dashboard and the admin has issued this user a personal ingest token. This is the ONE-TIME onboarding that makes usage logging automatic afterwards: once the token is in the credential store, `/multi-agent:update` auto-enables `usageLog` and every run reports itself. Skipping it leaves logging fully off.
|
|
212
|
+
|
|
213
|
+
Ask (in `outputLanguage`), and proceed only on an explicit yes:
|
|
214
|
+
|
|
215
|
+
```
|
|
216
|
+
Do you have a usage-dashboard ingest token from your admin?
|
|
217
|
+
It turns on private run telemetry (who/what/when/tokens) for the team dashboard.
|
|
218
|
+
[ Paste token / Skip ]
|
|
219
|
+
```
|
|
220
|
+
|
|
221
|
+
On paste, store the secret in the credential store ONLY - never in a file, prefs value, git, or any synced/published tree. Use the standard per-user key name so it is revocable independently and consistent across the user's machines:
|
|
222
|
+
|
|
223
|
+
```bash
|
|
224
|
+
~/.claude/lib/credential-store.sh set "${USER}_Usage_Ingest_Token" "<pasted-token>"
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
Then map it and enable logging (the token itself stays in the credential store; only the logical mapping + the on-switch land in prefs):
|
|
228
|
+
|
|
229
|
+
```bash
|
|
230
|
+
node -e '
|
|
231
|
+
const fs=require("fs"),os=require("os"),p=os.homedir()+"/.claude/multi-agent-preferences.json";
|
|
232
|
+
const j=JSON.parse(fs.readFileSync(p,"utf8"));
|
|
233
|
+
j.global=j.global||{}; j.global.keychainMapping=j.global.keychainMapping||{};
|
|
234
|
+
j.global.keychainMapping.usage_ingest=process.argv[1];
|
|
235
|
+
j.global.usageLog=Object.assign({enabled:true},j.global.usageLog||{},{enabled:true});
|
|
236
|
+
fs.writeFileSync(p,JSON.stringify(j,null,2)+"\n");
|
|
237
|
+
' "${USER}_Usage_Ingest_Token"
|
|
238
|
+
echo " -> usage logging onboarded (token in credential store; logging on)"
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
Security notes to surface to the user: the token is **write-only** (it can only append activity metadata to the dashboard - no read access, no other scope), it is stored **only in the OS credential store**, and it is **per-user** so the admin can revoke this one token without affecting anyone else. `usage-report.mjs` reads it from the credential store at runtime via the `usage_ingest` mapping; it is never written to a file or transmitted except over TLS to the ingest endpoint.
|
|
242
|
+
|
|
209
243
|
### Auto-learned fields (no setup step needed)
|
|
210
244
|
|
|
211
245
|
**Jira Project Key**: auto-learned from pipeline usage. User runs `/multi-agent ABC-123` → `ABC` is extracted and saved to `prefs.global.defaultJiraKey` (first ever) and `prefs.projects[{project}].jiraProjectKeys` (per-project). Multiple keys accumulate over time - most recent first, deduped. Phase 0 Step 1 (Parse Input) handles extraction.
|
|
@@ -71,6 +71,33 @@ Update the pipeline in one command. Existing preferences are preserved; only ski
|
|
|
71
71
|
fi
|
|
72
72
|
```
|
|
73
73
|
|
|
74
|
+
5b. **Auto-enable usage logging when a token is already onboarded.** The private
|
|
75
|
+
usage dashboard is opt-in and off by default. This step flips it ON only when a
|
|
76
|
+
token can be resolved - it NEVER fabricates a secret or ships one, so a machine
|
|
77
|
+
that was never given the token stays silent. Resolution order: env
|
|
78
|
+
`MULTI_AGENT_USAGE_TOKEN`, then `usageLog.token`, then the Keychain item named by
|
|
79
|
+
`keychainMapping.usage_ingest`. Endpoint is left to the emitter's default.
|
|
80
|
+
```bash
|
|
81
|
+
PREFS="$HOME/.claude/multi-agent-preferences.json"
|
|
82
|
+
if [ -f "$PREFS" ] && command -v jq >/dev/null 2>&1; then
|
|
83
|
+
ENABLED=$(jq -r '.global.usageLog.enabled // false' "$PREFS" 2>/dev/null)
|
|
84
|
+
if [ "$ENABLED" != "true" ]; then
|
|
85
|
+
TOK="${MULTI_AGENT_USAGE_TOKEN:-}"
|
|
86
|
+
[ -z "$TOK" ] && TOK=$(jq -r '.global.usageLog.token // empty' "$PREFS" 2>/dev/null)
|
|
87
|
+
if [ -z "$TOK" ]; then
|
|
88
|
+
KNAME=$(jq -r '.global.keychainMapping.usage_ingest // empty' "$PREFS" 2>/dev/null)
|
|
89
|
+
[ -n "$KNAME" ] && TOK=$(bash "$HOME/.claude/lib/credential-store.sh" get "$KNAME" 2>/dev/null)
|
|
90
|
+
fi
|
|
91
|
+
if [ -n "$TOK" ]; then
|
|
92
|
+
node -e 'const fs=require("fs"),p=process.argv[1];const j=JSON.parse(fs.readFileSync(p,"utf8"));j.global=j.global||{};j.global.usageLog=j.global.usageLog||{};j.global.usageLog.enabled=true;fs.writeFileSync(p,JSON.stringify(j,null,2)+"\n");' "$PREFS"
|
|
93
|
+
echo " -> usage logging activated (ingest token found)"
|
|
94
|
+
else
|
|
95
|
+
echo " -> usage logging left off (no ingest token onboarded)"
|
|
96
|
+
fi
|
|
97
|
+
fi
|
|
98
|
+
fi
|
|
99
|
+
```
|
|
100
|
+
|
|
74
101
|
6. **Show the new version**:
|
|
75
102
|
```bash
|
|
76
103
|
NEW_VERSION=$(node -p "require('$PIPE_DIR/package.json').version" 2>/dev/null || echo "unknown")
|
|
@@ -188,6 +188,13 @@
|
|
|
188
188
|
"null"
|
|
189
189
|
]
|
|
190
190
|
},
|
|
191
|
+
"usage_ingest": {
|
|
192
|
+
"type": [
|
|
193
|
+
"string",
|
|
194
|
+
"null"
|
|
195
|
+
],
|
|
196
|
+
"description": "Keychain item holding the shared ingest token for the private usage dashboard. When set, usage-report.mjs reads the token from here (never from a synced file), and /multi-agent:update auto-enables usageLog once the token is onboarded. Absent = usage logging stays off."
|
|
197
|
+
},
|
|
191
198
|
"figma_pat": {
|
|
192
199
|
"type": [
|
|
193
200
|
"string",
|
|
@@ -32,6 +32,7 @@ import { readFileSync, existsSync, readdirSync, appendFileSync } from "fs";
|
|
|
32
32
|
import { homedir, platform } from "os";
|
|
33
33
|
import { dirname, join } from "path";
|
|
34
34
|
import { fileURLToPath } from "url";
|
|
35
|
+
import { execFileSync } from "child_process";
|
|
35
36
|
import { costUsd } from "./_cost.mjs";
|
|
36
37
|
|
|
37
38
|
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
@@ -70,6 +71,36 @@ function resolvePrefs() {
|
|
|
70
71
|
return resolveGlobalPrefs().usageLog ?? {};
|
|
71
72
|
}
|
|
72
73
|
|
|
74
|
+
/**
|
|
75
|
+
* Resolve the ingest token without ever storing it in a synced file.
|
|
76
|
+
* Order: env, then prefs.usageLog.token, then the Keychain entry mapped by
|
|
77
|
+
* prefs.global.keychainMapping.usage_ingest (via credential-store.sh). This
|
|
78
|
+
* lets update flip usageLog.enabled on while the secret stays in the Keychain.
|
|
79
|
+
*/
|
|
80
|
+
function resolveToken() {
|
|
81
|
+
if (process.env.MULTI_AGENT_USAGE_TOKEN) return process.env.MULTI_AGENT_USAGE_TOKEN;
|
|
82
|
+
const g = resolveGlobalPrefs();
|
|
83
|
+
const inline = g.usageLog?.token;
|
|
84
|
+
if (typeof inline === "string" && inline.trim()) return inline.trim();
|
|
85
|
+
const name = g.keychainMapping?.usage_ingest;
|
|
86
|
+
if (typeof name === "string" && name.trim()) {
|
|
87
|
+
const store = join(homedir(), ".claude", "lib", "credential-store.sh");
|
|
88
|
+
if (existsSync(store)) {
|
|
89
|
+
try {
|
|
90
|
+
const out = execFileSync("bash", [store, "get", name.trim()], {
|
|
91
|
+
encoding: "utf-8",
|
|
92
|
+
timeout: 4000,
|
|
93
|
+
stdio: ["ignore", "pipe", "ignore"],
|
|
94
|
+
}).trim();
|
|
95
|
+
if (out) return out;
|
|
96
|
+
} catch {
|
|
97
|
+
/* keychain unavailable - stay silent */
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return "";
|
|
102
|
+
}
|
|
103
|
+
|
|
73
104
|
function enabledPlugins(state) {
|
|
74
105
|
const root = state.projectRoot || process.cwd();
|
|
75
106
|
const settings = readJson(join(root, ".claude", "settings.json"));
|
|
@@ -393,7 +424,7 @@ async function post(endpoint, token, event) {
|
|
|
393
424
|
async function main() {
|
|
394
425
|
const args = parseArgs(process.argv.slice(2));
|
|
395
426
|
const prefs = resolvePrefs();
|
|
396
|
-
const token =
|
|
427
|
+
const token = resolveToken();
|
|
397
428
|
const endpoint = prefs.endpoint || ENDPOINT_DEFAULT;
|
|
398
429
|
|
|
399
430
|
if (!args.dryRun && (prefs.enabled !== true || !token)) return;
|