@eventmodelers/cli 2.0.5 → 2.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.
package/README.md CHANGED
@@ -774,6 +774,7 @@ npx @eventmodelers/cli listen --port 4000 # same, on a different port
774
774
  npx @eventmodelers/cli re-init # refresh the installed build kit (.build-kit/) + its skills
775
775
  npx @eventmodelers/cli re-init --modeling # refresh the modeling kit (.agent-modeling-kit/) + its skills
776
776
  npx @eventmodelers/cli re-init --stack supabase # override which stack to refresh from (manifest missing/stale, or switching stacks)
777
+ npx @eventmodelers/cli scaffold re-init [dir] # a scaffolded app: refresh every kit in it (root + web/) — `re-init --stack` for each
777
778
  ```
778
779
 
779
780
  `re-init` re-runs `init` against whichever stack `install-manifest.json` says was installed (no need to pass `--stack` again), but skips step 2 of `init` entirely — the root project scaffold (`package.json`, `src/`, `server.ts`, `docker-compose.yml`, etc.) and the root `CLAUDE.md` router are never touched. Use it after upgrading the CLI to pick up fixes to `ralph.js`/skills without re-scaffolding a project you've since built on top of.
package/cli.js CHANGED
@@ -20,7 +20,7 @@ import { createInterface, emitKeypressEvents, moveCursor, clearScreenDown } from
20
20
  import { homedir, tmpdir } from 'os';
21
21
  import { randomUUID } from 'crypto';
22
22
  import { runFetch, FetchAuthError } from './lib/fetch.js';
23
- import { SCAFFOLD_TYPES, scaffoldTypeNames, missingPrerequisites, runScaffold, builtInTemplates, initTemplates } from './lib/scaffold.js';
23
+ import { SCAFFOLD_TYPES, scaffoldTypeNames, missingPrerequisites, runScaffold, reinitKits, builtInTemplates, initTemplates } from './lib/scaffold.js';
24
24
  import { supervise } from './lib/supervise.js';
25
25
  import { findBuildKitDirs } from './lib/build-kits.js';
26
26
  import { buildModel } from './lib/scaffold-model.js';
@@ -4228,7 +4228,7 @@ program
4228
4228
 
4229
4229
  program
4230
4230
  .command('scaffold <target> [args...]')
4231
- .description('`scaffold add-user <email> <password> [dir]` adds a sign-in user to a scaffolded app (run in its folder, or pass dir). Otherwise: generate a runnable app skeleton from the board — sign-in, navigation with one entry per timeline, a page shell per screen, 501 for every unbuilt endpoint, hot reload — and install the build kits of the chosen --type into it, ready for `run` to add slices. <target> is an empty or new directory, or a skeleton made earlier (which is refreshed from the current model).')
4231
+ .description('`scaffold add-user <email> <password> [dir]` adds a sign-in user to a scaffolded app (run in its folder, or pass dir). `scaffold re-init [dir]` refreshes every kit the app has (root and web/) from this CLI version — `re-init --stack` for each, the skeleton itself untouched. Otherwise: generate a runnable app skeleton from the board — sign-in, navigation with one entry per timeline, a page shell per screen, 501 for every unbuilt endpoint, hot reload — and install the build kits of the chosen --type into it, ready for `run` to add slices. <target> is an empty or new directory, or a skeleton made earlier (which is refreshed from the current model).')
4232
4232
  .option('--type <name>', `Kind of app to scaffold (${scaffoldTypeNames().join(', ')})`, 'supabase')
4233
4233
  .option('--no-install', 'Stop after generating the skeleton: no npm install, checks or commit')
4234
4234
  .option('--no-check', 'Install dependencies but skip the type-check, tests and web build/lint')
@@ -4259,6 +4259,24 @@ program
4259
4259
  }
4260
4260
  return;
4261
4261
  }
4262
+ if (target === 're-init') {
4263
+ if (args.length > 1) {
4264
+ console.error('❌ usage: eventmodelers scaffold re-init [dir]');
4265
+ process.exit(1);
4266
+ }
4267
+ if (!SCAFFOLD_TYPES[opts.type]) {
4268
+ console.error(`❌ Unknown --type "${opts.type}". Available: ${scaffoldTypeNames().join(', ')}`);
4269
+ process.exit(1);
4270
+ }
4271
+ try {
4272
+ const refreshed = reinitKits({ typeName: opts.type, target: resolve(process.cwd(), args[0] ?? '.'), cliPath: join(__dirname, 'cli.js') });
4273
+ console.log(`\n✅ ${refreshed.length} kit(s) refreshed to ${CLI_VERSION}${refreshed.length ? `: ${refreshed.join(', ')}` : ''}`);
4274
+ } catch (err) {
4275
+ console.error(`❌ ${err.message}`);
4276
+ process.exit(1);
4277
+ }
4278
+ return;
4279
+ }
4262
4280
  if (args.length) {
4263
4281
  console.error(`❌ Unexpected argument(s): ${args.join(' ')}`);
4264
4282
  process.exit(1);
package/lib/scaffold.js CHANGED
@@ -222,3 +222,26 @@ export async function runScaffold({ typeName, target, cfg, model, cliPath, insta
222
222
  }
223
223
  return { root, ports, modelFile };
224
224
  }
225
+
226
+ // `scaffold re-init`: refreshes every kit the type installed in a skeleton from this CLI's version — each through
227
+ // `re-init --stack <its stack>` in its own directory, so the skeleton and the root CLAUDE.md are left alone.
228
+ // Returns the kits refreshed, as their dirs.
229
+ export function reinitKits({ typeName, target, cliPath, log = console.log }) {
230
+ const type = SCAFFOLD_TYPES[typeName];
231
+ const root = resolve(target);
232
+ if (targetState(root) !== 'skeleton') {
233
+ throw new Error(`${root} is not a scaffolded skeleton (no skeleton.json) — run this in its folder or pass the folder`);
234
+ }
235
+ const refreshed = [];
236
+ for (const kit of type.kits) {
237
+ const cwd = join(root, kit.dir);
238
+ if (!existsSync(join(cwd, '.build-kit'))) {
239
+ log(`▶ ${kit.stack}: not installed in ${kit.dir}, skipping — \`scaffold ${relative(process.cwd(), root) || '.'}\` installs it`);
240
+ continue;
241
+ }
242
+ log(`▶ Refreshing the ${kit.stack} kit in ${kit.dir}`);
243
+ run(process.execPath, [cliPath, 're-init', '--stack', kit.stack, '--print'], { cwd });
244
+ refreshed.push(kit.dir);
245
+ }
246
+ return refreshed;
247
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "2.0.5",
3
+ "version": "2.0.7",
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": {
@@ -2,15 +2,14 @@
2
2
  // runner that sees its agent's individual tool calls records them through here, so every runner logs the same shape.
3
3
 
4
4
  import { appendEvent } from './slice-events.js';
5
- import { redactString } from './redact.js';
6
5
 
7
- // Best effort, like the rest of the sharing: a failed write must not cost the build. `detail` is the one-line
8
- // account of the call's input, with the token and anything JWT-shaped masked — a Bash command can hold
9
- // credentials, and this log is shared. Only a planned-slice build (`slice.sliceId`) records anything.
10
- export function recordToolCall({ kitDir, slice, tool, detail, cfg, meta }) {
6
+ // Only the tool's name is recorded — never its input. A Bash command, a skill's arguments or a path can hold
7
+ // credentials or local details, and this log is shared with everyone who can open the board. Best effort, like the
8
+ // rest of the sharing: a failed write must not cost the build. Only a planned-slice build (`slice.sliceId`) records.
9
+ export function recordToolCall({ kitDir, slice, tool, meta }) {
11
10
  if (!slice?.sliceId) return;
12
11
  try {
13
- appendEvent(kitDir, { type: 'tool-call', slice: slice.sliceId, tool, detail: redactString(detail, [cfg?.token]) }, meta);
12
+ appendEvent(kitDir, { type: 'tool-call', slice: slice.sliceId, tool }, meta);
14
13
  } catch (err) {
15
14
  console.error(`[ralph] could not record a tool call (${err.message})`);
16
15
  }
@@ -107,7 +107,7 @@ function runClaude(prompt, slice = null, extraEnv = {}) {
107
107
  for (const block of msg.message?.content ?? []) {
108
108
  if (block.type === 'text' && block.text && verbose) console.log(block.text);
109
109
  if (block.type === 'tool_use') {
110
- recordToolCall({ kitDir, slice, tool: block.name, detail: describeToolUse(block), cfg, meta: eventMeta(cfg) });
110
+ recordToolCall({ kitDir, slice, tool: block.name, meta: eventMeta(cfg) });
111
111
  if (verbose) console.log(`→ ${describeToolUse(block)}`);
112
112
  else if (block.name === 'Skill') console.log(`→ Skill: ${block.input?.skill ?? ''}`);
113
113
  else console.log(`→ ${block.name}`);