agent-orchestrator-kit 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Maksim Shevyakov
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,446 @@
1
+ # agent-orchestrator-kit
2
+
3
+ Universal AI agent orchestration kit for **Cursor**, **Claude Code**, and **Amp Code** — spec-driven pipeline built on [OpenSpec](https://github.com/fission-ai/openspec).
4
+
5
+ [![npm version](https://img.shields.io/npm/v/agent-orchestrator-kit)](https://www.npmjs.com/package/agent-orchestrator-kit)
6
+ [![license](https://img.shields.io/npm/l/agent-orchestrator-kit)](LICENSE)
7
+
8
+ ## What It Is
9
+
10
+ A portable kit that installs a **5-role AI pipeline** into any project:
11
+
12
+ ```
13
+ explore → propose → review → apply → verify → archive
14
+ ```
15
+
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
+
18
+ Works with:
19
+ - [Cursor](https://cursor.sh) — via `.cursor/rules/` + `.cursor/skills/`
20
+ - [Claude Code](https://code.claude.com) — via `CLAUDE.md` + `.claude/skills/`
21
+ - [Amp Code](https://ampcode.com) — via `AGENTS.md` + `.agents/skills/` (native, no sync needed)
22
+
23
+ ## Why
24
+
25
+ Without role separation, AI agents tend to mix thinking with implementation, skip spec review, and accumulate context debt across one long chat. This kit enforces the discipline at the filesystem level: each role has explicit allowed files, a checklist, and a handoff gate before the next role starts.
26
+
27
+ The `AGENTS.md` / `CLAUDE.md` files tell each IDE exactly what the roles are, so you don't repeat yourself every session.
28
+
29
+ ## Installation
30
+
31
+ ### Prerequisites
32
+
33
+ - Node.js ≥ 18
34
+ - [OpenSpec](https://github.com/fission-ai/openspec) installed in the project:
35
+
36
+ ```bash
37
+ npm i -D @fission-ai/openspec
38
+ npx openspec init
39
+ ```
40
+
41
+ ### Install the kit
42
+
43
+ ```bash
44
+ npx agent-orchestrator-kit init
45
+ ```
46
+
47
+ With a stack profile:
48
+
49
+ ```bash
50
+ npx agent-orchestrator-kit init --profile vue3
51
+ npx agent-orchestrator-kit init --profile node
52
+ npx agent-orchestrator-kit init --profile generic
53
+ ```
54
+
55
+ With options:
56
+
57
+ ```bash
58
+ npx agent-orchestrator-kit init \
59
+ --profile vue3 \
60
+ --name "My Project" \
61
+ --lang uk
62
+ ```
63
+
64
+ ### Sync to local IDEs
65
+
66
+ After init (and after every update):
67
+
68
+ ```bash
69
+ ./scripts/sync-local-agent-skills.sh
70
+ ```
71
+
72
+ This copies `.agents/` to your local IDE directories (not committed to git).
73
+
74
+ ## What Gets Installed
75
+
76
+ ```
77
+ your-project/
78
+ ├── AGENTS.md # Amp Code + universal pipeline manifest
79
+ ├── CLAUDE.md # Claude Code context
80
+ ├── .agents/
81
+ │ ├── orchestrator.yaml # Pipeline config (committed)
82
+ │ ├── mcp.json.example # MCP template
83
+ │ ├── commands/
84
+ │ │ ├── opsx-explore.md
85
+ │ │ ├── opsx-propose.md
86
+ │ │ ├── opsx-review.md # new: read-only spec review
87
+ │ │ ├── opsx-apply.md
88
+ │ │ ├── opsx-archive.md
89
+ │ │ └── opsx-sync.md
90
+ │ ├── rules/
91
+ │ │ ├── agent-orchestration.mdc
92
+ │ │ ├── openspec-workflow.mdc
93
+ │ │ └── memory-mcp-autosetup.mdc
94
+ │ └── skills/
95
+ │ └── agent-orchestration/
96
+ │ └── SKILL.md
97
+ └── scripts/
98
+ └── sync-local-agent-skills.sh
99
+ ```
100
+
101
+ Git-committed: `.agents/` + `AGENTS.md` + `CLAUDE.md` + `scripts/`
102
+ Local only (not committed): `.cursor/` `.claude/` `.amp/`
103
+
104
+ ## IDE Integration
105
+
106
+ ### Amp Code (primary — zero config)
107
+
108
+ Amp reads `.agents/skills/` and `AGENTS.md` **natively** — no sync needed.
109
+
110
+ 1. Install the kit → `AGENTS.md` is created automatically.
111
+ 2. Amp picks up skills from `.agents/skills/` on session start.
112
+ 3. Configure Memory MCP in `.amp/settings.json`:
113
+
114
+ ```json
115
+ {
116
+ "amp.mcpServers": {
117
+ "memory": {
118
+ "command": "npx",
119
+ "args": ["-y", "@modelcontextprotocol/server-memory"],
120
+ "env": { "MEMORY_FILE_PATH": ".cursor/memory.json" }
121
+ }
122
+ }
123
+ }
124
+ ```
125
+
126
+ 4. Use commands directly:
127
+
128
+ ```
129
+ /opsx:explore
130
+ /opsx:propose add-feature-name
131
+ /opsx:review add-feature-name
132
+ /opsx:apply add-feature-name
133
+ /opsx:archive
134
+ ```
135
+
136
+ **Model hints per role** (Amp modes):
137
+
138
+ | Role | Recommended Amp mode |
139
+ |------|---------------------|
140
+ | explore | `rush` |
141
+ | propose | `smart` or `deep` |
142
+ | review | `smart` |
143
+ | apply (complex) | `smart` or `deep` |
144
+ | apply (simple task) | `rush` |
145
+
146
+ Switch modes in Amp CLI: `Ctrl+O` → `mode`.
147
+
148
+ ### Claude Code
149
+
150
+ 1. Run sync: `./scripts/sync-local-agent-skills.sh`
151
+ 2. This creates:
152
+ - `.claude/CLAUDE.md` — project context
153
+ - `.claude/skills/` — all skills from `.agents/skills/`
154
+ 3. Skills are auto-loaded by Claude Code from `.claude/skills/`.
155
+ 4. Invoke directly: `/agent-orchestration`, `/openspec-howto`, etc.
156
+
157
+ **CLAUDE.md tiers used:**
158
+ - Project level: `.claude/CLAUDE.md` (synced from `CLAUDE.md`)
159
+ - Personal (optional): `~/.claude/CLAUDE.md` for preferences
160
+
161
+ **Claude Code subagent config** (in skill frontmatter):
162
+
163
+ ```yaml
164
+ ---
165
+ name: openspec-explore
166
+ context: fork
167
+ agent: Explore
168
+ allowed-tools: Read, Bash
169
+ ---
170
+ ```
171
+
172
+ The kit pre-configures Explore skills to use `context: fork` + `agent: Explore` for clean context isolation.
173
+
174
+ ### Cursor
175
+
176
+ 1. Run sync: `./scripts/sync-local-agent-skills.sh`
177
+ 2. Creates:
178
+ - `.cursor/skills/` — all skills
179
+ - `.cursor/rules/` — `.mdc` rule files
180
+ - `.mcp.json` — from `mcp.json.example` (if not present)
181
+ 3. Rules are applied automatically per `alwaysApply: true`.
182
+
183
+ **Memory MCP for Cursor** (`.mcp.json`):
184
+
185
+ ```json
186
+ {
187
+ "mcpServers": {
188
+ "memory": {
189
+ "command": "npx",
190
+ "args": ["-y", "@modelcontextprotocol/server-memory"],
191
+ "env": { "MEMORY_FILE_PATH": ".cursor/memory.json" }
192
+ }
193
+ }
194
+ }
195
+ ```
196
+
197
+ ## The Pipeline in Detail
198
+
199
+ ### Role 1: Explorer — `/opsx:explore`
200
+
201
+ **Mode:** read-only. Cannot edit any files.
202
+ **Model:** fast/cheap.
203
+ **Purpose:** Understand the problem. Surface options. Choose a direction.
204
+
205
+ **Exit criteria (before starting Architect):**
206
+ - Problem stated in 3–5 sentences
207
+ - 2–3 solution options + recommendation
208
+ - kebab-case change name chosen
209
+ - Non-goals listed
210
+
211
+ ```
212
+ /opsx:explore How should we handle bulk camera export?
213
+ ```
214
+
215
+ ---
216
+
217
+ ### Role 2: Architect — `/opsx:propose <name>`
218
+
219
+ **Mode:** writes `openspec/changes/<name>/` only. Cannot touch `src/`.
220
+ **Model:** strong reasoning.
221
+ **Purpose:** Create all change artifacts: proposal, design, tasks, delta specs.
222
+
223
+ **Exit gate:**
224
+ ```bash
225
+ openspec validate <name> --strict --type change # must be ✓
226
+ ```
227
+
228
+ ```
229
+ /opsx:propose add-bulk-camera-export
230
+ ```
231
+
232
+ ---
233
+
234
+ ### Role 3: Spec Reviewer — `/opsx:review <name>`
235
+
236
+ **Mode:** read-only. No code edits.
237
+ **Model:** medium or strong.
238
+ **Purpose:** Review artifacts. Output **Approve ✓** or **Request Changes ✗**.
239
+
240
+ Checks:
241
+ - Acceptance criteria are testable
242
+ - Tasks ≤ ~2 hours each
243
+ - No scope creep vs Non-goals
244
+ - No conflicts with existing domain specs
245
+
246
+ ```
247
+ /opsx:review add-bulk-camera-export
248
+ ```
249
+
250
+ **Only after explicit APPROVE can apply start.**
251
+
252
+ ---
253
+
254
+ ### Role 4: Implementer — `/opsx:apply <name>`
255
+
256
+ **Mode:** writes `src/`. Marks `tasks.md [x]`.
257
+ **Model:** strong. Use fast for simple mechanical tasks.
258
+ **Purpose:** Implement tasks. One session = 1–3 tasks (not all 15 at once).
259
+
260
+ **Exit gate:**
261
+ ```bash
262
+ npm run build # must pass
263
+ npm run lint # must pass
264
+ ```
265
+
266
+ ```
267
+ /opsx:apply add-bulk-camera-export
268
+ ```
269
+
270
+ ---
271
+
272
+ ### Role 5: Verifier — CI (automatic)
273
+
274
+ ```yaml
275
+ # .github/workflows/agent-verify.yml (generated by kit)
276
+ - run: npx openspec validate --all --strict
277
+ - run: npm run lint
278
+ - run: npm run build
279
+ ```
280
+
281
+ Blocks merge if any gate fails.
282
+
283
+ ---
284
+
285
+ ### Archive — `/opsx:archive`
286
+
287
+ After PR merged + CI green:
288
+ ```
289
+ /opsx:archive add-bulk-camera-export
290
+ ```
291
+
292
+ Merges delta specs into `openspec/specs/` and moves change to `archive/`.
293
+
294
+ ## Configuration
295
+
296
+ Edit `.agents/orchestrator.yaml` after init:
297
+
298
+ ```yaml
299
+ project:
300
+ name: "My Project"
301
+ agent_language: uk # response language for agents
302
+
303
+ pipeline:
304
+ require_spec_review: true
305
+ max_active_changes: 1
306
+ archive_after_merge: true
307
+
308
+ verifier:
309
+ lint_command: "npm run lint"
310
+ build_command: "npm run build"
311
+ test_command: "npm test" # optional
312
+ ```
313
+
314
+ ## Update
315
+
316
+ When a new version of the kit is released:
317
+
318
+ ```bash
319
+ npx agent-orchestrator-kit update
320
+ ./scripts/sync-local-agent-skills.sh
321
+ ```
322
+
323
+ `update` only touches kit-managed files (commands, rules, skills). It never overwrites:
324
+ - `orchestrator.yaml`
325
+ - `openspec/config.yaml`
326
+ - `openspec/specs/`
327
+ - `openspec/changes/`
328
+ - Any project-conventions skills
329
+
330
+ ## Profiles
331
+
332
+ | Profile | Stack | Extra skills installed |
333
+ |---------|-------|----------------------|
334
+ | `generic` | Any | Orchestration only |
335
+ | `vue3` | Vue 3 + Vite | + vue-cursor-skills (separate install) |
336
+ | `node` | Node.js | + javascript-core, javascript-node |
337
+
338
+ For `vue3`, after kit init also run:
339
+
340
+ ```bash
341
+ npx vue-cursor-skills install
342
+ rsync -a .cursor/skills/ .agents/skills/
343
+ ./scripts/sync-local-agent-skills.sh
344
+ ```
345
+
346
+ ## Memory MCP — Shared State Between Sessions
347
+
348
+ Each role starts a fresh session. Memory MCP persists orchestration state across sessions so you don't re-explain context every time.
349
+
350
+ **Standard entities to save:**
351
+
352
+ ```
353
+ Change:add-bulk-export status: spec-approved, tasks: 0/7
354
+ Decision:export-format chosen: xlsx, reason: matches existing reports
355
+ Convention:api-errors use ApiError class, not raw Error
356
+ Handoff:add-bulk-export next_role: implementer, session_count: 1
357
+ ```
358
+
359
+ At the start of each implementer/reviewer session, read relevant memory:
360
+ ```
361
+ What do we know about Change:add-bulk-export?
362
+ ```
363
+
364
+ ## Amp Code — Deep Integration Notes
365
+
366
+ Amp is the **primary target** of this kit. It reads `.agents/skills/` and `AGENTS.md` without any sync step — your team commits `.agents/` and everyone gets the same orchestration behavior automatically.
367
+
368
+ **Amp-specific features used:**
369
+
370
+ | Feature | How the kit uses it |
371
+ |---------|-------------------|
372
+ | `AGENTS.md` subtree loading | Per-domain AGENTS.md in `openspec/` subtree |
373
+ | `.agents/skills/` | All orchestration + domain skills |
374
+ | `mcp.json` in skill dir | Lazy MCP loading (Memory only when needed) |
375
+ | Subagents | Explore and Review skills use forked subagents |
376
+ | Amp modes (rush/smart/deep) | Per-role model hints in AGENTS.md |
377
+
378
+ **Amp subagent in skill** (`.agents/skills/openspec-explore/SKILL.md`):
379
+
380
+ ```yaml
381
+ ---
382
+ name: openspec-explore
383
+ description: Enter explore mode — read-only thinking partner
384
+ disable-model-invocation: false
385
+ allowed-tools: Read, Bash
386
+ ---
387
+ ```
388
+
389
+ Amp will run this skill as a subagent when invoked.
390
+
391
+ **Team workflow with Amp:**
392
+
393
+ 1. Commit `.agents/` to git.
394
+ 2. Team members clone — skills available immediately.
395
+ 3. No `sync-local-agent-skills.sh` needed for Amp users.
396
+ 4. Cursor/Claude Code users run sync once after clone.
397
+
398
+ ## CLI Reference
399
+
400
+ ```bash
401
+ npx agent-orchestrator-kit init [options]
402
+ --profile <name> Stack profile: generic | vue3 | node | python
403
+ --lang <code> Agent language: en | uk | ...
404
+ --name <name> Project name (default: directory name)
405
+ --force Overwrite existing files
406
+
407
+ npx agent-orchestrator-kit update
408
+ Updates kit-managed files, preserves project overlay
409
+
410
+ npx agent-orchestrator-kit sync [options]
411
+ --target <ide> cursor | claude | all (default: all)
412
+ Copies .agents/ to local IDE directories
413
+ ```
414
+
415
+ ## Directory Reference
416
+
417
+ ```
418
+ .agents/ # Committed — source of truth for all IDEs
419
+ commands/ # /opsx:* command definitions
420
+ rules/ # Auto-applied rules for Cursor
421
+ skills/ # Skills for Cursor, Claude Code, Amp
422
+ orchestrator.yaml # Project pipeline config
423
+
424
+ .cursor/ # Local only — Cursor IDE runtime
425
+ skills/ # Synced from .agents/skills/
426
+ rules/ # Synced from .agents/rules/
427
+ memory.json # Memory MCP data
428
+
429
+ .claude/ # Local only — Claude Code runtime
430
+ skills/ # Synced from .agents/skills/
431
+ CLAUDE.md # Synced from root CLAUDE.md
432
+
433
+ .amp/ # Local only — Amp config
434
+ settings.json # MCP servers (manual or via amp mcp add)
435
+
436
+ AGENTS.md # Committed — Amp + Claude (AGENT.md fallback)
437
+ CLAUDE.md # Committed — synced to .claude/CLAUDE.md
438
+ openspec/ # Committed — spec-driven workflow
439
+ config.yaml # Project context for AI
440
+ specs/ # Source of truth after archive
441
+ changes/ # Active work
442
+ ```
443
+
444
+ ## License
445
+
446
+ MIT © [Maksim Shevyakov](https://github.com/makshc2)
@@ -0,0 +1,229 @@
1
+ #!/usr/bin/env node
2
+ import { program } from 'commander';
3
+ import pc from 'picocolors';
4
+ import { readFileSync, existsSync, mkdirSync, copyFileSync, readdirSync, statSync, writeFileSync } from 'fs';
5
+ import { join, dirname, basename } from 'path';
6
+ import { fileURLToPath } from 'url';
7
+ import { execSync } from 'child_process';
8
+
9
+ const __dirname = dirname(fileURLToPath(import.meta.url));
10
+ const KIT_ROOT = join(__dirname, '..');
11
+ const KIT_VERSION = JSON.parse(readFileSync(join(KIT_ROOT, 'package.json'), 'utf-8')).version;
12
+
13
+ const log = {
14
+ info: (msg) => console.log(pc.cyan(' →'), msg),
15
+ ok: (msg) => console.log(pc.green(' ✓'), msg),
16
+ warn: (msg) => console.log(pc.yellow(' !'), msg),
17
+ err: (msg) => console.log(pc.red(' ✗'), msg),
18
+ title: (msg) => console.log(pc.bold(pc.white(`\n${msg}`))),
19
+ };
20
+
21
+ function copyDir(src, dest, opts = {}) {
22
+ const { overwrite = true, skip = [] } = opts;
23
+ if (!existsSync(src)) return;
24
+ mkdirSync(dest, { recursive: true });
25
+ for (const entry of readdirSync(src)) {
26
+ if (skip.includes(entry)) continue;
27
+ const srcPath = join(src, entry);
28
+ const destPath = join(dest, entry);
29
+ if (statSync(srcPath).isDirectory()) {
30
+ copyDir(srcPath, destPath, opts);
31
+ } else {
32
+ if (!overwrite && existsSync(destPath)) {
33
+ log.warn(`skip (exists): ${destPath}`);
34
+ continue;
35
+ }
36
+ copyFileSync(srcPath, destPath);
37
+ log.ok(destPath.replace(process.cwd() + '/', ''));
38
+ }
39
+ }
40
+ }
41
+
42
+ function mergeGitignore(projectDir, lines) {
43
+ const gitignorePath = join(projectDir, '.gitignore');
44
+ let content = existsSync(gitignorePath) ? readFileSync(gitignorePath, 'utf-8') : '';
45
+ let changed = false;
46
+ for (const line of lines) {
47
+ if (!content.includes(line)) {
48
+ content += `\n${line}`;
49
+ changed = true;
50
+ }
51
+ }
52
+ if (changed) {
53
+ writeFileSync(gitignorePath, content.trimStart());
54
+ log.ok('.gitignore updated');
55
+ }
56
+ }
57
+
58
+ function resolveTemplate(templateName, profile) {
59
+ const profilePath = join(KIT_ROOT, 'profiles', profile, templateName);
60
+ if (existsSync(profilePath)) return profilePath;
61
+ return join(KIT_ROOT, 'templates', templateName);
62
+ }
63
+
64
+ function applyPlaceholders(filePath, vars) {
65
+ if (!existsSync(filePath)) return;
66
+ let content = readFileSync(filePath, 'utf-8');
67
+ for (const [key, val] of Object.entries(vars)) {
68
+ content = content.replaceAll(`{{${key}}}`, val);
69
+ }
70
+ writeFileSync(filePath, content);
71
+ }
72
+
73
+ program
74
+ .name('agent-orchestrator')
75
+ .description('Universal AI agent orchestration kit for Cursor, Claude Code, and Amp Code')
76
+ .version(KIT_VERSION);
77
+
78
+ program
79
+ .command('init')
80
+ .description('Install orchestrator kit into the current project')
81
+ .option('--profile <profile>', 'Stack profile: generic | vue3 | node | python', 'generic')
82
+ .option('--lang <lang>', 'Agent response language (en | uk | ...)', 'en')
83
+ .option('--name <name>', 'Project name (defaults to directory name)')
84
+ .option('--force', 'Overwrite existing files', false)
85
+ .action((opts) => {
86
+ const projectDir = process.cwd();
87
+ const projectName = opts.name || basename(projectDir);
88
+
89
+ log.title(`agent-orchestrator init v${KIT_VERSION}`);
90
+ log.info(`Project: ${projectName}`);
91
+ log.info(`Profile: ${opts.profile}`);
92
+ log.info(`Language: ${opts.lang}`);
93
+
94
+ const templateDir = join(KIT_ROOT, 'templates');
95
+ const profileDir = join(KIT_ROOT, 'profiles', opts.profile);
96
+ const vars = { PROJECT_NAME: projectName, LANG: opts.lang, KIT_VERSION };
97
+
98
+ log.title('Installing .agents/');
99
+ copyDir(join(templateDir, '.agents'), join(projectDir, '.agents'), { overwrite: opts.force });
100
+ if (existsSync(join(profileDir, '.agents'))) {
101
+ copyDir(join(profileDir, '.agents'), join(projectDir, '.agents'), { overwrite: opts.force });
102
+ }
103
+
104
+ log.title('Installing scripts/');
105
+ copyDir(join(templateDir, 'scripts'), join(projectDir, 'scripts'), { overwrite: opts.force });
106
+ try {
107
+ execSync(`chmod +x ${join(projectDir, 'scripts', 'sync-local-agent-skills.sh')}`);
108
+ } catch {}
109
+
110
+ log.title('Installing root files');
111
+ for (const f of ['AGENTS.md', 'CLAUDE.md']) {
112
+ const src = resolveTemplate(f, opts.profile);
113
+ const dest = join(projectDir, f);
114
+ if (!opts.force && existsSync(dest)) {
115
+ log.warn(`skip (exists): ${f}`);
116
+ continue;
117
+ }
118
+ if (existsSync(src)) {
119
+ copyFileSync(src, dest);
120
+ applyPlaceholders(dest, vars);
121
+ log.ok(f);
122
+ }
123
+ }
124
+
125
+ const orchSrc = resolveTemplate('orchestrator.yaml', opts.profile);
126
+ const orchDest = join(projectDir, '.agents', 'orchestrator.yaml');
127
+ if (!opts.force && existsSync(orchDest)) {
128
+ log.warn('skip (exists): .agents/orchestrator.yaml');
129
+ } else if (existsSync(orchSrc)) {
130
+ copyFileSync(orchSrc, orchDest);
131
+ applyPlaceholders(orchDest, vars);
132
+ log.ok('.agents/orchestrator.yaml');
133
+ }
134
+
135
+ log.title('Updating .gitignore');
136
+ mergeGitignore(projectDir, ['.cursor', '.cursor/memory.json', '.amp/settings.json']);
137
+
138
+ log.title('Done');
139
+ log.ok(`agent-orchestrator-kit v${KIT_VERSION} installed`);
140
+ console.log(`
141
+ ${pc.bold('Next steps:')}
142
+ 1. Review ${pc.cyan('AGENTS.md')} and ${pc.cyan('.agents/orchestrator.yaml')}
143
+ 2. Sync to your IDE:
144
+ ${pc.cyan('./scripts/sync-local-agent-skills.sh')}
145
+ 3. Install Memory MCP in .mcp.json (Cursor) / .amp/settings.json (Amp)
146
+ 4. Start your first change:
147
+ ${pc.cyan('/opsx:explore')}
148
+ `);
149
+ });
150
+
151
+ program
152
+ .command('update')
153
+ .description('Update kit files without overwriting project overlay (orchestrator.yaml, project-conventions)')
154
+ .action(() => {
155
+ const projectDir = process.cwd();
156
+ const templateDir = join(KIT_ROOT, 'templates');
157
+
158
+ log.title(`agent-orchestrator update v${KIT_VERSION}`);
159
+
160
+ const KIT_FILES = [
161
+ '.agents/commands',
162
+ '.agents/rules',
163
+ '.agents/skills/agent-orchestration',
164
+ ];
165
+
166
+ for (const rel of KIT_FILES) {
167
+ const src = join(templateDir, rel);
168
+ const dest = join(projectDir, rel);
169
+ if (existsSync(src)) {
170
+ copyDir(src, dest, { overwrite: true });
171
+ }
172
+ }
173
+
174
+ for (const f of ['scripts/sync-local-agent-skills.sh']) {
175
+ const src = join(templateDir, f);
176
+ const dest = join(projectDir, f);
177
+ if (existsSync(src)) {
178
+ copyFileSync(src, dest);
179
+ log.ok(f);
180
+ }
181
+ }
182
+
183
+ log.ok(`Updated to v${KIT_VERSION}`);
184
+ log.info('Run ./scripts/sync-local-agent-skills.sh to sync to local IDE');
185
+ });
186
+
187
+ program
188
+ .command('sync')
189
+ .description('Sync .agents/ to local IDE directories (Cursor, Claude Code)')
190
+ .option('--target <target>', 'cursor | claude | amp | all', 'all')
191
+ .action((opts) => {
192
+ const projectDir = process.cwd();
193
+
194
+ log.title('agent-orchestrator sync');
195
+
196
+ const syncCursor = ['cursor', 'all'].includes(opts.target);
197
+ const syncClaude = ['claude', 'all'].includes(opts.target);
198
+
199
+ if (syncCursor) {
200
+ log.info('Syncing .agents/ → .cursor/');
201
+ copyDir(join(projectDir, '.agents', 'skills'), join(projectDir, '.cursor', 'skills'), { overwrite: true });
202
+ copyDir(join(projectDir, '.agents', 'rules'), join(projectDir, '.cursor', 'rules'), { overwrite: true });
203
+
204
+ const mcpExample = join(projectDir, '.agents', 'mcp.json.example');
205
+ const mcpDest = join(projectDir, '.mcp.json');
206
+ if (existsSync(mcpExample) && !existsSync(mcpDest)) {
207
+ copyFileSync(mcpExample, mcpDest);
208
+ log.ok('.mcp.json created from example');
209
+ }
210
+ }
211
+
212
+ if (syncClaude) {
213
+ log.info('Syncing .agents/ → .claude/');
214
+ copyDir(join(projectDir, '.agents', 'skills'), join(projectDir, '.claude', 'skills'), { overwrite: true });
215
+
216
+ const claudeMd = join(projectDir, 'CLAUDE.md');
217
+ const claudeDir = join(projectDir, '.claude');
218
+ if (existsSync(claudeMd)) {
219
+ mkdirSync(claudeDir, { recursive: true });
220
+ copyFileSync(claudeMd, join(claudeDir, 'CLAUDE.md'));
221
+ log.ok('.claude/CLAUDE.md');
222
+ }
223
+ }
224
+
225
+ log.ok('Sync complete');
226
+ log.warn('.cursor/ and .claude/ are local only — not committed to git');
227
+ });
228
+
229
+ program.parse();