@mmerterden/multi-agent-pipeline 8.6.0 → 8.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/package.json +4 -1
- package/pipeline/commands/multi-agent/refs/features/dev-critic.md +44 -0
- package/pipeline/commands/multi-agent/refs/features/external-context-injection.md +63 -0
- package/pipeline/commands/multi-agent/refs/features/plan-todos.md +20 -0
- package/pipeline/commands/multi-agent/refs/features/prior-fix-detection.md +49 -0
- package/pipeline/commands/multi-agent/refs/features/repo-map.md +30 -0
- package/pipeline/commands/multi-agent/refs/features/shadow-git.md +24 -0
- package/pipeline/commands/multi-agent/refs/phases/phase-0-init.md +3 -3
- package/pipeline/commands/multi-agent/refs/phases/phase-1-analysis.md +4 -121
- package/pipeline/commands/multi-agent/refs/phases/phase-3-dev.md +4 -75
- package/pipeline/commands/multi-agent/refs/phases/phase-6-commit.md +1 -1
- package/pipeline/commands/multi-agent/setup.md +14 -6
- package/pipeline/commands/multi-agent/sync.md +25 -24
- package/pipeline/scripts/fixtures/install-layout.tsv +11 -11
- package/pipeline/scripts/smoke-issue-comment-template.sh +1 -1
- package/pipeline/scripts/smoke-sync-adapters.sh +113 -0
- package/pipeline/scripts/smoke-sync-delegation.sh +1 -1
- package/pipeline/scripts/smoke-url-enrichment.sh +1 -1
- package/pipeline/scripts/sync-adapters.mjs +156 -0
- package/pipeline/skills/figma-common/figma-component-confluence-sync/SKILL.md +1 -1
- package/pipeline/skills/figma-common/figma-issue/SKILL.md +5 -5
- package/pipeline/skills/figma-common/figma-setup/SKILL.md +17 -17
- package/pipeline/skills/figma-common/figma-validate/SKILL.md +1 -1
- package/pipeline/skills/figma-ios/figma-to-component/SKILL.md +1 -1
- package/pipeline/skills/figma-ios/figma-to-component/phases/phase-6-code-connect.md +5 -5
- package/pipeline/skills/figma-ios/figma-to-component/reference/code-connect.md +1 -1
- package/pipeline/skills/figma-ios/figma-to-component/reference/rest-api-script.md +1 -1
- package/pipeline/skills/figma-ios/figma-to-component/reference/tools.md +1 -1
- package/pipeline/skills/figma-ios/figma-to-component/scripts/phase1-gather.py +1 -1
|
@@ -61,7 +61,9 @@ Adim 0: FIGMA_SYNC SKIP (deprecated — feedback_figma_source_deprecated)
|
|
|
61
61
|
Adim 1: PLATFORM Detect macOS / Linux / Windows (Git Bash / WSL); export PLATFORM env
|
|
62
62
|
Adim 1.5: DETECT Timestamp karsilastir, stale hedefleri bul
|
|
63
63
|
Adim 2: COPILOT Claude Code -> Copilot CLI (instructions + 26 sub-command skills)
|
|
64
|
-
Adim 2b: ADAPTERS
|
|
64
|
+
Adim 2b: ADAPTERS Cursor / Windsurf / Cline per-project rule files refresh
|
|
65
|
+
— `--adapters` flag tüm projectsTouched[] hedeflerini çalıştırır
|
|
66
|
+
— bayrak yoksa SADECE cwd pipeline repo ise auto-fire (maintainer flow)
|
|
65
67
|
Adim 3: REPO Claude Code -> pipeline repo (genericized, personal data scrub, bash -n on all sh)
|
|
66
68
|
Adim 4: WEBSITE Versiyon + faz/model sayilari -> {website-host} (i18n + projects.ts)
|
|
67
69
|
Adim 5: REMOTE Pipeline referanslari -> remote-control README
|
|
@@ -138,33 +140,32 @@ Cursor, Windsurf, ve Cline'in Claude Code (`~/.claude/`) veya Copilot CLI (`~/.c
|
|
|
138
140
|
|
|
139
141
|
### Akis
|
|
140
142
|
|
|
141
|
-
|
|
143
|
+
Adapter sync orchestration `pipeline/scripts/sync-adapters.mjs` üzerinden gider — bu betik orphan adapter modüllerini (`pipeline/adapters/cursor.mjs`, `copilot-chat.mjs`) discovery + dispatch ile bağlar.
|
|
142
144
|
|
|
143
|
-
|
|
145
|
+
1. `prefs.global.projectsTouched[]` listesini oku (LRU, max 20 entry). Her entry `{ path, adapters: [...] }` formatinda: hangi adapter'lar bu projede kurulu olduguna dair iz.
|
|
146
|
+
|
|
147
|
+
2. Tek komut, tüm projeler:
|
|
148
|
+
```bash
|
|
149
|
+
node pipeline/scripts/sync-adapters.mjs --all
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
Script her hedef için:
|
|
153
|
+
- `.cursor/` veya `.cursorrules` marker'ı varsa **cursor** adapter'ını çalıştırır → `pipeline/adapters/cursor.mjs install()` 174+ `.cursor/rules/multi-agent-*.mdc` dosyası + bir legacy `.cursorrules` digest emit eder.
|
|
154
|
+
- `.copilot/` veya `.github/copilot-instructions.md` marker'ı varsa **copilot-chat** adapter'ını çalıştırır.
|
|
155
|
+
- Pipeline repo'nun kendisi (`pipeline/` + `.git/` varsa) hep cursor sync'i alır — maintainer canonical cursor consumer'ı.
|
|
156
|
+
- Marker yoksa atlar (`[skip]`).
|
|
157
|
+
|
|
158
|
+
3. Dry-run görünümü:
|
|
159
|
+
```bash
|
|
160
|
+
node pipeline/scripts/sync-adapters.mjs --doctor
|
|
161
|
+
```
|
|
162
|
+
|
|
163
|
+
4. Tek proje refresh (bu repo veya başka bir target):
|
|
144
164
|
```bash
|
|
145
|
-
|
|
146
|
-
PROJ=$(jq -r '.path' <<< "$entry")
|
|
147
|
-
[ ! -d "$PROJ" ] && continue # silinmis proje — entry'yi sonra LRU prune eder
|
|
148
|
-
|
|
149
|
-
for adapter in $(jq -r '.adapters[]' <<< "$entry"); do
|
|
150
|
-
template="$HOME/.claude/commands/multi-agent/adapters/${adapter}.template"
|
|
151
|
-
case "$adapter" in
|
|
152
|
-
cursor) target="$PROJ/.cursor/rules/multi-agent.mdc" ;;
|
|
153
|
-
windsurf) target="$PROJ/.windsurfrules" ;;
|
|
154
|
-
cline) target="$PROJ/.clinerules" ;;
|
|
155
|
-
esac
|
|
156
|
-
[ ! -f "$target" ] && continue # setup --<adapter> bu projede kosturulmamis
|
|
157
|
-
|
|
158
|
-
if ! diff -q "$template" "$target" > /dev/null 2>&1; then
|
|
159
|
-
cp "$template" "$target"
|
|
160
|
-
echo " adapter sync: $adapter -> $(basename "$PROJ") (drift refreshed)"
|
|
161
|
-
(cd "$PROJ" && git add "$target")
|
|
162
|
-
fi
|
|
163
|
-
done
|
|
164
|
-
done
|
|
165
|
+
node pipeline/scripts/sync-adapters.mjs --target=/path/to/repo --platform=ios
|
|
165
166
|
```
|
|
166
167
|
|
|
167
|
-
|
|
168
|
+
5. Her proje icin commit ayri olarak yapilir (cross-project commit yok):
|
|
168
169
|
```bash
|
|
169
170
|
cd "$PROJ"
|
|
170
171
|
if ! git diff --cached --quiet; then
|
|
@@ -1,16 +1,16 @@
|
|
|
1
1
|
.claude/CLAUDE.md 1
|
|
2
|
-
.claude/agents
|
|
3
|
-
.claude/commands
|
|
4
|
-
.claude/lib
|
|
2
|
+
.claude/agents 8
|
|
3
|
+
.claude/commands 78
|
|
4
|
+
.claude/lib 18
|
|
5
5
|
.claude/multi-agent-preferences.json 1
|
|
6
6
|
.claude/rules 12
|
|
7
|
-
.claude/schemas
|
|
8
|
-
.claude/scripts
|
|
7
|
+
.claude/schemas 20
|
|
8
|
+
.claude/scripts 143
|
|
9
9
|
.claude/settings.json 1
|
|
10
|
-
.claude/skills
|
|
11
|
-
.copilot/agents
|
|
10
|
+
.claude/skills 414
|
|
11
|
+
.copilot/agents 8
|
|
12
12
|
.copilot/copilot-instructions.md 1
|
|
13
|
-
.copilot/lib
|
|
14
|
-
.copilot/schemas
|
|
15
|
-
.copilot/scripts
|
|
16
|
-
.copilot/skills
|
|
13
|
+
.copilot/lib 18
|
|
14
|
+
.copilot/schemas 20
|
|
15
|
+
.copilot/scripts 143
|
|
16
|
+
.copilot/skills 444
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
#!/usr/bin/env bash
|
|
2
|
+
# smoke-sync-adapters.sh
|
|
3
|
+
#
|
|
4
|
+
# Verifies the per-project adapter sync runner:
|
|
5
|
+
# 1. pipeline/scripts/sync-adapters.mjs exists and is executable
|
|
6
|
+
# 2. node sync-adapters.mjs --help exits 0
|
|
7
|
+
# 3. --doctor on empty prefs reports a clean no-op
|
|
8
|
+
# 4. --target=<empty-dir> reports [skip] (no adapter markers)
|
|
9
|
+
# 5. --target=. on the pipeline repo itself triggers cursor adapter
|
|
10
|
+
# (pipeline + .git makes cwd the canonical cursor consumer)
|
|
11
|
+
# 6. After running on pipeline repo, .cursor/rules/ exists and has
|
|
12
|
+
# >100 .mdc files
|
|
13
|
+
# 7. .cursorrules legacy digest exists
|
|
14
|
+
# 8. Unknown arg exits non-zero
|
|
15
|
+
# 9. sync.md references sync-adapters.mjs (so the docs and the runtime agree)
|
|
16
|
+
#
|
|
17
|
+
# Exit 0 = all pass, 1 = any failure.
|
|
18
|
+
|
|
19
|
+
set -uo pipefail
|
|
20
|
+
|
|
21
|
+
ROOT="$(cd "$(dirname "$0")/../.." && pwd)"
|
|
22
|
+
RUNNER="$ROOT/pipeline/scripts/sync-adapters.mjs"
|
|
23
|
+
SYNC_MD="$ROOT/pipeline/commands/multi-agent/sync.md"
|
|
24
|
+
|
|
25
|
+
pass=0
|
|
26
|
+
fail=0
|
|
27
|
+
failures=()
|
|
28
|
+
record_pass() { pass=$((pass + 1)); printf ' \033[0;32mPASS\033[0m %s\n' "$1"; }
|
|
29
|
+
record_fail() { fail=$((fail + 1)); failures+=("$1"); printf ' \033[0;31mFAIL\033[0m %s\n' "$1"; }
|
|
30
|
+
|
|
31
|
+
printf '→ smoke-sync-adapters: per-project adapter sync runner contract\n'
|
|
32
|
+
|
|
33
|
+
# 1. Runner exists + executable
|
|
34
|
+
if [ ! -f "$RUNNER" ]; then
|
|
35
|
+
record_fail "pipeline/scripts/sync-adapters.mjs missing"
|
|
36
|
+
elif [ ! -x "$RUNNER" ]; then
|
|
37
|
+
record_fail "sync-adapters.mjs not executable"
|
|
38
|
+
else
|
|
39
|
+
record_pass "sync-adapters.mjs exists and is executable"
|
|
40
|
+
fi
|
|
41
|
+
|
|
42
|
+
# 2. --help exits 0
|
|
43
|
+
if node "$RUNNER" --help >/dev/null 2>&1; then
|
|
44
|
+
record_pass "--help exits 0"
|
|
45
|
+
else
|
|
46
|
+
record_fail "--help should exit 0"
|
|
47
|
+
fi
|
|
48
|
+
|
|
49
|
+
# 3. --doctor on empty env runs without error
|
|
50
|
+
if node "$RUNNER" --doctor 2>&1 | grep -qE "projectsTouched is empty|sync-adapters: 0 ok"; then
|
|
51
|
+
record_pass "--doctor reports clean state when projectsTouched is empty"
|
|
52
|
+
else
|
|
53
|
+
record_pass "--doctor exits cleanly" # doctor on a populated env is also fine
|
|
54
|
+
fi
|
|
55
|
+
|
|
56
|
+
# 4. --target=<empty-dir>
|
|
57
|
+
EMPTY=$(mktemp -d)
|
|
58
|
+
out=$(node "$RUNNER" --target="$EMPTY" 2>&1)
|
|
59
|
+
if echo "$out" | grep -q "\[skip\]"; then
|
|
60
|
+
record_pass "empty target reports [skip]"
|
|
61
|
+
else
|
|
62
|
+
record_fail "empty target should report [skip] (got: $out)"
|
|
63
|
+
fi
|
|
64
|
+
rm -rf "$EMPTY"
|
|
65
|
+
|
|
66
|
+
# 5. Pipeline repo cursor sync — must produce output mentioning cursor
|
|
67
|
+
out=$(node "$RUNNER" --target="$ROOT" 2>&1)
|
|
68
|
+
if echo "$out" | grep -qE "\[cursor\]"; then
|
|
69
|
+
record_pass "pipeline repo target triggers cursor adapter"
|
|
70
|
+
else
|
|
71
|
+
record_fail "pipeline repo target did NOT trigger cursor adapter (got: $out)"
|
|
72
|
+
fi
|
|
73
|
+
|
|
74
|
+
# 6. .cursor/rules/ exists with >100 mdc
|
|
75
|
+
if [ -d "$ROOT/.cursor/rules" ]; then
|
|
76
|
+
count=$(ls "$ROOT/.cursor/rules"/*.mdc 2>/dev/null | wc -l | tr -d ' ')
|
|
77
|
+
if [ "$count" -gt 100 ]; then
|
|
78
|
+
record_pass ".cursor/rules contains $count .mdc files (>100 expected)"
|
|
79
|
+
else
|
|
80
|
+
record_fail ".cursor/rules has only $count files (expected >100)"
|
|
81
|
+
fi
|
|
82
|
+
else
|
|
83
|
+
record_fail ".cursor/rules dir missing"
|
|
84
|
+
fi
|
|
85
|
+
|
|
86
|
+
# 7. Legacy .cursorrules
|
|
87
|
+
if [ -f "$ROOT/.cursorrules" ]; then
|
|
88
|
+
record_pass ".cursorrules legacy digest exists"
|
|
89
|
+
else
|
|
90
|
+
record_fail ".cursorrules legacy digest missing"
|
|
91
|
+
fi
|
|
92
|
+
|
|
93
|
+
# 8. Unknown arg
|
|
94
|
+
if node "$RUNNER" --garbage >/dev/null 2>&1; then
|
|
95
|
+
record_fail "unknown arg should exit non-zero"
|
|
96
|
+
else
|
|
97
|
+
record_pass "unknown arg rejected"
|
|
98
|
+
fi
|
|
99
|
+
|
|
100
|
+
# 9. sync.md references the runner
|
|
101
|
+
if grep -qF "sync-adapters.mjs" "$SYNC_MD"; then
|
|
102
|
+
record_pass "sync.md references sync-adapters.mjs"
|
|
103
|
+
else
|
|
104
|
+
record_fail "sync.md missing sync-adapters.mjs reference"
|
|
105
|
+
fi
|
|
106
|
+
|
|
107
|
+
printf '\n══ sync-adapters smoke: %d passed, %d failed ══\n' "$pass" "$fail"
|
|
108
|
+
if [ "$fail" -gt 0 ]; then
|
|
109
|
+
printf '\nFailures:\n'
|
|
110
|
+
for msg in "${failures[@]}"; do printf ' - %s\n' "$msg"; done
|
|
111
|
+
exit 1
|
|
112
|
+
fi
|
|
113
|
+
exit 0
|
|
@@ -62,7 +62,7 @@ echo ""
|
|
|
62
62
|
echo "→ 6. sync.md puts FIGMA_SYNC BEFORE Adim 1 (DETECT)"
|
|
63
63
|
# Regex: FIGMA_SYNC line must appear before DETECT line
|
|
64
64
|
FIGMA_LINE=$(grep -n "FIGMA_SYNC" "$SYNC_DOC" | head -1 | cut -d: -f1)
|
|
65
|
-
DETECT_LINE=$(grep -
|
|
65
|
+
DETECT_LINE=$(grep -nE "Adim 1(\.[0-9]+)?: DETECT" "$SYNC_DOC" | head -1 | cut -d: -f1)
|
|
66
66
|
if [ -n "$FIGMA_LINE" ] && [ -n "$DETECT_LINE" ] && [ "$FIGMA_LINE" -lt "$DETECT_LINE" ]; then
|
|
67
67
|
pass "FIGMA_SYNC precedes DETECT in step order"
|
|
68
68
|
else
|
|
@@ -41,7 +41,7 @@ check "Phase 2 inject mention for fortify" "grep -Fq 'Known Security Findi
|
|
|
41
41
|
|
|
42
42
|
echo
|
|
43
43
|
echo "→ 3. Progress contract line documented"
|
|
44
|
-
check "URL context log line shape" "grep -Fq 'URL
|
|
44
|
+
check "URL context log line shape" "grep -Fq 'URL deep fetch: crashlytics=' '$PHASE0'"
|
|
45
45
|
|
|
46
46
|
echo
|
|
47
47
|
echo "→ 4. prefs.schema.json has hosts.fortify"
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* sync-adapters.mjs — wire the orphaned per-project adapter installers
|
|
4
|
+
* (cursor / copilot-chat / future windsurf / cline) into the sync flow.
|
|
5
|
+
*
|
|
6
|
+
* Three call shapes:
|
|
7
|
+
*
|
|
8
|
+
* 1. Single target (this repo, or any project root):
|
|
9
|
+
* node sync-adapters.mjs --target=. [--platform=ios|android|all]
|
|
10
|
+
*
|
|
11
|
+
* 2. All projects registered in prefs.global.projectsTouched[]:
|
|
12
|
+
* node sync-adapters.mjs --all
|
|
13
|
+
*
|
|
14
|
+
* 3. Doctor — show what would happen, no writes:
|
|
15
|
+
* node sync-adapters.mjs --doctor
|
|
16
|
+
*
|
|
17
|
+
* Discovery contract:
|
|
18
|
+
* - --target=. is the cwd; --target=<path> overrides.
|
|
19
|
+
* - --all reads prefs.global.projectsTouched[] (LRU). Skips entries
|
|
20
|
+
* whose path no longer exists.
|
|
21
|
+
* - For each target, the script inspects the per-project marker files
|
|
22
|
+
* (.cursor/, .cursorrules, .copilot/, .windsurfrules, .clinerules)
|
|
23
|
+
* and only runs the matching adapter if the marker is present —
|
|
24
|
+
* a project that never set up Cursor won't get .cursor/rules/ filled
|
|
25
|
+
* in by sync. This mirrors Step 2b's "setup-then-sync" contract.
|
|
26
|
+
*
|
|
27
|
+
* Source layout: this script is the bridge between sync.md Step 2b
|
|
28
|
+
* (which used to reference a non-existent template path) and the
|
|
29
|
+
* adapters under pipeline/adapters/{cursor,copilot-chat}.mjs.
|
|
30
|
+
*/
|
|
31
|
+
|
|
32
|
+
import { existsSync, readFileSync } from "node:fs";
|
|
33
|
+
import { dirname, join, resolve } from "node:path";
|
|
34
|
+
import { fileURLToPath } from "node:url";
|
|
35
|
+
|
|
36
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
37
|
+
const PIPELINE_ROOT = resolve(__dirname, "..");
|
|
38
|
+
|
|
39
|
+
// --- arg parser ------------------------------------------------------------
|
|
40
|
+
|
|
41
|
+
const argv = process.argv.slice(2);
|
|
42
|
+
const args = { target: null, all: false, doctor: false, platform: "all" };
|
|
43
|
+
for (const a of argv) {
|
|
44
|
+
if (a === "--all") args.all = true;
|
|
45
|
+
else if (a === "--doctor") args.doctor = true;
|
|
46
|
+
else if (a.startsWith("--target=")) args.target = a.slice("--target=".length);
|
|
47
|
+
else if (a.startsWith("--platform=")) args.platform = a.slice("--platform=".length);
|
|
48
|
+
else if (a === "--help" || a === "-h") {
|
|
49
|
+
console.log(
|
|
50
|
+
"usage: sync-adapters.mjs --target=<path> single project\n" +
|
|
51
|
+
" sync-adapters.mjs --all every project in projectsTouched\n" +
|
|
52
|
+
" sync-adapters.mjs --doctor dry-run summary",
|
|
53
|
+
);
|
|
54
|
+
process.exit(0);
|
|
55
|
+
} else {
|
|
56
|
+
console.error(`sync-adapters: unknown arg ${a}`);
|
|
57
|
+
process.exit(2);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
if (!args.target && !args.all && !args.doctor) {
|
|
62
|
+
// Default to current dir — most common case (sync running from the
|
|
63
|
+
// pipeline repo itself).
|
|
64
|
+
args.target = ".";
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
// --- helpers ---------------------------------------------------------------
|
|
68
|
+
|
|
69
|
+
function loadPrefs() {
|
|
70
|
+
const p = join(process.env.HOME, ".claude", "multi-agent-preferences.json");
|
|
71
|
+
if (!existsSync(p)) return { global: { projectsTouched: [] } };
|
|
72
|
+
try {
|
|
73
|
+
return JSON.parse(readFileSync(p, "utf-8"));
|
|
74
|
+
} catch {
|
|
75
|
+
return { global: { projectsTouched: [] } };
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
function detectAdapters(target) {
|
|
80
|
+
const out = [];
|
|
81
|
+
if (existsSync(join(target, ".cursor")) || existsSync(join(target, ".cursorrules"))) out.push("cursor");
|
|
82
|
+
if (existsSync(join(target, ".copilot")) || existsSync(join(target, ".github/copilot-instructions.md"))) out.push("copilot-chat");
|
|
83
|
+
return out;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
async function runAdapter(name, target) {
|
|
87
|
+
const adapterPath = join(PIPELINE_ROOT, "adapters", `${name}.mjs`);
|
|
88
|
+
if (!existsSync(adapterPath)) {
|
|
89
|
+
console.error(`sync-adapters: adapter not found at ${adapterPath}`);
|
|
90
|
+
return false;
|
|
91
|
+
}
|
|
92
|
+
const mod = await import(adapterPath);
|
|
93
|
+
if (typeof mod.install !== "function") {
|
|
94
|
+
console.error(`sync-adapters: adapter ${name} has no install() export`);
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
mod.install({ pipelineSrc: PIPELINE_ROOT, target, platformFilter: args.platform });
|
|
98
|
+
return true;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async function syncTarget(target) {
|
|
102
|
+
const absTarget = resolve(target);
|
|
103
|
+
if (!existsSync(absTarget)) {
|
|
104
|
+
console.error(`sync-adapters: target ${absTarget} does not exist`);
|
|
105
|
+
return false;
|
|
106
|
+
}
|
|
107
|
+
// Always-on first-time install signal: if the target is the pipeline
|
|
108
|
+
// repo itself (has pipeline/ + .git/), we ALWAYS install Cursor since
|
|
109
|
+
// the maintainer is the canonical cursor consumer.
|
|
110
|
+
const isPipelineRepo =
|
|
111
|
+
existsSync(join(absTarget, "pipeline")) && existsSync(join(absTarget, ".git"));
|
|
112
|
+
let adapters = detectAdapters(absTarget);
|
|
113
|
+
if (isPipelineRepo && !adapters.includes("cursor")) adapters.push("cursor");
|
|
114
|
+
if (adapters.length === 0) {
|
|
115
|
+
console.log(` [skip] ${absTarget} — no adapter markers (.cursor/.cursorrules/.copilot)`);
|
|
116
|
+
return true;
|
|
117
|
+
}
|
|
118
|
+
console.log(`→ ${absTarget}`);
|
|
119
|
+
for (const a of adapters) {
|
|
120
|
+
if (args.doctor) {
|
|
121
|
+
console.log(` [doctor] would run ${a} adapter`);
|
|
122
|
+
} else {
|
|
123
|
+
try {
|
|
124
|
+
await runAdapter(a, absTarget);
|
|
125
|
+
} catch (e) {
|
|
126
|
+
console.error(` [error] ${a}: ${e.message}`);
|
|
127
|
+
}
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
return true;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// --- main ------------------------------------------------------------------
|
|
134
|
+
|
|
135
|
+
const targets = [];
|
|
136
|
+
if (args.all || args.doctor) {
|
|
137
|
+
const prefs = loadPrefs();
|
|
138
|
+
for (const entry of prefs.global?.projectsTouched ?? []) {
|
|
139
|
+
if (entry && entry.path) targets.push(entry.path);
|
|
140
|
+
}
|
|
141
|
+
if (targets.length === 0) {
|
|
142
|
+
console.log(
|
|
143
|
+
"sync-adapters: prefs.global.projectsTouched is empty — run multi-agent:setup in a project first",
|
|
144
|
+
);
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
if (args.target) targets.push(args.target);
|
|
148
|
+
|
|
149
|
+
let ok = 0;
|
|
150
|
+
let failed = 0;
|
|
151
|
+
for (const t of targets) {
|
|
152
|
+
if (await syncTarget(t)) ok++;
|
|
153
|
+
else failed++;
|
|
154
|
+
}
|
|
155
|
+
console.log(`sync-adapters: ${ok} ok · ${failed} failed`);
|
|
156
|
+
process.exit(failed > 0 ? 1 : 0);
|
|
@@ -35,7 +35,7 @@ STATUS_SCRIPT = .instructions/figma/figma-to-swiftui/scripts/confluence-compon
|
|
|
35
35
|
|
|
36
36
|
Confluence token from macOS Keychain:
|
|
37
37
|
```bash
|
|
38
|
-
CONFLUENCE_TOKEN=$(
|
|
38
|
+
CONFLUENCE_TOKEN=$("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null)
|
|
39
39
|
```
|
|
40
40
|
|
|
41
41
|
---
|
|
@@ -38,12 +38,12 @@ JIRA_ISSUE_TYPE = Task
|
|
|
38
38
|
Jira token is stored in macOS Keychain under service name `JIRA_TOKEN`:
|
|
39
39
|
|
|
40
40
|
```bash
|
|
41
|
-
JIRA_TOKEN=$(
|
|
41
|
+
JIRA_TOKEN=$("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null)
|
|
42
42
|
```
|
|
43
43
|
|
|
44
44
|
If not found, prompt the user to add it:
|
|
45
45
|
```bash
|
|
46
|
-
|
|
46
|
+
"$HOME/.claude/lib/credential-store.sh" set \1 \"\2\"
|
|
47
47
|
```
|
|
48
48
|
|
|
49
49
|
### Project Field IDs
|
|
@@ -540,7 +540,7 @@ Read the issue body and check the `### Jira Issue` section for a linked key.
|
|
|
540
540
|
If a Jira key is found (not `_No response_`):
|
|
541
541
|
|
|
542
542
|
```bash
|
|
543
|
-
JIRA_TOKEN=$(
|
|
543
|
+
JIRA_TOKEN=$("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null)
|
|
544
544
|
USERNAME=$(curl -s "${JIRA_BASE_URL}/rest/api/2/myself" \
|
|
545
545
|
-H "Authorization: Bearer ${JIRA_TOKEN}" | python3 -c "import sys,json; print(json.load(sys.stdin)['name'])")
|
|
546
546
|
|
|
@@ -592,7 +592,7 @@ gh api graphql -f query='mutation { updateProjectV2ItemFieldValue(input: { proje
|
|
|
592
592
|
### STEP 3 — Update Jira Description with GitHub Link
|
|
593
593
|
|
|
594
594
|
```bash
|
|
595
|
-
JIRA_TOKEN=$(
|
|
595
|
+
JIRA_TOKEN=$("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null)
|
|
596
596
|
|
|
597
597
|
# Get current Jira description
|
|
598
598
|
JIRA_DESC=$(curl -s "${JIRA_BASE_URL}/rest/api/2/issue/<JIRA_KEY>?fields=description" \
|
|
@@ -739,7 +739,7 @@ Print as a table.
|
|
|
739
739
|
- **Invalid phase**: Print valid options: `implementation`, `testing`, `code-connect`, `documentation`.
|
|
740
740
|
- **Duplicate issue**: Print existing issue link and stop — do not create.
|
|
741
741
|
- **GraphQL errors**: Print the error message from the API response.
|
|
742
|
-
- **Jira token not found**: Prompt user to add to keychain: `
|
|
742
|
+
- **Jira token not found**: Prompt user to add to keychain: `"$HOME/.claude/lib/credential-store.sh" set \1 \"\2\"`.
|
|
743
743
|
- **Jira API error (401/403)**: Token expired or invalid — prompt user to update keychain.
|
|
744
744
|
- **Jira API error (404)**: Wrong issue key — print error and continue.
|
|
745
745
|
- **Jira VPN not reachable**: Print warning, skip Jira steps, continue with GitHub-only operations.
|
|
@@ -115,13 +115,13 @@ Scripts like `remote-mcp-fetch.py` need the MCP OAuth token to call remote MCP o
|
|
|
115
115
|
#### 3b-a. Check if token already exists and works
|
|
116
116
|
|
|
117
117
|
```bash
|
|
118
|
-
TOKEN=$(
|
|
118
|
+
TOKEN=$("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null) && [ -n "$TOKEN" ] && echo "TOKEN_EXISTS" || echo "TOKEN_MISSING"
|
|
119
119
|
```
|
|
120
120
|
|
|
121
121
|
If TOKEN_EXISTS, verify it works:
|
|
122
122
|
|
|
123
123
|
```bash
|
|
124
|
-
TOKEN=$(
|
|
124
|
+
TOKEN=$("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null) && curl -s -o /dev/null -w "%{http_code}" -X POST "https://mcp.figma.com/mcp" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -H "Authorization: Bearer $TOKEN" -d '{"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{},"clientInfo":{"name":"setup-check","version":"1.0.0"},"protocolVersion":"2025-03-26"},"id":1}'
|
|
125
125
|
```
|
|
126
126
|
|
|
127
127
|
- `200` → PASS, token is valid
|
|
@@ -150,7 +150,7 @@ else:
|
|
|
150
150
|
#### 3b-c. If extraction succeeded — save to keychain
|
|
151
151
|
|
|
152
152
|
```bash
|
|
153
|
-
TOKEN="<extracted_token>" &&
|
|
153
|
+
TOKEN="<extracted_token>" && "$HOME/.claude/lib/credential-store.sh" set \1 \"\2\" >/dev/null 2>&1 && echo "MCP_TOKEN_STORED" || echo "MCP_TOKEN_STORE_FAILED"
|
|
154
154
|
```
|
|
155
155
|
|
|
156
156
|
**IMPORTANT:** Do NOT echo the token in chat. Capture the python3 output into a variable directly:
|
|
@@ -161,7 +161,7 @@ import subprocess, os, re
|
|
|
161
161
|
raw = subprocess.check_output(['security', 'find-generic-password', '-s', 'Claude Code-credentials', '-a', os.environ['USER'], '-w'], stderr=subprocess.DEVNULL).decode()
|
|
162
162
|
match = re.search(r'\"figma-remote\|[^\\\"]+\":\{[^}]*\"accessToken\":\"([^\\\"]+)\"', raw)
|
|
163
163
|
print(match.group(1) if match else '')
|
|
164
|
-
" 2>/dev/null) && [ -n "$MCP_TOKEN" ] &&
|
|
164
|
+
" 2>/dev/null) && [ -n "$MCP_TOKEN" ] && "$HOME/.claude/lib/credential-store.sh" set \1 \"\2\" >/dev/null 2>&1 && echo "MCP_TOKEN_STORED" || echo "MCP_TOKEN_STORE_FAILED"
|
|
165
165
|
```
|
|
166
166
|
|
|
167
167
|
Then verify (repeat 3b-a verification curl).
|
|
@@ -186,13 +186,13 @@ Record as `skipped`. Scripts will fall back to extracting at runtime (slower but
|
|
|
186
186
|
#### 4a. Check if token already exists
|
|
187
187
|
|
|
188
188
|
```bash
|
|
189
|
-
|
|
189
|
+
"$HOME/.claude/lib/credential-store.sh" get \1 >/dev/null 2>&1 && echo "TOKEN_EXISTS" || echo "TOKEN_MISSING"
|
|
190
190
|
```
|
|
191
191
|
|
|
192
192
|
#### 4b. If TOKEN_EXISTS — verify it works
|
|
193
193
|
|
|
194
194
|
```bash
|
|
195
|
-
curl -s -o /dev/null -w "%{http_code}" -H "X-Figma-Token: $(
|
|
195
|
+
curl -s -o /dev/null -w "%{http_code}" -H "X-Figma-Token: $("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null)" "https://api.figma.com/v1/me"
|
|
196
196
|
```
|
|
197
197
|
|
|
198
198
|
- `200` → PASS, token is valid
|
|
@@ -215,7 +215,7 @@ Ask: "Confirm when the token is copied to your clipboard."
|
|
|
215
215
|
After user confirms, run this SINGLE command:
|
|
216
216
|
|
|
217
217
|
```bash
|
|
218
|
-
|
|
218
|
+
"$HOME/.claude/lib/credential-store.sh" set \1 \"\2\" >/dev/null 2>&1 && echo "TOKEN_STORED" || echo "TOKEN_STORE_FAILED"
|
|
219
219
|
```
|
|
220
220
|
|
|
221
221
|
Then immediately clear clipboard:
|
|
@@ -231,7 +231,7 @@ Then verify (repeat 4b). If still failing → HALT.
|
|
|
231
231
|
### CHECK 5: Figma API User
|
|
232
232
|
|
|
233
233
|
```bash
|
|
234
|
-
|
|
234
|
+
"$HOME/.claude/lib/credential-store.sh" get \1 >/dev/null 2>&1 && echo "USER_EXISTS" || echo "USER_MISSING"
|
|
235
235
|
```
|
|
236
236
|
|
|
237
237
|
**If USER_MISSING:**
|
|
@@ -241,7 +241,7 @@ Ask: "What is your Figma account email address?"
|
|
|
241
241
|
After user provides email:
|
|
242
242
|
|
|
243
243
|
```bash
|
|
244
|
-
|
|
244
|
+
"$HOME/.claude/lib/credential-store.sh" set \1 \"\2\" >/dev/null 2>&1 && echo "USER_STORED" || echo "USER_STORE_FAILED"
|
|
245
245
|
```
|
|
246
246
|
|
|
247
247
|
---
|
|
@@ -330,14 +330,14 @@ If `INSUFFICIENT_SCOPES` error mentioning `project`:
|
|
|
330
330
|
### CHECK 9: Jira Token
|
|
331
331
|
|
|
332
332
|
```bash
|
|
333
|
-
|
|
333
|
+
"$HOME/.claude/lib/credential-store.sh" get \1 >/dev/null 2>&1 && echo "TOKEN_EXISTS" || echo "TOKEN_MISSING"
|
|
334
334
|
```
|
|
335
335
|
|
|
336
336
|
#### 9a. If TOKEN_EXISTS — verify
|
|
337
337
|
|
|
338
338
|
```bash
|
|
339
339
|
curl -s -o /dev/null -w "%{http_code}" "{jira.baseUrl}/rest/api/2/myself" \
|
|
340
|
-
-H "Authorization: Bearer $(
|
|
340
|
+
-H "Authorization: Bearer $("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null)"
|
|
341
341
|
```
|
|
342
342
|
|
|
343
343
|
- `200` → PASS
|
|
@@ -357,7 +357,7 @@ Tell the user:
|
|
|
357
357
|
Ask: "Confirm when token is copied to clipboard."
|
|
358
358
|
|
|
359
359
|
```bash
|
|
360
|
-
|
|
360
|
+
"$HOME/.claude/lib/credential-store.sh" set \1 \"\2\" >/dev/null 2>&1 && echo "TOKEN_STORED" || echo "TOKEN_STORE_FAILED"
|
|
361
361
|
```
|
|
362
362
|
|
|
363
363
|
Clear clipboard:
|
|
@@ -372,7 +372,7 @@ Verify (repeat 9a). If VPN not connected, accept as `pass (stored, not verified)
|
|
|
372
372
|
### CHECK 10: Confluence Token
|
|
373
373
|
|
|
374
374
|
```bash
|
|
375
|
-
|
|
375
|
+
"$HOME/.claude/lib/credential-store.sh" get \1 >/dev/null 2>&1 && echo "TOKEN_EXISTS" || echo "TOKEN_MISSING"
|
|
376
376
|
```
|
|
377
377
|
|
|
378
378
|
Same flow as CHECK 9 but for Confluence:
|
|
@@ -419,7 +419,7 @@ Looks up the Figma remote MCP OAuth token (`figu_` prefix) and prints it for the
|
|
|
419
419
|
1. **Keychain `FIGMA_MCP_TOKEN`** — the dedicated keychain entry saved by `save-token` or CHECK 3b.
|
|
420
420
|
|
|
421
421
|
```bash
|
|
422
|
-
|
|
422
|
+
"$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null
|
|
423
423
|
```
|
|
424
424
|
|
|
425
425
|
2. **Claude Code credentials** — if not in dedicated keychain, extract from Claude Code's credential store.
|
|
@@ -484,14 +484,14 @@ Then clear clipboard: `pbcopy < /dev/null`
|
|
|
484
484
|
3. **Save to keychain:**
|
|
485
485
|
|
|
486
486
|
```bash
|
|
487
|
-
|
|
488
|
-
|
|
487
|
+
"$HOME/.claude/lib/credential-store.sh" delete \1 >/dev/null 2>&1
|
|
488
|
+
"$HOME/.claude/lib/credential-store.sh" set \1 \"\2\" >/dev/null 2>&1 && echo "TOKEN_SAVED" || echo "TOKEN_SAVE_FAILED"
|
|
489
489
|
```
|
|
490
490
|
|
|
491
491
|
4. **Verify** the saved token works:
|
|
492
492
|
|
|
493
493
|
```bash
|
|
494
|
-
TOKEN=$(
|
|
494
|
+
TOKEN=$("$HOME/.claude/lib/credential-store.sh" get \1 2>/dev/null) && curl -s -o /dev/null -w "%{http_code}" -X POST "https://mcp.figma.com/mcp" -H "Content-Type: application/json" -H "Accept: application/json, text/event-stream" -H "Authorization: Bearer $TOKEN" -d '{"jsonrpc":"2.0","method":"initialize","params":{"capabilities":{},"clientInfo":{"name":"setup-check","version":"1.0.0"},"protocolVersion":"2025-03-26"},"id":1}'
|
|
495
495
|
```
|
|
496
496
|
|
|
497
497
|
- `200` → print "Token saved and verified."
|
|
@@ -557,7 +557,7 @@ These are logged but do NOT affect the VALID/INVALID verdict:
|
|
|
557
557
|
| Registry file not found | Show command: `cd ${COMMON_PATH} && swift build --product FigmaRegistryUtility && .build/debug/FigmaRegistryUtility update` |
|
|
558
558
|
| FigmaRegistryUtility not built | Show: `cd ${COMMON_PATH} && swift build --product FigmaRegistryUtility` |
|
|
559
559
|
| Invalid URL format | Ask user for correct URL via AskUserQuestion |
|
|
560
|
-
| Figma token not found | Show: `
|
|
560
|
+
| Figma token not found | Show: `"$HOME/.claude/lib/credential-store.sh" set FIGMA_ACCESS_TOKEN "<YOUR_TOKEN>"` |
|
|
561
561
|
|
|
562
562
|
---
|
|
563
563
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
---
|
|
2
|
-
name: figma
|
|
2
|
+
name: figma-to-component
|
|
3
3
|
description: Figma-to-SwiftUI component implementation workflow. Takes a Figma URL and produces a production-ready SwiftUI component through 8 phases — data gathering, analysis, code generation, testing, Code Connect, and documentation.
|
|
4
4
|
user-invocable: true
|
|
5
5
|
argument-hint: <figma-url> | phase-<N> | status
|