@mmerterden/multi-agent-pipeline 10.4.0 → 10.6.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 +66 -0
- package/README.md +13 -13
- package/package.json +1 -1
- package/pipeline/agents/android-architect.md +3 -3
- package/pipeline/agents/backend-architect.md +3 -3
- package/pipeline/agents/code-reviewer.md +3 -3
- package/pipeline/agents/ios-architect.md +3 -3
- package/pipeline/commands/multi-agent/finish.md +4 -4
- package/pipeline/commands/multi-agent/help.md +4 -4
- package/pipeline/commands/multi-agent/refs/features/model-fallback.md +18 -10
- package/pipeline/commands/multi-agent/setup.md +18 -0
- package/pipeline/commands/multi-agent/stack.md +71 -25
- package/pipeline/commands/multi-agent/sync.md +48 -4
- package/pipeline/commands/multi-agent/update.md +14 -1
- package/pipeline/scripts/README.md +0 -1
- package/pipeline/scripts/build-stack-plugins.mjs +137 -0
- package/pipeline/scripts/smoke-model-fallback.sh +11 -10
- package/pipeline/skills/shared/core/multi-agent-finish/SKILL.md +1 -1
- package/pipeline/skills/shared/core/multi-agent-stack/SKILL.md +31 -36
- package/pipeline/skills/shared/core/multi-agent-sync/SKILL.md +2 -1
- package/pipeline/skills/shared/core/multi-agent-update/SKILL.md +2 -0
- package/pipeline/scripts/smoke-stack-swap.sh +0 -132
- package/pipeline/scripts/stack-swap.sh +0 -182
package/CHANGELOG.md
CHANGED
|
@@ -14,6 +14,72 @@ Internal file-layout changes that don't affect the slash-command surface are sti
|
|
|
14
14
|
|
|
15
15
|
---
|
|
16
16
|
|
|
17
|
+
## [10.6.0] - 2026-07-02
|
|
18
|
+
|
|
19
|
+
Fable 5 restored as the top model tier; `stack-swap` fully removed; setup gains a default stack step.
|
|
20
|
+
|
|
21
|
+
### Added
|
|
22
|
+
|
|
23
|
+
- **`multi-agent:setup` Step 9 — default stack plugin enablement.** First-run
|
|
24
|
+
setup detects the project stack from markers (`.xcodeproj`/`Package.swift` → iOS,
|
|
25
|
+
`build.gradle` → Android, `package.json`+react → Frontend, `requirements.txt`/
|
|
26
|
+
`pyproject.toml` → Backend) and enables the matching marketplace plugin plus the
|
|
27
|
+
always-on `ai-common-engineering-toolkit`. **No clear marker → default iOS.** So a
|
|
28
|
+
fresh install works out of the box and a repo at any org gets its correct stack.
|
|
29
|
+
|
|
30
|
+
### Changed
|
|
31
|
+
|
|
32
|
+
- **Fable 5 is the top model tier again.** Architect (`ios/android/backend-architect`)
|
|
33
|
+
and Reviewer-1 (`code-reviewer`) personas declare `preferredModel: fable`. The tier
|
|
34
|
+
ladder is now `fable → opus → sonnet → haiku`: **if Fable 5 is unavailable, the first
|
|
35
|
+
fallback is Opus 4.8**, applied per-dispatch with no file edits. Security personas keep
|
|
36
|
+
opus. Reverses the 2026-06 "fable retired" state now that `claude-fable-5` is available.
|
|
37
|
+
|
|
38
|
+
### Removed
|
|
39
|
+
|
|
40
|
+
- **`stack-swap.sh` + `smoke-stack-swap.sh` deleted.** The SessionStart skill-dir-swap
|
|
41
|
+
mechanic is gone entirely; stack selection is marketplace-plugin enablement
|
|
42
|
+
(`/multi-agent:stack`). No dead code or legacy hook remains.
|
|
43
|
+
|
|
44
|
+
### Fixed
|
|
45
|
+
|
|
46
|
+
- Genericized a leaked corporate Jira key (`DIJITAL` → `PROJ`/`{JIRA_KEY}`) in the
|
|
47
|
+
`finish` command + skill so the personal-data gate passes.
|
|
48
|
+
|
|
49
|
+
## [10.5.0] - 2026-07-02
|
|
50
|
+
|
|
51
|
+
Stack skills move from the local `stack-swap` mechanic to versioned marketplace plugins.
|
|
52
|
+
|
|
53
|
+
### Added
|
|
54
|
+
|
|
55
|
+
- **`build-stack-plugins.mjs`** — rebuilds each stack plugin's `knowledge/`
|
|
56
|
+
layer in the `{owner}/multi-agent-plugins` marketplace from the pipeline's
|
|
57
|
+
authoring source (`pipeline/skills/shared/external/`), regenerates each
|
|
58
|
+
`plugin.json` `skills[]`, and **bumps the patch version of any plugin whose
|
|
59
|
+
skill set changed**. Idempotent (`--dry-run` supported); a no-op run bumps
|
|
60
|
+
nothing. Cross-stack skills (accessibility audit, humanizer, Firebase) route
|
|
61
|
+
to `ai-common-engineering-toolkit`; Apple/Xcode-only skills stay in the iOS
|
|
62
|
+
plugin. This is the version-based-management backbone: the pipeline is the
|
|
63
|
+
single authoring source, the marketplace is a derived, versioned artifact.
|
|
64
|
+
- **`multi-agent:sync` Step 3c (PLUGINS)** — runs the generator, then commits +
|
|
65
|
+
pushes the plugins repo when a plugin version was bumped.
|
|
66
|
+
|
|
67
|
+
### Changed
|
|
68
|
+
|
|
69
|
+
- **`/multi-agent:stack`** — selecting a stack no longer moves skill directories
|
|
70
|
+
via `stack-swap.sh`. It now enables the matching marketplace plugin(s) (stack
|
|
71
|
+
toolkit + `ai-common-engineering-toolkit`) in the current repo's
|
|
72
|
+
`.claude/settings.json` `enabledPlugins`, disabling the stack toolkits that
|
|
73
|
+
don't apply. Declarative, per-repo, versioned. No SessionStart hook.
|
|
74
|
+
- **`/multi-agent:update`** — added a step that refreshes the plugin marketplace
|
|
75
|
+
(`claude marketplace update multi-agent-plugins`) so the latest published
|
|
76
|
+
plugin versions are picked up alongside the pipeline update.
|
|
77
|
+
|
|
78
|
+
### Deprecated
|
|
79
|
+
|
|
80
|
+
- **`stack-swap.sh`** — no longer wired to any SessionStart hook. Retained for
|
|
81
|
+
manual/offline use only; stack selection is now plugin enablement.
|
|
82
|
+
|
|
17
83
|
## [10.4.0] - 2026-07-02
|
|
18
84
|
|
|
19
85
|
New `finish` command: run the pipeline tail over work you already did locally.
|
package/README.md
CHANGED
|
@@ -528,7 +528,7 @@ Stack is auto-detected. Build commands, test runners, lint tools, and review foc
|
|
|
528
528
|
| Fastest | `/multi-agent:dev-autopilot "task"` | `multi-agent-dev-autopilot "task"` | Zero interaction |
|
|
529
529
|
| Test | `/multi-agent:test` | `multi-agent-test` | UI Bug Hunter - visual + accessibility |
|
|
530
530
|
| Channels | `/multi-agent:channels <target>` | `multi-agent-channels <target>` | Post report to Jira / Confluence / Wiki / PR (multi-select, humanizer pass, reviewer-preserving) |
|
|
531
|
-
| Stack | `/multi-agent:stack ios` | `multi-agent-stack ios` |
|
|
531
|
+
| Stack | `/multi-agent:stack ios` | `multi-agent-stack ios` | Select stack by enabling the matching marketplace plugin(s) |
|
|
532
532
|
| Language | `/multi-agent:language [prompt\|output] <en\|tr>` | `multi-agent-language [prompt\|output] <en\|tr>` | Toggle `promptLanguage` (interactive prompts) and/or `outputLanguage` (assistant explanations). External payloads stay English. |
|
|
533
533
|
|
|
534
534
|
## UI Bug Hunter + Audit Tools
|
|
@@ -563,22 +563,22 @@ All audits run via **direct Bash commands** - no MCP server dependency. Pipeline
|
|
|
563
563
|
|
|
564
564
|
**No external dependencies** - only standard Xcode CLI tools (iOS) and Android SDK (Android). Platform guides include **compliance rules** that map 1:1 to audit checks - follow the guide, pass the audit.
|
|
565
565
|
|
|
566
|
-
## Stack
|
|
566
|
+
## Stack Selection (marketplace plugins)
|
|
567
567
|
|
|
568
|
-
Stack
|
|
568
|
+
Stack skills ship as versioned plugins in the `{owner}/multi-agent-plugins` marketplace. Selecting a stack **enables the matching plugin(s)** in the repo's `.claude/settings.json` `enabledPlugins` — the stack toolkit plus `ai-common-engineering-toolkit` (cross-stack skills). This replaced the old `stack-swap.sh` mechanic (which physically moved skill directories on a SessionStart hook); enablement is now declarative, per-repo, and versioned.
|
|
569
569
|
|
|
570
570
|
```bash
|
|
571
571
|
# Claude Code # Copilot CLI
|
|
572
|
-
/multi-agent:stack multi-agent-stack # show
|
|
573
|
-
/multi-agent:stack ios multi-agent-stack ios # SwiftUI +
|
|
574
|
-
/multi-agent:stack android multi-agent-stack android # Compose +
|
|
575
|
-
/multi-agent:stack backend multi-agent-stack backend # Python/Node
|
|
576
|
-
/multi-agent:stack frontend multi-agent-stack frontend # React/
|
|
577
|
-
/multi-agent:stack mobile multi-agent-stack mobile # iOS + Android
|
|
578
|
-
/multi-agent:stack all multi-agent-stack all #
|
|
572
|
+
/multi-agent:stack multi-agent-stack # show enabled plugins
|
|
573
|
+
/multi-agent:stack ios multi-agent-stack ios # SwiftUI toolkit + common
|
|
574
|
+
/multi-agent:stack android multi-agent-stack android # Compose toolkit + common
|
|
575
|
+
/multi-agent:stack backend multi-agent-stack backend # Python/Node toolkit + common
|
|
576
|
+
/multi-agent:stack frontend multi-agent-stack frontend # React/TSX toolkit + common
|
|
577
|
+
/multi-agent:stack mobile multi-agent-stack mobile # iOS + Android + common
|
|
578
|
+
/multi-agent:stack all multi-agent-stack all # all four toolkits + common
|
|
579
579
|
```
|
|
580
580
|
|
|
581
|
-
|
|
581
|
+
Add the marketplace once with `claude marketplace add {owner}/multi-agent-plugins`. Newly published plugin versions are pulled by `/multi-agent:update`. The plugins are rebuilt from `pipeline/skills/shared/external/` via `pipeline/scripts/build-stack-plugins.mjs` (run by `multi-agent:sync` Step 3c), which bumps the patch version of any plugin whose skill set changed. The old `stack-swap.sh` mechanic has been removed.
|
|
582
582
|
|
|
583
583
|
## Setup
|
|
584
584
|
|
|
@@ -638,7 +638,7 @@ Runs unit tests, smoke suites, eval fixtures, schema validation, and lint - the
|
|
|
638
638
|
| Script | Purpose |
|
|
639
639
|
| ---------------------- | ------------------------------------------------ |
|
|
640
640
|
| `pre-commit-check.sh` | Secret detection before commits |
|
|
641
|
-
| `stack-
|
|
641
|
+
| `build-stack-plugins.mjs` | Rebuild stack plugins from `shared/external`, bump changed plugin versions |
|
|
642
642
|
| `keychain-save.sh` | Save tokens/JSON to macOS Keychain (interactive) |
|
|
643
643
|
| `keychain.py` | Deterministic Python Keychain helper (get/set/delete/list/doctor); shell driver auto-delegates on macOS/Linux |
|
|
644
644
|
| `github-ssh-setup.sh` | GitHub SSH key generation + config |
|
|
@@ -783,7 +783,7 @@ pipeline/
|
|
|
783
783
|
01-10/ 10 adversarial eval fixtures
|
|
784
784
|
scripts/
|
|
785
785
|
pre-commit-check.sh Secret detection hook
|
|
786
|
-
stack-
|
|
786
|
+
build-stack-plugins.mjs Rebuild stack plugins + version bump
|
|
787
787
|
keychain-save.sh Save tokens/JSON to macOS Keychain
|
|
788
788
|
github-ssh-setup.sh GitHub SSH key generation + setup
|
|
789
789
|
ui-tree-dumper.swift iOS accessibility tree dumper
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@mmerterden/multi-agent-pipeline",
|
|
3
|
-
"version": "10.
|
|
3
|
+
"version": "10.6.0",
|
|
4
4
|
"description": "8-phase AI development pipeline with full orchestration on Claude Code, Copilot CLI, Cursor, Antigravity, and VS Code Copilot Chat. Analysis, planning, TDD, CLI-aware parallel review with consensus surfacing + Opus 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,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Android architect - evaluates design decisions, patterns, and module structure
|
|
3
|
-
model:
|
|
4
|
-
preferredModel:
|
|
5
|
-
modelRationale: "Architecture decisions across Gradle modules, Compose stability, Hilt graphs, and migration paths run on
|
|
3
|
+
model: fable
|
|
4
|
+
preferredModel: fable
|
|
5
|
+
modelRationale: "Architecture decisions across Gradle modules, Compose stability, Hilt graphs, and migration paths run on fable, the top tier (opus is the first fallback). No downgrade recommended."
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
You are a senior Android architect with deep expertise in large-scale modular Android applications.
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: Backend architect - evaluates API design, data modeling, and system architecture
|
|
3
|
-
model:
|
|
4
|
-
preferredModel:
|
|
5
|
-
modelRationale: "API design + migration safety + scaling analysis are top-tier concerns;
|
|
3
|
+
model: fable
|
|
4
|
+
preferredModel: fable
|
|
5
|
+
modelRationale: "API design + migration safety + scaling analysis are top-tier concerns; fable is the top tier (opus is the first fallback) and handles concurrent-write / rollback edge cases in database migration reviews."
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
You are a senior backend architect with expertise in API design, distributed systems, and data modeling.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "Code reviewer for multi-agent Phase 4 - security, architecture, quality, performance. Default model is opus; Phase 4 orchestrator overrides to sonnet for Reviewer 3."
|
|
3
|
-
model:
|
|
4
|
-
preferredModel:
|
|
2
|
+
description: "Code reviewer for multi-agent Phase 4 - security, architecture, quality, performance. Default model is fable (opus is the first fallback); Phase 4 orchestrator overrides to sonnet for Reviewer 3."
|
|
3
|
+
model: fable
|
|
4
|
+
preferredModel: fable
|
|
5
5
|
modelRationale: "Reviewer 1 tier - deep security + architecture review runs on opus (top available intelligence tier). Phase 4 orchestrator overrides to sonnet for Reviewer 3 (quality/correctness focus) via CLAUDE_CODE_SUBAGENT_MODEL before dispatch. Copilot CLI adds Reviewer 2 on gpt-5.4 for cross-model diversity."
|
|
6
6
|
---
|
|
7
7
|
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
description: iOS architect - evaluates design decisions, patterns, and module structure
|
|
3
|
-
model:
|
|
4
|
-
preferredModel:
|
|
5
|
-
modelRationale: "Architecture decisions require deep reasoning across modules, protocols, and migration paths -
|
|
3
|
+
model: fable
|
|
4
|
+
preferredModel: fable
|
|
5
|
+
modelRationale: "Architecture decisions require deep reasoning across modules, protocols, and migration paths - fable is the top tier (opus is the first fallback). No downgrade recommended; if cost is a concern, skip the architect consultation entirely."
|
|
6
6
|
---
|
|
7
7
|
|
|
8
8
|
You are a senior iOS architect with deep expertise in large-scale modular iOS applications.
|
|
@@ -24,7 +24,7 @@ You already did the work locally - wrote code on the current branch and maybe
|
|
|
24
24
|
|
|
25
25
|
```bash
|
|
26
26
|
/multi-agent:finish # current branch vs its base; resolve Jira id from branch name
|
|
27
|
-
/multi-agent:finish
|
|
27
|
+
/multi-agent:finish PROJ-12345 # bind to an explicit Jira id for the Phase 7 comment
|
|
28
28
|
/multi-agent:finish --base develop # override the base branch for the diff
|
|
29
29
|
/multi-agent:finish autopilot # no gate prompts: auto-fix blocking findings, auto-PR, auto-comment
|
|
30
30
|
```
|
|
@@ -45,7 +45,7 @@ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - `finish` treats
|
|
|
45
45
|
|
|
46
46
|
1. **Project + branch:** detect project (cwd), current branch (`git branch --show-current`). No worktree; work stays on the current branch.
|
|
47
47
|
2. **Base + diff:** resolve base branch in order: `--base <arg>` → `figma-config.project.baseBranch` → `develop` → the branch's upstream/merge-base. The **work under review** is `git diff <base>...HEAD` PLUS uncommitted working-tree changes (`git status`). Abort with a clear message if the diff is empty (`ERR: no local work to finish on <branch> vs <base>`).
|
|
48
|
-
3. **Task binding:** Jira id from the `--`/positional arg, else parse the branch name (`bugfix/
|
|
48
|
+
3. **Task binding:** Jira id from the `--`/positional arg, else parse the branch name (`bugfix/PROJ-XXXX` / `feature/PROJ-XXXX`); `taskType` inferred from the diff (bugfix/feature/refactor/chore) for the report wording. GitHub issue `#N` from branch/arg when present.
|
|
49
49
|
4. **Prior state (optional):** if an `agent-state.json` / tracker-state exists for this branch (left by a prior `dev-local`/`local` run), load its analysis summary + Jira/issue binding to enrich the report; otherwise synthesize a minimal state over the diff. Never require a prior full-pipeline run.
|
|
50
50
|
5. Persist state under `.claude/logs/multi-agent/{project}/{taskId}/` (same as `--local`).
|
|
51
51
|
|
|
@@ -55,7 +55,7 @@ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - `finish` treats
|
|
|
55
55
|
- interactive: present them and ask (`AskUserQuestion`) whether to fix now (loop back through a minimal Phase-3-style TDD fix) or proceed;
|
|
56
56
|
- `autopilot` (or `prefs.global.finish.autoFix == true`): auto-fix accepted blocking/important findings, then re-review the fix, before advancing.
|
|
57
57
|
- **Phase 5 Build+Test** — the **automated success gate** (this is what "build+test success" means here; the interactive device user-test is `/multi-agent:manual-test`). Stack-aware: build via `figma-config.build` (iOS scheme / Android gradle / detected backend/frontend build) and run the existing test suite if present (`swift test` / `xcodebuild test` / `./gradlew test` / `pytest` / `npm test` / `vitest`). Require success to advance; on failure, surface logs and (interactive) stop or (autopilot) attempt a bounded fix loop. **If the repo has no tests, report "no tests present" — never fabricate test results.**
|
|
58
|
-
- **Phase 6 Commit/PR** — per `refs/phases/phase-6-commit.md`: stage + commit any remaining local changes with a conventional message (`{type}(scope): desc [
|
|
58
|
+
- **Phase 6 Commit/PR** — per `refs/phases/phase-6-commit.md`: stage + commit any remaining local changes with a conventional message (`{type}(scope): desc [{JIRA_KEY}-{id}]`), push, and open a PR **only if one does not already exist** for the branch. PR body per `refs/pipeline-output-formatting` and `rules/git-conventions` — `Ref: #N` / `Related: #N`, never `Closes/Fixes/Resolves`; NO AI/bot attribution anywhere.
|
|
59
59
|
- **Phase 7 Report** — per `refs/phases/phase-7-report.md` + `channels.md`: produce the **technical analysis** and **test scenarios**, then post to the configured channels. Default content for `finish`: a Jira **comment** carrying the technical analysis + the test scenarios (and, when the PR was opened, the PR description). Every body runs through the humanizer; bot/tool/AI signatures are FORBIDDEN in comments.
|
|
60
60
|
|
|
61
61
|
## Modes
|
|
@@ -92,7 +92,7 @@ No TaskList widget. After every state change call `bash $HOME/.claude/scripts/ph
|
|
|
92
92
|
## Examples
|
|
93
93
|
|
|
94
94
|
```bash
|
|
95
|
-
/multi-agent:dev-local "
|
|
95
|
+
/multi-agent:dev-local "PROJ-12345" # develop locally (Init→Dev→Commit→Report, no review/test)
|
|
96
96
|
# … you inspect / hand-test the change …
|
|
97
97
|
/multi-agent:finish # now: review + build/test + PR + Jira analysis & test scenarios
|
|
98
98
|
```
|
|
@@ -120,7 +120,7 @@ Setup & Maintenance:
|
|
|
120
120
|
|
|
121
121
|
/multi-agent:setup First-run wizard - Keychain tokens + Git identity + language
|
|
122
122
|
/multi-agent:language [en|tr] Show or set outputLanguage (promptLanguage stays English)
|
|
123
|
-
/multi-agent:stack <id>
|
|
123
|
+
/multi-agent:stack <id> Select stack by enabling the matching marketplace plugin(s) (ios / android / backend / frontend / fullstack / all)
|
|
124
124
|
/multi-agent:sync Sync ecosystem (Claude Code + Copilot CLI + pipeline + website + remote-control)
|
|
125
125
|
/multi-agent:update Pull latest pipeline + reinstall + run migrations
|
|
126
126
|
/multi-agent:delete Uninstall pipeline from every CLI (Keychain tokens left intact, double confirm)
|
|
@@ -177,7 +177,7 @@ Key Features:
|
|
|
177
177
|
|
|
178
178
|
Multi-Platform iOS, Android, Backend, Frontend - auto-detected
|
|
179
179
|
Build Queue xcodebuild/Gradle serialized with lock file - parallel safe
|
|
180
|
-
Stack Aware Auto-detects iOS/Android/Python/Node/Go/Docker,
|
|
180
|
+
Stack Aware Auto-detects iOS/Android/Python/Node/Go/Docker, uses the enabled stack plugin's skills
|
|
181
181
|
Det. Gates Build + lint + test + secret scan BEFORE AI review
|
|
182
182
|
Multi-Repo Per-repo worktrees, per-repo identity, integration build before commit
|
|
183
183
|
Identity Routing Git identity auto-picked from repo origin URL (corporate vs personal)
|
|
@@ -327,7 +327,7 @@ Setup & Maintenance:
|
|
|
327
327
|
|
|
328
328
|
/multi-agent:setup İlk kurulum sihirbazı - Keychain token + Git kimliği + dil
|
|
329
329
|
/multi-agent:language [en|tr] outputLanguage'ı göster veya ayarla (promptLanguage İngilizce kalır)
|
|
330
|
-
/multi-agent:stack <id>
|
|
330
|
+
/multi-agent:stack <id> Stack'i eşleşen marketplace plugin'i etkinleştirerek seç (ios / android / backend / frontend / fullstack / all)
|
|
331
331
|
/multi-agent:sync Ekosistemi senkronize et (Claude Code + Copilot CLI + pipeline + website + remote-control)
|
|
332
332
|
/multi-agent:update En son pipeline'ı çek + reinstall + migration çalıştır
|
|
333
333
|
/multi-agent:delete Pipeline'ı tüm CLI'lerden kaldır (Keychain token dokunulmaz, çift onay)
|
|
@@ -384,7 +384,7 @@ Temel Özellikler:
|
|
|
384
384
|
|
|
385
385
|
Multi-Platform iOS, Android, Backend, Frontend - otomatik tespit
|
|
386
386
|
Build Queue xcodebuild/Gradle lock file ile seri - parallel güvenli
|
|
387
|
-
Stack Aware iOS/Android/Python/Node/Go/Docker algılanır,
|
|
387
|
+
Stack Aware iOS/Android/Python/Node/Go/Docker algılanır, etkin stack plugin'inin skilleri kullanılır
|
|
388
388
|
Det. Gates AI review'dan ÖNCE build + lint + test + secret scan
|
|
389
389
|
Multi-Repo Repo başına worktree, repo başına identity, commit öncesi entegrasyon build'i
|
|
390
390
|
Identity Routing Repo origin URL'sinden git kimliği seçimi (kurumsal vs kişisel)
|
|
@@ -1,22 +1,30 @@
|
|
|
1
1
|
# Model Fallback Contract (v10.1.0)
|
|
2
2
|
|
|
3
|
-
Personas
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
Personas route to the top available intelligence tier they declare in
|
|
4
|
+
`preferredModel`. That tier can be quota-limited or temporarily unavailable.
|
|
5
|
+
This contract defines when and how the orchestrator falls back, deterministically,
|
|
6
|
+
without ever editing persona files at runtime.
|
|
7
7
|
|
|
8
|
-
> **Fable
|
|
9
|
-
>
|
|
10
|
-
>
|
|
11
|
-
>
|
|
12
|
-
>
|
|
8
|
+
> **Fable 5 available again (2026-07).** `claude-fable-5` is the top tier once
|
|
9
|
+
> more. Architect (`ios/android/backend-architect`), Reviewer-1 (`code-reviewer`),
|
|
10
|
+
> and triage personas declare `preferredModel: fable` — the deepest-reasoning
|
|
11
|
+
> roles. **If Fable 5 is unavailable, the first fallback is opus (`claude-opus-4-8`).**
|
|
12
|
+
> Security and other `preferredModel: opus` personas keep opus as their top tier.
|
|
13
|
+
> The `premiumTierUntil` date gate stays in the contract as a generic mechanism
|
|
14
|
+
> for any plan-window-limited premium tier.
|
|
13
15
|
|
|
14
16
|
## Tier ladder
|
|
15
17
|
|
|
16
18
|
```
|
|
17
|
-
opus -> sonnet -> haiku
|
|
19
|
+
fable -> opus -> sonnet -> haiku
|
|
18
20
|
```
|
|
19
21
|
|
|
22
|
+
The orchestrator walks **one step down per trigger** from whichever tier a
|
|
23
|
+
persona prefers: a `fable` persona degrades `fable -> opus` first, then
|
|
24
|
+
`opus -> sonnet`, then `sonnet -> haiku`; an `opus` persona starts at
|
|
25
|
+
`opus -> sonnet`. So a Fable 5 outage transparently promotes Opus 4.8 into the
|
|
26
|
+
architect/reviewer roles with no file edits.
|
|
27
|
+
|
|
20
28
|
One step down per trigger, walking the ladder until a tier dispatches or the
|
|
21
29
|
floor (`haiku`) is reached. `haiku` is the last-resort floor: a run that reaches
|
|
22
30
|
it is heavily degraded but still makes progress instead of hard-halting because
|
|
@@ -800,3 +800,21 @@ Offer to make the secret scan a HARD pre-commit gate (a non-zero exit blocks the
|
|
|
800
800
|
- On Yes, deep-merge the template's `hooks.PreToolUse` into the user's `settings.json` (preserve any existing hooks; do not duplicate a matcher that already calls `pre-commit-check.sh`).
|
|
801
801
|
- Honest note to show: this is the only deterministic gate that is OS-enforceable as a hook (it needs no run-specific arguments). The evidence / consensus / intent / learnings gates are invoked by the pipeline phases with per-run arguments, so they are enforced by the phase contract + the installed gate scripts, not by a hook.
|
|
802
802
|
- On the adapter platforms (Cursor / Antigravity / VS Code Copilot Chat) there is no PreToolUse equivalent; the gate scripts live in `~/.multi-agent/` and are run as workflow steps. See `refs/picker-contract.md`.
|
|
803
|
+
### Step 9 - Default stack plugin enablement
|
|
804
|
+
|
|
805
|
+
Stack skills ship as versioned plugins in the `{owner}/multi-agent-plugins` marketplace. On first setup, wire the stack so the pipeline works out of the box.
|
|
806
|
+
|
|
807
|
+
1. Ensure the marketplace is known (idempotent):
|
|
808
|
+
```bash
|
|
809
|
+
claude marketplace add {owner}/multi-agent-plugins 2>/dev/null || true
|
|
810
|
+
```
|
|
811
|
+
2. Detect the project stack from markers and enable the matching plugin(s) plus the always-on common plugin in the project's `.claude/settings.json` `enabledPlugins`:
|
|
812
|
+
- `.xcodeproj` / `Package.swift` / `*.xcworkspace` → `ai-ios-engineering-toolkit`
|
|
813
|
+
- `build.gradle` / `settings.gradle` → `ai-android-engineering-toolkit`
|
|
814
|
+
- `package.json` with `react`/`next` → `ai-frontend-engineering-toolkit`
|
|
815
|
+
- `requirements.txt` / `pyproject.toml` / server `package.json` → `ai-backend-toolkit`
|
|
816
|
+
- **no clear marker → default `ai-ios-engineering-toolkit`**
|
|
817
|
+
`ai-common-engineering-toolkit@multi-agent-plugins` is always set `true` alongside the stack plugin.
|
|
818
|
+
3. Report the enabled set. To change later, run `/multi-agent:stack <ios|android|frontend|backend|...>` in the repo. Pipeline Phase 1 auto-detects the stack for its own routing regardless of enablement.
|
|
819
|
+
|
|
820
|
+
The marketplace repo name (`multi-agent-plugins`) is generic; a different org points `{owner}` at its own fork — nothing in the pipeline is coupled to a specific account.
|
|
@@ -1,48 +1,94 @@
|
|
|
1
1
|
---
|
|
2
|
-
description: "
|
|
3
|
-
allowed-tools: Bash
|
|
2
|
+
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)."
|
|
3
|
+
allowed-tools: Bash, Read, Edit, Write
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# multi-agent stack -
|
|
6
|
+
# multi-agent stack - Select Stack via Plugin Enablement
|
|
7
7
|
|
|
8
|
-
|
|
8
|
+
Stack skills ship as plugins in the `{owner}/multi-agent-plugins` marketplace. Selecting a stack = **enabling the matching plugin(s)** in the current repo's `.claude/settings.json` `enabledPlugins`. The `ai-common-engineering-toolkit` (accessibility audit, humanizer, Firebase) is always enabled alongside the stack plugin.
|
|
9
|
+
|
|
10
|
+
This replaces the old `stack-swap.sh` mechanic that physically moved skill directories in `~/.claude/skills/`. There is no SessionStart hook and no directory shuffling — enablement is declarative, per-repo, and versioned.
|
|
9
11
|
|
|
10
12
|
## Usage
|
|
11
13
|
|
|
12
14
|
```bash
|
|
13
|
-
/multi-agent:stack # show
|
|
14
|
-
/multi-agent:stack ios # SwiftUI +
|
|
15
|
-
/multi-agent:stack android # Compose +
|
|
16
|
-
/multi-agent:stack mobile # iOS + Android
|
|
17
|
-
/multi-agent:stack backend # Python / Node
|
|
18
|
-
/multi-agent:stack frontend # React /
|
|
19
|
-
/multi-agent:stack fullstack # backend +
|
|
20
|
-
/multi-agent:stack all #
|
|
15
|
+
/multi-agent:stack # show which plugins are enabled here
|
|
16
|
+
/multi-agent:stack ios # SwiftUI toolkit + common
|
|
17
|
+
/multi-agent:stack android # Compose toolkit + common
|
|
18
|
+
/multi-agent:stack mobile # iOS + Android + common
|
|
19
|
+
/multi-agent:stack backend # Python / Node spec-driven toolkit + common
|
|
20
|
+
/multi-agent:stack frontend # React / TSX toolkit + common
|
|
21
|
+
/multi-agent:stack fullstack # frontend + backend + common
|
|
22
|
+
/multi-agent:stack all # all four stack toolkits + common
|
|
21
23
|
```
|
|
22
24
|
|
|
25
|
+
## Stack → plugin map
|
|
26
|
+
|
|
27
|
+
| Stack | Plugins enabled (all `@multi-agent-plugins`) |
|
|
28
|
+
|---|---|
|
|
29
|
+
| `ios` | `ai-common-engineering-toolkit`, `ai-ios-engineering-toolkit` |
|
|
30
|
+
| `android` | `ai-common-engineering-toolkit`, `ai-android-engineering-toolkit` |
|
|
31
|
+
| `frontend` | `ai-common-engineering-toolkit`, `ai-frontend-engineering-toolkit` |
|
|
32
|
+
| `backend` | `ai-common-engineering-toolkit`, `ai-backend-toolkit` |
|
|
33
|
+
| `mobile` | common + `ai-ios-engineering-toolkit` + `ai-android-engineering-toolkit` |
|
|
34
|
+
| `fullstack` | common + `ai-frontend-engineering-toolkit` + `ai-backend-toolkit` |
|
|
35
|
+
| `all` | common + all four stack toolkits |
|
|
36
|
+
|
|
23
37
|
## Behaviour
|
|
24
38
|
|
|
25
|
-
1. No arg → status mode
|
|
26
|
-
2. Arg present →
|
|
27
|
-
3.
|
|
28
|
-
4. Unknown arg → the script returns `exit 1` with an error message; do not re-prompt, show the list to the user.
|
|
39
|
+
1. **No arg → status mode.** Read `.claude/settings.json` (repo) + `~/.claude/settings.json` (global) and print which `@multi-agent-plugins` plugins are currently enabled. Do not modify anything.
|
|
40
|
+
2. **Arg present → enable mode.** Ensure the marketplace is known, then write the matching `enabledPlugins` entries into the **current repo's** `.claude/settings.json`, disabling the stack toolkits that don't belong to the selected stack. `ai-common-engineering-toolkit` is always set to `true`.
|
|
41
|
+
3. **Unknown arg** → show the list above; do not guess.
|
|
29
42
|
|
|
30
43
|
## Implementation
|
|
31
44
|
|
|
32
45
|
```bash
|
|
33
|
-
|
|
46
|
+
REPO_SETTINGS=".claude/settings.json"
|
|
47
|
+
MP="multi-agent-plugins"
|
|
48
|
+
ARG="${1:-status}"
|
|
34
49
|
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
50
|
+
# --- ensure the marketplace is known (idempotent) -------------------------
|
|
51
|
+
if ! claude marketplace list 2>/dev/null | grep -q "$MP"; then
|
|
52
|
+
claude marketplace add {owner}/multi-agent-plugins 2>/dev/null \
|
|
53
|
+
|| echo "note: add the marketplace once with: claude marketplace add {owner}/multi-agent-plugins"
|
|
38
54
|
fi
|
|
39
55
|
|
|
40
|
-
|
|
41
|
-
"
|
|
56
|
+
COMMON="ai-common-engineering-toolkit@${MP}"
|
|
57
|
+
IOS="ai-ios-engineering-toolkit@${MP}"
|
|
58
|
+
ANDROID="ai-android-engineering-toolkit@${MP}"
|
|
59
|
+
FRONTEND="ai-frontend-engineering-toolkit@${MP}"
|
|
60
|
+
BACKEND="ai-backend-toolkit@${MP}"
|
|
61
|
+
|
|
62
|
+
if [ "$ARG" = "status" ]; then
|
|
63
|
+
echo "Enabled multi-agent plugins (repo + global):"
|
|
64
|
+
{ [ -f "$REPO_SETTINGS" ] && cat "$REPO_SETTINGS"; cat "$HOME/.claude/settings.json"; } 2>/dev/null \
|
|
65
|
+
| grep -oE "ai-[a-z-]+@${MP}\"[[:space:]]*:[[:space:]]*(true|false)" | sort -u
|
|
66
|
+
exit 0
|
|
67
|
+
fi
|
|
68
|
+
|
|
69
|
+
# resolve the desired ON set
|
|
70
|
+
case "$ARG" in
|
|
71
|
+
ios) ON="$COMMON $IOS" ;;
|
|
72
|
+
android) ON="$COMMON $ANDROID" ;;
|
|
73
|
+
frontend) ON="$COMMON $FRONTEND" ;;
|
|
74
|
+
backend) ON="$COMMON $BACKEND" ;;
|
|
75
|
+
mobile) ON="$COMMON $IOS $ANDROID" ;;
|
|
76
|
+
fullstack) ON="$COMMON $FRONTEND $BACKEND" ;;
|
|
77
|
+
all) ON="$COMMON $IOS $ANDROID $FRONTEND $BACKEND" ;;
|
|
78
|
+
*) echo "Unknown stack '$ARG'. One of: ios android mobile backend frontend fullstack all"; exit 1 ;;
|
|
79
|
+
esac
|
|
42
80
|
```
|
|
43
81
|
|
|
82
|
+
After resolving `$ON`, edit `.claude/settings.json` (create `{ "enabledPlugins": {} }` if absent) so that:
|
|
83
|
+
- every plugin in `$ON` is set to `true`,
|
|
84
|
+
- every stack toolkit **not** in `$ON` is set to `false` (leave non-`@multi-agent-plugins` entries untouched),
|
|
85
|
+
- `ai-common-engineering-toolkit@multi-agent-plugins` is always `true`.
|
|
86
|
+
|
|
87
|
+
Use the Read + Edit/Write tools (JSON must stay valid). Then print the resulting `enabledPlugins` block.
|
|
88
|
+
|
|
44
89
|
## Notes
|
|
45
90
|
|
|
46
|
-
-
|
|
47
|
-
-
|
|
48
|
-
- Pipeline Phase 1 stack detection is independent
|
|
91
|
+
- Enablement is per-repo and declarative — commit `.claude/settings.json` so teammates get the same stack.
|
|
92
|
+
- Restart the conversation (or reload the window) for Claude Code to pick up newly enabled plugins.
|
|
93
|
+
- Pipeline Phase 1 stack detection is independent (it reads project files); `stack` only sets which plugin skill set is active.
|
|
94
|
+
- The old `stack-swap.sh` skill-dir swap has been removed; stack selection is entirely plugin enablement.
|
|
@@ -61,7 +61,7 @@ Run every step automatically:
|
|
|
61
61
|
Step 0: FIGMA_SYNC SKIP (deprecated - feedback_figma_source_deprecated)
|
|
62
62
|
Step 1: PLATFORM Detect macOS / Linux / Windows (Git Bash / WSL); export PLATFORM env
|
|
63
63
|
Step 1.5: DETECT Compare timestamps, find stale targets
|
|
64
|
-
Step 2: COPILOT Claude Code -> Copilot CLI (instructions +
|
|
64
|
+
Step 2: COPILOT Claude Code -> Copilot CLI (instructions + 34 sub-command skills)
|
|
65
65
|
Step 2a: CODEX Claude Code -> Codex CLI (global ~/.codex prompt + AGENTS.md + config.toml mcp)
|
|
66
66
|
- runs via `node pipeline/scripts/sync-adapters.mjs`, which fires the
|
|
67
67
|
codex adapter ONCE (global) when `~/.codex` exists on this machine
|
|
@@ -70,6 +70,8 @@ Step 2b: ADAPTERS Cursor / Antigravity / Copilot Chat per-project rule files r
|
|
|
70
70
|
- `--no-adapters` skips this step entirely
|
|
71
71
|
- writes files + a LOCAL commit per project; push stays the user's call
|
|
72
72
|
Step 3: REPO Claude Code -> pipeline repo (genericized, personal data scrub, bash -n on all sh)
|
|
73
|
+
Step 3c: PLUGINS pipeline shared/external -> multi-agent-plugins marketplace (rebuild knowledge/,
|
|
74
|
+
bump changed plugins' patch version, commit + push the plugins repo)
|
|
73
75
|
Step 4: WEBSITE Version + phase/model counts -> {website-host} (i18n + projects.ts)
|
|
74
76
|
Step 5: REMOTE Pipeline references -> remote-control README
|
|
75
77
|
Step 6: Commit Commit + push all changed repos
|
|
@@ -215,7 +217,7 @@ Adapter sync orchestration goes through `pipeline/scripts/sync-adapters.mjs` -
|
|
|
215
217
|
5. **Files NOT synced** (local-only, may contain personal data):
|
|
216
218
|
- `~/.claude/multi-agent-preferences.json`
|
|
217
219
|
- `~/.claude/CLAUDE.md`, `~/.claude/rules/`, `~/.claude/knowledge/`
|
|
218
|
-
- `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh` and `stack-
|
|
220
|
+
- `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh` and `build-stack-plugins.mjs` (generic, synced)
|
|
219
221
|
- `~/.claude/settings.json`
|
|
220
222
|
|
|
221
223
|
6. **Cross-platform smoke gate** (final step of the REPO sync, before push):
|
|
@@ -234,6 +236,48 @@ Adapter sync orchestration goes through `pipeline/scripts/sync-adapters.mjs` -
|
|
|
234
236
|
|
|
235
237
|
---
|
|
236
238
|
|
|
239
|
+
## Stack-Plugin Sync (Step 3c)
|
|
240
|
+
|
|
241
|
+
Stack skills are distributed as versioned plugins in the `{owner}/multi-agent-plugins` marketplace. The pipeline's `pipeline/skills/shared/external/` is the **single authoring source**; the marketplace is a derived, versioned publish artifact. This step rebuilds it and publishes only when something changed.
|
|
242
|
+
|
|
243
|
+
**Source of truth:** author/vendor knowledge skills in `pipeline/skills/shared/external/` (the pipeline's own phases also consume them). The plugins' authored lifecycle skills (`index` / `reference` / `workflow` / `tools`) live in the plugins repo and are never touched by sync.
|
|
244
|
+
|
|
245
|
+
**Flow:**
|
|
246
|
+
|
|
247
|
+
```bash
|
|
248
|
+
PLUGINS_REPO="$HOME/multi-agent-plugins"
|
|
249
|
+
[ ! -d "$PLUGINS_REPO/.git" ] && gh repo clone {owner}/multi-agent-plugins "$PLUGINS_REPO"
|
|
250
|
+
cd "$PLUGINS_REPO" && git pull origin main
|
|
251
|
+
|
|
252
|
+
# 1. Preview what would change (routing + version bumps), no writes:
|
|
253
|
+
node "$HOME/multi-agent-pipeline/pipeline/scripts/build-stack-plugins.mjs" --dry-run
|
|
254
|
+
|
|
255
|
+
# 2. Apply: rebuild each stack plugin's knowledge/ from shared/external,
|
|
256
|
+
# regenerate plugin.json skills[], bump the patch version of any plugin
|
|
257
|
+
# whose skill set changed. Cross-stack skills -> ai-common-engineering-toolkit;
|
|
258
|
+
# Apple/Xcode-only skills -> iOS plugin only.
|
|
259
|
+
node "$HOME/multi-agent-pipeline/pipeline/scripts/build-stack-plugins.mjs"
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
**Version-based management:** the generator bumps a plugin's `version` (patch) only when its skill set actually changed. Idempotent — a no-op run bumps nothing. Consumers pick up new versions via `/multi-agent:update` (which runs `claude marketplace update multi-agent-plugins`).
|
|
263
|
+
|
|
264
|
+
**Publish (only if the generator reported bumps):**
|
|
265
|
+
|
|
266
|
+
```bash
|
|
267
|
+
cd "$PLUGINS_REPO"
|
|
268
|
+
if ! git diff --quiet; then
|
|
269
|
+
git config user.name "$(git config user.name)"; git config user.email "$(git config user.email)"
|
|
270
|
+
git add -A
|
|
271
|
+
git commit -m "chore: rebuild stack plugins from pipeline shared/external"
|
|
272
|
+
gh auth switch --user {owner} 2>/dev/null || true
|
|
273
|
+
git push origin main
|
|
274
|
+
fi
|
|
275
|
+
```
|
|
276
|
+
|
|
277
|
+
Never author skills directly in the plugins repo's `knowledge/` — they will be overwritten on the next rebuild. Author in `shared/external`, then run this step.
|
|
278
|
+
|
|
279
|
+
---
|
|
280
|
+
|
|
237
281
|
## Website Sync (Step 4)
|
|
238
282
|
|
|
239
283
|
Propagate pipeline version, phase count, model count, and feature descriptions to the website.
|
|
@@ -302,11 +346,11 @@ This step runs only on the Claude <-> Copilot axis. Cursor / Copilot Chat do not
|
|
|
302
346
|
|-------------|-------------|
|
|
303
347
|
| `~/.claude/commands/multi-agent/{cmd}.md` | `~/.copilot/skills/multi-agent-{cmd}/SKILL.md` |
|
|
304
348
|
|
|
305
|
-
**
|
|
349
|
+
**34 commands are synced** (canonical inventory - must match `cross-cli-contract.md` section 1; drift = contract violation):
|
|
306
350
|
|
|
307
351
|
```
|
|
308
352
|
analysis, analysis-resolve, autopilot, build-optimize, channels, delete, dev,
|
|
309
|
-
dev-autopilot, dev-local, dev-local-autopilot, diff-explain,
|
|
353
|
+
dev-autopilot, dev-local, dev-local-autopilot, diff-explain, garbage-collect,
|
|
310
354
|
help, issue, jira, kill, language, local, local-autopilot, log, manual-test,
|
|
311
355
|
prune-logs, purge, refactor, resume, review, scan, search, setup, stack, status,
|
|
312
356
|
sync, test, update
|
|
@@ -17,7 +17,7 @@ Update the pipeline in one command. Existing preferences are preserved; only ski
|
|
|
17
17
|
done
|
|
18
18
|
if [ -z "$PIPE_DIR" ]; then
|
|
19
19
|
echo "Pipeline repo not found. Clone it:"
|
|
20
|
-
echo " git clone git@github.com:
|
|
20
|
+
echo " git clone git@github.com:{owner}/multi-agent-pipeline.git"
|
|
21
21
|
exit 1
|
|
22
22
|
fi
|
|
23
23
|
```
|
|
@@ -38,6 +38,19 @@ Update the pipeline in one command. Existing preferences are preserved; only ski
|
|
|
38
38
|
node "$PIPE_DIR/install.js" --all
|
|
39
39
|
```
|
|
40
40
|
|
|
41
|
+
4b. **Update the stack-plugin marketplace** (pulls the latest plugin versions):
|
|
42
|
+
```bash
|
|
43
|
+
# Stack skills ship as versioned plugins in {owner}/multi-agent-plugins.
|
|
44
|
+
# Refresh the marketplace so newly published plugin versions are picked up.
|
|
45
|
+
if claude marketplace list 2>/dev/null | grep -q "multi-agent-plugins"; then
|
|
46
|
+
claude marketplace update multi-agent-plugins 2>/dev/null \
|
|
47
|
+
|| claude marketplace add {owner}/multi-agent-plugins 2>/dev/null
|
|
48
|
+
echo " -> marketplace multi-agent-plugins refreshed"
|
|
49
|
+
else
|
|
50
|
+
echo " -> marketplace not added yet; add with: claude marketplace add {owner}/multi-agent-plugins"
|
|
51
|
+
fi
|
|
52
|
+
```
|
|
53
|
+
|
|
41
54
|
5. **Migrate preferences** (if there is an old schema):
|
|
42
55
|
```bash
|
|
43
56
|
if [ -f "$HOME/.claude/scripts/migrate-prefs.mjs" ]; then
|
|
@@ -52,7 +52,6 @@ Validate contracts. Each emits `══ <name> smoke: N passed, M failed ══`
|
|
|
52
52
|
- `smoke-prefs-language.sh` - `prefs.global.promptLanguage` contract
|
|
53
53
|
- `smoke-progress-contract.sh` - progress-line quiet/normal/verbose
|
|
54
54
|
- `smoke-search.sh` - `/multi-agent:search` log search + smart ranking
|
|
55
|
-
- `smoke-stack-swap.sh` - `/multi-agent:stack` auto-detect + manual override
|
|
56
55
|
- `smoke-subagent-validators.sh` - Phase 1/2 validator schemas
|
|
57
56
|
- `smoke-telemetry.sh` - opt-in telemetry contract
|
|
58
57
|
- `smoke-validator-contradiction.sh` - Phase 4 approved/blocking contradiction detection
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* build-stack-plugins.mjs
|
|
4
|
+
*
|
|
5
|
+
* Rebuild the per-stack plugin `knowledge/` trees in the multi-agent-plugins
|
|
6
|
+
* marketplace from the pipeline's authoring source (pipeline/skills/shared/external),
|
|
7
|
+
* regenerate each plugin.json `skills[]`, and bump the patch version of any plugin
|
|
8
|
+
* whose skill set changed. This is the version-based management backbone: the
|
|
9
|
+
* pipeline is the single authoring source; the marketplace is a derived, versioned
|
|
10
|
+
* publish artifact.
|
|
11
|
+
*
|
|
12
|
+
* The authored lifecycle skills (index / reference / workflow / tools) live in the
|
|
13
|
+
* plugin repo and are NEVER touched here — only the `knowledge/` layer + plugin.json
|
|
14
|
+
* knowledge entries are regenerated.
|
|
15
|
+
*
|
|
16
|
+
* Routing uses the per-stack skill patterns (formerly carried by stack-swap.sh). Genuinely cross-stack
|
|
17
|
+
* skills go to ai-common-engineering-toolkit (not into each stack plugin). Apple/
|
|
18
|
+
* Xcode-only vendored skills that match no stack pattern belong to iOS only.
|
|
19
|
+
*
|
|
20
|
+
* Usage:
|
|
21
|
+
* node build-stack-plugins.mjs [--plugins-repo <path>] [--pipeline <path>] [--dry-run]
|
|
22
|
+
*
|
|
23
|
+
* Exit code 0 always (report-only); prints a JSON-ish summary + per-plugin diff.
|
|
24
|
+
*/
|
|
25
|
+
import {
|
|
26
|
+
readdirSync, existsSync, rmSync, cpSync, readFileSync, writeFileSync, mkdirSync, statSync,
|
|
27
|
+
} from 'node:fs';
|
|
28
|
+
import { join } from 'node:path';
|
|
29
|
+
|
|
30
|
+
const args = process.argv.slice(2);
|
|
31
|
+
const getArg = (k, d) => { const i = args.indexOf(k); return i >= 0 ? args[i + 1] : d; };
|
|
32
|
+
const HOME = process.env.HOME;
|
|
33
|
+
const PLUGINS_REPO = getArg('--plugins-repo', join(HOME, 'multi-agent-plugins'));
|
|
34
|
+
const PIPE_ROOT = getArg('--pipeline', join(HOME, 'multi-agent-pipeline'));
|
|
35
|
+
const EXTERNAL = join(PIPE_ROOT, 'pipeline/skills/shared/external');
|
|
36
|
+
const DRY = args.includes('--dry-run');
|
|
37
|
+
|
|
38
|
+
const COMMON_PLUGIN = 'ai-common-engineering-toolkit';
|
|
39
|
+
const COMMON_SKILLS = ['accessibility-compliance-accessibility-audit', 'firebase', 'humanizer'];
|
|
40
|
+
|
|
41
|
+
// Apple/Xcode-only skills that match no stack pattern → iOS plugin only.
|
|
42
|
+
const APPLE_ONLY = [
|
|
43
|
+
'avkit', 'cryptokit', 'metrickit-diagnostics', 'pdfkit', 'spm-build-analysis',
|
|
44
|
+
'swiftlint', 'xcode-build-benchmark', 'xcode-build-fixer', 'xcode-build-orchestrator',
|
|
45
|
+
'xcode-compilation-analyzer', 'xcode-project-analyzer',
|
|
46
|
+
];
|
|
47
|
+
|
|
48
|
+
// stack → matching pattern (per-stack routing patterns (formerly in stack-swap.sh))
|
|
49
|
+
const STACK_PATTERNS = {
|
|
50
|
+
'ai-ios-engineering-toolkit': /(swiftui|swift-|ios-|hig-|apple-|storekit|widgetkit|healthkit|homekit|mapkit|musickit|passkit|pencilkit|realitykit|weatherkit|alarmkit|callkit|cloudkit|coreml|core-|eventkit|energykit|permissionkit|tipkit|shareplay|live-activities|background-processing|app-store|app-clips|app-intents|authentication|contacts-framework|device-integrity|macos-|natural-language|photos-camera|push-notifications|speech-recognition|swiftdata|vision-framework|debugging-instruments|help-skills)/i,
|
|
51
|
+
'ai-android-engineering-toolkit': /(android|compose-|kotlin-|room-database|retrofit-|gradle-|play-store)/i,
|
|
52
|
+
'ai-backend-toolkit': /(fastapi|nodejs|docker|api-pattern|api-security|github-actions|observability|architecture|monorepo|clean-code|debugging-strategies|agentflow|closed-loop|context-compression|python-patterns|database-patterns|rest-api-design|testing-backend|ci-cd-pipelines)/i,
|
|
53
|
+
'ai-frontend-engineering-toolkit': /(react-|nextjs-|typescript-|tailwind-|vue-|web-accessibility|web-performance|css-modern|web-testing|html-semantic)/i,
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
const isDir = (p) => { try { return statSync(p).isDirectory(); } catch { return false; } };
|
|
57
|
+
const listDirs = (p) => (existsSync(p) ? readdirSync(p).filter((n) => isDir(join(p, n))) : []);
|
|
58
|
+
|
|
59
|
+
// --- 1. enumerate authoring source ---------------------------------------
|
|
60
|
+
if (!existsSync(EXTERNAL)) {
|
|
61
|
+
console.error(`source not found: ${EXTERNAL}`);
|
|
62
|
+
process.exit(0);
|
|
63
|
+
}
|
|
64
|
+
const allSkills = listDirs(EXTERNAL);
|
|
65
|
+
|
|
66
|
+
// --- 2. compute desired knowledge set per plugin -------------------------
|
|
67
|
+
const desired = { [COMMON_PLUGIN]: new Set() };
|
|
68
|
+
for (const p of Object.keys(STACK_PATTERNS)) desired[p] = new Set();
|
|
69
|
+
|
|
70
|
+
const unrouted = [];
|
|
71
|
+
for (const skill of allSkills) {
|
|
72
|
+
if (COMMON_SKILLS.includes(skill)) { desired[COMMON_PLUGIN].add(skill); continue; }
|
|
73
|
+
if (APPLE_ONLY.includes(skill)) { desired['ai-ios-engineering-toolkit'].add(skill); continue; }
|
|
74
|
+
let matched = false;
|
|
75
|
+
for (const [plugin, re] of Object.entries(STACK_PATTERNS)) {
|
|
76
|
+
if (re.test(skill)) { desired[plugin].add(skill); matched = true; }
|
|
77
|
+
}
|
|
78
|
+
if (!matched) unrouted.push(skill);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// --- 3. sync each plugin's knowledge/ + regenerate plugin.json -----------
|
|
82
|
+
const report = [];
|
|
83
|
+
for (const [plugin, want] of Object.entries(desired)) {
|
|
84
|
+
const pdir = join(PLUGINS_REPO, 'plugins', plugin);
|
|
85
|
+
const kdir = join(pdir, 'skills', 'knowledge');
|
|
86
|
+
const pjPath = join(pdir, '.claude-plugin', 'plugin.json');
|
|
87
|
+
if (!existsSync(pjPath)) { report.push({ plugin, error: 'plugin.json missing' }); continue; }
|
|
88
|
+
|
|
89
|
+
const have = new Set(listDirs(kdir));
|
|
90
|
+
const toAdd = [...want].filter((s) => !have.has(s)).sort();
|
|
91
|
+
const toRemove = [...have].filter((s) => !want.has(s)).sort();
|
|
92
|
+
const changed = toAdd.length > 0 || toRemove.length > 0;
|
|
93
|
+
|
|
94
|
+
if (!DRY && changed) {
|
|
95
|
+
if (!existsSync(kdir)) mkdirSync(kdir, { recursive: true });
|
|
96
|
+
for (const s of toAdd) cpSync(join(EXTERNAL, s), join(kdir, s), { recursive: true });
|
|
97
|
+
for (const s of toRemove) rmSync(join(kdir, s), { recursive: true, force: true });
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
// regenerate plugin.json skills[]: keep non-knowledge entries, rebuild knowledge set
|
|
101
|
+
const pj = JSON.parse(readFileSync(pjPath, 'utf8'));
|
|
102
|
+
const nonKnowledge = (pj.skills || []).filter((s) => !s.startsWith('./skills/knowledge/'));
|
|
103
|
+
const finalKnowledge = (DRY ? [...want] : listDirs(kdir)).map((s) => `./skills/knowledge/${s}`);
|
|
104
|
+
const newSkills = [...new Set([...nonKnowledge, ...finalKnowledge])].sort();
|
|
105
|
+
const skillsChanged = JSON.stringify(pj.skills) !== JSON.stringify(newSkills);
|
|
106
|
+
|
|
107
|
+
const oldV = pj.version || '0.1.0';
|
|
108
|
+
let newV = oldV;
|
|
109
|
+
if (changed || skillsChanged) {
|
|
110
|
+
const [maj, min, patch] = oldV.split('.').map((n) => parseInt(n, 10) || 0);
|
|
111
|
+
newV = `${maj}.${min}.${patch + 1}`;
|
|
112
|
+
}
|
|
113
|
+
if (!DRY && (changed || skillsChanged)) {
|
|
114
|
+
pj.skills = newSkills;
|
|
115
|
+
pj.version = newV;
|
|
116
|
+
writeFileSync(pjPath, `${JSON.stringify(pj, null, 2)}\n`);
|
|
117
|
+
}
|
|
118
|
+
report.push({ plugin, added: toAdd, removed: toRemove, skillCount: newSkills.length, version: oldV === newV ? oldV : `${oldV} → ${newV}`, bumped: oldV !== newV });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
// --- 4. report ------------------------------------------------------------
|
|
122
|
+
console.log(`build-stack-plugins ${DRY ? '(dry-run)' : ''}`);
|
|
123
|
+
console.log(`source: ${EXTERNAL} (${allSkills.length} skills)`);
|
|
124
|
+
console.log(`target: ${PLUGINS_REPO}`);
|
|
125
|
+
for (const r of report) {
|
|
126
|
+
if (r.error) { console.log(` ✗ ${r.plugin}: ${r.error}`); continue; }
|
|
127
|
+
const flag = r.bumped ? 'BUMPED' : 'unchanged';
|
|
128
|
+
console.log(` ${r.plugin}: skills=${r.skillCount} version=${r.version} [${flag}]`);
|
|
129
|
+
if (r.added.length) console.log(` + ${r.added.join(', ')}`);
|
|
130
|
+
if (r.removed.length) console.log(` - ${r.removed.join(', ')}`);
|
|
131
|
+
}
|
|
132
|
+
if (unrouted.length) {
|
|
133
|
+
console.log(` ⚠ unrouted (matched no stack, not common/apple-only) — NOT copied anywhere:`);
|
|
134
|
+
console.log(` ${unrouted.join(', ')}`);
|
|
135
|
+
}
|
|
136
|
+
const anyBump = report.some((r) => r.bumped);
|
|
137
|
+
console.log(anyBump ? 'result: changes detected (versions bumped)' : 'result: all plugins up to date');
|
|
@@ -62,19 +62,20 @@ echo "→ 3. Phase wiring references the contract"
|
|
|
62
62
|
grep -q "model-fallback.md" "$P0" && ok "phase-0-init wires the date gate" || fail "phase-0-init missing fallback wiring"
|
|
63
63
|
grep -q "model-fallback.md" "$P4" && ok "phase-4-review wires the per-dispatch triggers" || fail "phase-4-review missing fallback wiring"
|
|
64
64
|
|
|
65
|
-
echo "→ 4.
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
echo "→ 4. Top-tier personas declare their preferred model (fallback is dispatch-time, not file-time)"
|
|
66
|
+
# Fable 5 is the top tier again: architect + Reviewer-1 (+ triage) personas pin it.
|
|
67
|
+
FABLE_COUNT=$(grep -l "^preferredModel: fable" "$REPO_ROOT"/pipeline/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
68
|
+
if [ "$FABLE_COUNT" -ge 4 ]; then
|
|
69
|
+
ok "fable top-tier personas present ($FABLE_COUNT files)"
|
|
69
70
|
else
|
|
70
|
-
fail "expected >=
|
|
71
|
+
fail "expected >=4 fable personas (architects + Reviewer-1), found $FABLE_COUNT"
|
|
71
72
|
fi
|
|
72
|
-
#
|
|
73
|
-
|
|
74
|
-
if [ "$
|
|
75
|
-
ok "
|
|
73
|
+
# Opus stays a valid tier — the first fallback below fable, and the top tier for security personas.
|
|
74
|
+
OPUS_COUNT=$(grep -l "^preferredModel: opus" "$REPO_ROOT"/pipeline/agents/*.md 2>/dev/null | wc -l | tr -d ' ')
|
|
75
|
+
if [ "$OPUS_COUNT" -ge 1 ]; then
|
|
76
|
+
ok "opus personas intact ($OPUS_COUNT files)"
|
|
76
77
|
else
|
|
77
|
-
fail "expected
|
|
78
|
+
fail "expected >=1 opus persona (fallback tier / security), found $OPUS_COUNT"
|
|
78
79
|
fi
|
|
79
80
|
|
|
80
81
|
echo ""
|
|
@@ -35,7 +35,7 @@ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - the branch's lo
|
|
|
35
35
|
|
|
36
36
|
```bash
|
|
37
37
|
multi-agent finish # current branch vs base; Jira id from branch name
|
|
38
|
-
multi-agent finish
|
|
38
|
+
multi-agent finish PROJ-12345 # explicit Jira id for the Phase 7 comment
|
|
39
39
|
multi-agent finish --base develop # override base branch for the diff
|
|
40
40
|
multi-agent finish autopilot # no gate prompts: auto-fix, auto-PR, auto-comment
|
|
41
41
|
```
|
|
@@ -1,55 +1,50 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: multi-agent-stack
|
|
3
3
|
language: en
|
|
4
|
-
description: "
|
|
4
|
+
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)."
|
|
5
5
|
user-invocable: true
|
|
6
6
|
---
|
|
7
7
|
|
|
8
|
-
# multi-agent stack -
|
|
8
|
+
# multi-agent stack - Select Stack via Plugin Enablement
|
|
9
9
|
|
|
10
|
-
|
|
10
|
+
Stack skills ship as plugins in the `{owner}/multi-agent-plugins` marketplace. Selecting a stack = **enabling the matching plugin(s)** in the current repo's `.claude/settings.json` `enabledPlugins`. The `ai-common-engineering-toolkit` (accessibility audit, humanizer, Firebase) is always enabled alongside the stack plugin.
|
|
11
|
+
|
|
12
|
+
This replaces the old `stack-swap.sh` mechanic that physically moved skill directories. No SessionStart hook, no directory shuffling — enablement is declarative, per-repo, and versioned.
|
|
11
13
|
|
|
12
14
|
## Usage
|
|
13
15
|
|
|
14
16
|
```bash
|
|
15
|
-
multi-agent-stack # show
|
|
16
|
-
multi-agent-stack ios # SwiftUI +
|
|
17
|
-
multi-agent-stack android # Compose +
|
|
18
|
-
multi-agent-stack mobile # iOS + Android
|
|
19
|
-
multi-agent-stack backend # Python / Node
|
|
20
|
-
multi-agent-stack frontend # React /
|
|
21
|
-
multi-agent-stack fullstack # backend +
|
|
22
|
-
multi-agent-stack all #
|
|
17
|
+
multi-agent-stack # show which plugins are enabled here
|
|
18
|
+
multi-agent-stack ios # SwiftUI toolkit + common
|
|
19
|
+
multi-agent-stack android # Compose toolkit + common
|
|
20
|
+
multi-agent-stack mobile # iOS + Android + common
|
|
21
|
+
multi-agent-stack backend # Python / Node spec-driven toolkit + common
|
|
22
|
+
multi-agent-stack frontend # React / TSX toolkit + common
|
|
23
|
+
multi-agent-stack fullstack # frontend + backend + common
|
|
24
|
+
multi-agent-stack all # all four stack toolkits + common
|
|
23
25
|
```
|
|
24
26
|
|
|
25
|
-
##
|
|
27
|
+
## Stack → plugin map
|
|
26
28
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
29
|
+
| Stack | Plugins enabled (all `@multi-agent-plugins`) |
|
|
30
|
+
|---|---|
|
|
31
|
+
| `ios` | `ai-common-engineering-toolkit`, `ai-ios-engineering-toolkit` |
|
|
32
|
+
| `android` | `ai-common-engineering-toolkit`, `ai-android-engineering-toolkit` |
|
|
33
|
+
| `frontend` | `ai-common-engineering-toolkit`, `ai-frontend-engineering-toolkit` |
|
|
34
|
+
| `backend` | `ai-common-engineering-toolkit`, `ai-backend-toolkit` |
|
|
35
|
+
| `mobile` | common + `ai-ios-engineering-toolkit` + `ai-android-engineering-toolkit` |
|
|
36
|
+
| `fullstack` | common + `ai-frontend-engineering-toolkit` + `ai-backend-toolkit` |
|
|
37
|
+
| `all` | common + all four stack toolkits |
|
|
31
38
|
|
|
32
|
-
##
|
|
39
|
+
## Behaviour
|
|
33
40
|
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
# --all install (shared machine, either CLI's copy is up-to-date).
|
|
38
|
-
if [ -x "$HOME/.copilot/scripts/stack-swap.sh" ]; then
|
|
39
|
-
SCRIPT="$HOME/.copilot/scripts/stack-swap.sh"
|
|
40
|
-
elif [ -x "$HOME/.claude/scripts/stack-swap.sh" ]; then
|
|
41
|
-
SCRIPT="$HOME/.claude/scripts/stack-swap.sh"
|
|
42
|
-
else
|
|
43
|
-
echo "stack-swap.sh not found - run install.js --copilot (or --all) to deploy pipeline scripts."
|
|
44
|
-
exit 1
|
|
45
|
-
fi
|
|
46
|
-
|
|
47
|
-
ARG="${1:-status}"
|
|
48
|
-
"$SCRIPT" "$ARG"
|
|
49
|
-
```
|
|
41
|
+
1. **No arg → status mode.** Read `.claude/settings.json` (repo) + the global settings and print which `@multi-agent-plugins` plugins are enabled. Modify nothing.
|
|
42
|
+
2. **Arg present → enable mode.** Ensure the marketplace is known (`claude marketplace add {owner}/multi-agent-plugins`), then write the matching `enabledPlugins` entries into the current repo's `.claude/settings.json`, setting the stack toolkits that don't belong to `false`. `ai-common-engineering-toolkit` is always `true`.
|
|
43
|
+
3. **Unknown arg** → show the list above; do not guess.
|
|
50
44
|
|
|
51
45
|
## Notes
|
|
52
46
|
|
|
53
|
-
-
|
|
54
|
-
-
|
|
55
|
-
- Pipeline Phase 1 stack detection is independent
|
|
47
|
+
- Enablement is per-repo and declarative — commit `.claude/settings.json` so teammates get the same stack.
|
|
48
|
+
- Restart the conversation to pick up newly enabled plugins.
|
|
49
|
+
- Pipeline Phase 1 stack detection is independent (it reads project files); `stack` only sets which plugin skill set is active.
|
|
50
|
+
- The old `stack-swap.sh` skill-dir swap has been removed; stack selection is entirely plugin enablement.
|
|
@@ -90,7 +90,8 @@ If nothing is stale -> report "All targets up to date" and stop.
|
|
|
90
90
|
5. **Files NOT synced** (local-only, may contain personal data):
|
|
91
91
|
- `~/.claude/multi-agent-preferences.json`
|
|
92
92
|
- `~/.claude/CLAUDE.md`, `~/.claude/rules/`, `~/.claude/knowledge/`
|
|
93
|
-
- `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh` and `stack-
|
|
93
|
+
- `~/.claude/scripts/` - EXCEPT `pre-commit-check.sh` and `build-stack-plugins.mjs` (generic, synced)
|
|
94
|
+
- Step 3c (PLUGINS): rebuild the `{owner}/multi-agent-plugins` marketplace from `shared/external` via `build-stack-plugins.mjs` (bumps changed plugins' patch version), then commit + push the plugins repo
|
|
94
95
|
- `~/.claude/settings.json`
|
|
95
96
|
|
|
96
97
|
|
|
@@ -16,6 +16,8 @@ Update the pipeline with a single command. Preferences are preserved; only skill
|
|
|
16
16
|
2. Record the current version
|
|
17
17
|
3. `git pull origin main`
|
|
18
18
|
4. `node install.js --all` (Claude + Copilot)
|
|
19
|
+
4b. Refresh the stack-plugin marketplace so the latest plugin versions are picked up:
|
|
20
|
+
`claude marketplace update multi-agent-plugins` (or `claude marketplace add {owner}/multi-agent-plugins` if not yet added)
|
|
19
21
|
5. `node migrate-prefs.mjs` (if there is a schema upgrade)
|
|
20
22
|
6. Show the new version + changelog
|
|
21
23
|
7. Smoke test (schema + cross-cli)
|
|
@@ -1,132 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# smoke-stack-swap.sh - verify stack-swap.sh argument dispatch and skill movement.
|
|
3
|
-
# Bootstraps a temp HOME with fixture skills, runs the script in forced mode for
|
|
4
|
-
# each supported stack, asserts skills move between active and inactive
|
|
5
|
-
# directories, and validates the JSON systemMessage output contract.
|
|
6
|
-
#
|
|
7
|
-
# Covers v5.3.4+ /multi-agent:stack command backend: ios, android, mobile,
|
|
8
|
-
# backend, frontend, fullstack, all, status, and unknown-arg rejection.
|
|
9
|
-
|
|
10
|
-
set -uo pipefail
|
|
11
|
-
|
|
12
|
-
SCRIPT_DIR="$(cd "$(dirname "$0")" && pwd)"
|
|
13
|
-
STACK_SWAP="$SCRIPT_DIR/stack-swap.sh"
|
|
14
|
-
|
|
15
|
-
if [ ! -x "$STACK_SWAP" ]; then
|
|
16
|
-
echo "FAIL: stack-swap.sh not found or not executable at $STACK_SWAP" >&2
|
|
17
|
-
exit 1
|
|
18
|
-
fi
|
|
19
|
-
|
|
20
|
-
PASS=0
|
|
21
|
-
FAIL=0
|
|
22
|
-
pass() { PASS=$((PASS+1)); echo " ✓ $1"; }
|
|
23
|
-
fail() { FAIL=$((FAIL+1)); echo " ✗ $1"; }
|
|
24
|
-
|
|
25
|
-
TMPHOME=$(mktemp -d) || { echo "FAIL: mktemp" >&2; exit 1; }
|
|
26
|
-
trap 'rm -rf "$TMPHOME"' EXIT
|
|
27
|
-
|
|
28
|
-
export HOME="$TMPHOME"
|
|
29
|
-
SKILLS="$TMPHOME/.claude/skills"
|
|
30
|
-
INACTIVE="$TMPHOME/.claude/skills-inactive"
|
|
31
|
-
mkdir -p "$SKILLS" "$INACTIVE"
|
|
32
|
-
|
|
33
|
-
# Fixture skill dirs - one matching each stack's pattern catalog.
|
|
34
|
-
bootstrap_fixtures() {
|
|
35
|
-
rm -rf "$SKILLS" "$INACTIVE"
|
|
36
|
-
mkdir -p "$SKILLS" "$INACTIVE"
|
|
37
|
-
# iOS pattern hits
|
|
38
|
-
mkdir -p "$SKILLS/swiftui-patterns" "$SKILLS/ios-networking" "$SKILLS/hig-foundations"
|
|
39
|
-
# Android pattern hits
|
|
40
|
-
mkdir -p "$SKILLS/android-security" "$SKILLS/compose-navigation" "$SKILLS/kotlin-coroutines-expert"
|
|
41
|
-
# Backend pattern hits
|
|
42
|
-
mkdir -p "$SKILLS/fastapi-patterns" "$SKILLS/nodejs-tips"
|
|
43
|
-
# Frontend pattern hits
|
|
44
|
-
mkdir -p "$SKILLS/react-best-practices" "$SKILLS/nextjs-app-router"
|
|
45
|
-
# Unrelated skill that should never move
|
|
46
|
-
mkdir -p "$SKILLS/general-writing"
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
echo "→ 1. status mode prints JSON with active+inactive counts, no file movement"
|
|
50
|
-
bootstrap_fixtures
|
|
51
|
-
COUNT_BEFORE=$(ls "$SKILLS" | wc -l | tr -d ' ')
|
|
52
|
-
OUT=$("$STACK_SWAP" status 2>&1)
|
|
53
|
-
if echo "$OUT" | grep -q '"systemMessage"'; then
|
|
54
|
-
pass "status emits {\"systemMessage\": ...} JSON"
|
|
55
|
-
else
|
|
56
|
-
fail "status output missing systemMessage field: $OUT"
|
|
57
|
-
fi
|
|
58
|
-
COUNT_AFTER=$(ls "$SKILLS" | wc -l | tr -d ' ')
|
|
59
|
-
if [ "$COUNT_BEFORE" = "$COUNT_AFTER" ]; then
|
|
60
|
-
pass "status does not move files (before=$COUNT_BEFORE after=$COUNT_AFTER)"
|
|
61
|
-
else
|
|
62
|
-
fail "status moved files (before=$COUNT_BEFORE after=$COUNT_AFTER)"
|
|
63
|
-
fi
|
|
64
|
-
|
|
65
|
-
echo ""
|
|
66
|
-
echo "→ 2. ios mode keeps iOS skills active, deactivates Android/backend/frontend"
|
|
67
|
-
bootstrap_fixtures
|
|
68
|
-
"$STACK_SWAP" ios >/dev/null 2>&1
|
|
69
|
-
[ -d "$SKILLS/swiftui-patterns" ] && pass "iOS skill stays active: swiftui-patterns" || fail "swiftui-patterns missing from active"
|
|
70
|
-
[ -d "$SKILLS/ios-networking" ] && pass "iOS skill stays active: ios-networking" || fail "ios-networking missing from active"
|
|
71
|
-
[ -d "$INACTIVE/android-security" ] && pass "Android skill moved to inactive: android-security" || fail "android-security not in inactive"
|
|
72
|
-
[ -d "$INACTIVE/react-best-practices" ] && pass "Frontend skill moved to inactive: react-best-practices" || fail "react-best-practices not in inactive"
|
|
73
|
-
[ -d "$SKILLS/general-writing" ] && pass "Unrelated skill untouched: general-writing" || fail "general-writing was moved"
|
|
74
|
-
|
|
75
|
-
echo ""
|
|
76
|
-
echo "→ 3. android mode keeps Android skills active, deactivates iOS"
|
|
77
|
-
bootstrap_fixtures
|
|
78
|
-
"$STACK_SWAP" android >/dev/null 2>&1
|
|
79
|
-
[ -d "$SKILLS/android-security" ] && pass "Android skill stays active" || fail "android-security missing from active"
|
|
80
|
-
[ -d "$SKILLS/compose-navigation" ] && pass "Compose skill stays active" || fail "compose-navigation missing from active"
|
|
81
|
-
[ -d "$INACTIVE/swiftui-patterns" ] && pass "iOS skill moved to inactive" || fail "swiftui-patterns not in inactive"
|
|
82
|
-
|
|
83
|
-
echo ""
|
|
84
|
-
echo "→ 4. mobile mode keeps iOS AND Android active, deactivates backend"
|
|
85
|
-
bootstrap_fixtures
|
|
86
|
-
"$STACK_SWAP" mobile >/dev/null 2>&1
|
|
87
|
-
[ -d "$SKILLS/swiftui-patterns" ] && pass "mobile keeps iOS active" || fail "iOS deactivated by mobile"
|
|
88
|
-
[ -d "$SKILLS/android-security" ] && pass "mobile keeps Android active" || fail "Android deactivated by mobile"
|
|
89
|
-
[ -d "$INACTIVE/fastapi-patterns" ] && pass "backend moved to inactive under mobile" || fail "backend stayed active under mobile"
|
|
90
|
-
|
|
91
|
-
echo ""
|
|
92
|
-
echo "→ 5. all mode keeps every stack active"
|
|
93
|
-
bootstrap_fixtures
|
|
94
|
-
# Pre-deactivate something so "all" has work to do
|
|
95
|
-
mv "$SKILLS/fastapi-patterns" "$INACTIVE/fastapi-patterns"
|
|
96
|
-
"$STACK_SWAP" all >/dev/null 2>&1
|
|
97
|
-
[ -d "$SKILLS/swiftui-patterns" ] && pass "all keeps iOS" || fail "all dropped iOS"
|
|
98
|
-
[ -d "$SKILLS/android-security" ] && pass "all keeps Android" || fail "all dropped Android"
|
|
99
|
-
[ -d "$SKILLS/fastapi-patterns" ] && pass "all re-activates backend" || fail "all did not re-activate backend"
|
|
100
|
-
|
|
101
|
-
echo ""
|
|
102
|
-
echo "→ 6. unknown arg returns exit 1 with error message"
|
|
103
|
-
bootstrap_fixtures
|
|
104
|
-
OUT=$("$STACK_SWAP" badstack 2>&1)
|
|
105
|
-
RC=$?
|
|
106
|
-
if [ "$RC" -eq 1 ]; then
|
|
107
|
-
pass "unknown arg exits 1"
|
|
108
|
-
else
|
|
109
|
-
fail "unknown arg exit code was $RC, expected 1"
|
|
110
|
-
fi
|
|
111
|
-
if echo "$OUT" | grep -qi "unknown"; then
|
|
112
|
-
pass "unknown arg error message mentions 'unknown'"
|
|
113
|
-
else
|
|
114
|
-
fail "unknown arg message lacks expected text: $OUT"
|
|
115
|
-
fi
|
|
116
|
-
|
|
117
|
-
echo ""
|
|
118
|
-
echo "→ 7. exit code 0 on every valid mode"
|
|
119
|
-
bootstrap_fixtures
|
|
120
|
-
for arg in status ios android mobile backend frontend all; do
|
|
121
|
-
"$STACK_SWAP" "$arg" >/dev/null 2>&1
|
|
122
|
-
RC=$?
|
|
123
|
-
if [ "$RC" -eq 0 ]; then
|
|
124
|
-
pass "$arg exits 0"
|
|
125
|
-
else
|
|
126
|
-
fail "$arg exit code was $RC"
|
|
127
|
-
fi
|
|
128
|
-
done
|
|
129
|
-
|
|
130
|
-
echo ""
|
|
131
|
-
echo "══ stack-swap smoke: $PASS passed, $FAIL failed ══"
|
|
132
|
-
[ "$FAIL" -eq 0 ] || exit 1
|
|
@@ -1,182 +0,0 @@
|
|
|
1
|
-
#!/bin/bash
|
|
2
|
-
# stack-swap.sh - Auto-detect project stack and swap skills
|
|
3
|
-
# Called by SessionStart hook
|
|
4
|
-
# Default: iOS. Swaps Android/backend in only when detected.
|
|
5
|
-
|
|
6
|
-
set -uo pipefail
|
|
7
|
-
|
|
8
|
-
SKILLS="$HOME/.claude/skills"
|
|
9
|
-
INACTIVE="$HOME/.claude/skills-inactive"
|
|
10
|
-
mkdir -p "$INACTIVE"
|
|
11
|
-
|
|
12
|
-
# Skill group definitions (folder name prefixes/patterns)
|
|
13
|
-
IOS_PATTERNS="swiftui|swift-|ios-|hig-|apple-|storekit|widgetkit|healthkit|homekit|mapkit|musickit|passkit|pencilkit|realitykit|weatherkit|alarmkit|callkit|cloudkit|coreml|core-|eventkit|energykit|permissionkit|tipkit|shareplay|live-activities|background-processing|app-store|app-clips|app-intents|authentication|contacts-framework|device-integrity|macos-|natural-language|photos-camera|push-notifications|speech-recognition|swiftdata|vision-framework|debugging-instruments|help-skills"
|
|
14
|
-
ANDROID_PATTERNS="android|compose-|kotlin-|room-database|retrofit-|gradle-|play-store"
|
|
15
|
-
BACKEND_PATTERNS="fastapi|nodejs|docker|api-pattern|api-security|github-actions|observability|architecture|monorepo|clean-code|debugging-strategies|agentflow|closed-loop|context-compression|python-patterns|database-patterns|rest-api-design|testing-backend|ci-cd-pipelines"
|
|
16
|
-
FRONTEND_PATTERNS="react-|nextjs-|typescript-|tailwind-|vue-|web-accessibility|web-performance|css-modern|web-testing|html-semantic"
|
|
17
|
-
|
|
18
|
-
activate_stack() {
|
|
19
|
-
local patterns="$1"
|
|
20
|
-
# Move matching skills from inactive to active
|
|
21
|
-
for dir in "$INACTIVE"/*/; do
|
|
22
|
-
[ -d "$dir" ] || continue
|
|
23
|
-
name=$(basename "$dir")
|
|
24
|
-
if echo "$name" | grep -qiE "$patterns"; then
|
|
25
|
-
mv "$dir" "$SKILLS/$name" 2>/dev/null
|
|
26
|
-
fi
|
|
27
|
-
done
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
deactivate_stack() {
|
|
31
|
-
local patterns="$1"
|
|
32
|
-
# Move matching skills from active to inactive
|
|
33
|
-
for dir in "$SKILLS"/*/; do
|
|
34
|
-
[ -d "$dir" ] || continue
|
|
35
|
-
name=$(basename "$dir")
|
|
36
|
-
if echo "$name" | grep -qiE "$patterns"; then
|
|
37
|
-
mv "$dir" "$INACTIVE/$name" 2>/dev/null
|
|
38
|
-
fi
|
|
39
|
-
done
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
# Manual mode: if argument provided, force that stack
|
|
43
|
-
FORCE_STACK="${1:-}"
|
|
44
|
-
|
|
45
|
-
if [ -n "$FORCE_STACK" ]; then
|
|
46
|
-
case "$FORCE_STACK" in
|
|
47
|
-
ios)
|
|
48
|
-
activate_stack "$IOS_PATTERNS"
|
|
49
|
-
deactivate_stack "$ANDROID_PATTERNS"
|
|
50
|
-
deactivate_stack "$BACKEND_PATTERNS"
|
|
51
|
-
deactivate_stack "$FRONTEND_PATTERNS"
|
|
52
|
-
;;
|
|
53
|
-
android)
|
|
54
|
-
deactivate_stack "$IOS_PATTERNS"
|
|
55
|
-
activate_stack "$ANDROID_PATTERNS"
|
|
56
|
-
deactivate_stack "$BACKEND_PATTERNS"
|
|
57
|
-
deactivate_stack "$FRONTEND_PATTERNS"
|
|
58
|
-
;;
|
|
59
|
-
mobile)
|
|
60
|
-
activate_stack "$IOS_PATTERNS"
|
|
61
|
-
activate_stack "$ANDROID_PATTERNS"
|
|
62
|
-
deactivate_stack "$BACKEND_PATTERNS"
|
|
63
|
-
deactivate_stack "$FRONTEND_PATTERNS"
|
|
64
|
-
;;
|
|
65
|
-
backend)
|
|
66
|
-
deactivate_stack "$IOS_PATTERNS"
|
|
67
|
-
deactivate_stack "$ANDROID_PATTERNS"
|
|
68
|
-
activate_stack "$BACKEND_PATTERNS"
|
|
69
|
-
deactivate_stack "$FRONTEND_PATTERNS"
|
|
70
|
-
;;
|
|
71
|
-
frontend)
|
|
72
|
-
deactivate_stack "$IOS_PATTERNS"
|
|
73
|
-
deactivate_stack "$ANDROID_PATTERNS"
|
|
74
|
-
deactivate_stack "$BACKEND_PATTERNS"
|
|
75
|
-
activate_stack "$FRONTEND_PATTERNS"
|
|
76
|
-
;;
|
|
77
|
-
fullstack)
|
|
78
|
-
deactivate_stack "$IOS_PATTERNS"
|
|
79
|
-
deactivate_stack "$ANDROID_PATTERNS"
|
|
80
|
-
activate_stack "$BACKEND_PATTERNS"
|
|
81
|
-
activate_stack "$FRONTEND_PATTERNS"
|
|
82
|
-
;;
|
|
83
|
-
all)
|
|
84
|
-
activate_stack "$IOS_PATTERNS"
|
|
85
|
-
activate_stack "$ANDROID_PATTERNS"
|
|
86
|
-
activate_stack "$BACKEND_PATTERNS"
|
|
87
|
-
activate_stack "$FRONTEND_PATTERNS"
|
|
88
|
-
;;
|
|
89
|
-
status)
|
|
90
|
-
ACTIVE=$(ls "$SKILLS" 2>/dev/null | wc -l | tr -d ' ')
|
|
91
|
-
INACTIVE_COUNT=$(ls "$INACTIVE" 2>/dev/null | wc -l | tr -d ' ')
|
|
92
|
-
echo "{\"systemMessage\": \"Active: $ACTIVE | Inactive: $INACTIVE_COUNT\"}"
|
|
93
|
-
exit 0
|
|
94
|
-
;;
|
|
95
|
-
*)
|
|
96
|
-
echo "{\"systemMessage\": \"Unknown stack: $FORCE_STACK. Use: ios, android, mobile, backend, frontend, fullstack, all, status\"}"
|
|
97
|
-
exit 1
|
|
98
|
-
;;
|
|
99
|
-
esac
|
|
100
|
-
ACTIVE=$(ls "$SKILLS" 2>/dev/null | wc -l | tr -d ' ')
|
|
101
|
-
echo "{\"systemMessage\": \"Stack switched to $FORCE_STACK ($ACTIVE skills active). Restart conversation for full effect.\"}"
|
|
102
|
-
exit 0
|
|
103
|
-
fi
|
|
104
|
-
|
|
105
|
-
# Auto-detect mode (SessionStart hook)
|
|
106
|
-
CWD=$(pwd)
|
|
107
|
-
|
|
108
|
-
# If cwd is $HOME, skip detection - keep default (iOS)
|
|
109
|
-
if [ "$CWD" = "$HOME" ]; then
|
|
110
|
-
activate_stack "$IOS_PATTERNS"
|
|
111
|
-
ACTIVE=$(ls "$SKILLS" 2>/dev/null | wc -l | tr -d ' ')
|
|
112
|
-
echo "{\"systemMessage\": \"Stack: iOS - default ($ACTIVE skills active)\"}"
|
|
113
|
-
exit 0
|
|
114
|
-
fi
|
|
115
|
-
|
|
116
|
-
HAS_IOS=$(find "$CWD" -maxdepth 2 \( -name "*.xcodeproj" -o -name "Package.swift" \) -not -path "*/.claude/*" -not -path "*/node_modules/*" 2>/dev/null | head -1)
|
|
117
|
-
HAS_ANDROID=$(find "$CWD" -maxdepth 2 \( -name "build.gradle" -o -name "build.gradle.kts" \) -not -path "*/.claude/*" 2>/dev/null | head -1)
|
|
118
|
-
HAS_FRONTEND=$(find "$CWD" -maxdepth 2 \( -name "next.config.*" -o -name "vite.config.*" -o -name "nuxt.config.*" -o -name "tailwind.config.*" -o -name "tsconfig.json" \) -not -path "*/.claude/*" -not -path "*/node_modules/*" 2>/dev/null | head -1)
|
|
119
|
-
HAS_BACKEND=$(find "$CWD" -maxdepth 2 \( -name "requirements.txt" -o -name "pyproject.toml" -o -name "Pipfile" -o -name "Dockerfile" \) -not -path "*/.claude/*" -not -path "*/node_modules/*" 2>/dev/null | head -1)
|
|
120
|
-
|
|
121
|
-
# Determine stack
|
|
122
|
-
if [ -n "$HAS_IOS" ] && [ -n "$HAS_ANDROID" ]; then
|
|
123
|
-
STACK="mobile"
|
|
124
|
-
elif [ -n "$HAS_ANDROID" ]; then
|
|
125
|
-
STACK="android"
|
|
126
|
-
elif [ -n "$HAS_IOS" ]; then
|
|
127
|
-
STACK="ios"
|
|
128
|
-
elif [ -n "$HAS_FRONTEND" ] && [ -n "$HAS_BACKEND" ]; then
|
|
129
|
-
STACK="fullstack"
|
|
130
|
-
elif [ -n "$HAS_FRONTEND" ]; then
|
|
131
|
-
STACK="frontend"
|
|
132
|
-
elif [ -n "$HAS_BACKEND" ]; then
|
|
133
|
-
STACK="backend"
|
|
134
|
-
else
|
|
135
|
-
STACK="ios" # default
|
|
136
|
-
fi
|
|
137
|
-
|
|
138
|
-
# Apply swap
|
|
139
|
-
case "$STACK" in
|
|
140
|
-
ios)
|
|
141
|
-
activate_stack "$IOS_PATTERNS"
|
|
142
|
-
deactivate_stack "$ANDROID_PATTERNS"
|
|
143
|
-
deactivate_stack "$BACKEND_PATTERNS"
|
|
144
|
-
MSG="iOS"
|
|
145
|
-
;;
|
|
146
|
-
android)
|
|
147
|
-
deactivate_stack "$IOS_PATTERNS"
|
|
148
|
-
activate_stack "$ANDROID_PATTERNS"
|
|
149
|
-
deactivate_stack "$BACKEND_PATTERNS"
|
|
150
|
-
MSG="Android"
|
|
151
|
-
;;
|
|
152
|
-
mobile)
|
|
153
|
-
activate_stack "$IOS_PATTERNS"
|
|
154
|
-
activate_stack "$ANDROID_PATTERNS"
|
|
155
|
-
deactivate_stack "$BACKEND_PATTERNS"
|
|
156
|
-
MSG="Mobile (iOS + Android)"
|
|
157
|
-
;;
|
|
158
|
-
frontend)
|
|
159
|
-
deactivate_stack "$IOS_PATTERNS"
|
|
160
|
-
deactivate_stack "$ANDROID_PATTERNS"
|
|
161
|
-
deactivate_stack "$BACKEND_PATTERNS"
|
|
162
|
-
activate_stack "$FRONTEND_PATTERNS"
|
|
163
|
-
MSG="Frontend"
|
|
164
|
-
;;
|
|
165
|
-
fullstack)
|
|
166
|
-
deactivate_stack "$IOS_PATTERNS"
|
|
167
|
-
deactivate_stack "$ANDROID_PATTERNS"
|
|
168
|
-
activate_stack "$BACKEND_PATTERNS"
|
|
169
|
-
activate_stack "$FRONTEND_PATTERNS"
|
|
170
|
-
MSG="Fullstack (Frontend + Backend)"
|
|
171
|
-
;;
|
|
172
|
-
backend)
|
|
173
|
-
deactivate_stack "$IOS_PATTERNS"
|
|
174
|
-
deactivate_stack "$ANDROID_PATTERNS"
|
|
175
|
-
activate_stack "$BACKEND_PATTERNS"
|
|
176
|
-
deactivate_stack "$FRONTEND_PATTERNS"
|
|
177
|
-
MSG="Backend"
|
|
178
|
-
;;
|
|
179
|
-
esac
|
|
180
|
-
|
|
181
|
-
ACTIVE=$(ls "$SKILLS" 2>/dev/null | wc -l | tr -d ' ')
|
|
182
|
-
echo "{\"systemMessage\": \"Stack: $MSG ($ACTIVE skills active)\"}"
|