@eventmodelers/cli 0.0.24 → 0.0.25

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 (3) hide show
  1. package/cli.js +26 -9
  2. package/lib/fetch.js +15 -0
  3. package/package.json +1 -1
package/cli.js CHANGED
@@ -18,7 +18,7 @@ import { execSync, spawn } from 'child_process';
18
18
  import { createInterface, emitKeypressEvents, moveCursor, clearScreenDown } from 'readline';
19
19
  import { homedir } from 'os';
20
20
  import { randomUUID } from 'crypto';
21
- import { runFetch } from './lib/fetch.js';
21
+ import { runFetch, FetchAuthError } from './lib/fetch.js';
22
22
 
23
23
  const __filename = fileURLToPath(import.meta.url);
24
24
  const __dirname = dirname(__filename);
@@ -1467,14 +1467,16 @@ program
1467
1467
  const effective = loadEffectiveConfig(cwd, kitDir, explicitConfig);
1468
1468
  let cfg = effective.config;
1469
1469
 
1470
+ // Same default (project-root .eventmodelers/config.json, or --config) that
1471
+ // installStack uses — kept identical rather than deriving a path from
1472
+ // `effective`, which can point at a kit-dir-scoped config instead.
1473
+ const configPath = explicitConfig ? resolve(cwd, explicitConfig) : join(cwd, '.eventmodelers', 'config.json');
1470
1474
  const requiredFields = ['organizationId', 'boardId', 'token'];
1471
- if (requiredFields.some((f) => !cfg[f])) {
1472
- // Same default (project-root .eventmodelers/config.json, or --config) that
1473
- // installStack uses kept identical rather than deriving a path from
1474
- // `effective`, which can point at a kit-dir-scoped config instead.
1475
- const configPath = explicitConfig ? resolve(cwd, explicitConfig) : join(cwd, '.eventmodelers', 'config.json');
1476
- // Same prompt (paste/manual/instructions/skip) `install`/`init-config` use —
1477
- // reusing it here means `fetch` also works as a first-run credential setup.
1475
+
1476
+ // Same prompt (paste/manual/instructions/skip) `install`/`init-config` use
1477
+ // reusing it here means `fetch` also works as a first-run credential setup.
1478
+ // Also re-entered below if the API rejects whatever we already had.
1479
+ async function promptForCredentials() {
1478
1480
  cfg = await configureCredentials({
1479
1481
  config: cfg,
1480
1482
  configPath,
@@ -1489,7 +1491,22 @@ program
1489
1491
  process.exit(1);
1490
1492
  }
1491
1493
  }
1492
- await runFetch({ cwd, kitDir, cfg, opts });
1494
+
1495
+ if (requiredFields.some((f) => !cfg[f])) await promptForCredentials();
1496
+
1497
+ try {
1498
+ await runFetch({ cwd, kitDir, cfg, opts });
1499
+ } catch (err) {
1500
+ if (!(err instanceof FetchAuthError)) throw err;
1501
+ // Present but wrong, not missing — the connect skill's Step 4 (Verify) treats
1502
+ // 401/403/404 the same way: clear the field that's implicated and re-prompt,
1503
+ // rather than leaving the caller stuck re-running with the same bad value.
1504
+ console.error(`❌ ${err.message}`);
1505
+ if (err.status === 404) delete cfg.boardId;
1506
+ else delete cfg.token;
1507
+ await promptForCredentials();
1508
+ await runFetch({ cwd, kitDir, cfg, opts });
1509
+ }
1493
1510
  });
1494
1511
 
1495
1512
  program
package/lib/fetch.js CHANGED
@@ -3,6 +3,18 @@ import { join, relative } from 'path';
3
3
 
4
4
  const DEFAULT_BASE_URL = 'https://api.eventmodelers.ai';
5
5
 
6
+ // Thrown instead of exiting on 401/403/404 — these mean the *credentials* (not the
7
+ // network/server) are the problem, so the caller gets a chance to re-prompt and retry
8
+ // instead of just dying, the same way the connect skill's Step 4 (Verify) reacts to
9
+ // each status. Other statuses (500, etc.) still exit directly — reconfiguring
10
+ // credentials wouldn't fix those.
11
+ export class FetchAuthError extends Error {
12
+ constructor(status, message) {
13
+ super(message);
14
+ this.status = status;
15
+ }
16
+ }
17
+
6
18
  function readJsonSafe(path) {
7
19
  if (!path || !existsSync(path)) return {};
8
20
  try {
@@ -50,6 +62,9 @@ export async function runFetch({ cwd, kitDir, cfg, opts = {} }) {
50
62
  console.error(`❌ Request failed (${what}): ${err.message}`);
51
63
  process.exit(1);
52
64
  }
65
+ if (res.status === 401) throw new FetchAuthError(401, `${what}: invalid or expired token`);
66
+ if (res.status === 403) throw new FetchAuthError(403, `${what}: token's organization does not match this board`);
67
+ if (res.status === 404) throw new FetchAuthError(404, `${what}: board not found`);
53
68
  if (!res.ok) {
54
69
  console.error(`❌ ${what}: HTTP ${res.status}`);
55
70
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "0.0.24",
3
+ "version": "0.0.25",
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": {