@eventmodelers/cli 0.0.5 → 0.0.7
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/cli.js +30 -35
- package/package.json +1 -1
package/cli.js
CHANGED
|
@@ -156,9 +156,13 @@ async function promptPasteBlock() {
|
|
|
156
156
|
return lines.join('\n').trim();
|
|
157
157
|
}
|
|
158
158
|
|
|
159
|
+
// Canonical order the account page pastes values in, regardless of which fields a
|
|
160
|
+
// given stack actually requires — a modeling-kit install (no boardId required) still
|
|
161
|
+
// gets a paste containing all 4 fields, so we must not drop the ones we don't need.
|
|
162
|
+
const PASTE_FIELD_ORDER = ['organizationId', 'boardId', 'token'];
|
|
163
|
+
|
|
159
164
|
// Accepts either a JSON object (as copied from the account page) or a comma-separated
|
|
160
|
-
// line of values, in
|
|
161
|
-
// with an optional base URL anywhere in the list.
|
|
165
|
+
// line of values, in PASTE_FIELD_ORDER, with an optional base URL anywhere in the list.
|
|
162
166
|
function parseCredentialsPaste(text, requiredFields) {
|
|
163
167
|
const trimmed = text.trim();
|
|
164
168
|
if (!trimmed) return null;
|
|
@@ -186,8 +190,13 @@ function parseCredentialsPaste(text, requiredFields) {
|
|
|
186
190
|
else remaining.push(v);
|
|
187
191
|
}
|
|
188
192
|
if (remaining.length < requiredFields.length) return null;
|
|
189
|
-
|
|
190
|
-
|
|
193
|
+
// If more values were pasted than this stack strictly requires (e.g. a boardId
|
|
194
|
+
// in a modeling-kit paste), use the full canonical order so the extra field is
|
|
195
|
+
// still captured instead of being mis-zipped against the shorter requiredFields
|
|
196
|
+
// list and silently dropped/misassigned.
|
|
197
|
+
const fieldOrder = remaining.length > requiredFields.length ? PASTE_FIELD_ORDER : requiredFields;
|
|
198
|
+
fieldOrder.forEach((field, i) => {
|
|
199
|
+
if (remaining[i] !== undefined) result[field] = remaining[i];
|
|
191
200
|
});
|
|
192
201
|
|
|
193
202
|
return requiredFields.every((f) => result[f]) ? result : null;
|
|
@@ -311,6 +320,7 @@ function findAllInstalledKitDirs(cwd) {
|
|
|
311
320
|
function copyDirContents(srcDir, destDir, { skip = [] } = {}) {
|
|
312
321
|
if (!existsSync(srcDir)) return;
|
|
313
322
|
mkdirSync(destDir, { recursive: true });
|
|
323
|
+
let count = 0;
|
|
314
324
|
for (const item of readdirSync(srcDir)) {
|
|
315
325
|
if (skip.includes(item)) continue;
|
|
316
326
|
const src = join(srcDir, item);
|
|
@@ -319,8 +329,9 @@ function copyDirContents(srcDir, destDir, { skip = [] } = {}) {
|
|
|
319
329
|
recursive: true,
|
|
320
330
|
filter: (s) => !relative(src, s).split(sep).includes('node_modules'),
|
|
321
331
|
});
|
|
322
|
-
|
|
332
|
+
count++;
|
|
323
333
|
}
|
|
334
|
+
if (count) console.log(` ✓ Installed ${count} item${count === 1 ? '' : 's'} into ${relative(process.cwd(), destDir) || '.'}`);
|
|
324
335
|
}
|
|
325
336
|
|
|
326
337
|
async function resolveStack(cliStack) {
|
|
@@ -360,12 +371,10 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
360
371
|
|
|
361
372
|
if (options.global) {
|
|
362
373
|
const globalSkillsDir = join(homedir(), '.claude', 'skills');
|
|
363
|
-
console.log('📦 Installing
|
|
364
|
-
console.log(` Copies skills into ${globalSkillsDir} so they're available in every project, not just this one.\n`);
|
|
374
|
+
console.log('📦 Installing skills globally...');
|
|
365
375
|
copyDirContents(claudeSkillsSrc, globalSkillsDir);
|
|
366
376
|
} else {
|
|
367
|
-
console.log('📦 Installing
|
|
368
|
-
console.log(' Copies skills and settings into .claude/ so Claude Code picks them up automatically.\n');
|
|
377
|
+
console.log('📦 Installing skills...');
|
|
369
378
|
copyDirContents(join(templatesSource, '.claude'), join(targetDir, '.claude'));
|
|
370
379
|
claudeExtras = existsSync(join(templatesSource, '.claude'))
|
|
371
380
|
? readdirSync(join(templatesSource, '.claude')).filter((f) => f !== 'skills')
|
|
@@ -375,15 +384,14 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
375
384
|
// --- 2. Spread stack scaffold files into the project root ---
|
|
376
385
|
const rootSrc = join(templatesSource, 'root');
|
|
377
386
|
if (existsSync(rootSrc)) {
|
|
378
|
-
console.log('
|
|
387
|
+
console.log('📦 Installing project files...');
|
|
379
388
|
copyDirContents(rootSrc, targetDir);
|
|
380
389
|
}
|
|
381
390
|
|
|
382
391
|
// --- 3. Create the kit dir and install the agent runner ---
|
|
383
392
|
const kitDir = join(targetDir, stackCfg.kitDirName);
|
|
384
393
|
mkdirSync(kitDir, { recursive: true });
|
|
385
|
-
console.log(
|
|
386
|
-
console.log(' Sets up the Ralph agent loop, scripts, and configuration that drive realtime modeling.\n');
|
|
394
|
+
console.log(`📦 Installing agent kit into ${stackCfg.kitDirName}/...`);
|
|
387
395
|
|
|
388
396
|
if (stackCfg.useShared) {
|
|
389
397
|
copyDirContents(sharedBuildKit, kitDir);
|
|
@@ -400,8 +408,7 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
400
408
|
|
|
401
409
|
// --- 4. Install kit dependencies ---
|
|
402
410
|
if (existsSync(join(kitDir, 'package.json'))) {
|
|
403
|
-
console.log('
|
|
404
|
-
console.log(' Installs npm packages required by the agent scripts (e.g. websocket client, utilities).');
|
|
411
|
+
console.log('📦 Installing kit dependencies...');
|
|
405
412
|
try {
|
|
406
413
|
execSync('npm install', { cwd: kitDir, stdio: ['ignore', 'inherit', 'inherit'] });
|
|
407
414
|
console.log(' ✓ kit dependencies installed');
|
|
@@ -411,9 +418,7 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
411
418
|
}
|
|
412
419
|
|
|
413
420
|
// --- 5. Credentials ---
|
|
414
|
-
console.log('
|
|
415
|
-
console.log(' Stores your Organization ID (and Board ID, if this stack needs one) and token');
|
|
416
|
-
console.log(' so the agent can connect to app.eventmodelers.ai.\n');
|
|
421
|
+
console.log('🔐 Configuring credentials...');
|
|
417
422
|
|
|
418
423
|
// Written at the project root (not inside the kit dir) so a modeling-kit install
|
|
419
424
|
// and a build-kit install in the same project share one config.json instead of
|
|
@@ -476,9 +481,10 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
476
481
|
} else if (choice === 'manual') {
|
|
477
482
|
console.log('\n🔑 Enter your Eventmodelers credentials:\n');
|
|
478
483
|
config.organizationId = await prompt(' Organization ID: ');
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
}
|
|
484
|
+
// Always ask, even when this stack doesn't strictly require it — it's still
|
|
485
|
+
// used as a fallback default by the agent loop (see BOARD_ID resolution).
|
|
486
|
+
const boardId = await prompt(` Board ID${stackCfg.needsBoardId ? '' : ' (optional)'}: `);
|
|
487
|
+
if (boardId) config.boardId = boardId;
|
|
482
488
|
config.token = await prompt(' Token: ');
|
|
483
489
|
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
484
490
|
console.log(`\n ✓ Credentials saved to ${relative(targetDir, configPath)}`);
|
|
@@ -488,9 +494,7 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
488
494
|
console.log(`\n (or any ancestor directory's .eventmodelers/config.json, e.g. ~/.eventmodelers/config.json`);
|
|
489
495
|
console.log(` to share the same credentials across multiple projects)\n`);
|
|
490
496
|
console.log(` The file should look like:`);
|
|
491
|
-
const sample =
|
|
492
|
-
? ` {\n "token": "...",\n "boardId": "...",\n "organizationId": "...",\n "baseUrl": "https://api.eventmodelers.ai"\n }\n`
|
|
493
|
-
: ` {\n "token": "...",\n "organizationId": "...",\n "baseUrl": "https://api.eventmodelers.ai"\n }\n`;
|
|
497
|
+
const sample = ` {\n "token": "...",\n "boardId": "...",\n "organizationId": "...",\n "baseUrl": "https://api.eventmodelers.ai"\n }\n`;
|
|
494
498
|
console.log(sample);
|
|
495
499
|
console.log(' Then re-run this installer, or just run the agent afterwards.\n');
|
|
496
500
|
} else {
|
|
@@ -509,8 +513,7 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
509
513
|
console.log(`\n ✓ Saved to ${relative(targetDir, configPath)}`);
|
|
510
514
|
|
|
511
515
|
// --- 6. MCP server in .claude/settings.json ---
|
|
512
|
-
console.log('
|
|
513
|
-
console.log(' Registers the Eventmodelers MCP server in .claude/settings.json so Claude Code can call modeling tools directly.\n');
|
|
516
|
+
console.log('🔌 Configuring MCP server...');
|
|
514
517
|
const claudeSettingsDir = join(targetDir, '.claude');
|
|
515
518
|
const settingsPath = join(claudeSettingsDir, 'settings.json');
|
|
516
519
|
mkdirSync(claudeSettingsDir, { recursive: true });
|
|
@@ -578,16 +581,8 @@ async function installStack(stackKey, stackCfg, options = {}) {
|
|
|
578
581
|
JSON.stringify({ stack: stackKey, global: !!options.global, skills: installedSkills, claudeExtras, mcpRegistered: true }, null, 2),
|
|
579
582
|
);
|
|
580
583
|
|
|
581
|
-
console.log('\n✅ Done
|
|
582
|
-
console.log('
|
|
583
|
-
console.log(' npx @eventmodelers/cli run\n');
|
|
584
|
-
console.log('Or using Ollama (run `ollama serve` first):');
|
|
585
|
-
console.log(' npx @eventmodelers/cli run --ollama\n');
|
|
586
|
-
console.log('Or using the bash loop only (no realtime):');
|
|
587
|
-
console.log(' npx @eventmodelers/cli run --bash\n');
|
|
588
|
-
console.log(`Skills are ready in ${options.global ? join(homedir(), '.claude', 'skills') : '.claude/skills/'} — use /connect to set a board ID.\n`);
|
|
589
|
-
console.log('💡 Recommended: add Chrome DevTools MCP for browser inspection:');
|
|
590
|
-
console.log(' claude mcp add chrome-devtools --scope user -- npx chrome-devtools-mcp@latest\n');
|
|
584
|
+
console.log('\n✅ Done! Start your agent:\n');
|
|
585
|
+
console.log(' npx @eventmodelers/cli run (--ollama or --bash for other runners)\n');
|
|
591
586
|
}
|
|
592
587
|
|
|
593
588
|
const program = new Command();
|
package/package.json
CHANGED