@mmerterden/multi-agent-pipeline 13.5.0 → 14.0.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.
Files changed (119) hide show
  1. package/CHANGELOG.md +243 -0
  2. package/README.md +3 -3
  3. package/docs/features.md +1 -1
  4. package/install/_common.mjs +73 -0
  5. package/install/_mcp-register.mjs +70 -31
  6. package/install/_plugin-skills.mjs +73 -14
  7. package/install/claude.mjs +28 -4
  8. package/install/codex.mjs +33 -2
  9. package/install/copilot.mjs +145 -9
  10. package/install/index.mjs +10 -6
  11. package/install/templates/copilot-instructions.md +1 -1
  12. package/package.json +1 -1
  13. package/pipeline/agents/code-reviewer.md +58 -1
  14. package/pipeline/commands/multi-agent/SKILL.md +7 -5
  15. package/pipeline/commands/multi-agent/analysis/SKILL.md +7 -7
  16. package/pipeline/commands/multi-agent/analysis-resolve/SKILL.md +1 -1
  17. package/pipeline/commands/multi-agent/build-optimize/SKILL.md +7 -7
  18. package/pipeline/commands/multi-agent/channels/SKILL.md +5 -5
  19. package/pipeline/commands/multi-agent/dev/SKILL.md +23 -18
  20. package/pipeline/commands/multi-agent/dev-autopilot/SKILL.md +19 -13
  21. package/pipeline/commands/multi-agent/dev-local/SKILL.md +14 -12
  22. package/pipeline/commands/multi-agent/dev-local-autopilot/SKILL.md +17 -12
  23. package/pipeline/commands/multi-agent/garbage-collect/SKILL.md +1 -1
  24. package/pipeline/commands/multi-agent/help/SKILL.md +4 -4
  25. package/pipeline/commands/multi-agent/ios-coding-standard/SKILL.md +2 -2
  26. package/pipeline/commands/multi-agent/local-autopilot/SKILL.md +4 -4
  27. package/pipeline/commands/multi-agent/resume/SKILL.md +1 -1
  28. package/pipeline/commands/multi-agent/review/SKILL.md +5 -5
  29. package/pipeline/commands/multi-agent/scan/SKILL.md +1 -1
  30. package/pipeline/commands/multi-agent/search/SKILL.md +1 -1
  31. package/pipeline/commands/multi-agent/setup/SKILL.md +6 -6
  32. package/pipeline/commands/multi-agent/{finish → ship}/SKILL.md +12 -12
  33. package/pipeline/commands/multi-agent/testflight-validation/SKILL.md +1 -1
  34. package/pipeline/commands/multi-agent/update/SKILL.md +5 -2
  35. package/pipeline/commands/sim-test.md +2 -2
  36. package/pipeline/lib/credential-store-resolver.sh +16 -0
  37. package/pipeline/lib/credential-store.sh +47 -4
  38. package/pipeline/lib/fetch-figma-annotations.sh +26 -28
  39. package/pipeline/lib/figma-screenshot.sh +28 -39
  40. package/pipeline/lib/figma-token.sh +63 -0
  41. package/pipeline/multi-agent-refs/analysis-template.md +1 -1
  42. package/pipeline/multi-agent-refs/android-guide.md +1 -1
  43. package/pipeline/multi-agent-refs/channels/issue-comment.md +1 -1
  44. package/pipeline/multi-agent-refs/component-dispatch.md +2 -2
  45. package/pipeline/multi-agent-refs/cross-cli-contract.md +4 -4
  46. package/pipeline/multi-agent-refs/features/dev-critic.md +2 -2
  47. package/pipeline/multi-agent-refs/features/model-fallback.md +35 -2
  48. package/pipeline/multi-agent-refs/features/plan-todos.md +1 -1
  49. package/pipeline/multi-agent-refs/features/repo-map.md +1 -1
  50. package/pipeline/multi-agent-refs/features/review-multi-repo.md +3 -3
  51. package/pipeline/multi-agent-refs/features/shadow-git.md +1 -1
  52. package/pipeline/multi-agent-refs/features/skill-conformance.md +116 -0
  53. package/pipeline/multi-agent-refs/features/verify-by-test.md +1 -1
  54. package/pipeline/multi-agent-refs/generate-issue.md +1 -1
  55. package/pipeline/multi-agent-refs/multi-repo-integration-build.md +1 -1
  56. package/pipeline/multi-agent-refs/phases/log-format.md +4 -4
  57. package/pipeline/multi-agent-refs/phases/modes.md +7 -7
  58. package/pipeline/multi-agent-refs/phases/phase-0-init.md +13 -11
  59. package/pipeline/multi-agent-refs/phases/phase-1-analysis.md +17 -15
  60. package/pipeline/multi-agent-refs/phases/phase-2-planning.md +7 -7
  61. package/pipeline/multi-agent-refs/phases/phase-3-dev.md +28 -13
  62. package/pipeline/multi-agent-refs/phases/phase-4-review.md +90 -58
  63. package/pipeline/multi-agent-refs/phases/phase-5-test.md +7 -7
  64. package/pipeline/multi-agent-refs/phases/phase-6-commit.md +8 -8
  65. package/pipeline/multi-agent-refs/phases/phase-7-report.md +8 -8
  66. package/pipeline/multi-agent-refs/phases.md +13 -13
  67. package/pipeline/multi-agent-refs/progress-contract.md +2 -2
  68. package/pipeline/multi-agent-refs/rules.md +7 -5
  69. package/pipeline/multi-agent-refs/swiftui-guide.md +1 -1
  70. package/pipeline/multi-agent-refs/tracker-contract.md +16 -15
  71. package/pipeline/preferences-template.json +7 -1
  72. package/pipeline/rules/figma-pipeline.md +2 -2
  73. package/pipeline/schemas/agent-state.schema.json +333 -79
  74. package/pipeline/schemas/criteria-manifest.schema.json +228 -0
  75. package/pipeline/schemas/migrations/prefs-2.4.0-to-2.5.0.mjs +64 -0
  76. package/pipeline/schemas/prefs.schema.json +118 -262
  77. package/pipeline/schemas/reviewer-output.schema.json +48 -3
  78. package/pipeline/schemas/token-budget.json +34 -10
  79. package/pipeline/schemas/triage-output.schema.json +112 -27
  80. package/pipeline/scripts/cost-table.json +7 -4
  81. package/pipeline/scripts/gc-worktrees.sh +1 -1
  82. package/pipeline/scripts/gen-mode-dispatch.mjs +6 -6
  83. package/pipeline/scripts/match-skills.mjs +37 -4
  84. package/pipeline/scripts/migrate-prefs.mjs +88 -17
  85. package/pipeline/scripts/phase-tracker.sh +14 -3
  86. package/pipeline/scripts/pre-commit-check.sh +49 -2
  87. package/pipeline/scripts/skill-conformance.mjs +960 -0
  88. package/pipeline/scripts/smoke-schema-validation.sh +17 -4
  89. package/pipeline/scripts/uninstall.mjs +35 -9
  90. package/pipeline/scripts/validate-reviewer.mjs +108 -1
  91. package/pipeline/skills/.skill-manifest.json +1 -1
  92. package/pipeline/skills/.skills-index.json +36 -9
  93. package/pipeline/skills/shared/README.md +15 -12
  94. package/pipeline/skills/shared/core/apple-archive-compliance/SKILL.md +1 -0
  95. package/pipeline/skills/shared/core/apple-archive-compliance/references/rules.yml +167 -0
  96. package/pipeline/skills/shared/core/google-play-compliance/SKILL.md +1 -0
  97. package/pipeline/skills/shared/core/google-play-compliance/references/rules.yml +184 -0
  98. package/pipeline/skills/shared/core/multi-agent/SKILL.md +10 -10
  99. package/pipeline/skills/shared/core/multi-agent-analysis/SKILL.md +4 -4
  100. package/pipeline/skills/shared/core/multi-agent-analysis-resolve/SKILL.md +3 -3
  101. package/pipeline/skills/shared/core/multi-agent-build-optimize/SKILL.md +2 -2
  102. package/pipeline/skills/shared/core/multi-agent-create-jira/SKILL.md +1 -1
  103. package/pipeline/skills/shared/core/multi-agent-dev/SKILL.md +6 -5
  104. package/pipeline/skills/shared/core/multi-agent-dev-autopilot/SKILL.md +7 -6
  105. package/pipeline/skills/shared/core/multi-agent-dev-local/SKILL.md +4 -3
  106. package/pipeline/skills/shared/core/multi-agent-dev-local-autopilot/SKILL.md +2 -1
  107. package/pipeline/skills/shared/core/multi-agent-help/SKILL.md +2 -2
  108. package/pipeline/skills/shared/core/multi-agent-ios-coding-standard/SKILL.md +1 -1
  109. package/pipeline/skills/shared/core/multi-agent-local-autopilot/SKILL.md +4 -4
  110. package/pipeline/skills/shared/core/multi-agent-review/SKILL.md +5 -5
  111. package/pipeline/skills/shared/core/multi-agent-scan/SKILL.md +1 -1
  112. package/pipeline/skills/shared/core/multi-agent-search/SKILL.md +1 -1
  113. package/pipeline/skills/shared/core/{multi-agent-finish → multi-agent-ship}/SKILL.md +8 -8
  114. package/pipeline/skills/shared/external/ios-coding-standard/SKILL.md +44 -5
  115. package/pipeline/skills/shared/external/ios-coding-standard/modules/_TEMPLATE.yml +82 -0
  116. package/pipeline/skills/shared/external/ios-coding-standard/references/STANDARD.md +169 -10
  117. package/pipeline/skills/shared/external/ios-coding-standard/references/lint-local.sh +13 -1
  118. package/pipeline/skills/shared/external/ios-coding-standard/references/rules.yml +335 -16
  119. package/pipeline/skills/skills-index.md +11 -8
@@ -75,7 +75,7 @@ Pipeline (after Phase 0) - shown as visual cards in terminal:
75
75
  Modes:
76
76
 
77
77
  (normal) Full 8 phases, Sonnet dev, Plan Approval Gate active, parallel review + Fable triage
78
- --dev Fast: Init -> Dev(Opus) -> Commit -> Report (no plan gate)
78
+ --dev Fast: Init -> Dev(Opus) -> Review -> Test -> Commit -> Report
79
79
  --local No worktree - works directly on local branch
80
80
  autopilot Skip all confirmations INCLUDING plan gate, auto commit/PR
81
81
  (EXCEPT Phase 7 channels menu - always pauses)
@@ -91,7 +91,7 @@ Dedicated commands (same as flags above):
91
91
  /multi-agent:local-autopilot "task" = multi-agent "task" --local autopilot
92
92
  /multi-agent:dev-local "task" = multi-agent "task" --dev --local
93
93
  /multi-agent:dev-local-autopilot "task" = multi-agent "task" --dev --local autopilot
94
- /multi-agent:finish [jira-id] [autopilot] Continue already-done LOCAL work: Review → Build+Test → PR → Jira analysis + test scenarios (no dev)
94
+ /multi-agent:ship [jira-id] [autopilot] Continue already-done LOCAL work: Review → Build+Test → PR → Jira analysis + test scenarios (no dev)
95
95
 
96
96
  ------------------------------------------------------------
97
97
 
@@ -318,7 +318,7 @@ Pipeline (Phase 0'dan sonra) - terminalde görsel kart olarak görünür:
318
318
  Modlar:
319
319
 
320
320
  (normal) Tam 8 faz, Sonnet dev, Plan Onay Kapısı aktif, paralel review + Fable triage
321
- --dev Hızlı: Init -> Dev(Opus) -> Commit -> Report (plan gate yok)
321
+ --dev Hızlı: Init -> Dev(Opus) -> Review -> Test -> Commit -> Report
322
322
  --local Worktree yok - doğrudan local branch'te çalışır
323
323
  autopilot Plan gate dahil tüm onayları atla, otomatik commit/PR
324
324
  (İSTİSNA: Phase 7 channels menüsü - her zaman durur)
@@ -334,7 +334,7 @@ Dedicated komutlar (yukarıdaki flag'lerin eşdeğeri):
334
334
  /multi-agent:local-autopilot "task" = multi-agent "task" --local autopilot
335
335
  /multi-agent:dev-local "task" = multi-agent "task" --dev --local
336
336
  /multi-agent:dev-local-autopilot "task" = multi-agent "task" --dev --local autopilot
337
- /multi-agent:finish [jira-id] [autopilot] Lokalde biten işi sürdür: Review → Build+Test → PR → Jira teknik analiz + test senaryoları (dev yok)
337
+ /multi-agent:ship [jira-id] [autopilot] Lokalde biten işi sürdür: Review → Build+Test → PR → Jira teknik analiz + test senaryoları (dev yok)
338
338
 
339
339
  ------------------------------------------------------------
340
340
 
@@ -1,6 +1,6 @@
1
1
  ---
2
- description: "Audit an iOS module against the shared coding-standard registry (95 stable-ID rules), produce a remediation plan, then hand off to dev/dev-local. Use for a standards pass on a module, or when a review needs rule IDs rather than opinions."
3
- description-tr: "Bir iOS modulunu paylasilan kodlama-standardi registry'sine (95 sabit-ID kural) gore denetler, duzeltme plani cikarir, sonra dev/dev-local'e devreder. Bir modulde standart gecisi icin, ya da bir review'un gorus yerine kural ID'si istedigi durumda kullan."
2
+ description: "Audit an iOS module against the shared coding-standard registry (99 stable-ID rules), produce a remediation plan, then hand off to dev/dev-local. Use for a standards pass on a module, or when a review needs rule IDs rather than opinions."
3
+ description-tr: "Bir iOS modulunu paylasilan kodlama-standardi registry'sine (99 sabit-ID kural) gore denetler, duzeltme plani cikarir, sonra dev/dev-local'e devreder. Bir modulde standart gecisi icin, ya da bir review'un gorus yerine kural ID'si istedigi durumda kullan."
4
4
  argument-hint: "[module name or path]"
5
5
  allowed-tools: Skill, Bash, Read, Edit, Write, AskUserQuestion
6
6
  ---
@@ -21,10 +21,10 @@ Run the full pipeline **without a worktree** and **with every confirmation skipp
21
21
  | `/multi-agent:autopilot "task"` | 7 phases (no User Test) | ✅ | ❌ (autopilot) |
22
22
  | `/multi-agent:local "task"` | 7 phases (no User Test) | ❌ | ✅ (interactive) |
23
23
  | **`/multi-agent:local-autopilot "task"`** | **7 phases (no User Test)** | **❌** | **❌ (autopilot)** |
24
- | `/multi-agent:dev "task"` | Init → Dev → Commit → Report | ✅ | ✅ |
25
- | `/multi-agent:dev-autopilot "task"` | Init → Dev → Commit → Report | ✅ | ❌ |
26
- | `/multi-agent:dev-local "task"` | Init → Dev → Commit → Report | ❌ | ✅ |
27
- | `/multi-agent:dev-local-autopilot "task"` | Init → Dev → Commit → Report | ❌ | ❌ (fastest) |
24
+ | `/multi-agent:dev "task"` | Init → Dev → Review → Test → Commit → Report | ✅ | ✅ |
25
+ | `/multi-agent:dev-autopilot "task"` | Init → Dev → Review → Commit → Report | ✅ | ❌ |
26
+ | `/multi-agent:dev-local "task"` | Init → Dev → Review → Commit → Report | ❌ | ✅ |
27
+ | `/multi-agent:dev-local-autopilot "task"` | Init → Dev → Review → Commit → Report | ❌ | ❌ (fastest) |
28
28
 
29
29
  ## What changes
30
30
 
@@ -10,7 +10,7 @@ argument-hint: "[#id] - optional: task ID (e.g. #2). If omitted, the most rece
10
10
 
11
11
  Resume a paused or failed task from the last successful phase.
12
12
 
13
- > **Not the same as `/multi-agent:finish`.** `resume` continues a **tracked pipeline task** (needs its `agent-state.json`/worktree) from where it stopped. `/multi-agent:finish` takes **ad-hoc local work** on the current branch (no prior task required) and runs the pipeline tail - Review → Build+Test → PR → Jira report - over it.
13
+ > **Not the same as `/multi-agent:ship`.** `resume` continues a **tracked pipeline task** (needs its `agent-state.json`/worktree) from where it stopped. `/multi-agent:ship` takes **ad-hoc local work** on the current branch (no prior task required) and runs the pipeline tail - Review → Build+Test → PR → Jira report - over it.
14
14
 
15
15
  ## Steps
16
16
 
@@ -177,12 +177,12 @@ Scope note: a guide governs only files under its own directory - a guide found
177
177
 
178
178
  **Claude Code (2 in parallel):**
179
179
  - Agent 1: `claude-fable-5` → security + architecture
180
- - Agent 2: `claude-sonnet-4-6` → general quality
180
+ - Agent 2: `claude-sonnet-5` → general quality
181
181
 
182
182
  **Copilot CLI (3 in parallel):**
183
- - Agent 1: `claude-opus-4-8` → security + architecture (Fable 5 is not offered on Copilot CLI)
183
+ - Agent 1: `claude-opus-5` → security + architecture (Fable 5 is not offered on Copilot CLI)
184
184
  - Agent 2: `gpt-5.4` → edge cases, alternate perspective
185
- - Agent 3: `claude-sonnet-4-6` → general quality
185
+ - Agent 3: `claude-sonnet-5` → general quality
186
186
 
187
187
  Each reviewer receives the diff, the module review guides from Step 2b (when any were found), plus the standard reviewer system prompt (see `$HOME/.claude/multi-agent-refs/phases/phase-4-review.md` for the prompt contract). Output: structured `findings[]` per reviewer.
188
188
 
@@ -192,8 +192,8 @@ When release-relevant iOS/Android files change, load the matching catalog:
192
192
 
193
193
  | Platform | Trigger files | Catalog |
194
194
  |---|---|---|
195
- | iOS | `**/Info.plist`, `**/PrivacyInfo.xcprivacy`, `**/*.entitlements`, `**/*App.swift`, `**/AppDelegate*.swift`, `**/SceneDelegate*.swift`, `**/project.pbxproj` | `pipeline/skills/shared/core/apple-archive-compliance/SKILL.md` - 18 rules + ITMS refs |
196
- | Android | `**/AndroidManifest.xml`, `**/build.gradle(.kts)`, `**/proguard-rules.pro`, `**/network_security_config.xml` | `pipeline/skills/shared/core/google-play-compliance/SKILL.md` - 21 rules + Play policy refs |
195
+ | iOS | `**/Info.plist`, `**/PrivacyInfo.xcprivacy`, `**/*.entitlements`, `**/*App.swift`, `**/AppDelegate*.swift`, `**/SceneDelegate*.swift`, `**/project.pbxproj` | `$HOME/.claude/skills/apple-archive-compliance/SKILL.md` - 18 rules + ITMS refs |
196
+ | Android | `**/AndroidManifest.xml`, `**/build.gradle(.kts)`, `**/proguard-rules.pro`, `**/network_security_config.xml` | `$HOME/.claude/skills/google-play-compliance/SKILL.md` - 21 rules + Play policy refs |
197
197
 
198
198
  Each finding gets the `ruleID` from the catalog plus the platform policy ref:
199
199
  - iOS: `(apple-archive-compliance / info-plist - Guideline 5.1.1)`
@@ -45,7 +45,7 @@ A single command that scans `pipeline/skills/` (or optionally `~/.claude/skills/
45
45
 
46
46
  1. **Run the script:**
47
47
  ```bash
48
- bash "$REPO_ROOT/pipeline/scripts/scan-skills.sh" $ARGUMENTS
48
+ bash "$HOME/.claude/scripts/scan-skills.sh" $ARGUMENTS
49
49
  ```
50
50
 
51
51
  2. **Interpret the output:**
@@ -79,7 +79,7 @@ JSON mode - for embedded automation:
79
79
 
80
80
  1. **Run the script:**
81
81
  ```bash
82
- bash "$REPO_ROOT/pipeline/scripts/search-logs.sh" "$ARGUMENTS"
82
+ bash "$HOME/.claude/scripts/search-logs.sh" "$ARGUMENTS"
83
83
  ```
84
84
 
85
85
  2. **Exit code:**
@@ -103,10 +103,8 @@ These are the RECOMMENDED key names. When creating NEW keys, use these. But exis
103
103
  | `bitbucket_user` | `${USER}_Bitbucket_Username` | `bitbucket` + (`user` or `name`) |
104
104
  | `github` | `${USER}_Github_Access_Token` | `github` or `gh` (exclude `ssh`) |
105
105
  | `confluence` | `${USER}_Confluence_Access_Token` | `confluence` |
106
- | `figma_pat` | `${USER}_Figma_Access_Token` | `figma` + (`token` or `pat` or `access`) + NOT `mcp` |
106
+ | `figma` | `${USER}_Figma_Access_Token` | `figma` + (`token` or `pat` or `access`) + NOT `mcp` |
107
107
  | `figma_mcp` | `${USER}_Figma_Mcp_Access_Token` | `figma` + `mcp` |
108
-
109
- > Multi-agent setup onboards **both** Figma tokens because the pipeline's 3-tier Figma access chain (see `pipeline/rules/figma-pipeline.md`) uses them in priority order: Tier 1 = MCP (`figma_mcp`), Tier 2 = REST PAT (`figma_pat`), Tier 3 = user screenshot fallback. Missing either token forces a downshift; missing both leaves Tier 3 as the only path.
110
108
  | `fortify` | `${USER}_Fortify_Access_Token` | `fortify` |
111
109
  | `graylog` | `${USER}_Graylog_Access_Token` | `graylog` |
112
110
  | `firebase` | `${USER}_Firebase_Access_Json` | `firebase` (any variant: `sa`, `service`, `account`, `access`, `json`) |
@@ -116,6 +114,8 @@ These are the RECOMMENDED key names. When creating NEW keys, use these. But exis
116
114
  | `appstore_connect_apple_id` | `${USER}_AppStoreConnect_Apple_Id` | (`appstore` or `asc`) + (`apple` or `account` or `user`) |
117
115
  | `appstore_connect_password_item` | `${USER}_AppStoreConnect_Password_Item` | (`appstore` or `asc` or `altool`) + (`password` or `app_specific`) |
118
116
 
117
+ > Multi-agent setup onboards **both** Figma tokens because the pipeline's 3-tier Figma access chain (see `$HOME/.claude/rules/figma-pipeline.md`) uses them in priority order: Tier 1 = MCP (`figma_mcp`), Tier 2 = REST PAT (`figma`), Tier 3 = user screenshot fallback. Missing either token forces a downshift; missing both leaves Tier 3 as the only path. The Tier 2 logical key is `figma`, not `figma_pat`: `figma_pat` is the pre-v13.6 name that `migrate-prefs.mjs` consolidates away, and writing a new mapping under it means the next migration deletes it.
118
+
119
119
  > The four App Store Connect entries are **iOS-only and optional**: skip them all and the pipeline still works, it just reports Gate 2 of `/multi-agent:testflight-validation` as `SKIPPED` (never as a pass). They mirror the Figma 3-tier shape - Tier 1 = API key (`appstore_connect_key_id` + `appstore_connect_issuer_id`), Tier 2 = Apple ID + app-specific password (`appstore_connect_apple_id` + `appstore_connect_password_item`), Tier 3 = nothing configured. **Offer Tier 2 first when the user says they cannot create an API key**: creating one needs an Admin or App Manager role in App Store Connect, while an app-specific password is generated by the account holder at `appleid.apple.com` with no team permission at all. Two of these hold identifiers rather than secrets (key id, issuer id) and one holds a keychain ITEM NAME, not a password - they still go through the mapping layer so every credential is read the same way. Onboarding mechanics in Step 3b.
120
120
 
121
121
  **1c. Resolution logic (per service):**
@@ -193,7 +193,7 @@ Save the resolved mapping to preferences:
193
193
  "bitbucket_user": "${USER}_Bitbucket_Username",
194
194
  "github": "${USER}_Github",
195
195
  "confluence": null,
196
- "figma_pat": "${USER}_Figma_Access_Token",
196
+ "figma": "${USER}_Figma_Access_Token",
197
197
  "figma_mcp": "${USER}_Figma_Mcp_Access_Token",
198
198
  "fortify": null,
199
199
  "graylog": null,
@@ -761,7 +761,7 @@ Clipboard helpers (`pbpaste`, `pbcopy`) are macOS-specific - for Copilot CLI o
761
761
  | `pbpaste` | `xclip -selection clipboard -o` (X11) or `wl-paste` (Wayland) | Install with `apt install xclip` or `apt install wl-clipboard` |
762
762
  | `pbcopy < /dev/null` | `xclip -selection clipboard < /dev/null` or `wl-copy --clear` | Same intent: clear clipboard after token paste |
763
763
 
764
- If you need to bypass the helper (debugging, raw inspection), the underlying platform commands are documented at the top of `pipeline/lib/credential-store.sh`. Otherwise stay on the helper - it keeps secrets off argv (stdin sentinel `-`) and writes both `-l` and `-s` attributes on macOS.
764
+ If you need to bypass the helper (debugging, raw inspection), the underlying platform commands are documented at the top of `$HOME/.claude/lib/credential-store.sh`. Otherwise stay on the helper - it keeps secrets off argv (stdin sentinel `-`) and writes both `-l` and `-s` attributes on macOS.
765
765
 
766
766
  If no backend is available, setup falls back to a plain-text prompt + a warning that the token is **not persisted** - pipeline phases will re-ask each session.
767
767
 
@@ -776,7 +776,7 @@ Standard key names (used when creating NEW tokens). Discovery may find existing
776
776
  | `bitbucket_user` | `${USER}_Bitbucket_Username` | Plain text | Bitbucket profile username |
777
777
  | `github` | `${USER}_Github_Access_Token` | PAT | GitHub Settings -> Tokens (scopes: repo, read:org, project) |
778
778
  | `confluence` | `${USER}_Confluence_Access_Token` | PAT | Confluence -> Profile -> Personal Access Tokens (VPN required) |
779
- | `figma_pat` | `${USER}_Figma_Access_Token` | PAT (Tier 2, REST API) | Figma Developer Settings (max 90 days). Token Save Flow prompt copy: "Figma Personal Access Token (for Tier 2)". |
779
+ | `figma` | `${USER}_Figma_Access_Token` | PAT (Tier 2, REST API) | Figma Developer Settings (max 90 days). Token Save Flow prompt copy: "Figma Personal Access Token (for Tier 2)". |
780
780
  | `figma_mcp` | `${USER}_Figma_Mcp_Access_Token` | OAuth (Tier 1, MCP) | Automatic via Claude Code Figma MCP remote auth. Token Save Flow prompt copy: "Figma MCP token (for Tier 1)". |
781
781
  | `fortify` | `${USER}_Fortify_Access_Token` | API Token | Fortify SSC -> Token Management (VPN required) |
782
782
  | `graylog` | `${USER}_Graylog_Access_Token` | PAT (API Basic `<token>:token`) | Graylog -> System -> Users and Teams -> Edit Tokens (VPN required). Auth is HTTP Basic with the token as username and literal `token` as password. |
@@ -4,11 +4,11 @@ description-tr: "Halihazırda bitmiş LOKAL işi pipeline kuyruğundan geçirir:
4
4
  allowed-tools: Agent, Bash, Read, Write, Edit, Glob, Grep, TaskCreate, TaskUpdate, TaskList, TaskGet, AskUserQuestion, WebFetch, WebSearch, Skill
5
5
  ---
6
6
 
7
- # multi-agent finish - Ship Local Work Through the Pipeline Tail
7
+ # multi-agent ship - Take Existing Branch Work Through the Pipeline Tail
8
8
 
9
9
  > **Language (read FIRST)**: Before any status output, read `prefs.global.outputLanguage` and render every conversational line in it. `AskUserQuestion` and external payloads stay English. Full contract: `$HOME/.claude/multi-agent-refs/rules.md` "Language Application".
10
10
 
11
- You already did the work locally - wrote code on the current branch and maybe tested it by hand (or ran `/multi-agent:local` / `/multi-agent:dev-local`, which skip Review + Test). `/multi-agent:finish` picks up from there and runs the **pipeline tail** over that existing local work in one command: parallel review, a build + test success gate, commit/push + PR, then the technical analysis and a **Jira comment with test scenarios**. It does NOT re-develop - Analysis / Planning / Dev (phases 1-3) are intentionally skipped; the diff already on the branch IS the input.
11
+ You already did the work locally - wrote code on the current branch and maybe tested it by hand, or committed it outside the pipeline entirely. (As of v14.0.0 the `--dev` family reviews its own output, so this command is for work that had no pipeline run behind it, not a patch for a mode that skipped review.) `/multi-agent:ship` picks up from there and runs the **pipeline tail** over that existing local work in one command: parallel review, a build + test success gate, commit/push + PR, then the technical analysis and a **Jira comment with test scenarios**. It does NOT re-develop - Analysis / Planning / Dev (phases 1-3) are intentionally skipped; the diff already on the branch IS the input.
12
12
 
13
13
  ## When to use it
14
14
 
@@ -24,10 +24,10 @@ You already did the work locally - wrote code on the current branch and maybe
24
24
  ## Input
25
25
 
26
26
  ```bash
27
- /multi-agent:finish # current branch vs its base; resolve Jira id from branch name
28
- /multi-agent:finish PROJ-12345 # bind to an explicit Jira id for the Phase 7 comment
29
- /multi-agent:finish --base develop # override the base branch for the diff
30
- /multi-agent:finish autopilot # no gate prompts: auto-fix blocking findings, auto-PR, auto-comment
27
+ /multi-agent:ship # current branch vs its base; resolve Jira id from branch name
28
+ /multi-agent:ship PROJ-12345 # bind to an explicit Jira id for the Phase 7 comment
29
+ /multi-agent:ship --base develop # override the base branch for the diff
30
+ /multi-agent:ship autopilot # no gate prompts: auto-fix blocking findings, auto-PR, auto-comment
31
31
  ```
32
32
 
33
33
  ## Pipeline
@@ -40,7 +40,7 @@ Phase 6: Commit → commit remaining local changes + push + open PR if no
40
40
  Phase 7: Report → technical analysis + Jira comment with test scenarios (channels: Jira / PR / Confluence / Wiki)
41
41
  ```
42
42
 
43
- Phases 1-3 (Analysis / Planning / Dev) are skipped by design - `finish` treats the current branch's local changes as the Phase 3 output.
43
+ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - `ship` treats the current branch's local changes as the Phase 3 output.
44
44
 
45
45
  ## Phase 0 - Context resolution (finish-specific)
46
46
 
@@ -54,10 +54,10 @@ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - `finish` treats
54
54
 
55
55
  - **Phase 4 Review** - run per `$HOME/.claude/multi-agent-refs/phases/phase-4-review.md` against the resolved diff: deterministic gates (Step 1.x), stack-specific parallel reviewers (Fable + Sonnet on Claude Code; GPT + Opus + Sonnet on Copilot CLI), Fable triage → `triage.accepted`. Blocking/important accepted findings:
56
56
  - interactive: present them and ask (`AskUserQuestion`) whether to fix now (loop back through a minimal Phase-3-style TDD fix) or proceed;
57
- - `autopilot` (or `prefs.global.finish.autoFix == true`): auto-fix accepted blocking/important findings, then re-review the fix, before advancing.
57
+ - `autopilot` (or `prefs.global.ship.autoFix == true`): auto-fix accepted blocking/important findings, then re-review the fix, before advancing.
58
58
  - **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.**
59
- - **Phase 6 Commit/PR** - per `$HOME/.claude/multi-agent-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 `$HOME/.claude/rules/pipeline-output-formatting.md` and `$HOME/.claude/rules/git-conventions.md` - `Ref: #N` / `Related: #N`, never `Closes/Fixes/Resolves`; NO AI/bot attribution anywhere.
60
- - **Phase 7 Report** - per `$HOME/.claude/multi-agent-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.
59
+ - **Phase 6 Commit/PR** - per `$HOME/.claude/multi-agent-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 `$HOME/.claude/multi-agent-refs/rules.md "External System Outputs"` and `$HOME/.claude/rules/git-conventions.md` - `Ref: #N` / `Related: #N`, never `Closes/Fixes/Resolves`; NO AI/bot attribution anywhere.
60
+ - **Phase 7 Report** - per `$HOME/.claude/multi-agent-refs/phases/phase-7-report.md` + `channels.md`: produce the **technical analysis** and **test scenarios**, then post to the configured channels. Default content for `ship`: 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.
61
61
 
62
62
  ## Modes
63
63
 
@@ -66,7 +66,7 @@ Phases 1-3 (Analysis / Planning / Dev) are skipped by design - `finish` treats
66
66
 
67
67
  ## Required: Phase Tracker Contract
68
68
 
69
- **The phase tracker is required.** Full spec: [`$HOME/.claude/multi-agent-refs/tracker-contract.md`]($HOME/.claude/multi-agent-refs/tracker-contract.md). `finish` registers its active phase set - `0:Init 4:Review 5:Build+Test 6:Commit 7:Report` - but NEVER resets a tracker that an earlier run already built (load-or-continue; contract section "Continuation runs"):
69
+ **The phase tracker is required.** Full spec: [`$HOME/.claude/multi-agent-refs/tracker-contract.md`]($HOME/.claude/multi-agent-refs/tracker-contract.md). `ship` registers its active phase set - `0:Init 4:Review 5:Build+Test 6:Commit 7:Report` - but NEVER resets a tracker that an earlier run already built (load-or-continue; contract section "Continuation runs"):
70
70
 
71
71
  ```bash
72
72
  # Phase 0, first shell call (every CLI). init ONLY when no prior state exists -
@@ -104,5 +104,5 @@ No TaskList widget. After every state change call `bash $HOME/.claude/scripts/ph
104
104
  ```bash
105
105
  /multi-agent:dev-local "PROJ-12345" # develop locally (Init→Dev→Commit→Report, no review/test)
106
106
  # ... you inspect / hand-test the change ...
107
- /multi-agent:finish # now: review + build/test + PR + Jira analysis & test scenarios
107
+ /multi-agent:ship # now: review + build/test + PR + Jira analysis & test scenarios
108
108
  ```
@@ -205,7 +205,7 @@ Rules for the report:
205
205
  - No AI or assistant attribution anywhere, per
206
206
  `$HOME/.claude/rules/git-conventions.md`.
207
207
  - Real newlines, no HTML entities, per
208
- `$HOME/.claude/rules/pipeline-output-formatting.md`.
208
+ `$HOME/.claude/multi-agent-refs/rules.md "External System Outputs"`.
209
209
 
210
210
  ## Step 8 - offer the next action, do not take it
211
211
 
@@ -89,8 +89,11 @@ Update the pipeline in one command. Existing preferences are preserved; only ski
89
89
  ```bash
90
90
  echo ""
91
91
  echo "Verification:"
92
- cd "$PIPE_DIR" && bash pipeline/scripts/smoke-schema-validation.sh 2>&1 | tail -1
93
- bash pipeline/scripts/smoke-cross-cli-behavior.sh 2>&1 | tail -1
92
+ # Repo-relative on purpose: these are maintainer smokes, excluded from installs.
93
+ # Both lines name $PIPE_DIR rather than relying on the cd from the line above,
94
+ # so neither can be read - or copied - as an installed-tree invocation.
95
+ bash "$PIPE_DIR/pipeline/scripts/smoke-schema-validation.sh" 2>&1 | tail -1
96
+ bash "$PIPE_DIR/pipeline/scripts/smoke-cross-cli-behavior.sh" 2>&1 | tail -1
94
97
  ```
95
98
 
96
99
  ## Output
@@ -133,7 +133,7 @@ Step A - run the standard visual + accessibility sweep (light + dark + large t
133
133
 
134
134
  Step B - dispatch compliance skill:
135
135
  iOS:
136
- Load pipeline/skills/shared/core/apple-archive-compliance/SKILL.md
136
+ Load $HOME/.claude/skills/apple-archive-compliance/SKILL.md
137
137
  Prereq: @mmerterden/dev-toolkit-mcp ≥ v2.9.0 (provides ios_app_store_audit MCP tool)
138
138
  - installable via npm; standalone ArchiveGuard binary deprecated in v8.4.0
139
139
  Artifact: pick newest .xcarchive under ~/Library/Developer/Xcode/Archives/**
@@ -142,7 +142,7 @@ Step B - dispatch compliance skill:
142
142
  OR (Node fallback): node -e "import('@mmerterden/dev-toolkit-mcp/tools/ios-app-store-audit/index.js').then(m => m.runAudit({ archivePath: '<path>', rules: 'all' }).then(r => console.log(JSON.stringify(r))))"
143
143
  Humanize via --lang en (promptLanguage is locked to "en"; pass --lang=tr explicitly to opt into Turkish)
144
144
  Android:
145
- Load pipeline/skills/shared/core/google-play-compliance/SKILL.md
145
+ Load $HOME/.claude/skills/google-play-compliance/SKILL.md
146
146
  Prereq: bundletool, aapt2, apksigner in PATH (Android SDK build-tools)
147
147
  Artifact: newest .aab under **/build/outputs/bundle/**/*.aab
148
148
  OR explicit path argument
@@ -31,6 +31,22 @@
31
31
  # always succeeds by design, so the caller stays alive to report a useful error.
32
32
 
33
33
  resolve_credential_store() {
34
+ # An explicit override wins. The usage note below has always documented
35
+ # `CRED_STORE` as an override, but this function used to assign over it
36
+ # unconditionally, so setting it did nothing whenever any host tree happened to
37
+ # carry a credential-store.sh - which is every normal machine. Honour it, and
38
+ # require it to be executable so a typo surfaces here rather than as a confusing
39
+ # failure three layers down.
40
+ if [ -n "${CRED_STORE:-}" ]; then
41
+ if [ -x "$CRED_STORE" ]; then
42
+ export CRED_STORE
43
+ return 0
44
+ fi
45
+ echo "credential helper: CRED_STORE is set to '$CRED_STORE', which is not executable." >&2
46
+ echo "Unset it to fall back to the installed helpers, or point it at a real file." >&2
47
+ return 1
48
+ fi
49
+
34
50
  # All three supported hosts. Codex was missing here, so a Codex-only install could
35
51
  # not resolve the credential helper at all - every fetcher on that host reported
36
52
  # "credential helper not found" while the file sat in ~/.codex/lib.
@@ -94,10 +94,18 @@ require_cmd() {
94
94
  # entries whose name already equals the logical key).
95
95
  PREFS_FILE="${MULTI_AGENT_PREFS:-$HOME/.claude/multi-agent-preferences.json}"
96
96
 
97
+ # Reader order is python3 then node, and both are here on purpose. python3 is present
98
+ # on macOS and every mainstream Linux; node is guaranteed wherever this pipeline is
99
+ # installed at all, because the installer IS a node program. Windows commonly has node
100
+ # and no python3, and with a python3-only reader the mapping was skipped there in
101
+ # silence: the lookup fell back to the LOGICAL key, searched Credential Manager for a
102
+ # target that does not exist, and reported the token as missing while it sat under its
103
+ # mapped name. A missing interpreter must not look like a missing token.
97
104
  resolve_key() {
98
105
  local logical="$1" mapped=""
99
- if [ -f "$PREFS_FILE" ] && command -v python3 >/dev/null 2>&1; then
100
- mapped=$(python3 -c '
106
+ if [ -f "$PREFS_FILE" ]; then
107
+ if command -v python3 >/dev/null 2>&1; then
108
+ mapped=$(python3 -c '
101
109
  import json, sys
102
110
  try:
103
111
  with open(sys.argv[1], encoding="utf-8") as fh:
@@ -108,6 +116,19 @@ name = prefs.get("global", {}).get("keychainMapping", {}).get(sys.argv[2])
108
116
  if isinstance(name, str) and name.strip():
109
117
  sys.stdout.write(name.strip())
110
118
  ' "$PREFS_FILE" "$logical" 2>/dev/null || true)
119
+ fi
120
+ if [ -z "$mapped" ] && command -v node >/dev/null 2>&1; then
121
+ mapped=$(node -e '
122
+ try {
123
+ const prefs = JSON.parse(require("fs").readFileSync(process.argv[1], "utf-8"));
124
+ const name = ((prefs.global || {}).keychainMapping || {})[process.argv[2]];
125
+ if (typeof name === "string" && name.trim()) process.stdout.write(name.trim());
126
+ } catch { /* no mapping readable - caller falls back to the logical key */ }
127
+ ' "$PREFS_FILE" "$logical" 2>/dev/null || true)
128
+ fi
129
+ if [ -z "$mapped" ] && ! command -v python3 >/dev/null 2>&1 && ! command -v node >/dev/null 2>&1; then
130
+ echo "WARN: neither python3 nor node found; keychainMapping ignored, looking up '$logical' verbatim." >&2
131
+ fi
111
132
  fi
112
133
  printf '%s' "${mapped:-$logical}"
113
134
  }
@@ -239,8 +260,23 @@ do_delete() {
239
260
  do_list() {
240
261
  case "$PLATFORM" in
241
262
  macos)
263
+ # Read `svce` - the SERVICE attribute, which is what `set` writes with -s and
264
+ # `get` looks up with -s. This used to read `0x00000007`, which is the LABEL:
265
+ # it happens to match for items written by keychain.py (which stamps both -l and
266
+ # -s), but it is the wrong key in principle and diverges on any item whose label
267
+ # was set independently, listing a name `get` cannot resolve.
268
+ #
269
+ # `dump-keychain` prints the first few attributes under numeric tags and the rest
270
+ # under named ones, and `svce` is in the named group - so the tag to match is
271
+ # `"svce"`, not `0x00000008`.
272
+ #
273
+ # Without `-d` this reads attributes only and does not prompt for access; only
274
+ # the data-dumping form does.
275
+ #
276
+ # A trailing `\000` appears when security prints the value in its hex+C-string
277
+ # form; it is not part of the service name.
242
278
  security dump-keychain 2>/dev/null \
243
- | awk -F'"' '/0x00000007 <blob>=/{print $2}' \
279
+ | awk -F'"' '/"svce"<blob>=/ && NF >= 5 { v = $4; sub(/\\000$/, "", v); if (v != "") print v }' \
244
280
  | sort -u
245
281
  ;;
246
282
  linux)
@@ -287,7 +323,14 @@ do_doctor() {
287
323
  fi
288
324
  ;;
289
325
  *)
290
- echo "Backend: (no platform support - falling back to env vars)"
326
+ # This used to advertise an env-var fallback. There isn't one here: `get` on an
327
+ # unrecognised platform exits 2. Individual callers have their own env escape
328
+ # hatches (figma-token.sh honours $FIGMA_PAT, for instance), but this helper
329
+ # does not, and claiming otherwise sent people looking for a mechanism that
330
+ # does not exist.
331
+ echo "Backend: none - unrecognised platform, \`get\` exits 2"
332
+ echo "Workaround: set the credential in the caller's own env var where one"
333
+ echo " exists (e.g. FIGMA_PAT), or run on macOS / Linux / Windows"
291
334
  ;;
292
335
  esac
293
336
  }
@@ -16,9 +16,10 @@
16
16
  # [--lang-prefixes TR,EN] [--batch 4]
17
17
  # fetch-figma-annotations.sh --url <figma-url> [--lang-prefixes TR,EN]
18
18
  #
19
- # Token source: credential-store.sh get <logical-key>, where <logical-key> is
20
- # read from prefs.global.keychainMapping.figma_pat. Falls back to the FIGMA_PAT
21
- # environment variable. No literal keychain service name is embedded here.
19
+ # Token source: figma-token.sh, which resolves the canonical `figma` logical key
20
+ # through credential-store.sh (falling back to the legacy `figma_pat` key, then
21
+ # to the FIGMA_PAT environment variable). No literal keychain service name is
22
+ # embedded here.
22
23
  #
23
24
  # Label parsing (config-driven via --lang-prefixes, ordered):
24
25
  # prefixed : lines like "TR: ...", "EN: ..." win regardless of order
@@ -37,7 +38,6 @@
37
38
 
38
39
  set -uo pipefail
39
40
 
40
- PREFS="$HOME/.claude/multi-agent-preferences.json"
41
41
  # Locate the resolver with an existence check, not a `.`-chain: sourcing a missing file
42
42
  # aborts the shell under `set -e`, `||` included, so a chain skips both its later
43
43
  # candidates and its trailing `|| true`. A missing store is tolerated here - CRED_STORE
@@ -57,6 +57,26 @@ for _cred_resolver in \
57
57
  done
58
58
  unset _cred_resolver
59
59
  CRED_STORE="${CRED_STORE:-}"
60
+
61
+ # Tier 2 token lookup lives in one file so it cannot drift per fetcher. Same
62
+ # existence-check discipline as the resolver loop above, and the same tolerance:
63
+ # without it, resolution still works through the FIGMA_PAT env fallback below.
64
+ for _figma_token_lib in \
65
+ "$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/figma-token.sh" \
66
+ "$HOME/.claude/lib/figma-token.sh" \
67
+ "$HOME/.copilot/lib/figma-token.sh" \
68
+ "$HOME/.codex/lib/figma-token.sh"; do
69
+ [ -f "$_figma_token_lib" ] || continue
70
+ # shellcheck source=/dev/null
71
+ . "$_figma_token_lib" 2>/dev/null || true
72
+ if command -v resolve_figma_token >/dev/null 2>&1; then break; fi
73
+ done
74
+ unset _figma_token_lib
75
+ if ! command -v resolve_figma_token >/dev/null 2>&1; then
76
+ resolve_figma_token() { [ -n "${FIGMA_PAT:-}" ] && printf '%s' "$FIGMA_PAT"; }
77
+ figma_token_remediation() { printf 'figma-token.sh not found - reinstall the pipeline, or export FIGMA_PAT.'; }
78
+ fi
79
+
60
80
  FIGMA_API="https://api.figma.com/v1"
61
81
  HTTP_TIMEOUT=60
62
82
 
@@ -92,32 +112,10 @@ fi
92
112
  [ -z "$FILE_KEY" ] && die 1 "missing --file-key (or a --url to parse it from)"
93
113
  [ -z "$NODE_IDS" ] && die 1 "missing --node-id (or a --url to parse it from)"
94
114
 
95
- # Resolve the Figma PAT (keychain via prefs mapping, then FIGMA_PAT env).
96
- resolve_token() {
97
- local token_key=""
98
- if [ -f "$PREFS" ] && command -v python3 >/dev/null 2>&1; then
99
- token_key=$(python3 -c "
100
- import json
101
- try:
102
- p = json.load(open('$PREFS'))
103
- print(p.get('global', {}).get('keychainMapping', {}).get('figma_pat') or '')
104
- except Exception:
105
- print('')
106
- " 2>/dev/null || true)
107
- fi
108
- if [ -n "$token_key" ] && [ -n "$CRED_STORE" ] && [ -x "$CRED_STORE" ]; then
109
- local tok
110
- tok=$("$CRED_STORE" get "$token_key" 2>/dev/null || true)
111
- if [ -n "$tok" ]; then printf '%s' "$tok"; return 0; fi
112
- fi
113
- if [ -n "${FIGMA_PAT:-}" ]; then printf '%s' "$FIGMA_PAT"; return 0; fi
114
- return 1
115
- }
116
-
117
- FIGMA_TOKEN=$(resolve_token || true)
115
+ FIGMA_TOKEN=$(resolve_figma_token || true)
118
116
  if [ -z "$FIGMA_TOKEN" ]; then
119
117
  printf '{"ok":false,"reason":"missing-token","source":"figma-rest","fileKey":"%s"}\n' "$FILE_KEY"
120
- die 2 "no Figma PAT (map prefs.global.keychainMapping.figma_pat or set FIGMA_PAT)"
118
+ die 2 "$(figma_token_remediation)"
121
119
  fi
122
120
 
123
121
  TMPDIR_A=$(mktemp -d "${TMPDIR:-/tmp}/figma-annot.XXXXXX")
@@ -23,10 +23,10 @@
23
23
  # Tier 2 (Figma REST + PAT) -> primary path here
24
24
  # Tier 3 (user screenshot) -> not handled; exit 3 with guidance
25
25
  #
26
- # Token source: credential-store.sh get <logical-key>, where <logical-key>
27
- # is read from prefs.global.keychainMapping.figma_pat. Falls back to the
28
- # FIGMA_PAT environment variable. No literal keychain service name is
29
- # embedded in this script.
26
+ # Token source: figma-token.sh, which resolves the canonical `figma` logical
27
+ # key through credential-store.sh (falling back to the legacy `figma_pat` key,
28
+ # then to the FIGMA_PAT environment variable). No literal keychain service name
29
+ # is embedded in this script.
30
30
  #
31
31
  # Exit codes:
32
32
  # 0 success
@@ -41,7 +41,6 @@ set -euo pipefail
41
41
 
42
42
  # --- Globals ----------------------------------------------------------------
43
43
 
44
- PREFS="$HOME/.claude/multi-agent-preferences.json"
45
44
  # Locate the resolver with an existence check, not a `.`-chain: sourcing a missing file
46
45
  # aborts the shell under `set -e`, `||` included, so a chain skips both its later
47
46
  # candidates and its trailing `|| true`. A missing store is tolerated here - CRED_STORE
@@ -61,6 +60,26 @@ for _cred_resolver in \
61
60
  done
62
61
  unset _cred_resolver
63
62
  CRED_STORE="${CRED_STORE:-}"
63
+
64
+ # Tier 2 token lookup lives in one file so it cannot drift per fetcher. Same
65
+ # existence-check discipline as the resolver loop above, and the same tolerance:
66
+ # without it, resolution still works through the FIGMA_PAT env fallback.
67
+ for _figma_token_lib in \
68
+ "$(cd "$(dirname "${BASH_SOURCE[0]:-$0}")" && pwd)/figma-token.sh" \
69
+ "$HOME/.claude/lib/figma-token.sh" \
70
+ "$HOME/.copilot/lib/figma-token.sh" \
71
+ "$HOME/.codex/lib/figma-token.sh"; do
72
+ [ -f "$_figma_token_lib" ] || continue
73
+ # shellcheck source=/dev/null
74
+ . "$_figma_token_lib" 2>/dev/null || true
75
+ if command -v resolve_figma_token >/dev/null 2>&1; then break; fi
76
+ done
77
+ unset _figma_token_lib
78
+ if ! command -v resolve_figma_token >/dev/null 2>&1; then
79
+ resolve_figma_token() { [ -n "${FIGMA_PAT:-}" ] && printf '%s' "$FIGMA_PAT"; }
80
+ figma_token_remediation() { printf 'figma-token.sh not found - reinstall the pipeline, or export FIGMA_PAT.'; }
81
+ fi
82
+
64
83
  FIGMA_API="https://api.figma.com/v1"
65
84
  PARALLEL_DL=4
66
85
  HTTP_TIMEOUT=60
@@ -105,8 +124,8 @@ Options:
105
124
  --help Show this help text and exit.
106
125
 
107
126
  Token resolution:
108
- Read via credential-store.sh using
109
- prefs.global.keychainMapping.figma_pat. Falls back to FIGMA_PAT env.
127
+ Read via credential-store.sh using prefs.global.keychainMapping.figma
128
+ (legacy figma_pat still honoured). Falls back to FIGMA_PAT env.
110
129
 
111
130
  Output:
112
131
  PNG files plus manifest.json in the output directory.
@@ -151,35 +170,6 @@ print(f"{file_key}\t{node}")
151
170
  PY
152
171
  }
153
172
 
154
- resolve_token() {
155
- # 1) Try the keychain via credential-store.sh, keyed by prefs mapping.
156
- local token_key=""
157
- if [ -f "$PREFS" ] && command -v python3 >/dev/null 2>&1; then
158
- token_key=$(python3 -c "
159
- import json, sys
160
- try:
161
- p = json.load(open('$PREFS'))
162
- print(p.get('global', {}).get('keychainMapping', {}).get('figma_pat') or '')
163
- except Exception:
164
- print('')
165
- " 2>/dev/null || true)
166
- fi
167
- if [ -n "$token_key" ] && [ -x "$CRED_STORE" ]; then
168
- local tok
169
- tok=$("$CRED_STORE" get "$token_key" 2>/dev/null || true)
170
- if [ -n "$tok" ]; then
171
- printf '%s' "$tok"
172
- return 0
173
- fi
174
- fi
175
- # 2) Env fallback so CI / one-shot use still works.
176
- if [ -n "${FIGMA_PAT:-}" ]; then
177
- printf '%s' "$FIGMA_PAT"
178
- return 0
179
- fi
180
- return 1
181
- }
182
-
183
173
  # curl_figma <output> <url>
184
174
  # Honours retries: 429 retries once after a 5s pause; 5xx uses exponential
185
175
  # backoff (1s, 2s, 4s). Writes the body to <output>, returns the HTTP code on
@@ -409,11 +399,10 @@ require_cmd python3
409
399
  # Tier 1 (Figma MCP) is not reachable from a bash script. Stay on Tier 2 (REST).
410
400
  log "INFO: Tier 1 (Figma MCP) not available from shell; using Tier 2 (REST)."
411
401
 
412
- FIGMA_TOKEN=$(resolve_token || true)
402
+ FIGMA_TOKEN=$(resolve_figma_token || true)
413
403
  if [ -z "${FIGMA_TOKEN:-}" ]; then
414
404
  log "Tier 3 (user-provided screenshot required): no PAT resolved."
415
- log "Hint: store the token via credential-store.sh, mapped through"
416
- log " prefs.global.keychainMapping.figma_pat, or export FIGMA_PAT."
405
+ log "Hint: $(figma_token_remediation)"
417
406
  exit 3
418
407
  fi
419
408