@eventmodelers/cli 1.0.4 → 1.0.6

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
@@ -101,6 +101,7 @@ Which skills install depends on the chosen stack — see `stacks/<name>/template
101
101
 
102
102
  ```bash
103
103
  npx @eventmodelers/cli init --stack <name> # scaffold a stack + install + configure (alias: install)
104
+ npx @eventmodelers/cli re-init # refresh an already-installed kit's scripts/skills only — never touches the root scaffold
104
105
  npx @eventmodelers/cli run # start the agent loop (ralph-claude.js) from the installed kit dir
105
106
  npx @eventmodelers/cli run --ollama # same, via local Ollama (ralph-ollama.js)
106
107
  npx @eventmodelers/cli run --bash # bash-only loop, no realtime (ralph.sh)
@@ -306,6 +307,19 @@ npx @eventmodelers/cli listen --port 4000 # same, on a different port
306
307
 
307
308
  `listen` is a dispatcher 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/`. Unlike `fetch`, it does receive screen images, since the board UI pushes them directly.
308
309
 
310
+ ### Re-init — refresh scripts/skills without touching your app
311
+
312
+ ```bash
313
+ npx @eventmodelers/cli re-init # refresh the installed build kit (.build-kit/) + its skills
314
+ npx @eventmodelers/cli re-init --modeling # refresh the modeling kit (.agent-modeling-kit/) + its skills
315
+ ```
316
+
317
+ `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`/`ralph.sh`/skills without re-scaffolding a project you've since built on top of.
318
+
319
+ Credentials are left alone unless you pass `--force` — same rule `init` already follows when everything required is already configured. `--global` defaults to however skills were originally installed; pass it explicitly to move them.
320
+
321
+ If the kit dir predates install-manifest.json tracking, or was installed via `init --git <url>` (a community/custom stack, not one of the built-in `STACKS` keys), `re-init` can't tell what to re-copy and tells you to re-run the original `init` command by hand instead.
322
+
309
323
  ### Uninstall
310
324
 
311
325
  Every `init`/`init-modeling` run writes an install manifest into `<kit-dir>/.eventmodelers/install-manifest.json` recording exactly what it put down. `uninstall` reads that manifest back and removes only:
package/cli.js CHANGED
@@ -754,6 +754,10 @@ async function installStack(stackKey, stackCfg, options = {}) {
754
754
  }
755
755
 
756
756
  // --- 2. Spread stack scaffold files into the project root ---
757
+ // Skipped entirely by `re-init` (options.skipRootScaffold) — that command only
758
+ // refreshes an already-scaffolded project's kit dir + skills, and must never
759
+ // re-touch root/ files the user has since built on top of, nor the root
760
+ // CLAUDE.md router below.
757
761
  const rootSrc = join(templatesSource, 'root');
758
762
  // root/CLAUDE.md is never copied to the project root directly (see step 3 below) —
759
763
  // built-in stacks no longer ship one at all, and an outdated community/--git stack
@@ -761,7 +765,7 @@ async function installStack(stackKey, stackCfg, options = {}) {
761
765
  // copy must never let it slip through to root and clobber the shared router there.
762
766
  const stackRootClaudeSrc = join(rootSrc, 'CLAUDE.md');
763
767
  const stackShipsOwnRootClaude = existsSync(stackRootClaudeSrc);
764
- if (existsSync(rootSrc)) {
768
+ if (!options.skipRootScaffold && existsSync(rootSrc)) {
765
769
  console.log('📦 Installing project files...');
766
770
  // .gitignore is the one file every stack's root/ ships that can collide with
767
771
  // another already-installed kit's own .gitignore (e.g. modeling-kit + a build-kit
@@ -796,7 +800,7 @@ async function installStack(stackKey, stackCfg, options = {}) {
796
800
  // instead of silently guessing either way.
797
801
  const rootClaudeDest = join(targetDir, 'CLAUDE.md');
798
802
  const sharedRootClaude = join(__dirname, 'shared', 'root-claude', 'CLAUDE.md');
799
- const routerContent = existsSync(sharedRootClaude) ? readFileSync(sharedRootClaude, 'utf-8') : null;
803
+ const routerContent = options.skipRootScaffold ? null : (existsSync(sharedRootClaude) ? readFileSync(sharedRootClaude, 'utf-8') : null);
800
804
  if (routerContent !== null) {
801
805
  if (!existsSync(rootClaudeDest)) {
802
806
  writeFileSync(rootClaudeDest, routerContent);
@@ -1620,6 +1624,49 @@ credentialFlags(program
1620
1624
  });
1621
1625
  });
1622
1626
 
1627
+ // Every kit config `re-init` can refresh, keyed the same way install-manifest.json's
1628
+ // `stack` field is — looked up after reading that manifest so re-init knows exactly
1629
+ // which templates to re-copy without the user having to pass --stack again.
1630
+ const REINITIABLE_STACKS = { ...STACKS, [MODELING_KIT.key]: MODELING_KIT, [BLANK_BUILD_KIT.key]: BLANK_BUILD_KIT };
1631
+
1632
+ credentialFlags(program
1633
+ .command('re-init')
1634
+ .description('Refresh an already-installed kit from the current CLI version — re-copies skills and the kit dir (.build-kit or .agent-modeling-kit) so you pick up script/skill updates after upgrading. Unlike `init`, never touches the project root scaffold or the root CLAUDE.md router, and leaves existing credentials alone unless --force is passed.')
1635
+ .option('--modeling', 'Refresh the modeling kit (.agent-modeling-kit) instead of a build kit')
1636
+ .option('--global', 'Re-install skills into ~/.claude/skills/ instead of the project — defaults to however they were originally installed')
1637
+ .option('-f, --force', 'Re-prompt for credentials even if a config already has everything required — overwrites the existing config.json'))
1638
+ .action(async (opts, command) => {
1639
+ const globalOpts = command.optsWithGlobals();
1640
+ const targetDir = process.cwd();
1641
+
1642
+ const kitDirName = opts.modeling ? MODELING_KIT.kitDirName : STACKS.node.kitDirName;
1643
+ const kitDir = join(targetDir, kitDirName);
1644
+
1645
+ if (!existsSync(kitDir)) {
1646
+ console.error(`❌ No ${kitDirName}/ found in ${targetDir} — run \`init${opts.modeling ? ' --modeling' : ''}\` first.`);
1647
+ process.exit(1);
1648
+ }
1649
+
1650
+ const manifest = readJsonSafe(join(kitDir, '.eventmodelers', 'install-manifest.json'));
1651
+ const stackKey = opts.modeling ? MODELING_KIT.key : manifest.stack;
1652
+ const stackCfg = stackKey ? REINITIABLE_STACKS[stackKey] : null;
1653
+
1654
+ if (!stackCfg) {
1655
+ console.error(`❌ Can't tell which stack ${relative(targetDir, kitDir)} was installed from (${manifest.stack ? `"${manifest.stack}" isn't one re-init recognizes — likely a --git community stack` : 'its install manifest predates this tracking, or is missing'}).`);
1656
+ console.error(' Re-run the original `init --git <url> --stack <name>` command by hand instead.');
1657
+ process.exit(1);
1658
+ }
1659
+
1660
+ await installStack(stackKey, stackCfg, {
1661
+ configPath: globalOpts.config,
1662
+ print: globalOpts.print,
1663
+ global: opts.global !== undefined ? opts.global : !!manifest.global,
1664
+ force: opts.force,
1665
+ credentialOverrides: credentialOverridesFromOpts(opts),
1666
+ skipRootScaffold: true,
1667
+ });
1668
+ });
1669
+
1623
1670
  program
1624
1671
  .command('init-mcp')
1625
1672
  .description('Register the eventmodelers MCP server in .claude/settings.json (and optionally another harness)')
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.4",
3
+ "version": "1.0.6",
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": {
@@ -66,6 +66,17 @@ Guidelines:
66
66
  - Don't add `<html>`/`<head>`/`<body>` tags to a page — every page is a body-only fragment. The canvas wraps each page in its own `<html><head>` (stylesheet + resize script) `<body>...</body></html>` at render time, so anything sent is placed inside that generated `<body>`.
67
67
  - Bulma CSS (0.9.4) is loaded by default in that `<head>` — classes like `title`, `button`, `is-primary`, `field`/`control`/`input` etc. all work out of the box, no need to write custom CSS for standard form/layout components. Note headings need a size modifier too, e.g. `class="title is-1"` — a bare `title` class alone is always 2rem regardless of the tag (`h1` vs `h2` etc.).
68
68
 
69
+ ### Marks — only when the user explicitly asks for one
70
+
71
+ The canvas has a native "Marks" feature (outline highlight, optional blur-outside spotlight) for calling out part of a screen. **Do not add marks by default.** Only apply one of the two effects below when the request explicitly asks to highlight/mark/call out/circle/spotlight or blur/obscure part of the screen (e.g. "highlight the submit button", "blur everything except the email field"). An ordinary "design a screen" request gets no marks.
72
+
73
+ Since this skill only has a `pages`/`backgroundColor` field to send (no separate marks API), reproduce the same visual language directly as inline CSS on the target element(s) — self-contained in the page HTML, same as any other styling in Step 3:
74
+
75
+ - **Mark / highlight an area** — add to the target element's `style`: `outline:4px solid <color> !important;outline-offset:1px;`. Default color `#e74c3c` (red) unless the user names one; other options mirror the app's mark picker: `#1e293b` (dark slate), `#2ecc71` (green), `#3b82f6` (blue), `#f1c40f` (yellow), `#ffffff` (white).
76
+ - **Blur outside / spotlight an area** — add `style="filter:blur(6px) !important;"` to every other top-level sibling/section on the page so only the called-out element stays sharp. Combine with the outline above if the user asked to both mark and blur.
77
+
78
+ Apply these only to the specific element(s) the request describes — don't guess at additional areas to call out.
79
+
69
80
  ## Step 4 — Render the pages
70
81
 
71
82
  **Updating an existing node** (`nodeId` was given) — always sends the **complete** pages array, not just the changed/new entry: