@mmerterden/multi-agent-pipeline 20.24.0 → 20.25.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 +24 -0
- package/README.md +6 -5
- package/README.tr.md +6 -5
- package/docs/architecture.md +3 -3
- package/docs/ecosystem.md +5 -5
- package/docs/facts.json +7 -6
- package/docs/features.md +9 -4
- package/install/catalog-history.json +1 -1
- package/install/templates/claude-hooks.json +1 -1
- package/install/templates/codex-hooks.json +18 -0
- package/manifest.json +89 -82
- package/package.json +1 -1
- package/pipeline/agents/task-clarifier.md +1 -1
- package/pipeline/commands/multi-agent/deps/SKILL.md +61 -0
- package/pipeline/commands/multi-agent/model/SKILL.md +2 -2
- package/pipeline/commands/multi-agent/postmortem/SKILL.md +18 -6
- package/pipeline/commands/multi-agent/review/SKILL.md +5 -5
- package/pipeline/commands/multi-agent/route-on/SKILL.md +1 -1
- package/pipeline/commands/multi-agent/setup/SKILL.md +7 -5
- package/pipeline/commands/multi-agent/sync/SKILL.md +3 -3
- package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +2 -3
- package/pipeline/contract/fixtures/runs-failed.json +1 -1
- package/pipeline/contract/fixtures/runs-old-schema.json +1 -1
- package/pipeline/contract/fixtures/runs-pr-opened-redacted.json +1 -1
- package/pipeline/contract/fixtures/runs-pr-opened.json +1 -1
- package/pipeline/contract/fixtures/runs-running.json +1 -1
- package/pipeline/lib/credential-inventory.sh +5 -5
- package/pipeline/lib/fetch-crashlytics.sh +6 -8
- package/pipeline/lib/model-rung.sh +1 -1
- package/pipeline/lib/plan-todos.sh +21 -4
- package/pipeline/lib/post-pr-review.sh +4 -6
- package/pipeline/lib/route-state.sh +1 -1
- package/pipeline/lib/shadow-git.sh +4 -5
- package/pipeline/multi-agent-refs/cross-cli-contract.md +8 -9
- package/pipeline/multi-agent-refs/features/cost-analysis.md +4 -0
- package/pipeline/multi-agent-refs/features/dep-bump.md +176 -0
- package/pipeline/multi-agent-refs/features/model-fallback.md +17 -12
- package/pipeline/multi-agent-refs/help/en.md +1 -0
- package/pipeline/multi-agent-refs/help/tr.md +1 -0
- package/pipeline/multi-agent-refs/phases/phase-0-init.md +1 -1
- package/pipeline/multi-agent-refs/phases/phase-2-dev.md +2 -0
- package/pipeline/multi-agent-refs/phases/phase-3-review.md +5 -5
- package/pipeline/multi-agent-refs/picker-contract.md +1 -1
- package/pipeline/multi-agent-refs/tracker-contract.md +6 -6
- package/pipeline/schemas/agent-state.schema.json +5 -0
- package/pipeline/schemas/phases.json +4 -0
- package/pipeline/schemas/plan-todos.schema.json +4 -4
- package/pipeline/schemas/prefs.schema.json +27 -4
- package/pipeline/scripts/_code-graph.mjs +2 -2
- package/pipeline/scripts/_transcript-hosts.mjs +406 -0
- package/pipeline/scripts/build-stack-plugins.mjs +3 -3
- package/pipeline/scripts/capture-flush.sh +7 -7
- package/pipeline/scripts/code-graph-rules/android.json +1 -1
- package/pipeline/scripts/cost-analyze.mjs +26 -19
- package/pipeline/scripts/cost-table.json +35 -19
- package/pipeline/scripts/dep-bump.mjs +1556 -0
- package/pipeline/scripts/edit-syntax-gate.mjs +151 -29
- package/pipeline/scripts/edit-syntax-gate.sh +9 -6
- package/pipeline/scripts/gc-abandoned.sh +2 -2
- package/pipeline/scripts/gen-mode-dispatch.mjs +3 -3
- package/pipeline/scripts/git-path.mjs +1 -2
- package/pipeline/scripts/host-hooks.mjs +265 -0
- package/pipeline/scripts/jira-attach.sh +1 -1
- package/pipeline/scripts/keychain.py +3 -3
- package/pipeline/scripts/output-quality-check.sh +1 -1
- package/pipeline/scripts/phase-tracker.sh +5 -6
- package/pipeline/scripts/phase0-exit-gate.mjs +3 -3
- package/pipeline/scripts/pre-push-check.sh +3 -6
- package/pipeline/scripts/transcript-index.mjs +423 -242
- package/pipeline/scripts/uninstall.mjs +90 -4
- package/pipeline/scripts/update-issue-progress.sh +4 -6
- package/pipeline/scripts/usage-report.mjs +2 -2
- package/pipeline/skills/.skill-manifest.json +14 -10
- package/pipeline/skills/.skills-index.json +12 -1
- package/pipeline/skills/shared/README.md +4 -3
- package/pipeline/skills/shared/core/multi-agent/SKILL.md +6 -6
- package/pipeline/skills/shared/core/multi-agent-deps/SKILL.md +60 -0
- package/pipeline/skills/shared/core/multi-agent-model/SKILL.md +2 -2
- package/pipeline/skills/shared/core/multi-agent-postmortem/SKILL.md +10 -7
- package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +5 -5
- package/pipeline/skills/shared/core/multi-agent-route-on/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-setup/SKILL.md +7 -5
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +3 -3
- package/pipeline/skills/shared/core/multi-agent-testflight-validation/SKILL.md +2 -3
- package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +2 -2
- package/pipeline/skills/skills-index.md +2 -1
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
---
|
|
2
|
+
description: "Bump one dependency, fix only what the bump broke, review, open a PR; rolls back past the fix round cap. SwiftPM, Gradle, npm, pip. Use when a library needs updating."
|
|
3
|
+
description-tr: "Tek bağımlılığı yükseltir, yalnızca yükseltmenin kırdığını düzeltir, review edip PR açar; düzeltme turu sınırında geri alır. SwiftPM, Gradle, npm, pip. Bir kütüphaneyi güncellemek için kullanılır."
|
|
4
|
+
argument-hint: "[package[@version]] [--major] - no package opens a picker over the outdated candidates; --major allows a breaking bump"
|
|
5
|
+
parameters: [{"name":"package","kind":"text"},{"name":"--major","kind":"flag"}]
|
|
6
|
+
gui: form
|
|
7
|
+
destructive: false
|
|
8
|
+
confirm: none
|
|
9
|
+
---
|
|
10
|
+
|
|
11
|
+
# multi-agent deps - bump one dependency and fix what it broke
|
|
12
|
+
|
|
13
|
+
> **Pickers follow** `$HOME/.claude/multi-agent-refs/picker-contract.md`: never a one-option call, and branch on the option selected, not on its text.
|
|
14
|
+
|
|
15
|
+
**Input**: $ARGUMENTS
|
|
16
|
+
|
|
17
|
+
> **Language (read FIRST)**: read `prefs.global.outputLanguage` and render every conversational line in it. `AskUserQuestion` renders `question`, option `label`s and `description`s in `outputLanguage`; only `header` stays English (<=12-char chip). Commit messages and branch names stay English. Full contract: `$HOME/.claude/multi-agent-refs/rules.md` "Language Application".
|
|
18
|
+
|
|
19
|
+
The normal pipeline with a fixed task. Read `$HOME/.claude/multi-agent-refs/features/dep-bump.md` first: it is the contract for every step below (run shape, scope rule, rollback). `dep-bump.mjs` does every deterministic step; never edit a version string or a lockfile by hand.
|
|
20
|
+
|
|
21
|
+
## Steps
|
|
22
|
+
|
|
23
|
+
1. **Repo and settings.** Resolve the repo as `/multi-agent` does for a free-text task (`_account-picker.md`, `_repo-picker.md`). Then:
|
|
24
|
+
```bash
|
|
25
|
+
node "$HOME/.claude/scripts/dep-bump.mjs" config # depBump.maxFixRounds, depBump.queryRegistry
|
|
26
|
+
node "$HOME/.claude/scripts/dep-bump.mjs" detect --dir "$REPO"
|
|
27
|
+
```
|
|
28
|
+
No ecosystem detected: say so and stop.
|
|
29
|
+
|
|
30
|
+
2. **Candidates.**
|
|
31
|
+
```bash
|
|
32
|
+
node "$HOME/.claude/scripts/dep-bump.mjs" list --dir "$REPO" [--registry] # --registry when queryRegistry is true
|
|
33
|
+
```
|
|
34
|
+
Show `registry.note` and every per-package `note`: an offline listing is reported as offline, never as "nothing outdated".
|
|
35
|
+
- `package@version` given: use it. `package` alone: its `latestInMajor`, else `latest`. Not in the list: stop with the manifests that were read.
|
|
36
|
+
- No package: a single-select picker over the candidates with a newer version, non-breaking first, each option `name current -> target (risk)`. Two or more options per the picker contract; one candidate is confirmed with a yes/no, none means report "nothing newer found" with the registry note.
|
|
37
|
+
|
|
38
|
+
3. **Major gate.** Risk `major` or `unknown`, or a prerelease target (`prerelease: true`), needs `--major` in the input or an explicit confirmation naming the versions (`Bump anyway` / `Take {latestInMajor} instead` when one exists / `Cancel`). An autopilot run without `--major` takes `latestInMajor` or stops.
|
|
39
|
+
|
|
40
|
+
4. **Run the pipeline** with `state.mode = "deps"`, `state.taskType = "chore"`, the free-text task `chore(deps): bump {name} from {current} to {target}` and the branch `chore/deps-{name}-{target}` (kebab rules from Phase 0 Step 4). Phase 0 intake, worktree and tracker run as in `/multi-agent`. Then:
|
|
41
|
+
- **Phase 1**: the fixed plan from the feature doc, with the changelog excerpt as evidence:
|
|
42
|
+
```bash
|
|
43
|
+
node "$HOME/.claude/scripts/dep-bump.mjs" notes --dir "$WORKTREE" --ecosystem E --name N --from A --to B
|
|
44
|
+
```
|
|
45
|
+
- **Phase 2**: apply first, then the exit gate as written:
|
|
46
|
+
```bash
|
|
47
|
+
node "$HOME/.claude/scripts/dep-bump.mjs" apply --dir "$WORKTREE" --ecosystem E --name N --to B [--allow-major]
|
|
48
|
+
```
|
|
49
|
+
Exit 1: report `error` and `lock.output` (or `dirty`: the worktree had uncommitted changes), stop with nothing to commit. Persist the output to `state.depBump`. Green: no dev agent, on to Phase 3. Red: fix rounds, at most `depBump.maxFixRounds`, each dispatched with the failing log tail, `surface` output, the changelog excerpt and the scope rule (feature doc section 4); after each round:
|
|
50
|
+
```bash
|
|
51
|
+
node "$HOME/.claude/scripts/dep-bump.mjs" scope --dir "$WORKTREE" --log "$GATE_LOG" # the round's build/test log
|
|
52
|
+
```
|
|
53
|
+
Only the surface recorded by `apply` is in scope. A file listed in `newImporters` with `cited: null` started importing the dependency without an error line behind it: revert it before the next round.
|
|
54
|
+
- **Cap reached and still red** (or still out of scope): `dep-bump.mjs rollback --dir "$WORKTREE"` (restores the manifest, lockfile and fix files; anything under `kept` is reported, not discarded), set `state.depBump.rolledBack = true`, and end with the report from feature doc section 5. No commit, no push, no PR.
|
|
55
|
+
- **Phase 3**: standard review. Each `outOfScope` file without a cited error line, and each `newImporters` entry with `cited: null`, is a blocking finding.
|
|
56
|
+
- **Phase 4**: commit with `commitMessage` from `apply` (plus ` [{jiraId}]` when present). PR body per the feature doc; `Ref:` or `Related:`, never `Closes`, `Fixes` or `Resolves`, and never close an issue.
|
|
57
|
+
- **Phase 5**: channels as in every mode.
|
|
58
|
+
|
|
59
|
+
## Report
|
|
60
|
+
|
|
61
|
+
In `outputLanguage`, at most 10 lines: the dependency, from and to, risk, lockfile command and result, rounds taken against the cap, files changed (in scope / justified), review verdict, and the PR URL or the rollback reason.
|
|
@@ -52,8 +52,8 @@ because it does not mean the same thing on all three:
|
|
|
52
52
|
|
|
53
53
|
| Host | What `off` does | Why |
|
|
54
54
|
|---|---|---|
|
|
55
|
-
| Claude Code | every `preferredModel: fable` persona (architects, reviewer 1, triage) starts on `opus` | the only host where the rung is Fable 5 |
|
|
56
|
-
| Copilot CLI | nothing | Fable
|
|
55
|
+
| Claude Code | every `preferredModel: fable` persona (architects, reviewer 1, triage) starts on `opus` | the only host where the rung is Fable 5.1 |
|
|
56
|
+
| Copilot CLI | nothing | Fable is not offered there; its personas never sat on this rung |
|
|
57
57
|
| Codex CLI | nothing, deliberately | the `fable` rung there means `gpt-5.6 @ xhigh`, a different model on a different account - switching it from a knob named after an Anthropic model would surprise a Codex user |
|
|
58
58
|
|
|
59
59
|
So on two of the three hosts this command is a **status report**, not a switch,
|
|
@@ -12,18 +12,30 @@ confirm: none
|
|
|
12
12
|
|
|
13
13
|
**Input**: $ARGUMENTS
|
|
14
14
|
|
|
15
|
-
Explains what a run actually did, read from the
|
|
16
|
-
|
|
15
|
+
Explains what a run actually did, read from the session transcripts it ran in,
|
|
16
|
+
not from what the run log says it decided. The evidence comes from a
|
|
17
17
|
deterministic indexer; the model only interprets it.
|
|
18
18
|
|
|
19
|
+
The indexer reads all three hosts and detects the format per file:
|
|
20
|
+
|
|
21
|
+
| Host | Session files |
|
|
22
|
+
|------|---------------|
|
|
23
|
+
| Claude Code | `~/.claude/projects/<dir>/<session>.jsonl` plus its subagent files |
|
|
24
|
+
| Copilot CLI | `~/.copilot/session-state/<session>/events.jsonl` (cited as `<first 8 of session>/events.jsonl`) |
|
|
25
|
+
| Codex | `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl` (cited as `rollout-<first 8 of session>.jsonl`) |
|
|
26
|
+
|
|
27
|
+
Copilot CLI reports tokens per session, so its turns carry output tokens only
|
|
28
|
+
and the totals come from the session's shutdown record; Codex reports them per
|
|
29
|
+
request.
|
|
30
|
+
|
|
19
31
|
**Read-only.** Nothing is sent anywhere: no issue comment, no PR, no channel.
|
|
20
32
|
The one write is the report itself, saved under the run's log directory.
|
|
21
33
|
|
|
22
34
|
## Steps
|
|
23
35
|
|
|
24
36
|
1. **Resolve the target.**
|
|
25
|
-
- A path ending in `.jsonl
|
|
26
|
-
included). There is no run directory, so nothing is saved unless the user
|
|
37
|
+
- A path ending in `.jsonl` (any of the three hosts): index that file
|
|
38
|
+
(Claude Code subagent files beside it are included). There is no run directory, so nothing is saved unless the user
|
|
27
39
|
names one.
|
|
28
40
|
- A task id or `#N`: locate the run and its transcripts:
|
|
29
41
|
```bash
|
|
@@ -31,8 +43,8 @@ The one write is the report itself, saved under the run's log directory.
|
|
|
31
43
|
```
|
|
32
44
|
`matchedBy: "session"` means the run recorded its session id and the match
|
|
33
45
|
is exact. `"time-window"` means it did not (attended runs record none), so
|
|
34
|
-
the files are the sessions that ran in the run's worktree or
|
|
35
|
-
it was active; say that this match is a heuristic. Exit 3 with a `reason`:
|
|
46
|
+
the files are the sessions, on any host, that ran in the run's worktree or
|
|
47
|
+
checkout while it was active; say that this match is a heuristic. Exit 3 with a `reason`:
|
|
36
48
|
report the reason, and offer to take a transcript path instead.
|
|
37
49
|
- No argument: take the most recent run from
|
|
38
50
|
`node "$HOME/.claude/scripts/runs-index.mjs" --json` (latest `startedAt`)
|
|
@@ -247,14 +247,14 @@ off: Agent 1 is dropped, the panel is Agent 2 + Agent 3, triage runs on
|
|
|
247
247
|
Never dispatch a Fable reviewer or a Fable triage on the model list below alone.
|
|
248
248
|
|
|
249
249
|
**Claude Code (3 in parallel while the fable rung is on, 2 while it is off):**
|
|
250
|
-
- Agent 1: `claude-fable-5` → security + architecture (only when `REVIEW_RUNG` is `fable`)
|
|
251
|
-
- Agent 2: `claude-opus-5` → edge cases, alternate perspective
|
|
252
|
-
- Agent 3: `claude-sonnet-5` → general quality
|
|
250
|
+
- Agent 1: `claude-fable-5-1` → security + architecture (only when `REVIEW_RUNG` is `fable`)
|
|
251
|
+
- Agent 2: `claude-opus-5-5` → edge cases, alternate perspective
|
|
252
|
+
- Agent 3: `claude-sonnet-5-5` → general quality
|
|
253
253
|
|
|
254
254
|
**Copilot CLI (3 in parallel):**
|
|
255
|
-
- Agent 1: `claude-opus-
|
|
255
|
+
- Agent 1: `claude-opus-4.7` → security + architecture (Fable is not offered on Copilot CLI)
|
|
256
256
|
- Agent 2: `gpt-5.4` → edge cases, alternate perspective
|
|
257
|
-
- Agent 3: `claude-sonnet-
|
|
257
|
+
- Agent 3: `claude-sonnet-4.6` → general quality
|
|
258
258
|
|
|
259
259
|
**Codex CLI (3 in parallel, single vendor):**
|
|
260
260
|
- Agent 1: `gpt-5.6` @ `xhigh` → security + architecture
|
|
@@ -30,7 +30,7 @@ honoured only at `bulk-read` and `delegate` and only while `--free` is on.
|
|
|
30
30
|
|
|
31
31
|
**Rung names are the contract; model ids are not.** `opus` is a rung here and a
|
|
32
32
|
model id in `cost-table.json`, and the second can change without anyone editing
|
|
33
|
-
a rule. Writing `claude-opus-5` into a rule pins a decision to a string that will
|
|
33
|
+
a rule. Writing `claude-opus-5-5` into a rule pins a decision to a string that will
|
|
34
34
|
go stale.
|
|
35
35
|
|
|
36
36
|
Set rules with:
|
|
@@ -429,14 +429,16 @@ To set up multi-agent on a new machine:
|
|
|
429
429
|
|
|
430
430
|
All tokens are optional in the sense that every service can be answered with Skip - but the ASKING is not optional: the Step 3 sequential loop still walks every missing service one by one (token → author → host). Phase 0 re-asks at runtime only for tokens the user skipped here.
|
|
431
431
|
|
|
432
|
-
### Step 8 - Enforcement hooks (optional
|
|
432
|
+
### Step 8 - Enforcement hooks (optional)
|
|
433
433
|
|
|
434
|
-
|
|
434
|
+
On Claude Code, offer to merge `$HOME/.claude/templates/claude-hooks.json`: three blocking `PreToolUse` gates (secret scan, agent-guard, read-size) plus four non-blocking hooks (`PreCompact`, `SessionEnd`, `SessionStart`, `PostToolUse`). What each does: `$HOME/.claude/multi-agent-refs/picker-contract.md`.
|
|
435
435
|
|
|
436
436
|
- Ask (picker): "Install the pipeline's hooks into `~/.claude/settings.json`?" Default Yes.
|
|
437
|
-
- On Yes, deep-merge EVERY event in the template's `hooks` object
|
|
438
|
-
- Say
|
|
439
|
-
- Say
|
|
437
|
+
- On Yes, deep-merge EVERY event in the template's `hooks` object (merging `PreToolUse` alone drops the capture hooks); keep existing hooks, never duplicate a matcher calling the same script.
|
|
438
|
+
- Say only the three gates are hookable (no run-specific arguments); the rest are phase-enforced.
|
|
439
|
+
- Say the read-size gate stays inert until `prefs.global.bulkRead.mode` is set; recommend `observe` first (why, and the Phase 3 exemption: `picker-contract.md`).
|
|
440
|
+
|
|
441
|
+
Codex: offer only the syntax gate, then run `node "$HOME/.codex/scripts/host-hooks.mjs" install --host codex`. Copilot CLI: offer no hook (it discards `postToolUse` output as of 1.0.45).
|
|
440
442
|
|
|
441
443
|
### Step 9 - Default stack plugin enablement
|
|
442
444
|
|
|
@@ -73,7 +73,7 @@ Run every step automatically:
|
|
|
73
73
|
```
|
|
74
74
|
Step 0: DOCTOR doctor.mjs - exit 2 or 4 stops the sync
|
|
75
75
|
Step 1.5: DETECT Compare timestamps, find stale targets
|
|
76
|
-
Step 2: COPILOT Claude Code -> Copilot CLI (instructions +
|
|
76
|
+
Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 66 sub-command skills)
|
|
77
77
|
Step 2b: CODEX Claude Code -> Codex CLI (1 router skill + sub-command specs as refs + agent TOML)
|
|
78
78
|
Step 3: REPO Claude Code -> pipeline repo (genericized, personal data scrub, bash -n on all sh)
|
|
79
79
|
Step 3c: PLUGINS pipeline shared/external -> multi-agent-plugins marketplace (rebuild knowledge/,
|
|
@@ -241,12 +241,12 @@ same specs as reference files rather than as peer skills, via Step 2b - see
|
|
|
241
241
|
|-------------|-------------|
|
|
242
242
|
| `~/.claude/commands/multi-agent/{cmd}/SKILL.md` | `~/.copilot/skills/multi-agent-{cmd}/SKILL.md` |
|
|
243
243
|
|
|
244
|
-
**
|
|
244
|
+
**66 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
|
|
245
245
|
|
|
246
246
|
```
|
|
247
247
|
analysis, analysis-jira, analysis-resolve, autopilot, autopilot-off, autopilot-on,
|
|
248
248
|
autopilot-status, bug-bash, build-optimize, channels, complaint-analysis, create-jira,
|
|
249
|
-
design-check, diff-explain, doctor, estimate, feedback, forget, garbage-collect, graph, help,
|
|
249
|
+
deps, design-check, diff-explain, doctor, estimate, feedback, forget, garbage-collect, graph, help,
|
|
250
250
|
ios-coding-standard, issue, jira, kill, language, log,
|
|
251
251
|
manual-test, model, postmortem, prune-logs, prune-prompts, purge, refactor, research, resume, review, review-analysis, review-issue, review-jira, route-off, route-on, route-status,
|
|
252
252
|
routines, save, scaffold, scan, scenario-audit, search, security-review, serve, setup, stack, status, steer, store-ready, sync, test,
|
|
@@ -11,10 +11,9 @@ allowed-tools: Agent, Bash, Read, Write, Edit, Glob, Grep, TaskCreate, TaskUpdat
|
|
|
11
11
|
|
|
12
12
|
# /multi-agent:testflight-validation - iOS alias for store-ready
|
|
13
13
|
|
|
14
|
-
This command is an alias. The implementation
|
|
14
|
+
This command is an alias. The implementation lives in
|
|
15
15
|
`/multi-agent:store-ready`, which runs the same three gates on iOS and adds the
|
|
16
|
-
Android side, so there is one flow to maintain instead of two that
|
|
17
|
-
started to drift.
|
|
16
|
+
Android side, so there is one flow to maintain instead of two that drift.
|
|
18
17
|
|
|
19
18
|
The name is kept because it is the one people reach for when the target is
|
|
20
19
|
TestFlight, and removing a command is a breaking change to the slash-command
|
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
#
|
|
4
4
|
# WHY THIS EXISTS
|
|
5
5
|
#
|
|
6
|
-
# A run
|
|
7
|
-
# service-account JSON
|
|
8
|
-
#
|
|
9
|
-
#
|
|
10
|
-
#
|
|
6
|
+
# A run that asks the user to paste a Crashlytics stack trace by hand while a valid
|
|
7
|
+
# Firebase service-account JSON sits in the Keychain, mapped as `firebase`, has failed
|
|
8
|
+
# even though nothing is broken. From the user's side that is worse than a failure: they
|
|
9
|
+
# supplied the key precisely so this would not happen. So the pipeline asks itself "do I
|
|
10
|
+
# already hold a credential that answers this?" before it asks the user.
|
|
11
11
|
#
|
|
12
12
|
# One command, so there is no excuse for asking blind. Run it before any question that
|
|
13
13
|
# requests data an external system holds, and let the answer shape the question:
|
|
@@ -214,15 +214,13 @@ if [ -z "$SA_JSON_RAW" ]; then
|
|
|
214
214
|
fi
|
|
215
215
|
|
|
216
216
|
# The credential store returns the JSON as stored - encoding is its internal
|
|
217
|
-
# business, not this script's
|
|
218
|
-
#
|
|
219
|
-
#
|
|
220
|
-
# nor JSON, so both branches failed and the failure surfaced three layers later
|
|
221
|
-
# as a token-exchange error.
|
|
217
|
+
# business, not this script's, so nothing here guesses at a decoding. A guess
|
|
218
|
+
# that misfires (bare hex read as base64, say) fails three layers later as a
|
|
219
|
+
# token-exchange error instead of here.
|
|
222
220
|
#
|
|
223
|
-
# With no decode step there is nothing to stage on disk, so
|
|
224
|
-
#
|
|
225
|
-
#
|
|
221
|
+
# With no decode step there is nothing to stage on disk, so there is no temp file
|
|
222
|
+
# and no cleanup trap: the service-account JSON only ever exists in a shell
|
|
223
|
+
# variable, which is one fewer place a GCP private key can be left behind.
|
|
226
224
|
SA_JSON="$SA_JSON_RAW"
|
|
227
225
|
|
|
228
226
|
# Verify project_id from SA JSON matches the URL - protects against pasting a
|
|
@@ -69,7 +69,7 @@ host_note() {
|
|
|
69
69
|
echo "Claude Code: the fable rung is Fable 5. This switch is live here."
|
|
70
70
|
;;
|
|
71
71
|
copilot)
|
|
72
|
-
echo "Copilot CLI: Fable
|
|
72
|
+
echo "Copilot CLI: Fable is not offered; its personas never sat on this rung."
|
|
73
73
|
echo "This setting is recorded but changes nothing on this host."
|
|
74
74
|
;;
|
|
75
75
|
codex)
|
|
@@ -13,6 +13,7 @@
|
|
|
13
13
|
# Subcommands:
|
|
14
14
|
# init <task-id> [title] Initialize with empty todos[] (Phase 2 usually pipes the JSON instead)
|
|
15
15
|
# set <task-id> <plan-json> Replace the whole plan from a JSON blob on stdin or arg
|
|
16
|
+
# (exit 2 when a dep names no todo id exactly)
|
|
16
17
|
# start <task-id> <todo-id> Mark in_progress, set startedAt; refuses if deps unsatisfied
|
|
17
18
|
# or the todo awaits re-plan confirmation
|
|
18
19
|
# complete <task-id> <todo-id> [notes] [--no-tests <reason>]
|
|
@@ -84,10 +85,9 @@ resolve_state() {
|
|
|
84
85
|
local task_id="$1"
|
|
85
86
|
local found=""
|
|
86
87
|
# multi-repo-pipeline.sh writes agent-state.json under a per-project
|
|
87
|
-
# directory ($HOME/.claude/logs/multi-agent/{project}/{taskId}/)
|
|
88
|
-
#
|
|
89
|
-
#
|
|
90
|
-
# This globbed ONLY the nested layout; flat-layout runs resolved to nothing.
|
|
88
|
+
# directory ($HOME/.claude/logs/multi-agent/{project}/{taskId}/), other
|
|
89
|
+
# writers write it flat; no writer uses ~/.claude/projects/*/state/.
|
|
90
|
+
# ma_resolve_run_file checks both layouts.
|
|
91
91
|
found="$(ma_resolve_run_file "$task_id" agent-state.json 2>/dev/null || true)"
|
|
92
92
|
if [ -z "$found" ]; then
|
|
93
93
|
echo "plan-todos: agent-state.json not found for task=$task_id" >&2
|
|
@@ -155,6 +155,23 @@ do_set() {
|
|
|
155
155
|
echo "plan-todos: every todo must be an object with string .id and .task fields" >&2
|
|
156
156
|
exit 2
|
|
157
157
|
fi
|
|
158
|
+
# Every dependency must name a todo exactly. Ids are compared as written, so
|
|
159
|
+
# `t1` against a todo `T1` would leave the dependent blocked for good; the
|
|
160
|
+
# error names the id that differs only by case.
|
|
161
|
+
local bad_deps
|
|
162
|
+
bad_deps=$(jq -r '
|
|
163
|
+
[.todos[].id] as $ids
|
|
164
|
+
| [.todos[] | .id as $owner | (.deps // [])[]
|
|
165
|
+
| select((type != "string") or (. as $d | $ids | index($d) | not))
|
|
166
|
+
| . as $d
|
|
167
|
+
| ($ids | map(select(($d | type) == "string" and ascii_downcase == ($d | ascii_downcase)))) as $near
|
|
168
|
+
| "\($owner) depends on \($d | tojson), which is no todo id"
|
|
169
|
+
+ (if ($near | length) > 0 then " (did you mean \($near | map(tojson) | join(", "))?)" else "" end)]
|
|
170
|
+
| .[]' <<<"$plan_blob" 2>/dev/null)
|
|
171
|
+
if [ -n "$bad_deps" ]; then
|
|
172
|
+
printf 'plan-todos: %s\n' "$bad_deps" >&2
|
|
173
|
+
exit 2
|
|
174
|
+
fi
|
|
158
175
|
local state_path; state_path=$(resolve_state "$task_id")
|
|
159
176
|
local now; now=$(iso_now)
|
|
160
177
|
local new
|
|
@@ -107,12 +107,10 @@ if [ -z "$TASK_ID" ]; then
|
|
|
107
107
|
fi
|
|
108
108
|
|
|
109
109
|
# Resolve agent-state.json. multi-repo-pipeline.sh writes it under a
|
|
110
|
-
# per-project directory ($HOME/.claude/logs/multi-agent/{project}/{taskId}/)
|
|
111
|
-
# -
|
|
112
|
-
#
|
|
113
|
-
#
|
|
114
|
-
# write flat, so on a real machine the majority of runs resolved to nothing and
|
|
115
|
-
# this script reported "no agent-state.json" for a run whose state existed.
|
|
110
|
+
# per-project directory ($HOME/.claude/logs/multi-agent/{project}/{taskId}/),
|
|
111
|
+
# while phase-tracker.sh and most Phase 0 paths write it flat; no writer uses
|
|
112
|
+
# ~/.claude/projects/*/state/. ma_resolve_run_file checks both layouts, so a
|
|
113
|
+
# run whose state exists is always found.
|
|
116
114
|
AGENT_STATE="$(ma_resolve_run_file "$TASK_ID" agent-state.json 2>/dev/null || true)"
|
|
117
115
|
|
|
118
116
|
if [ -z "$AGENT_STATE" ]; then
|
|
@@ -77,7 +77,7 @@ free_savings() {
|
|
|
77
77
|
since=$(( $(date +%s) - 7 * 86400 ))
|
|
78
78
|
jq -rs --argjson since "$since" --slurpfile ct "$COST_TABLE" '
|
|
79
79
|
map(select((.ts | sub("\\.[0-9]+Z$"; "Z") | fromdateiso8601? // 0) >= $since))
|
|
80
|
-
| ($ct[0].prices.haiku // {inPerMtok:
|
|
80
|
+
| ($ct[0].prices.haiku // {inPerMtok: 0.5, outPerMtok: 2.5}) as $h
|
|
81
81
|
| {
|
|
82
82
|
n: length,
|
|
83
83
|
ok: (map(select(.ok and (.cached | not))) | length),
|
|
@@ -227,11 +227,10 @@ do_prune() {
|
|
|
227
227
|
printf 'shadow-git: pruned shadow repo for %s\n' "$task_id" >&2
|
|
228
228
|
else
|
|
229
229
|
[ ! -d "$sd/.git" ] && { err "no shadow for $task_id"; exit 1; }
|
|
230
|
-
# Retention never touches a real work-tree:
|
|
231
|
-
#
|
|
232
|
-
#
|
|
233
|
-
#
|
|
234
|
-
# for a "keep the last N days" policy. Every git call below is
|
|
230
|
+
# Retention never touches a real work-tree: a `reset --hard` with
|
|
231
|
+
# --work-tree=$(pwd) would silently rewrite whatever directory prune is
|
|
232
|
+
# invoked from. It keeps every commit inside the window and drops the
|
|
233
|
+
# older ones, as a "keep the last N days" policy requires. Every git call below is
|
|
235
234
|
# git-dir-only plumbing (log/rev-parse/commit-tree/update-ref/gc - no
|
|
236
235
|
# checkout, no reset, no clean); the one --work-tree `sg` still wants
|
|
237
236
|
# points at $sd itself, which prune already owns.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
# Cross-CLI Contract (Claude Code · Copilot CLI · Codex CLI)
|
|
2
2
|
|
|
3
3
|
<!-- toc -->
|
|
4
|
-
- [1. Command Inventory (
|
|
4
|
+
- [1. Command Inventory (66 commands)](#1-command-inventory-66-commands)
|
|
5
5
|
- [2. Canonical Placeholder Vocabulary](#2-canonical-placeholder-vocabulary)
|
|
6
6
|
- [2.6 Intentional structural divergence - thin dispatcher vs inlined orchestrator](#26-intentional-structural-divergence---thin-dispatcher-vs-inlined-orchestrator)
|
|
7
7
|
- [2.7 One command, three different meanings: `/multi-agent:model`](#27-one-command-three-different-meanings-multi-agentmodel)
|
|
@@ -20,12 +20,12 @@
|
|
|
20
20
|
|
|
21
21
|
---
|
|
22
22
|
|
|
23
|
-
## 1. Command Inventory (
|
|
23
|
+
## 1. Command Inventory (66 commands)
|
|
24
24
|
|
|
25
25
|
```
|
|
26
26
|
analysis, analysis-jira, analysis-resolve, autopilot, autopilot-off,
|
|
27
27
|
autopilot-on, autopilot-status, bug-bash, build-optimize, channels, complaint-analysis,
|
|
28
|
-
create-jira, design-check, diff-explain, doctor, estimate, feedback, forget,
|
|
28
|
+
create-jira, deps, design-check, diff-explain, doctor, estimate, feedback, forget,
|
|
29
29
|
garbage-collect, graph, help, ios-coding-standard, issue, jira, kill,
|
|
30
30
|
language, log, manual-test, model, postmortem, prune-logs,
|
|
31
31
|
prune-prompts, purge, refactor, research, resume, review,
|
|
@@ -40,7 +40,7 @@ Categories:
|
|
|
40
40
|
|
|
41
41
|
- **Interactive pickers** (single-purpose, not modes): `jira`, `issue`
|
|
42
42
|
- **Issue generator** (one-shot, no worktree, asks type Task/Bug/Story, hard approval gate before create): `create-jira`
|
|
43
|
-
- **Pipeline entries**: `autopilot` (plus the bare `/multi-agent` in the dispatcher). The phase set is a property of the command, and every mode runs its whole set.
|
|
43
|
+
- **Pipeline entries**: `autopilot`, `deps` (plus the bare `/multi-agent` in the dispatcher). The phase set is a property of the command, and every mode runs its whole set.
|
|
44
44
|
- **Tail path** (the pipeline tail over work already on a branch, no run behind it): `resume`
|
|
45
45
|
- **Ops commands** (one-shot, no worktree): `status`, `log`, `kill`, `steer`, `purge`, `uninstall`, `resume`, `review`, `review-jira`, `review-issue`, `analysis`, `analysis-resolve`, `research`, `scaffold`, `complaint-analysis`, `bug-bash`, `build-optimize`, `channels`, `scan`, `search`, `diff-explain`, `garbage-collect`, `graph`, `postmortem`, `prune-logs`, `prune-prompts`, `serve`
|
|
46
46
|
- **Local audits** (worktree only to build; no commit, push, PR or channels): `design-check`, `testflight-validation`, `ios-coding-standard`. `testflight-validation` additionally never invokes `altool --upload-app` - a validation run must not be able to ship a build by accident.
|
|
@@ -262,8 +262,8 @@ that quietly no-ops is worse than one that says it cannot act.
|
|
|
262
262
|
|
|
263
263
|
| Host | What `model on|off` does | Why |
|
|
264
264
|
|---|---|---|
|
|
265
|
-
| Claude Code | live switch: flips `modelFallback.fableEnabled` and realigns `costBudget.pricingModel` | the only host where the `fable` rung is Fable 5 |
|
|
266
|
-
| Copilot CLI | writes the preference, changes no dispatch | Fable
|
|
265
|
+
| Claude Code | live switch: flips `modelFallback.fableEnabled` and realigns `costBudget.pricingModel` | the only host where the `fable` rung is Fable 5.1 |
|
|
266
|
+
| Copilot CLI | writes the preference, changes no dispatch | Fable is not offered there; its personas never sat on this rung |
|
|
267
267
|
| Codex CLI | writes the preference, changes no dispatch, **deliberately** | the `fable` rung on Codex means `gpt-5.6 @ xhigh` - a different model on a different account. A knob named after an Anthropic model must not silently retune a Codex run |
|
|
268
268
|
|
|
269
269
|
`model-rung.sh` prints which of the three it is on every invocation. The rule it
|
|
@@ -440,9 +440,8 @@ what keeps a secret off argv and what writes the audit entry.
|
|
|
440
440
|
something that is not a timestamp.
|
|
441
441
|
- `sed -E`, never `-r`; `sed -i ''` when editing in place.
|
|
442
442
|
|
|
443
|
-
Clipboard callers may use `pbpaste` / `pbcopy` directly;
|
|
444
|
-
|
|
445
|
-
installs on.
|
|
443
|
+
Clipboard callers may use `pbpaste` / `pbcopy` directly; a `command -v` guard
|
|
444
|
+
for other clipboard tools would serve hosts this package does not install on.
|
|
446
445
|
|
|
447
446
|
---
|
|
448
447
|
|
|
@@ -46,6 +46,10 @@ discovered later:
|
|
|
46
46
|
- A host with no such transcripts (Copilot, Codex) reports `UNMEASURED`, never
|
|
47
47
|
zero. Zero would read as "you spent nothing" when it means "I could not see".
|
|
48
48
|
|
|
49
|
+
A record is priced by its exact wire ID: a rung's `modelId`, a Copilot CLI
|
|
50
|
+
`copilotModelId` at its own model's rate from the table's `models` map, or a
|
|
51
|
+
previous-generation ID in the table's `legacy` map at that ID's own rate. A
|
|
52
|
+
dated snapshot (`<id>-<date>`) prices as the longest known ID it extends.
|
|
49
53
|
Records whose model is not in `cost-table.json` are COUNTED as unpriced and left
|
|
50
54
|
out of the total. Folding them in at zero would make an unknown model look free,
|
|
51
55
|
which is the direction that hurts.
|