@eventmodelers/cli 0.0.1 → 0.0.2
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 +41 -9
- package/cli.js +90 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -41,6 +41,16 @@ your-project/
|
|
|
41
41
|
|
|
42
42
|
The four backend stacks (`node`, `supabase`, `axon`, `cratis-csharp`) also scaffold a real project skeleton into your project root (`templates/root/`) — source layout, build files, migrations, etc. `modeling-kit` only installs skills + the agent loop, with no backend opinion.
|
|
43
43
|
|
|
44
|
+
### Installing skills globally
|
|
45
|
+
|
|
46
|
+
By default, skills are copied into the project's own `.claude/skills/`. Pass `--global` to `init` or `init-modeling` to install them into `~/.claude/skills/` instead — available in every project without re-running the installer each time:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
npx @eventmodelers/cli init-modeling --global
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
Everything else (the kit dir, project scaffold, credentials, MCP registration) still targets the current directory as usual — `--global` only changes where skills land.
|
|
53
|
+
|
|
44
54
|
## Claude execution & config resolution
|
|
45
55
|
|
|
46
56
|
During install you can optionally point the agent at a local LLM server (vLLM, Ollama) instead of the default Claude Code endpoint, and/or pin a specific model:
|
|
@@ -144,19 +154,41 @@ Which skills install depends on the chosen stack — see `stacks/<name>/template
|
|
|
144
154
|
## Commands
|
|
145
155
|
|
|
146
156
|
```bash
|
|
147
|
-
npx @eventmodelers/cli init --stack <name>
|
|
148
|
-
npx @eventmodelers/cli init
|
|
149
|
-
npx @eventmodelers/cli
|
|
150
|
-
npx @eventmodelers/cli
|
|
151
|
-
npx @eventmodelers/cli run
|
|
152
|
-
npx @eventmodelers/cli
|
|
153
|
-
npx @eventmodelers/cli
|
|
154
|
-
npx @eventmodelers/cli
|
|
155
|
-
npx @eventmodelers/cli
|
|
157
|
+
npx @eventmodelers/cli init --stack <name> # scaffold a stack + install + configure (alias: install)
|
|
158
|
+
npx @eventmodelers/cli init --stack <name> --global # same, but skills go to ~/.claude/skills/ (every project)
|
|
159
|
+
npx @eventmodelers/cli init-modeling # skills + agent loop only, no backend scaffold (alias: modeling)
|
|
160
|
+
npx @eventmodelers/cli init-modeling --global # same, but skills go to ~/.claude/skills/ (every project)
|
|
161
|
+
npx @eventmodelers/cli run # start the agent loop (ralph-claude.js) from the installed kit dir
|
|
162
|
+
npx @eventmodelers/cli run --ollama # same, via local Ollama (ralph-ollama.js)
|
|
163
|
+
npx @eventmodelers/cli run --bash # bash-only loop, no realtime (ralph.sh)
|
|
164
|
+
npx @eventmodelers/cli stacks # list available stacks
|
|
165
|
+
npx @eventmodelers/cli status # check what's installed
|
|
166
|
+
npx @eventmodelers/cli config # print the fully resolved config (file + env), token masked
|
|
167
|
+
npx @eventmodelers/cli uninstall # remove everything init/init-modeling installed
|
|
156
168
|
```
|
|
157
169
|
|
|
158
170
|
`run` is a thin dispatcher — it just finds the installed kit dir (whatever it's named for the stack) and execs the runner file already sitting in it. The agent loop's actual logic stays in the scaffolded `<kit-dir>/`, not in this package, since you (and the agent itself, via `AGENT.md`) may customize those files per project.
|
|
159
171
|
|
|
172
|
+
### Uninstall
|
|
173
|
+
|
|
174
|
+
Every `init`/`init-modeling` run writes an install manifest into `<kit-dir>/.eventmodelers/install-manifest.json` recording exactly what it put down. `uninstall` reads that manifest back and removes only:
|
|
175
|
+
|
|
176
|
+
- the kit dir (`.build-kit/` or `.agent-modeling-kit/`)
|
|
177
|
+
- the skills it copied — from `.claude/skills/` normally, or `~/.claude/skills/` if it was installed with `--global`
|
|
178
|
+
- the `eventmodelers` entry it added to `.claude/settings.json`'s `mcpServers` (the rest of that file, and the file itself, is left in place)
|
|
179
|
+
|
|
180
|
+
It deliberately **never** touches the root project scaffold (`package.json`, `src/`, `server.ts`, migrations, `docker-compose.yml`, etc.) — that's your actual application code, not tooling, so `uninstall` won't delete it even though `init` wrote it.
|
|
181
|
+
|
|
182
|
+
If a kit dir predates this tracking (no manifest present), `uninstall` falls back to only removing the kit dir itself and tells you so — any skills or MCP registration from that older install need to be cleaned up by hand.
|
|
183
|
+
|
|
184
|
+
Registering the MCP server with another harness (`claude mcp add`, `code --add-mcp`, or the manual Cursor/Windsurf steps) happens outside this project's files, so `uninstall` doesn't attempt to undo it — remove it yourself in that harness if you connected one.
|
|
185
|
+
|
|
186
|
+
```bash
|
|
187
|
+
npx @eventmodelers/cli uninstall # remove the one installed kit dir (errors if more than one is present)
|
|
188
|
+
npx @eventmodelers/cli uninstall --build-kit # remove .build-kit/ specifically
|
|
189
|
+
npx @eventmodelers/cli uninstall --modeling-kit # remove .agent-modeling-kit/ specifically
|
|
190
|
+
```
|
|
191
|
+
|
|
160
192
|
`--config <path>` and `--print` are global flags accepted by every command. `--print` skips the "connect MCP globally?" prompt during install and just prints the `claude mcp add` command instead of running it — combined with the env vars above, `--print` makes `init` fully non-interactive:
|
|
161
193
|
|
|
162
194
|
```bash
|
package/cli.js
CHANGED
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
} from 'fs';
|
|
16
16
|
import { execSync } from 'child_process';
|
|
17
17
|
import { createInterface, emitKeypressEvents, moveCursor, clearScreenDown } from 'readline';
|
|
18
|
+
import { homedir } from 'os';
|
|
18
19
|
|
|
19
20
|
const __filename = fileURLToPath(import.meta.url);
|
|
20
21
|
const __dirname = dirname(__filename);
|
|
@@ -285,10 +286,26 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
285
286
|
process.exit(1);
|
|
286
287
|
}
|
|
287
288
|
|
|
288
|
-
// --- 1. Install skills
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
289
|
+
// --- 1. Install skills (project-local by default, or ~/.claude/skills/ with --global) ---
|
|
290
|
+
// Recorded into the install manifest (step 8) so `uninstall` can remove exactly
|
|
291
|
+
// these files later and nothing the user added independently.
|
|
292
|
+
const claudeSkillsSrc = join(templatesSource, '.claude', 'skills');
|
|
293
|
+
const installedSkills = existsSync(claudeSkillsSrc) ? readdirSync(claudeSkillsSrc) : [];
|
|
294
|
+
let claudeExtras = [];
|
|
295
|
+
|
|
296
|
+
if (options.global) {
|
|
297
|
+
const globalSkillsDir = join(homedir(), '.claude', 'skills');
|
|
298
|
+
console.log('📦 Installing Claude skills globally...');
|
|
299
|
+
console.log(` Copies skills into ${globalSkillsDir} so they're available in every project, not just this one.\n`);
|
|
300
|
+
copyDirContents(claudeSkillsSrc, globalSkillsDir);
|
|
301
|
+
} else {
|
|
302
|
+
console.log('📦 Installing Claude skills...');
|
|
303
|
+
console.log(' Copies skills and settings into .claude/ so Claude Code picks them up automatically.\n');
|
|
304
|
+
copyDirContents(join(templatesSource, '.claude'), join(targetDir, '.claude'));
|
|
305
|
+
claudeExtras = existsSync(join(templatesSource, '.claude'))
|
|
306
|
+
? readdirSync(join(templatesSource, '.claude')).filter((f) => f !== 'skills')
|
|
307
|
+
: [];
|
|
308
|
+
}
|
|
292
309
|
|
|
293
310
|
// --- 2. Spread stack scaffold files into the project root ---
|
|
294
311
|
const rootSrc = join(templatesSource, 'root');
|
|
@@ -493,6 +510,17 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
493
510
|
}
|
|
494
511
|
}
|
|
495
512
|
|
|
513
|
+
// --- 8. Install manifest (drives precise `uninstall` later) ---
|
|
514
|
+
// Only the footprint listed here is ever removed by `uninstall` — the root
|
|
515
|
+
// scaffold (step 2) is real project source the user builds on, so it's
|
|
516
|
+
// deliberately left out and never touched by uninstall.
|
|
517
|
+
const manifestDir = join(kitDir, '.eventmodelers');
|
|
518
|
+
mkdirSync(manifestDir, { recursive: true });
|
|
519
|
+
writeFileSync(
|
|
520
|
+
join(manifestDir, 'install-manifest.json'),
|
|
521
|
+
JSON.stringify({ stack: stackKey, global: !!options.global, skills: installedSkills, claudeExtras, mcpRegistered: true }, null, 2),
|
|
522
|
+
);
|
|
523
|
+
|
|
496
524
|
console.log('\n✅ Done!\n');
|
|
497
525
|
console.log('Start the agent (realtime + task loop in one process):');
|
|
498
526
|
console.log(' npx @eventmodelers/cli run\n');
|
|
@@ -500,7 +528,7 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
500
528
|
console.log(' npx @eventmodelers/cli run --ollama\n');
|
|
501
529
|
console.log('Or using the bash loop only (no realtime):');
|
|
502
530
|
console.log(' npx @eventmodelers/cli run --bash\n');
|
|
503
|
-
console.log(`Skills are ready in .claude/skills/ — use /connect to set a board ID.\n`);
|
|
531
|
+
console.log(`Skills are ready in ${options.global ? join(homedir(), '.claude', 'skills') : '.claude/skills/'} — use /connect to set a board ID.\n`);
|
|
504
532
|
console.log('💡 Recommended: add Chrome DevTools MCP for browser inspection:');
|
|
505
533
|
console.log(' claude mcp add chrome-devtools --scope user -- npx chrome-devtools-mcp@latest\n');
|
|
506
534
|
}
|
|
@@ -519,19 +547,21 @@ program
|
|
|
519
547
|
.alias('install')
|
|
520
548
|
.description('Scaffold a stack + install the agent modeling kit into the current directory')
|
|
521
549
|
.option('--stack <name>', `Stack to install (${Object.keys(STACKS).join(', ')})`)
|
|
550
|
+
.option('--global', 'Install skills into ~/.claude/skills/ instead of the project — available in every project')
|
|
522
551
|
.action(async (opts, command) => {
|
|
523
552
|
const stackKey = await resolveStack(opts.stack);
|
|
524
553
|
const globalOpts = command.optsWithGlobals();
|
|
525
|
-
await installStack(stackKey, STACKS[stackKey], { configPath: globalOpts.config, print: globalOpts.print });
|
|
554
|
+
await installStack(stackKey, STACKS[stackKey], { configPath: globalOpts.config, print: globalOpts.print, global: opts.global });
|
|
526
555
|
});
|
|
527
556
|
|
|
528
557
|
program
|
|
529
558
|
.command('init-modeling')
|
|
530
559
|
.alias('modeling')
|
|
531
560
|
.description('Install skills + the agent loop only — no backend scaffold')
|
|
561
|
+
.option('--global', 'Install skills into ~/.claude/skills/ instead of the project — available in every project')
|
|
532
562
|
.action(async (opts, command) => {
|
|
533
563
|
const globalOpts = command.optsWithGlobals();
|
|
534
|
-
await installStack(MODELING_KIT.key, MODELING_KIT, { configPath: globalOpts.config, print: globalOpts.print });
|
|
564
|
+
await installStack(MODELING_KIT.key, MODELING_KIT, { configPath: globalOpts.config, print: globalOpts.print, global: opts.global });
|
|
535
565
|
});
|
|
536
566
|
|
|
537
567
|
program
|
|
@@ -579,9 +609,60 @@ program
|
|
|
579
609
|
console.log(`\nNot a stack — skills + agent loop only, no backend: npx @eventmodelers/cli init-modeling`);
|
|
580
610
|
});
|
|
581
611
|
|
|
612
|
+
// Removes exactly what a given `init`/`init-modeling` run put down — read back from
|
|
613
|
+
// the install manifest written at the end of installStack() — and nothing else: not
|
|
614
|
+
// unrelated skills the user added by hand, not the root project scaffold.
|
|
615
|
+
function uninstallKitDir(kitDir, cwd) {
|
|
616
|
+
const manifestPath = join(kitDir, '.eventmodelers', 'install-manifest.json');
|
|
617
|
+
const manifest = readJsonSafe(manifestPath);
|
|
618
|
+
|
|
619
|
+
if (manifest.skills?.length) {
|
|
620
|
+
const skillsDir = manifest.global ? join(homedir(), '.claude', 'skills') : join(cwd, '.claude', 'skills');
|
|
621
|
+
for (const name of manifest.skills) {
|
|
622
|
+
const p = join(skillsDir, name);
|
|
623
|
+
if (existsSync(p)) {
|
|
624
|
+
rmSync(p, { recursive: true, force: true });
|
|
625
|
+
console.log(` ✓ Removed ${relative(cwd, p) || p}`);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
628
|
+
}
|
|
629
|
+
|
|
630
|
+
if (manifest.claudeExtras?.length && !manifest.global) {
|
|
631
|
+
for (const name of manifest.claudeExtras) {
|
|
632
|
+
const p = join(cwd, '.claude', name);
|
|
633
|
+
if (existsSync(p)) {
|
|
634
|
+
rmSync(p, { recursive: true, force: true });
|
|
635
|
+
console.log(` ✓ Removed ${relative(cwd, p)}`);
|
|
636
|
+
}
|
|
637
|
+
}
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (manifest.mcpRegistered) {
|
|
641
|
+
const settingsPath = join(cwd, '.claude', 'settings.json');
|
|
642
|
+
if (existsSync(settingsPath)) {
|
|
643
|
+
try {
|
|
644
|
+
const settings = JSON.parse(readFileSync(settingsPath, 'utf-8'));
|
|
645
|
+
if (settings.mcpServers?.[MCP_SERVER_NAME]) {
|
|
646
|
+
delete settings.mcpServers[MCP_SERVER_NAME];
|
|
647
|
+
if (Object.keys(settings.mcpServers).length === 0) delete settings.mcpServers;
|
|
648
|
+
writeFileSync(settingsPath, JSON.stringify(settings, null, 2));
|
|
649
|
+
console.log(` ✓ Removed ${MCP_SERVER_NAME} MCP entry from ${relative(cwd, settingsPath)}`);
|
|
650
|
+
}
|
|
651
|
+
} catch {}
|
|
652
|
+
}
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
if (!existsSync(manifestPath)) {
|
|
656
|
+
console.log(` ℹ️ ${relative(cwd, kitDir)} predates install tracking — only the kit dir itself was removed; any installed skills or MCP registration must be cleaned up by hand.`);
|
|
657
|
+
}
|
|
658
|
+
|
|
659
|
+
rmSync(kitDir, { recursive: true, force: true });
|
|
660
|
+
console.log(` ✓ Removed ${relative(cwd, kitDir) || kitDir}`);
|
|
661
|
+
}
|
|
662
|
+
|
|
582
663
|
program
|
|
583
664
|
.command('uninstall')
|
|
584
|
-
.description('Remove
|
|
665
|
+
.description('Remove everything init/init-modeling installed: the kit dir, the skills it copied (project-local or ~/.claude/skills with --global), and its MCP entry in .claude/settings.json. Leaves the root project scaffold untouched.')
|
|
585
666
|
.option('--build-kit', `Remove ${STACKS.node.kitDirName}/ (the backend-stack kit dir)`)
|
|
586
667
|
.option('--modeling-kit', `Remove ${MODELING_KIT.kitDirName}/ (the modeling-only kit dir)`)
|
|
587
668
|
.action((opts) => {
|
|
@@ -611,8 +692,7 @@ program
|
|
|
611
692
|
}
|
|
612
693
|
|
|
613
694
|
for (const t of targets) {
|
|
614
|
-
|
|
615
|
-
console.log(` ✓ Removed ${t}`);
|
|
695
|
+
uninstallKitDir(t, cwd);
|
|
616
696
|
}
|
|
617
697
|
console.log('✅ Uninstalled');
|
|
618
698
|
});
|
package/package.json
CHANGED