@eventmodelers/cli 1.0.57 → 1.0.58
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 +13 -4
- package/cli.js +55 -7
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -179,13 +179,22 @@ when you upgrade the CLI. Pass `--global` to prefer it even when a local kit doe
|
|
|
179
179
|
npx @eventmodelers/cli run --standalone --board-id <uuid> # from any directory, nothing written there
|
|
180
180
|
```
|
|
181
181
|
|
|
182
|
+
**Which board?** When `--board-id` isn't given, the agent asks for it on start, pre-filled
|
|
183
|
+
with whatever the config resolved to — press Enter to accept it, or paste a different board
|
|
184
|
+
id. A board inherited from a config file can be arbitrarily stale, and which board a run
|
|
185
|
+
drives is the one thing worth confirming. Skipped when there's no one to ask (`--print`, or a
|
|
186
|
+
non-interactive stdin), where the resolved value stands on its own.
|
|
187
|
+
|
|
182
188
|
**Credentials are per board, not per directory.** The first time this machine runs a board it
|
|
183
|
-
asks one question — does this board get credentials of its own, or does it use your
|
|
189
|
+
asks one more question — does this board get credentials of its own, or does it use your
|
|
184
190
|
account-wide ones? Answer once and it's remembered: either the board's credentials or a
|
|
185
191
|
`useGlobal` marker lands in `~/.eventmodelers/boards/<board>.json`, and you're not asked
|
|
186
|
-
again.
|
|
187
|
-
|
|
188
|
-
|
|
192
|
+
again. If the credentials you paste name a *different* board than the one asked about — an easy
|
|
193
|
+
way to end up there is a stale `boardId` in `~/.eventmodelers/config.json` — the run switches
|
|
194
|
+
to the pasted board and leaves a pointer behind for the one it asked about, so the question is
|
|
195
|
+
asked once rather than on every start. The question is skipped entirely when the answer is
|
|
196
|
+
already implied (credentials given on the command line) or when there's no one to ask
|
|
197
|
+
(`--print`, or a non-interactive stdin such as CI or a process supervisor).
|
|
189
198
|
|
|
190
199
|
To configure a board up front instead, paste the blob from
|
|
191
200
|
[app.eventmodelers.ai/account](https://app.eventmodelers.ai/account):
|
package/cli.js
CHANGED
|
@@ -349,7 +349,16 @@ function getSharedRl() {
|
|
|
349
349
|
// called, hanging forever. Pulling from the iterator instead queues each line until
|
|
350
350
|
// something asks for it, so nothing emitted ahead of time is ever lost between prompts.
|
|
351
351
|
async function prompt(question = '') {
|
|
352
|
-
getSharedRl();
|
|
352
|
+
const rl = getSharedRl();
|
|
353
|
+
// selectPrompt pauses stdin when it tears down its raw-mode keypress handler. That was
|
|
354
|
+
// invisible for as long as every menu came BEFORE the first prompt() — getSharedRl's
|
|
355
|
+
// createInterface resumes stdin on the way in, so a freshly built readline never noticed.
|
|
356
|
+
// Once a prompt runs first (the Board ID question), the interface already exists and is
|
|
357
|
+
// reused, so the next prompt after a menu waits forever on a stream nobody resumed: the
|
|
358
|
+
// event loop drains and node reports an unsettled top-level await instead of reading the
|
|
359
|
+
// line. Both calls are no-ops when nothing paused anything.
|
|
360
|
+
rl.resume();
|
|
361
|
+
process.stdin.resume();
|
|
353
362
|
if (question) process.stdout.write(question);
|
|
354
363
|
const { value, done } = await sharedRlLines.next();
|
|
355
364
|
return (done ? '' : value).trim();
|
|
@@ -1345,13 +1354,17 @@ function boardCredentialsPath(boardId) {
|
|
|
1345
1354
|
return join(GLOBAL_DIR, 'boards', `${boardId}.json`);
|
|
1346
1355
|
}
|
|
1347
1356
|
|
|
1348
|
-
//
|
|
1349
|
-
//
|
|
1350
|
-
// once-per-board event
|
|
1357
|
+
// Three shapes, never mixed: the board's own credentials, a note that this board just uses
|
|
1358
|
+
// the account-wide ones, or a pointer to another board's file. All three exist for the same
|
|
1359
|
+
// reason — the first-run question has to be a once-per-board event rather than something to
|
|
1360
|
+
// dismiss on every start, so every possible answer has to be recordable against the board
|
|
1361
|
+
// that was ASKED about, including "actually, those credentials were for a different board".
|
|
1351
1362
|
function writeBoardCredentials(config) {
|
|
1352
1363
|
const path = boardCredentialsPath(config.boardId);
|
|
1353
1364
|
mkdirSync(dirname(path), { recursive: true, mode: 0o700 });
|
|
1354
|
-
const body = config.
|
|
1365
|
+
const body = config.useBoard
|
|
1366
|
+
? { boardId: config.boardId, useBoard: config.useBoard }
|
|
1367
|
+
: config.useGlobal
|
|
1355
1368
|
? { boardId: config.boardId, useGlobal: true, agentId: config.agentId }
|
|
1356
1369
|
: {
|
|
1357
1370
|
token: config.token,
|
|
@@ -1407,8 +1420,36 @@ async function resolveModelingCredentials(cwd, flags, explicitConfigPath, print)
|
|
|
1407
1420
|
// Which board comes first — everything else is stored per board, so there is nothing to
|
|
1408
1421
|
// look up until we know which board this run is for.
|
|
1409
1422
|
let boardId = explicit.boardId || process.env.EVENTMODELERS_BOARD_ID || walked.boardId || null;
|
|
1423
|
+
|
|
1424
|
+
// Which board a run drives is the single most consequential thing about it, and a boardId
|
|
1425
|
+
// inherited from a config file can be arbitrarily stale — so when it wasn't named on the
|
|
1426
|
+
// command line, confirm it. Enter accepts whatever the config resolved to, keeping the
|
|
1427
|
+
// common case to one keystroke. Skipped when there is no one to ask (--print, or a
|
|
1428
|
+
// non-interactive stdin such as CI or a process supervisor), where the resolved value
|
|
1429
|
+
// stands on its own exactly as before.
|
|
1430
|
+
let boardChosen = !!(explicit.boardId || process.env.EVENTMODELERS_BOARD_ID);
|
|
1431
|
+
if (!boardChosen && !print && process.stdin.isTTY) {
|
|
1432
|
+
const answer = await prompt(boardId ? `\n Board ID [${boardId}]: ` : '\n Board ID: ');
|
|
1433
|
+
if (answer) {
|
|
1434
|
+
boardId = answer;
|
|
1435
|
+
boardChosen = true;
|
|
1436
|
+
}
|
|
1437
|
+
}
|
|
1438
|
+
|
|
1410
1439
|
let stored = boardId ? readJsonSafe(boardCredentialsPath(boardId)) : {};
|
|
1411
1440
|
|
|
1441
|
+
// Follow a pointer left by an earlier answer: this directory (or the account config) keeps
|
|
1442
|
+
// resolving to one board, but the credentials pasted for it named another. Without this the
|
|
1443
|
+
// question below would be re-asked on every single start, since the board that gets a file
|
|
1444
|
+
// is never the board the next run resolves. Not followed when the board was named
|
|
1445
|
+
// explicitly — that is a direct instruction, not an inherited default. One hop only: a
|
|
1446
|
+
// pointer always targets a board that then holds real credentials, so a chain would mean a
|
|
1447
|
+
// corrupted store rather than something to chase.
|
|
1448
|
+
if (stored.useBoard && !boardChosen) {
|
|
1449
|
+
boardId = stored.useBoard;
|
|
1450
|
+
stored = readJsonSafe(boardCredentialsPath(boardId));
|
|
1451
|
+
}
|
|
1452
|
+
|
|
1412
1453
|
// First time this machine has seen this board, ask the one question that can't be
|
|
1413
1454
|
// guessed: does it get credentials of its own, or does it ride on the account-wide ones?
|
|
1414
1455
|
// The answer is recorded either way (as credentials, or as a useGlobal marker), so this
|
|
@@ -1439,8 +1480,15 @@ async function resolveModelingCredentials(cwd, flags, explicitConfigPath, print)
|
|
|
1439
1480
|
console.error("\n❌ Couldn't make sense of that paste — nothing was saved.");
|
|
1440
1481
|
process.exit(1);
|
|
1441
1482
|
}
|
|
1442
|
-
// The paste is the more specific answer about which board this is: someone who
|
|
1443
|
-
//
|
|
1483
|
+
// The paste is the more specific answer about which board this is: someone who copied
|
|
1484
|
+
// board B's credentials means board B, whatever the command line defaulted to. But the
|
|
1485
|
+
// question was asked ABOUT board A, so board A needs an answer on file too — otherwise
|
|
1486
|
+
// the next run resolves A again, finds nothing, and asks all over again.
|
|
1487
|
+
if (parsed.boardId && boardId && parsed.boardId !== boardId) {
|
|
1488
|
+
writeBoardCredentials({ boardId, useBoard: parsed.boardId });
|
|
1489
|
+
console.log(`\n ℹ️ Those credentials are for board ${parsed.boardId}, not ${boardId} — noted, so this is asked once and not again.`);
|
|
1490
|
+
console.log(` Pass --board-id to pick a different board, or drop the stale boardId from ~/.eventmodelers/config.json.`);
|
|
1491
|
+
}
|
|
1444
1492
|
if (parsed.boardId) boardId = parsed.boardId;
|
|
1445
1493
|
stored = parsed;
|
|
1446
1494
|
} else {
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.58",
|
|
4
4
|
"description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"bin": {
|