@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.
Files changed (2) hide show
  1. package/cli.js +30 -35
  2. 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 the same order as requiredFields (organizationId[, boardId], token),
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
- requiredFields.forEach((field, i) => {
190
- result[field] = remaining[i];
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
- console.log(` ✓ Installed ${relative(process.cwd(), dest)}`);
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 Claude skills globally...');
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 Claude skills...');
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('\n📦 Installing project files...\n');
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(`\n📦 Installing agent kit into ${stackCfg.kitDirName}/...`);
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('\n📦 Installing kit dependencies...');
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('\n🔐 Configuring credentials...');
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
- if (stackCfg.needsBoardId) {
480
- config.boardId = await prompt(' Board ID: ');
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 = stackCfg.needsBoardId
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('\n🔌 Configuring MCP server...');
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!\n');
582
- console.log('Start the agent (realtime + task loop in one process):');
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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "0.0.5",
3
+ "version": "0.0.7",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {