agent-orchestrator-kit 0.1.10 → 0.1.11
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 +17 -0
- package/README.md +64 -4
- package/bin/agent-orchestrator.js +277 -4
- package/package.json +4 -2
- package/profiles/generic/orchestrator.yaml +7 -0
- package/profiles/mvp/orchestrator.yaml +7 -0
- package/profiles/node/orchestrator.yaml +7 -0
- package/profiles/vue3/orchestrator.yaml +6 -0
- package/templates/.agents/amp.settings.json.example +4 -0
- package/templates/.agents/commands/opsx-apply.md +3 -3
- package/templates/.agents/commands/opsx-archive.md +2 -2
- package/templates/.agents/commands/opsx-design.md +2 -2
- package/templates/.agents/commands/opsx-explore.md +2 -2
- package/templates/.agents/commands/opsx-propose.md +5 -5
- package/templates/.agents/commands/opsx-quick.md +2 -2
- package/templates/.agents/commands/opsx-review.md +3 -3
- package/templates/.agents/commands/opsx-sync.md +2 -2
- package/templates/.agents/figma.local.env.example +10 -0
- package/templates/.agents/mcp.json.example +4 -0
- package/templates/.agents/rules/agent-orchestration.mdc +1 -0
- package/templates/.agents/rules/cli-via-npm.mdc +40 -0
- package/templates/.agents/rules/figma-token-setup.mdc +35 -0
- package/templates/.agents/rules/openspec-workflow.mdc +8 -5
- package/templates/.agents/skills/agent-orchestration/SKILL.md +8 -7
- package/templates/.agents/skills/openspec-apply-change/SKILL.md +3 -3
- package/templates/.agents/skills/openspec-archive-change/SKILL.md +2 -2
- package/templates/.agents/skills/openspec-explore/SKILL.md +2 -2
- package/templates/.agents/skills/openspec-howto/SKILL.md +4 -0
- package/templates/.agents/skills/openspec-propose/SKILL.md +5 -5
- package/templates/.agents/skills/openspec-sync-specs/SKILL.md +2 -2
- package/templates/.agents/subagents/code-reviewer.md +1 -1
- package/templates/.agents/subagents/openspec-guide.md +2 -2
- package/templates/.agents/subagents/setup-doctor.md +2 -1
- package/templates/.github/workflows/agent-verify.yml +3 -3
- package/templates/.github/workflows/spec-verify.yml +3 -3
- package/templates/AGENTS.md +15 -3
- package/templates/CLAUDE.md +3 -2
- package/templates/orchestrator.yaml +15 -0
- package/templates/scripts/figma-mcp-launcher.cjs +67 -0
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,23 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to this project will be documented in this file.
|
|
4
4
|
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [0.1.11] - 2026-07-21
|
|
8
|
+
|
|
9
|
+
### Added
|
|
10
|
+
- **Figma personal token setup** — local `.agents/figma.local.env` (gitignored) + committed `.agents/figma.local.env.example`
|
|
11
|
+
- **`scripts/figma-mcp-launcher.cjs`** — starts `figma-developer-mcp` with token from the env file (no secret in `.mcp.json`)
|
|
12
|
+
- **CLI** — `figma-setup`, `figma-status`, `figma-fetch` (REST file/nodes JSON via `X-Figma-Token`)
|
|
13
|
+
- Cursor/Amp MCP examples include optional `figma` server pointing at the launcher
|
|
14
|
+
- Agent rule `figma-token-setup.mdc`; setup-doctor + `/opsx:design` guidance (never ask for token in chat)
|
|
15
|
+
- `orchestrator.yaml` / profiles: `mcp.optional` includes `figma` + `figma.env_file` metadata
|
|
16
|
+
|
|
17
|
+
### Fixed
|
|
18
|
+
- **Amp / agent PATH** — templates now document and require `npx` / `npm run` for OpenSpec and `agent-orchestrator-kit` CLIs (bare binaries often exit 127 in Amp shells)
|
|
19
|
+
- Added always-apply rule `templates/.agents/rules/cli-via-npm.mdc`; updated openspec skills/commands, `AGENTS.md`, `CLAUDE.md`, `orchestrator.yaml` `cli.*` hints
|
|
20
|
+
- Never recommend `openspec validate --strict` without `<name>` / `--all`
|
|
21
|
+
|
|
5
22
|
## [0.1.10] - 2026-07-15
|
|
6
23
|
|
|
7
24
|
### Added
|
package/README.md
CHANGED
|
@@ -15,6 +15,8 @@ explore → [design] → propose → review → apply → verify → archive
|
|
|
15
15
|
|
|
16
16
|
Each role runs in a **separate agent session** with dedicated permissions, model hints, and handoff gates. The `openspec/changes/` folder acts as the **contract between agents** — no shared memory between sessions, only files.
|
|
17
17
|
|
|
18
|
+
**Figma PAT setup (v0.1.11+)** — local `.agents/figma.local.env` + MCP launcher (token never in chat / committed MCP JSON). See [Figma token](#figma-token-optional).
|
|
19
|
+
|
|
18
20
|
**Custom subagents (v0.1.10+)** ship with the kit and work in all three IDEs:
|
|
19
21
|
|
|
20
22
|
| Subagent | Role |
|
|
@@ -53,11 +55,12 @@ npx agent-orchestrator-kit@latest init --profile generic --ci gitlab --spec-veri
|
|
|
53
55
|
|
|
54
56
|
See [Installation](#installation) for profile/CI options.
|
|
55
57
|
|
|
56
|
-
**🔄 Already have the kit installed? Upgrade to latest (subagents in v0.1.10+):**
|
|
58
|
+
**🔄 Already have the kit installed? Upgrade to latest (Figma PAT in v0.1.11+, subagents in v0.1.10+):**
|
|
57
59
|
|
|
58
60
|
```bash
|
|
59
61
|
npx agent-orchestrator-kit@latest update
|
|
60
62
|
npx agent-orchestrator-kit@latest sync # or: ./scripts/sync-local-agent-skills.sh
|
|
63
|
+
npx agent-orchestrator-kit@latest figma-setup # optional — local Figma token
|
|
61
64
|
npx agent-orchestrator-kit@latest status
|
|
62
65
|
```
|
|
63
66
|
|
|
@@ -167,7 +170,7 @@ your-project/
|
|
|
167
170
|
| OpenSpec skills | All 7 skills for `/opsx:*` workflow |
|
|
168
171
|
| IDE sync | Cursor + Claude Code sync script (`--delete` semantics — removes stale skills/subagents) |
|
|
169
172
|
| Subagents | `openspec-guide`, `code-writer`, `code-reviewer`, `test-writer`, `setup-doctor`, `design-implementer` — native in Cursor (`.cursor/agents/`) + Claude Code (`.claude/agents/`), exposed to Amp as auto-generated `subagent-*` skill wrappers in `.agents/skills/` |
|
|
170
|
-
| CLI gates | `agent-orchestrator status` / `gate-check` — deterministic review-gate checks |
|
|
173
|
+
| CLI gates | `npx agent-orchestrator-kit status` / `gate-check` — deterministic review-gate checks (always via `npx`; see `cli-via-npm.mdc`) |
|
|
171
174
|
| CI | `agent-verify.yml` — GitHub (default) or GitLab fragment + `prebuild` hook, both run `gate-check` |
|
|
172
175
|
| AI Spec Verifier | `spec-verify.yml` + verifier scripts — GitLab or GitHub, opt-in (`--spec-verify`) |
|
|
173
176
|
| MCP templates | Memory MCP for Cursor and Amp |
|
|
@@ -190,6 +193,8 @@ Local only (not committed): `.cursor/` `.claude/` `.amp/`
|
|
|
190
193
|
|
|
191
194
|
Amp reads `.agents/skills/` and `AGENTS.md` **natively** — no sync needed.
|
|
192
195
|
|
|
196
|
+
**CLI note:** Amp shells often lack global `openspec` / `agent-orchestrator-kit` on PATH (exit 127). Agents must use `npx …` / `npm run …` — see always-apply rule `.agents/rules/cli-via-npm.mdc`.
|
|
197
|
+
|
|
193
198
|
1. Install the kit → `AGENTS.md` is created automatically.
|
|
194
199
|
2. Amp picks up skills from `.agents/skills/` on session start.
|
|
195
200
|
3. Copy Amp MCP config (on first sync):
|
|
@@ -262,7 +267,7 @@ You can add `context: fork` to explore/review skills for isolated subagent sessi
|
|
|
262
267
|
3. Rules are applied automatically per `alwaysApply: true`.
|
|
263
268
|
4. Subagents are invoked by name in chat (e.g. "use the code-reviewer subagent on this diff") or delegated to automatically by Cursor when their `description` matches the task. Add project-specific subagents by dropping `.md` files into `.agents/subagents/` and re-running sync.
|
|
264
269
|
|
|
265
|
-
**Memory MCP for Cursor** (`.mcp.json`):
|
|
270
|
+
**Memory + optional Figma MCP for Cursor** (`.mcp.json`):
|
|
266
271
|
|
|
267
272
|
```json
|
|
268
273
|
{
|
|
@@ -271,11 +276,17 @@ You can add `context: fork` to explore/review skills for isolated subagent sessi
|
|
|
271
276
|
"command": "npx",
|
|
272
277
|
"args": ["-y", "@modelcontextprotocol/server-memory"],
|
|
273
278
|
"env": { "MEMORY_FILE_PATH": ".cursor/memory.json" }
|
|
279
|
+
},
|
|
280
|
+
"figma": {
|
|
281
|
+
"command": "node",
|
|
282
|
+
"args": ["scripts/figma-mcp-launcher.cjs"]
|
|
274
283
|
}
|
|
275
284
|
}
|
|
276
285
|
}
|
|
277
286
|
```
|
|
278
287
|
|
|
288
|
+
Token lives in `.agents/figma.local.env` — see [Figma token](#figma-token-optional).
|
|
289
|
+
|
|
279
290
|
## The Pipeline in Detail
|
|
280
291
|
|
|
281
292
|
### Role 1: Explorer — `/opsx:explore`
|
|
@@ -304,7 +315,7 @@ You can add `context: fork` to explore/review skills for isolated subagent sessi
|
|
|
304
315
|
|
|
305
316
|
**Exit gate:**
|
|
306
317
|
```bash
|
|
307
|
-
openspec validate <name> --strict --type change # must be ✓
|
|
318
|
+
npx openspec validate <name> --strict --type change # must be ✓
|
|
308
319
|
```
|
|
309
320
|
|
|
310
321
|
```
|
|
@@ -582,6 +593,49 @@ npx frontend-agent-skills install --agent all --yes
|
|
|
582
593
|
|
|
583
594
|
> **Migrating from `vue-cursor-skills`?** Renamed to `frontend-agent-skills` v2 — same package, old CLI alias still works.
|
|
584
595
|
|
|
596
|
+
## Figma token (optional)
|
|
597
|
+
|
|
598
|
+
Personal Access Token for design intake (`/opsx:design`) and the optional Framelink `figma-developer-mcp` server. **Never paste the token into AI chat.**
|
|
599
|
+
|
|
600
|
+
### Setup (each developer, once)
|
|
601
|
+
|
|
602
|
+
```bash
|
|
603
|
+
npx agent-orchestrator-kit figma-setup
|
|
604
|
+
# open .agents/figma.local.env in the IDE and set:
|
|
605
|
+
# FIGMA_ACCESS_TOKEN=figd_...
|
|
606
|
+
npx agent-orchestrator-kit figma-status
|
|
607
|
+
```
|
|
608
|
+
|
|
609
|
+
Then restart Cursor / Amp.
|
|
610
|
+
|
|
611
|
+
| Path | Purpose | Git |
|
|
612
|
+
|------|---------|-----|
|
|
613
|
+
| `.agents/figma.local.env` | Your token (`FIGMA_ACCESS_TOKEN`) | **ignored** |
|
|
614
|
+
| `.agents/figma.local.env.example` | Template | committed |
|
|
615
|
+
| `scripts/figma-mcp-launcher.cjs` | Starts MCP with token from the env file | committed |
|
|
616
|
+
| `.mcp.json` → `figma` | Points at the launcher (no secret inline) | committed OK |
|
|
617
|
+
|
|
618
|
+
Create a token: Figma → Settings → Security → Personal access tokens (file content read as needed).
|
|
619
|
+
|
|
620
|
+
### CLI
|
|
621
|
+
|
|
622
|
+
```bash
|
|
623
|
+
npx agent-orchestrator-kit figma-setup
|
|
624
|
+
npx agent-orchestrator-kit figma-status
|
|
625
|
+
npx agent-orchestrator-kit figma-fetch --url "https://www.figma.com/design/FILE_KEY/Name?node-id=1-2" \
|
|
626
|
+
--out openspec/changes/<name>/assets/figma-nodes.json
|
|
627
|
+
```
|
|
628
|
+
|
|
629
|
+
`figma-fetch` uses the Figma REST API (`X-Figma-Token`) and writes JSON for design-brief capture. Live Figma is for design-intake only — apply uses `design-brief.md`.
|
|
630
|
+
|
|
631
|
+
### Upgrade existing projects
|
|
632
|
+
|
|
633
|
+
```bash
|
|
634
|
+
npx agent-orchestrator-kit@latest update
|
|
635
|
+
npx agent-orchestrator-kit figma-setup
|
|
636
|
+
./scripts/sync-local-agent-skills.sh
|
|
637
|
+
```
|
|
638
|
+
|
|
585
639
|
## Memory MCP — Shared State Between Sessions
|
|
586
640
|
|
|
587
641
|
Each role starts a fresh session. Memory MCP persists orchestration state across sessions so you don't re-explain context every time.
|
|
@@ -699,6 +753,12 @@ openspec/ # Committed — spec-driven workflow
|
|
|
699
753
|
|
|
700
754
|
## Changelog
|
|
701
755
|
|
|
756
|
+
### 0.1.11
|
|
757
|
+
- Optional **Figma personal token** setup: `.agents/figma.local.env` (gitignored) + `figma-mcp-launcher.cjs` (no secret in `.mcp.json`)
|
|
758
|
+
- CLI: `figma-setup`, `figma-status`, `figma-fetch` (REST nodes/file JSON)
|
|
759
|
+
- Agent rule + docs: never paste Figma tokens into chat
|
|
760
|
+
- Amp PATH hardening: prefer `npx` / `npm run` for OpenSpec and kit CLIs (`cli-via-npm` rule)
|
|
761
|
+
|
|
702
762
|
### 0.1.10
|
|
703
763
|
- Custom subagents (`.agents/subagents/`) synced to `.cursor/agents/` + `.claude/agents/`, exposed to Amp via auto-generated `subagent-*` skill wrappers
|
|
704
764
|
- 6 default subagents: `openspec-guide`, `code-writer`, `code-reviewer`, `test-writer`, `setup-doctor`, `design-implementer`
|
|
@@ -60,7 +60,23 @@ function specVerifyPathsFor(ci) {
|
|
|
60
60
|
const VALID_CI_PROVIDERS = ['gitlab', 'github', 'none'];
|
|
61
61
|
const VERIFY_OPENSPEC_SCRIPT = 'npx openspec validate --all --strict';
|
|
62
62
|
|
|
63
|
-
const GITIGNORE_LINES = [
|
|
63
|
+
const GITIGNORE_LINES = [
|
|
64
|
+
'.cursor',
|
|
65
|
+
'.cursor/memory.json',
|
|
66
|
+
'.amp/settings.json',
|
|
67
|
+
'.claude',
|
|
68
|
+
'.agents/figma.local.env',
|
|
69
|
+
];
|
|
70
|
+
|
|
71
|
+
const FIGMA_ENV_REL = join('.agents', 'figma.local.env');
|
|
72
|
+
const FIGMA_ENV_EXAMPLE_REL = join('.agents', 'figma.local.env.example');
|
|
73
|
+
const FIGMA_LAUNCHER_REL = join('scripts', 'figma-mcp-launcher.cjs');
|
|
74
|
+
const FIGMA_MANAGED_PATHS = [
|
|
75
|
+
FIGMA_ENV_EXAMPLE_REL,
|
|
76
|
+
FIGMA_LAUNCHER_REL,
|
|
77
|
+
join('.agents', 'mcp.json.example'),
|
|
78
|
+
join('.agents', 'amp.settings.json.example'),
|
|
79
|
+
];
|
|
64
80
|
|
|
65
81
|
const log = {
|
|
66
82
|
info: (msg) => console.log(pc.cyan(' →'), msg),
|
|
@@ -118,6 +134,141 @@ function mergeGitignore(projectDir, lines) {
|
|
|
118
134
|
log.ok('.gitignore updated');
|
|
119
135
|
}
|
|
120
136
|
|
|
137
|
+
function parseEnvFile(filePath) {
|
|
138
|
+
if (!existsSync(filePath)) return {};
|
|
139
|
+
const values = {};
|
|
140
|
+
for (const line of readFileSync(filePath, 'utf-8').split(/\r?\n/)) {
|
|
141
|
+
const trimmed = line.trim();
|
|
142
|
+
if (!trimmed || trimmed.startsWith('#')) continue;
|
|
143
|
+
const eq = trimmed.indexOf('=');
|
|
144
|
+
if (eq === -1) continue;
|
|
145
|
+
const key = trimmed.slice(0, eq).trim();
|
|
146
|
+
let value = trimmed.slice(eq + 1).trim();
|
|
147
|
+
if (
|
|
148
|
+
(value.startsWith('"') && value.endsWith('"')) ||
|
|
149
|
+
(value.startsWith("'") && value.endsWith("'"))
|
|
150
|
+
) {
|
|
151
|
+
value = value.slice(1, -1);
|
|
152
|
+
}
|
|
153
|
+
values[key] = value;
|
|
154
|
+
}
|
|
155
|
+
return values;
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
function readFigmaToken(projectDir) {
|
|
159
|
+
const envPath = join(projectDir, FIGMA_ENV_REL);
|
|
160
|
+
const values = parseEnvFile(envPath);
|
|
161
|
+
return values.FIGMA_ACCESS_TOKEN || values.FIGMA_API_KEY || '';
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
function isFigmaConfigured(projectDir) {
|
|
165
|
+
return Boolean(readFigmaToken(projectDir));
|
|
166
|
+
}
|
|
167
|
+
|
|
168
|
+
function ensureFigmaEnvFile(projectDir) {
|
|
169
|
+
const dest = join(projectDir, FIGMA_ENV_REL);
|
|
170
|
+
const example = join(projectDir, FIGMA_ENV_EXAMPLE_REL);
|
|
171
|
+
const kitExample = join(KIT_ROOT, 'templates', FIGMA_ENV_EXAMPLE_REL);
|
|
172
|
+
|
|
173
|
+
if (existsSync(dest)) {
|
|
174
|
+
return { created: false, path: dest };
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
const src = existsSync(example) ? example : kitExample;
|
|
178
|
+
if (!existsSync(src)) {
|
|
179
|
+
throw new Error(`Missing template: ${FIGMA_ENV_EXAMPLE_REL}`);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
183
|
+
copyFileSync(src, dest);
|
|
184
|
+
return { created: true, path: dest };
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
function refreshFigmaManagedFiles(projectDir) {
|
|
188
|
+
const templateDir = join(KIT_ROOT, 'templates');
|
|
189
|
+
for (const rel of FIGMA_MANAGED_PATHS) {
|
|
190
|
+
const src = join(templateDir, rel);
|
|
191
|
+
const dest = join(projectDir, rel);
|
|
192
|
+
if (!existsSync(src)) continue;
|
|
193
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
194
|
+
copyFileSync(src, dest);
|
|
195
|
+
log.ok(rel);
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
function ensureFigmaMcpEntry(projectDir) {
|
|
200
|
+
const figmaServer = {
|
|
201
|
+
command: 'node',
|
|
202
|
+
args: ['scripts/figma-mcp-launcher.cjs'],
|
|
203
|
+
};
|
|
204
|
+
|
|
205
|
+
const cursorPath = join(projectDir, '.mcp.json');
|
|
206
|
+
if (existsSync(cursorPath)) {
|
|
207
|
+
try {
|
|
208
|
+
const cfg = JSON.parse(readFileSync(cursorPath, 'utf-8'));
|
|
209
|
+
cfg.mcpServers = cfg.mcpServers || {};
|
|
210
|
+
if (!cfg.mcpServers.figma) {
|
|
211
|
+
cfg.mcpServers.figma = figmaServer;
|
|
212
|
+
writeFileSync(cursorPath, `${JSON.stringify(cfg, null, 2)}\n`);
|
|
213
|
+
log.ok('.mcp.json ← added figma server');
|
|
214
|
+
} else {
|
|
215
|
+
log.ok('.mcp.json already has figma server');
|
|
216
|
+
}
|
|
217
|
+
} catch {
|
|
218
|
+
log.warn('.mcp.json present but invalid JSON — merge figma server manually from .agents/mcp.json.example');
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
|
|
222
|
+
const ampPath = join(projectDir, '.amp', 'settings.json');
|
|
223
|
+
if (existsSync(ampPath)) {
|
|
224
|
+
try {
|
|
225
|
+
const cfg = JSON.parse(readFileSync(ampPath, 'utf-8'));
|
|
226
|
+
cfg['amp.mcpServers'] = cfg['amp.mcpServers'] || {};
|
|
227
|
+
if (!cfg['amp.mcpServers'].figma) {
|
|
228
|
+
cfg['amp.mcpServers'].figma = figmaServer;
|
|
229
|
+
writeFileSync(ampPath, `${JSON.stringify(cfg, null, 2)}\n`);
|
|
230
|
+
log.ok('.amp/settings.json ← added figma server');
|
|
231
|
+
} else {
|
|
232
|
+
log.ok('.amp/settings.json already has figma server');
|
|
233
|
+
}
|
|
234
|
+
} catch {
|
|
235
|
+
log.warn('.amp/settings.json present but invalid JSON — merge figma server manually');
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function parseFigmaUrl(url) {
|
|
241
|
+
try {
|
|
242
|
+
const parsed = new URL(url);
|
|
243
|
+
const parts = parsed.pathname.split('/').filter(Boolean);
|
|
244
|
+
const designIdx = parts.findIndex((p) => p === 'design' || p === 'file' || p === 'proto');
|
|
245
|
+
const fileKey = designIdx >= 0 ? parts[designIdx + 1] : '';
|
|
246
|
+
const nodeParam = parsed.searchParams.get('node-id') || '';
|
|
247
|
+
const nodeId = nodeParam ? nodeParam.replace(/-/g, ':') : '';
|
|
248
|
+
return { fileKey, nodeId };
|
|
249
|
+
} catch {
|
|
250
|
+
return { fileKey: '', nodeId: '' };
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
|
|
254
|
+
async function figmaApiGet(token, path) {
|
|
255
|
+
const response = await fetch(`https://api.figma.com/v1${path}`, {
|
|
256
|
+
headers: { 'X-Figma-Token': token },
|
|
257
|
+
});
|
|
258
|
+
const text = await response.text();
|
|
259
|
+
let data;
|
|
260
|
+
try {
|
|
261
|
+
data = JSON.parse(text);
|
|
262
|
+
} catch {
|
|
263
|
+
data = { err: text };
|
|
264
|
+
}
|
|
265
|
+
if (!response.ok) {
|
|
266
|
+
const message = data?.err || data?.message || response.statusText || `HTTP ${response.status}`;
|
|
267
|
+
throw new Error(String(message));
|
|
268
|
+
}
|
|
269
|
+
return data;
|
|
270
|
+
}
|
|
271
|
+
|
|
121
272
|
function resolveTemplate(templateName, profile) {
|
|
122
273
|
const profilePath = join(KIT_ROOT, 'profiles', profile, templateName);
|
|
123
274
|
if (existsSync(profilePath)) return profilePath;
|
|
@@ -406,14 +557,17 @@ function printNextSteps(profile, projectDir, ci = 'github', specVerify = false)
|
|
|
406
557
|
lines.push(` 3. Install Vue/JS stack skills:`);
|
|
407
558
|
lines.push(` ${pc.cyan('npx frontend-agent-skills install --agent all --yes')}`);
|
|
408
559
|
lines.push(` 4. MCP: copy .mcp.json (Cursor) / .amp/settings.json (Amp) from *.example files`);
|
|
409
|
-
lines.push(` 5.
|
|
560
|
+
lines.push(` 5. Optional Figma: ${pc.cyan('npx agent-orchestrator-kit figma-setup')} then paste token into ${pc.cyan('.agents/figma.local.env')} (never in chat)`);
|
|
561
|
+
lines.push(` 6. Start your first change:`);
|
|
410
562
|
} else if (profile === 'mvp') {
|
|
411
563
|
lines.push(` 3. For quick demos use ${pc.cyan('/opsx:quick <name>')} (propose + apply, no review gate)`);
|
|
412
564
|
lines.push(` 4. MCP: copy .mcp.json (Cursor) / .amp/settings.json (Amp) from *.example files`);
|
|
413
|
-
lines.push(` 5.
|
|
565
|
+
lines.push(` 5. Optional Figma: ${pc.cyan('npx agent-orchestrator-kit figma-setup')} then paste token into ${pc.cyan('.agents/figma.local.env')} (never in chat)`);
|
|
566
|
+
lines.push(` 6. Start exploring:`);
|
|
414
567
|
} else {
|
|
415
568
|
lines.push(` 3. MCP: copy .mcp.json (Cursor) / .amp/settings.json (Amp) from *.example files`);
|
|
416
|
-
lines.push(` 4.
|
|
569
|
+
lines.push(` 4. Optional Figma: ${pc.cyan('npx agent-orchestrator-kit figma-setup')} then paste token into ${pc.cyan('.agents/figma.local.env')} (never in chat)`);
|
|
570
|
+
lines.push(` 5. Start your first change:`);
|
|
417
571
|
}
|
|
418
572
|
|
|
419
573
|
const startCmd = profile === 'mvp' ? '/opsx:quick' : '/opsx:explore';
|
|
@@ -663,8 +817,13 @@ program
|
|
|
663
817
|
execSync(`chmod +x ${join(projectDir, 'scripts', 'sync-local-agent-skills.sh')}`);
|
|
664
818
|
} catch {}
|
|
665
819
|
|
|
820
|
+
log.title('Refreshing Figma setup templates');
|
|
821
|
+
refreshFigmaManagedFiles(projectDir);
|
|
822
|
+
mergeGitignore(projectDir, GITIGNORE_LINES);
|
|
823
|
+
|
|
666
824
|
log.ok(`Updated to v${KIT_VERSION}`);
|
|
667
825
|
log.info('Run ./scripts/sync-local-agent-skills.sh to sync to local IDE');
|
|
826
|
+
log.info('Optional Figma: npx agent-orchestrator-kit figma-setup');
|
|
668
827
|
});
|
|
669
828
|
|
|
670
829
|
program
|
|
@@ -839,4 +998,118 @@ program
|
|
|
839
998
|
}
|
|
840
999
|
});
|
|
841
1000
|
|
|
1001
|
+
program
|
|
1002
|
+
.command('figma-setup')
|
|
1003
|
+
.description('Create local Figma token env file (never prints the token)')
|
|
1004
|
+
.action(() => {
|
|
1005
|
+
const projectDir = process.cwd();
|
|
1006
|
+
log.title('agent-orchestrator figma-setup');
|
|
1007
|
+
|
|
1008
|
+
refreshFigmaManagedFiles(projectDir);
|
|
1009
|
+
mergeGitignore(projectDir, GITIGNORE_LINES);
|
|
1010
|
+
|
|
1011
|
+
const result = ensureFigmaEnvFile(projectDir);
|
|
1012
|
+
if (result.created) {
|
|
1013
|
+
log.ok(`Created ${FIGMA_ENV_REL}`);
|
|
1014
|
+
} else {
|
|
1015
|
+
log.ok(`${FIGMA_ENV_REL} already exists`);
|
|
1016
|
+
}
|
|
1017
|
+
|
|
1018
|
+
ensureFigmaMcpEntry(projectDir);
|
|
1019
|
+
|
|
1020
|
+
if (isFigmaConfigured(projectDir)) {
|
|
1021
|
+
log.ok('Figma token: configured');
|
|
1022
|
+
} else {
|
|
1023
|
+
log.warn('Figma token: missing — open .agents/figma.local.env and set FIGMA_ACCESS_TOKEN locally (do not paste into chat)');
|
|
1024
|
+
}
|
|
1025
|
+
|
|
1026
|
+
log.info('Restart Cursor / Amp after saving the token');
|
|
1027
|
+
log.info('Check: npx agent-orchestrator-kit figma-status');
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
program
|
|
1031
|
+
.command('figma-status')
|
|
1032
|
+
.description('Report whether a local Figma token is configured (never prints the token)')
|
|
1033
|
+
.action(() => {
|
|
1034
|
+
const projectDir = process.cwd();
|
|
1035
|
+
log.title('agent-orchestrator figma-status');
|
|
1036
|
+
|
|
1037
|
+
const envPath = join(projectDir, FIGMA_ENV_REL);
|
|
1038
|
+
if (!existsSync(envPath)) {
|
|
1039
|
+
log.err(`Figma token: not configured (missing ${FIGMA_ENV_REL})`);
|
|
1040
|
+
log.info('Run: npx agent-orchestrator-kit figma-setup');
|
|
1041
|
+
process.exitCode = 1;
|
|
1042
|
+
return;
|
|
1043
|
+
}
|
|
1044
|
+
|
|
1045
|
+
if (!isFigmaConfigured(projectDir)) {
|
|
1046
|
+
log.err('Figma token: not configured (FIGMA_ACCESS_TOKEN is empty)');
|
|
1047
|
+
log.info('Edit .agents/figma.local.env locally — never paste the token into chat');
|
|
1048
|
+
process.exitCode = 1;
|
|
1049
|
+
return;
|
|
1050
|
+
}
|
|
1051
|
+
|
|
1052
|
+
log.ok('Figma token: configured');
|
|
1053
|
+
if (existsSync(join(projectDir, FIGMA_LAUNCHER_REL))) {
|
|
1054
|
+
log.ok(`MCP launcher: ${FIGMA_LAUNCHER_REL}`);
|
|
1055
|
+
} else {
|
|
1056
|
+
log.warn(`MCP launcher missing — run npx agent-orchestrator-kit update`);
|
|
1057
|
+
}
|
|
1058
|
+
});
|
|
1059
|
+
|
|
1060
|
+
program
|
|
1061
|
+
.command('figma-fetch')
|
|
1062
|
+
.description('Fetch Figma file/nodes JSON via REST API using the local token')
|
|
1063
|
+
.option('--url <url>', 'Figma design URL (file key + optional node-id)')
|
|
1064
|
+
.option('--file <key>', 'Figma file key')
|
|
1065
|
+
.option('--nodes <ids>', 'Comma-separated node ids (1:2 or 1-2)')
|
|
1066
|
+
.option('--out <path>', 'Output JSON path', 'figma-nodes.json')
|
|
1067
|
+
.action(async (opts) => {
|
|
1068
|
+
const projectDir = process.cwd();
|
|
1069
|
+
log.title('agent-orchestrator figma-fetch');
|
|
1070
|
+
|
|
1071
|
+
const token = readFigmaToken(projectDir);
|
|
1072
|
+
if (!token) {
|
|
1073
|
+
log.err('Figma token: not configured');
|
|
1074
|
+
log.info('Run: npx agent-orchestrator-kit figma-setup');
|
|
1075
|
+
process.exitCode = 1;
|
|
1076
|
+
return;
|
|
1077
|
+
}
|
|
1078
|
+
|
|
1079
|
+
let fileKey = opts.file || '';
|
|
1080
|
+
let nodes = opts.nodes || '';
|
|
1081
|
+
if (opts.url) {
|
|
1082
|
+
const parsed = parseFigmaUrl(opts.url);
|
|
1083
|
+
fileKey = fileKey || parsed.fileKey;
|
|
1084
|
+
nodes = nodes || parsed.nodeId;
|
|
1085
|
+
}
|
|
1086
|
+
|
|
1087
|
+
if (!fileKey) {
|
|
1088
|
+
log.err('Missing --file <key> or --url <figma-url>');
|
|
1089
|
+
process.exitCode = 1;
|
|
1090
|
+
return;
|
|
1091
|
+
}
|
|
1092
|
+
|
|
1093
|
+
const nodeIds = String(nodes || '')
|
|
1094
|
+
.split(',')
|
|
1095
|
+
.map((id) => id.trim())
|
|
1096
|
+
.filter(Boolean)
|
|
1097
|
+
.map((id) => id.replace(/-/g, ':'));
|
|
1098
|
+
|
|
1099
|
+
try {
|
|
1100
|
+
const path = nodeIds.length
|
|
1101
|
+
? `/files/${encodeURIComponent(fileKey)}/nodes?ids=${encodeURIComponent(nodeIds.join(','))}`
|
|
1102
|
+
: `/files/${encodeURIComponent(fileKey)}`;
|
|
1103
|
+
log.info(nodeIds.length ? `Fetching ${nodeIds.length} node(s)…` : 'Fetching full file…');
|
|
1104
|
+
const data = await figmaApiGet(token, path);
|
|
1105
|
+
const outPath = join(projectDir, opts.out);
|
|
1106
|
+
mkdirSync(dirname(outPath), { recursive: true });
|
|
1107
|
+
writeFileSync(outPath, `${JSON.stringify(data, null, 2)}\n`);
|
|
1108
|
+
log.ok(`Wrote ${opts.out}`);
|
|
1109
|
+
} catch (error) {
|
|
1110
|
+
log.err(`Figma API error: ${error.message}`);
|
|
1111
|
+
process.exitCode = 1;
|
|
1112
|
+
}
|
|
1113
|
+
});
|
|
1114
|
+
|
|
842
1115
|
program.parse();
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "agent-orchestrator-kit",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"description": "Universal AI agent orchestration kit for Cursor, Claude Code, and Amp Code — spec-driven OpenSpec pipeline
|
|
3
|
+
"version": "0.1.11",
|
|
4
|
+
"description": "Universal AI agent orchestration kit for Cursor, Claude Code, and Amp Code — spec-driven OpenSpec pipeline, cross-IDE subagents, and optional local Figma PAT setup (figma-setup / figma-status / figma-fetch)",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai-agent",
|
|
7
7
|
"cursor",
|
|
@@ -13,6 +13,8 @@
|
|
|
13
13
|
"subagents",
|
|
14
14
|
"custom-subagents",
|
|
15
15
|
"design-to-code",
|
|
16
|
+
"figma",
|
|
17
|
+
"figma-mcp",
|
|
16
18
|
"developer-tools"
|
|
17
19
|
],
|
|
18
20
|
"author": "Maksim Shevyakov <makshc2>",
|
|
@@ -57,9 +57,15 @@ mcp:
|
|
|
57
57
|
baseline:
|
|
58
58
|
- memory
|
|
59
59
|
optional:
|
|
60
|
+
- figma
|
|
60
61
|
- github
|
|
61
62
|
- browser
|
|
62
63
|
|
|
64
|
+
figma:
|
|
65
|
+
env_file: .agents/figma.local.env
|
|
66
|
+
token_key: FIGMA_ACCESS_TOKEN
|
|
67
|
+
mcp_launcher: scripts/figma-mcp-launcher.cjs
|
|
68
|
+
|
|
63
69
|
verifier:
|
|
64
70
|
lint_command: "npm run lint"
|
|
65
71
|
build_command: "npm run build"
|
|
@@ -16,7 +16,7 @@ Implement tasks from an OpenSpec change.
|
|
|
16
16
|
If a name is provided, use it. Otherwise:
|
|
17
17
|
- Infer from conversation context if the user mentioned a change
|
|
18
18
|
- Auto-select if only one active change exists
|
|
19
|
-
- If ambiguous, run `openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select
|
|
19
|
+
- If ambiguous, run `npx openspec list --json` to get available changes and use the **AskUserQuestion tool** to let the user select
|
|
20
20
|
|
|
21
21
|
Always announce: "Using change: <name>" and how to override (e.g., `/opsx:apply <other>`).
|
|
22
22
|
|
|
@@ -35,7 +35,7 @@ Implement tasks from an OpenSpec change.
|
|
|
35
35
|
|
|
36
36
|
2. **Check status to understand the schema**
|
|
37
37
|
```bash
|
|
38
|
-
openspec status --change "<name>" --json
|
|
38
|
+
npx openspec status --change "<name>" --json
|
|
39
39
|
```
|
|
40
40
|
Parse the JSON to understand:
|
|
41
41
|
- `schemaName`: The workflow being used (e.g., "spec-driven")
|
|
@@ -45,7 +45,7 @@ Implement tasks from an OpenSpec change.
|
|
|
45
45
|
3. **Get apply instructions**
|
|
46
46
|
|
|
47
47
|
```bash
|
|
48
|
-
openspec instructions apply --change "<name>" --json
|
|
48
|
+
npx openspec instructions apply --change "<name>" --json
|
|
49
49
|
```
|
|
50
50
|
|
|
51
51
|
This returns:
|
|
@@ -13,7 +13,7 @@ Archive a completed change in the experimental workflow.
|
|
|
13
13
|
|
|
14
14
|
1. **If no change name provided, prompt for selection**
|
|
15
15
|
|
|
16
|
-
Run `openspec list --json` to get available changes. Use the **AskUserQuestion tool** to let the user select.
|
|
16
|
+
Run `npx openspec list --json` to get available changes. Use the **AskUserQuestion tool** to let the user select.
|
|
17
17
|
|
|
18
18
|
Show only active changes (not already archived).
|
|
19
19
|
Include the schema used for each change if available.
|
|
@@ -22,7 +22,7 @@ Archive a completed change in the experimental workflow.
|
|
|
22
22
|
|
|
23
23
|
2. **Check artifact completion status**
|
|
24
24
|
|
|
25
|
-
Run `openspec status --change "<name>" --json` to check artifact completion.
|
|
25
|
+
Run `npx openspec status --change "<name>" --json` to check artifact completion.
|
|
26
26
|
|
|
27
27
|
Parse the JSON to understand:
|
|
28
28
|
- `schemaName`: The workflow being used
|
|
@@ -18,7 +18,7 @@ Capture design into a durable brief for an OpenSpec change. One-shot intake from
|
|
|
18
18
|
### 1. Select the change
|
|
19
19
|
|
|
20
20
|
If name provided — use it. Otherwise:
|
|
21
|
-
- Run `openspec list --json` to list active changes.
|
|
21
|
+
- Run `npx openspec list --json` to list active changes.
|
|
22
22
|
- Auto-select if only one exists.
|
|
23
23
|
- Ask the user if ambiguous.
|
|
24
24
|
|
|
@@ -28,7 +28,7 @@ Announce: "Design intake for change: **<name>**"
|
|
|
28
28
|
|
|
29
29
|
Use the first available source; do not climb the ladder twice:
|
|
30
30
|
|
|
31
|
-
1. **Figma MCP** — one pass only (`get_design_context` / screenshot / metadata). Capture everything needed immediately; never call Figma again during later apply.
|
|
31
|
+
1. **Figma MCP** — one pass only (`get_design_context` / screenshot / metadata). Capture everything needed immediately; never call Figma again during later apply. If MCP fails, check `npx agent-orchestrator-kit figma-status`. If the token is missing, tell the user to run `figma-setup` and edit `.agents/figma.local.env` locally — **never ask them to paste the token into chat**. Optional REST dump: `npx agent-orchestrator-kit figma-fetch --url "<figma-url>" --out openspec/changes/<name>/assets/figma-nodes.json`.
|
|
32
32
|
2. **Exported images** — PNG/SVG already in the repo or attached by the user.
|
|
33
33
|
3. **Screenshots** — UI captures (desktop/mobile).
|
|
34
34
|
4. **Photos** — physical mockups or whiteboard photos.
|
|
@@ -86,7 +86,7 @@ You have full context of the OpenSpec system. Use it naturally, don't force it.
|
|
|
86
86
|
|
|
87
87
|
At the start, quickly check what exists:
|
|
88
88
|
```bash
|
|
89
|
-
openspec list --json
|
|
89
|
+
npx openspec list --json
|
|
90
90
|
```
|
|
91
91
|
|
|
92
92
|
This tells you:
|
|
@@ -108,7 +108,7 @@ Think freely. When insights crystallize, you might offer:
|
|
|
108
108
|
If the user mentions a change or you detect one is relevant:
|
|
109
109
|
|
|
110
110
|
1. **Resolve and read existing artifacts for context**
|
|
111
|
-
- Run `openspec status --change "<name>" --json`.
|
|
111
|
+
- Run `npx openspec status --change "<name>" --json`.
|
|
112
112
|
- Use `changeRoot`, `artifactPaths`, and `actionContext` from the status JSON.
|
|
113
113
|
- Read existing files from `artifactPaths.<artifact>.existingOutputPaths`.
|
|
114
114
|
|