@eventmodelers/cli 1.0.89 → 1.0.90

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.89",
3
+ "version": "1.0.90",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -28,21 +28,19 @@ async function fetchJSON(url, options) {
28
28
  return res.json();
29
29
  }
30
30
 
31
- async function retryOn401(label, fn, maxRetries = 3) {
32
- for (let attempt = 1; attempt <= maxRetries; attempt++) {
33
- try {
34
- return await fn();
35
- } catch (err) {
36
- if (err instanceof HttpError && err.status === 401) {
37
- if (attempt < maxRetries) {
38
- console.warn(`[agent] ${label} — 401, retrying (${attempt}/${maxRetries})...`);
39
- continue;
40
- }
41
- console.error(`[agent] ${label} — 401 after ${maxRetries} retries, shutting down`);
42
- process.exit(1);
43
- }
44
- throw err;
31
+ // A 401 from the platform always means the token itself is missing, invalid or revoked (see
32
+ // requireApiToken on the platform) — retrying the same token can't fix that, and neither can
33
+ // waiting, so the first one ends the process with a message saying what to fix.
34
+ async function exitOn401(label, fn) {
35
+ try {
36
+ return await fn();
37
+ } catch (err) {
38
+ if (err instanceof HttpError && err.status === 401) {
39
+ console.error(`[agent] ${label} — 401, the token was rejected: ${err.message}`);
40
+ console.error('[agent] Check the token in .eventmodelers/config.json (or EVENTMODELERS_TOKEN) — shutting down');
41
+ process.exit(1);
45
42
  }
43
+ throw err;
46
44
  }
47
45
  }
48
46
 
@@ -273,7 +271,7 @@ async function writeTask(payload, kitDir) {
273
271
 
274
272
  async function handleSliceChanged(payload, cfg, kitDir, queueAllStatuses) {
275
273
  console.log(`[agent] slice:changed — slice="${payload.sliceTitle}" status="${payload.sliceStatus}"`);
276
- await retryOn401('fetchAndPersistSlices', () => fetchAndPersistSlices(cfg, kitDir)).catch((err) =>
274
+ await exitOn401('fetchAndPersistSlices', () => fetchAndPersistSlices(cfg, kitDir)).catch((err) =>
277
275
  console.error('[agent] Slice persist error:', err),
278
276
  );
279
277
  // This agent's own status writes (claim → InProgress, → Done, → Blocked) come straight back
@@ -295,9 +293,9 @@ async function handleSliceChanged(payload, cfg, kitDir, queueAllStatuses) {
295
293
  }
296
294
 
297
295
  async function startRealtimeAgent(cfg, kitDir, { agentType = 'BUILD', queueAllStatuses = false } = {}) {
298
- let realtimeToken = await retryOn401('getRealtimeToken', () => getRealtimeToken(cfg));
296
+ let realtimeToken = await exitOn401('getRealtimeToken', () => getRealtimeToken(cfg));
299
297
 
300
- await retryOn401('fetchAndPersistSlices', () => fetchAndPersistSlices(cfg, kitDir)).catch((err) =>
298
+ await exitOn401('fetchAndPersistSlices', () => fetchAndPersistSlices(cfg, kitDir)).catch((err) =>
301
299
  console.error('[agent] Initial slice fetch error:', err),
302
300
  );
303
301
 
@@ -315,7 +313,7 @@ async function startRealtimeAgent(cfg, kitDir, { agentType = 'BUILD', queueAllSt
315
313
  console.log(`[agent] ${ts()} Refreshing realtime token (reason: ${reason})...`);
316
314
  refreshing = (async () => {
317
315
  try {
318
- realtimeToken = await retryOn401('getRealtimeToken (refresh)', () => getRealtimeToken(cfg));
316
+ realtimeToken = await exitOn401('getRealtimeToken (refresh)', () => getRealtimeToken(cfg));
319
317
  await realtime.setAuth(realtimeToken);
320
318
  console.log(`[agent] ${ts()} Token refreshed (reason: ${reason}, took ${Date.now() - startedAt}ms)`);
321
319
  } catch (err) {
@@ -335,7 +333,7 @@ async function startRealtimeAgent(cfg, kitDir, { agentType = 'BUILD', queueAllSt
335
333
  // the cap used to leave the channel dead for good — the scheduled refresh only calls
336
334
  // setAuth, it never re-joins — while the backoff alone keeps a genuinely revoked
337
335
  // access from hammering the platform. A revoked token ends the process anyway, via
338
- // retryOn401 inside refreshToken.
336
+ // exitOn401 inside refreshToken.
339
337
  let channelErrorStreak = 0;
340
338
  let resubscribeTimer = null;
341
339
  const onChannelFailure = (reason) => {
@@ -383,7 +381,7 @@ async function startRealtimeAgent(cfg, kitDir, { agentType = 'BUILD', queueAllSt
383
381
  // Broadcasts sent while the channel was down are gone. Re-read the slices once so a
384
382
  // slice set to Planned during the gap still gets built — .slices/ is what ralphLoop
385
383
  // picks Planned work from.
386
- retryOn401('fetchAndPersistSlices (after reconnect)', () => fetchAndPersistSlices(cfg, kitDir)).catch((err) =>
384
+ exitOn401('fetchAndPersistSlices (after reconnect)', () => fetchAndPersistSlices(cfg, kitDir)).catch((err) =>
387
385
  console.error(`[agent] ${ts()} Slice re-fetch after reconnect failed:`, err),
388
386
  );
389
387
  },
@@ -642,7 +640,7 @@ async function ralphLoop(kitDir, cfg, onTask, onPlannedSlice, localOnly = false)
642
640
 
643
641
  // ── Public API ────────────────────────────────────────────────────────────────
644
642
 
645
- export { loadLocalConfig, fetchPlatformConfig, retryOn401, startRealtimeAgent };
643
+ export { loadLocalConfig, fetchPlatformConfig, exitOn401, startRealtimeAgent };
646
644
 
647
645
  // Who this process is. RALPH_AGENT_ID/RALPH_AGENT_NAME are `eventmodelers run --id/--name`,
648
646
  // passed down as env (see cli.js's run dispatcher): a per-run identity override so a second
@@ -676,7 +674,7 @@ export async function startRalph({ kitDir, projectDir, onTask, onPlannedSlice, a
676
674
  return;
677
675
  }
678
676
 
679
- const cfg = await retryOn401('fetchPlatformConfig', () => fetchPlatformConfig(local));
677
+ const cfg = await exitOn401('fetchPlatformConfig', () => fetchPlatformConfig(local));
680
678
  console.log(` org=${cfg.organizationId}, board=${cfg.boardId}, base=${cfg.baseUrl}\n`);
681
679
 
682
680
  await Promise.all([
@@ -4,14 +4,14 @@
4
4
  // only need this if you want to run the agent independently (e.g. separate terminal).
5
5
  // Usage: node realtime-agent.js [kit_dir]
6
6
 
7
- import { loadLocalConfig, fetchPlatformConfig, retryOn401, startRealtimeAgent } from './lib/ralph.js';
7
+ import { loadLocalConfig, fetchPlatformConfig, exitOn401, startRealtimeAgent } from './lib/ralph.js';
8
8
  import { dirname, resolve } from 'path';
9
9
  import { fileURLToPath } from 'url';
10
10
 
11
11
  const kitDir = process.argv[2] ? resolve(process.argv[2]) : dirname(fileURLToPath(import.meta.url));
12
12
 
13
13
  const local = loadLocalConfig(kitDir);
14
- const cfg = await retryOn401('fetchPlatformConfig', () => fetchPlatformConfig(local));
14
+ const cfg = await exitOn401('fetchPlatformConfig', () => fetchPlatformConfig(local));
15
15
 
16
16
  console.log(`[agent] Starting — org=${cfg.organizationId}${cfg.boardId ? `, board=${cfg.boardId}` : ''}, base=${cfg.baseUrl}`);
17
17