@eventmodelers/cli 0.0.26 → 0.0.27
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 +2 -2
- package/cli.js +22 -10
- package/lib/fetch.js +18 -4
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -225,7 +225,7 @@ npx @eventmodelers/cli run --ollama # same, via local Ollama (ra
|
|
|
225
225
|
npx @eventmodelers/cli run --bash # bash-only loop, no realtime (ralph.sh)
|
|
226
226
|
npx @eventmodelers/cli listen # start the code-export listener (code-export.mjs) from the installed kit dir
|
|
227
227
|
npx @eventmodelers/cli listen --port 4000 # same, on a different port
|
|
228
|
-
npx @eventmodelers/cli fetch # pull full slice detail from every context on the board into <kit-dir>/.slices/
|
|
228
|
+
npx @eventmodelers/cli fetch # pull full slice detail from every context on the board into <kit-dir>/.slices/ (project root if no kit, or a modeling-kit, is installed)
|
|
229
229
|
npx @eventmodelers/cli fetch --slice-id <id> # same, then print just that slice
|
|
230
230
|
npx @eventmodelers/cli fetch --slice-title <title> # same, then print just the slice matching this title
|
|
231
231
|
npx @eventmodelers/cli stacks # list available stacks
|
|
@@ -238,7 +238,7 @@ npx @eventmodelers/cli uninstall # remove everything init/ini
|
|
|
238
238
|
|
|
239
239
|
`listen` is the same kind of dispatcher, but for `<kit-dir>/code-export.mjs` — a local HTTP server (port 3001 by default) that the eventmodelers board UI posts slice/screen data to, which then gets written under `<kit-dir>/.slices/`.
|
|
240
240
|
|
|
241
|
-
`fetch` is the pull-based counterpart to `listen`: instead of waiting for the board UI to push data to a running listener, it lists every `MODEL_CONTEXT` node on the board, calls `slicedata?contextId=<id>` for each (full slice detail — commands/events/readmodels/screens/processors/specifications/comments), and writes the same `.slices/<context>/<slice>/slice.json`, `index.json`, and `context.json` layout — useful in CI or any context where nothing is listening on a port. It does not fetch screen images (those only arrive via `listen`'s push). If credentials are missing, it prompts the same way `init-config` does. `--slice-id`/`--slice-title` still fetch and persist everything, then just print the one you asked about.
|
|
241
|
+
`fetch` is the pull-based counterpart to `listen`: instead of waiting for the board UI to push data to a running listener, it lists every `MODEL_CONTEXT` node on the board, calls `slicedata?contextId=<id>` for each (full slice detail — commands/events/readmodels/screens/processors/specifications/comments), and writes the same `.slices/<context>/<slice>/slice.json`, `index.json`, and `context.json` layout — useful in CI or any context where nothing is listening on a port. It does not fetch screen images (those only arrive via `listen`'s push). Unlike every other command, `fetch` also works with no kit installed at all — it only needs credentials, not kit-specific files — and, unique to modeling-kit, writes `.slices/` to the project root instead of nesting it under `.agent-modeling-kit/`, since nothing reads it from there (modeling-kit has no `code-export.mjs`/`listen`). If credentials are missing, it prompts the same way `init-config` does. `--slice-id`/`--slice-title` still fetch and persist everything, then just print the one you asked about.
|
|
242
242
|
|
|
243
243
|
### Uninstall
|
|
244
244
|
|
package/cli.js
CHANGED
|
@@ -734,8 +734,15 @@ async function configureCredentials({ config, configPath, targetDir, requiredFie
|
|
|
734
734
|
}
|
|
735
735
|
|
|
736
736
|
const stillMissing = force || requiredFields.some((f) => !config[f]);
|
|
737
|
+
// Sole gate on the persist step below — 'instructions'/'skip' and a paste that
|
|
738
|
+
// couldn't be parsed all explicitly tell the user nothing was saved, so the
|
|
739
|
+
// final write must not run for them (it used to run unconditionally, silently
|
|
740
|
+
// writing out whatever `config` happened to be — `{}` on a first run — which
|
|
741
|
+
// contradicted those messages and left behind a bogus config.json).
|
|
742
|
+
let skipWrite = false;
|
|
737
743
|
if (stillMissing && print) {
|
|
738
744
|
console.log('\n ℹ️ --print — skipping credential prompt, missing fields must be set via flags, EVENTMODELERS_* env vars, or config.json');
|
|
745
|
+
skipWrite = true;
|
|
739
746
|
} else if (stillMissing) {
|
|
740
747
|
const choice = await selectPrompt('How do you want to configure credentials?', [
|
|
741
748
|
{ label: 'Paste values copied from app.eventmodelers.ai/account', value: 'paste' },
|
|
@@ -751,12 +758,10 @@ async function configureCredentials({ config, configPath, targetDir, requiredFie
|
|
|
751
758
|
const parsed = parseCredentialsPaste(pasted, requiredFields);
|
|
752
759
|
if (parsed) {
|
|
753
760
|
config = { ...config, ...parsed };
|
|
754
|
-
if (!config.baseUrl) config.baseUrl = DEFAULT_BASE_URL;
|
|
755
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
756
|
-
console.log(`\n ✓ Saved to ${relative(targetDir, configPath)}`);
|
|
757
761
|
} else {
|
|
758
762
|
console.log(`\n ⚠️ Couldn't make sense of that paste — nothing was saved.`);
|
|
759
763
|
console.log(` Paste it into ${relative(targetDir, configPath)} yourself, or use /connect later.`);
|
|
764
|
+
skipWrite = true;
|
|
760
765
|
}
|
|
761
766
|
} else if (choice === 'manual') {
|
|
762
767
|
console.log('\n🔑 Enter your Eventmodelers credentials:\n');
|
|
@@ -766,9 +771,6 @@ async function configureCredentials({ config, configPath, targetDir, requiredFie
|
|
|
766
771
|
const boardId = await prompt(` Board ID${boardIdOptional ? ' (optional)' : ''}: `);
|
|
767
772
|
if (boardId) config.boardId = boardId;
|
|
768
773
|
config.token = await prompt(' Token: ');
|
|
769
|
-
if (!config.baseUrl) config.baseUrl = DEFAULT_BASE_URL;
|
|
770
|
-
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
771
|
-
console.log(`\n ✓ Credentials saved to ${relative(targetDir, configPath)}`);
|
|
772
774
|
} else if (choice === 'instructions') {
|
|
773
775
|
console.log(`\n Paste your credentials into:\n`);
|
|
774
776
|
console.log(` ${configPath}`);
|
|
@@ -778,8 +780,10 @@ async function configureCredentials({ config, configPath, targetDir, requiredFie
|
|
|
778
780
|
const sample = ` {\n "token": "...",\n "boardId": "...",\n "organizationId": "...",\n "baseUrl": "https://api.eventmodelers.ai"\n }\n`;
|
|
779
781
|
console.log(sample);
|
|
780
782
|
console.log(' Then re-run this installer, or just run the agent afterwards.\n');
|
|
783
|
+
skipWrite = true;
|
|
781
784
|
} else {
|
|
782
785
|
console.log('\n ℹ️ Skipped — use /connect in Claude Code to add credentials later');
|
|
786
|
+
skipWrite = true;
|
|
783
787
|
}
|
|
784
788
|
} else {
|
|
785
789
|
console.log('\n ✓ Config already present — skipping credential prompt');
|
|
@@ -791,8 +795,10 @@ async function configureCredentials({ config, configPath, targetDir, requiredFie
|
|
|
791
795
|
config.baseUrl = DEFAULT_BASE_URL;
|
|
792
796
|
}
|
|
793
797
|
|
|
794
|
-
|
|
795
|
-
|
|
798
|
+
if (!skipWrite) {
|
|
799
|
+
writeFileSync(configPath, JSON.stringify(config, null, 2));
|
|
800
|
+
console.log(`\n ✓ Saved to ${relative(targetDir, configPath)}`);
|
|
801
|
+
}
|
|
796
802
|
return config;
|
|
797
803
|
}
|
|
798
804
|
|
|
@@ -1463,6 +1469,12 @@ program
|
|
|
1463
1469
|
.action(async (opts, command) => {
|
|
1464
1470
|
const cwd = process.cwd();
|
|
1465
1471
|
const kitDir = findInstalledKitDir(cwd);
|
|
1472
|
+
// modeling-kit has no code-export.mjs (useShared:false, no `listen`) and no
|
|
1473
|
+
// skill reads a nested .agent-modeling-kit/.slices/ — so nothing expects fetch's
|
|
1474
|
+
// output there either. Every other kit dir does have a code-export.mjs that
|
|
1475
|
+
// hardcodes its .slices/ next to itself, so those still nest to stay
|
|
1476
|
+
// interchangeable with what `listen` produces.
|
|
1477
|
+
const slicesKitDir = kitDir?.endsWith(MODELING_KIT.kitDirName) ? null : kitDir;
|
|
1466
1478
|
const globalOpts = command.optsWithGlobals();
|
|
1467
1479
|
const explicitConfig = globalOpts.config;
|
|
1468
1480
|
const effective = loadEffectiveConfig(cwd, kitDir, explicitConfig);
|
|
@@ -1496,7 +1508,7 @@ program
|
|
|
1496
1508
|
if (requiredFields.some((f) => !cfg[f])) await promptForCredentials();
|
|
1497
1509
|
|
|
1498
1510
|
try {
|
|
1499
|
-
await runFetch({ cwd, kitDir, cfg, opts });
|
|
1511
|
+
await runFetch({ cwd, kitDir: slicesKitDir, cfg, opts });
|
|
1500
1512
|
} catch (err) {
|
|
1501
1513
|
if (!(err instanceof FetchAuthError)) throw err;
|
|
1502
1514
|
// Present but wrong, not missing — the connect skill's Step 4 (Verify) treats
|
|
@@ -1506,7 +1518,7 @@ program
|
|
|
1506
1518
|
if (err.status === 404) delete cfg.boardId;
|
|
1507
1519
|
else delete cfg.token;
|
|
1508
1520
|
await promptForCredentials();
|
|
1509
|
-
await runFetch({ cwd, kitDir, cfg, opts });
|
|
1521
|
+
await runFetch({ cwd, kitDir: slicesKitDir, cfg, opts });
|
|
1510
1522
|
}
|
|
1511
1523
|
});
|
|
1512
1524
|
|
package/lib/fetch.js
CHANGED
|
@@ -49,6 +49,8 @@ function sliceFolderName(title) {
|
|
|
49
49
|
// .slices/, mirroring the layout code-export.mjs's /api/generate handler produces
|
|
50
50
|
// (minus screen images, which only ever arrive via that push-based listener).
|
|
51
51
|
//
|
|
52
|
+
// kitDir here is null for modeling-kit (see cli.js's fetch action) — nothing
|
|
53
|
+
// nests .slices/ under .agent-modeling-kit/, so it lands at cwd instead.
|
|
52
54
|
// { cwd, kitDir, cfg: { token, organizationId, boardId, baseUrl }, opts: { sliceId?, sliceTitle? } }
|
|
53
55
|
export async function runFetch({ cwd, kitDir, cfg, opts = {} }) {
|
|
54
56
|
const baseUrl = cfg.baseUrl || DEFAULT_BASE_URL;
|
|
@@ -85,6 +87,10 @@ export async function runFetch({ cwd, kitDir, cfg, opts = {} }) {
|
|
|
85
87
|
return;
|
|
86
88
|
}
|
|
87
89
|
|
|
90
|
+
// Falls back to cwd when no kit is installed — fetch doesn't need kit-specific
|
|
91
|
+
// files, just somewhere to write .slices/.
|
|
92
|
+
const SLICES_DIR = join(kitDir || cwd, '.slices');
|
|
93
|
+
|
|
88
94
|
// /slicedata (buildSliceData) is per-context and returns full slice detail —
|
|
89
95
|
// commands/events/readmodels/screens/processors/specifications/comments — unlike
|
|
90
96
|
// the lightweight /slicedata/slices summary. There's no "all contexts in one
|
|
@@ -95,11 +101,22 @@ export async function runFetch({ cwd, kitDir, cfg, opts = {} }) {
|
|
|
95
101
|
// contextId is the normal path (we already have the node id); contextName is
|
|
96
102
|
// the fallback the endpoint itself supports when an id can't be resolved.
|
|
97
103
|
const contextQuery = node.id ? `contextId=${encodeURIComponent(node.id)}` : `contextName=${encodeURIComponent(contextName)}`;
|
|
98
|
-
const
|
|
104
|
+
const payload = await fetchJson(
|
|
99
105
|
`${baseUrl}/api/org/${cfg.organizationId}/boards/${cfg.boardId}/slicedata?${contextQuery}`,
|
|
100
106
|
`slicedata?${contextQuery}`,
|
|
101
107
|
);
|
|
108
|
+
const { slices } = payload;
|
|
102
109
|
allSlices.push(...slices);
|
|
110
|
+
|
|
111
|
+
if (slices.length) {
|
|
112
|
+
// Mirrors code-export.mjs's /api/generate: a raw per-context payload dump at
|
|
113
|
+
// .slices/<context>/config.json, alongside the per-slice output below — kept
|
|
114
|
+
// for parity with `listen` even though nothing in this repo reads it back.
|
|
115
|
+
const contextSlug = slugify(slices[0]?.context || contextName || 'default') || 'default';
|
|
116
|
+
const baseFolder = join(SLICES_DIR, contextSlug);
|
|
117
|
+
mkdirSync(baseFolder, { recursive: true });
|
|
118
|
+
writeFileSync(join(baseFolder, 'config.json'), JSON.stringify(payload, null, 2));
|
|
119
|
+
}
|
|
103
120
|
}
|
|
104
121
|
|
|
105
122
|
if (!allSlices.length) {
|
|
@@ -107,9 +124,6 @@ export async function runFetch({ cwd, kitDir, cfg, opts = {} }) {
|
|
|
107
124
|
return;
|
|
108
125
|
}
|
|
109
126
|
|
|
110
|
-
// Falls back to cwd when no kit is installed — fetch doesn't need kit-specific
|
|
111
|
-
// files, just somewhere to write .slices/.
|
|
112
|
-
const SLICES_DIR = join(kitDir || cwd, '.slices');
|
|
113
127
|
const contextNames = new Set();
|
|
114
128
|
|
|
115
129
|
for (const slice of allSlices) {
|
package/package.json
CHANGED