@eventmodelers/cli 1.0.120 → 1.0.121

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/cli.js CHANGED
@@ -2106,7 +2106,7 @@ async function runModeling(kitDir, projectDir, { codeDir = null, verbose = false
2106
2106
  const claudeArgs = ['--dangerously-skip-permissions', '-p', '--input-format', 'stream-json', '--output-format', 'stream-json', '--verbose'];
2107
2107
  if (cfg.model) claudeArgs.push('--model', cfg.model);
2108
2108
  // The global install runs in ~/.eventmodelers/kit, away from the code base the person started
2109
- // the agent in — hand that directory over so code-reading skills (detect-architecture-drift)
2109
+ // the agent in — hand that directory over so code-reading skills (detect-model-drift)
2110
2110
  // can still see it.
2111
2111
  if (codeDir) claudeArgs.push('--add-dir', codeDir);
2112
2112
  const claudeEnv = {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.120",
3
+ "version": "1.0.121",
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": {
@@ -689,6 +689,17 @@ async function runWithRetry(label, fn) {
689
689
  }
690
690
  }
691
691
 
692
+ // prompt.md and backend-prompt.md are instruction manuals with no request in them. Handed one
693
+ // alone, the agent read it as background, answered "what would you like me to help with?" with
694
+ // no tool calls, and a Planned slice stayed Planned until the stuck-slice guard blocked it. So
695
+ // every turn ends with the concrete request — here, once, for every runner.
696
+ function taskRequest(planned = null) {
697
+ const task = planned
698
+ ? `build the Planned slice "${planned.title}" (id=${planned.id}, context="${planned.ctx}")`
699
+ : 'process the pending tasks in tasks.json';
700
+ return `\n\n---\n\nYour task now: ${task}, following the instructions above. Start immediately.\n`;
701
+ }
702
+
692
703
  async function ralphLoop(kitDir, cfg, onTask, onPlannedSlice, localOnly = false) {
693
704
  const promptFile = join(kitDir, 'lib', 'prompt.md');
694
705
  const backendPromptFile = join(kitDir, 'lib', 'backend-prompt.md');
@@ -707,7 +718,7 @@ async function ralphLoop(kitDir, cfg, onTask, onPlannedSlice, localOnly = false)
707
718
  let didWork = false;
708
719
 
709
720
  if (credentialed && hasPendingTasks(kitDir)) {
710
- const prompt = readFileSync(promptFile, 'utf-8');
721
+ const prompt = readFileSync(promptFile, 'utf-8') + taskRequest();
711
722
  for (const t of readTasks(join(kitDir, 'tasks.json'))) await fetchFullSlice(cfg, kitDir, t.payload?.sliceId);
712
723
  await runWithRetry('onTask: loading slice from board...', () => inTurn(kitDir, () => onTask(prompt)));
713
724
  await fetchAndPersistSlices(cfg, kitDir).catch(() => {});
@@ -727,7 +738,7 @@ async function ralphLoop(kitDir, cfg, onTask, onPlannedSlice, localOnly = false)
727
738
  continue;
728
739
  }
729
740
 
730
- const prompt = readFileSync(backendPromptFile, 'utf-8');
741
+ const prompt = readFileSync(backendPromptFile, 'utf-8') + taskRequest(planned);
731
742
  if (credentialed) await fetchFullSlice(cfg, kitDir, planned.id);
732
743
  lastReply = null;
733
744
  const built = await runWithRetry(`onPlannedSlice: building slice "${planned.title}"...`, async () => { lastReply = await onPlannedSlice(prompt, {
@@ -80,15 +80,11 @@ function describeToolUse(block) {
80
80
  // `slice` is set for a planned-slice build (see startRalph) — the only turns that are traced.
81
81
  function runClaude(prompt, slice = null) {
82
82
  return new Promise((resolve, reject) => {
83
- // The prompt goes in on stdin, never as a `-p` argument: on Windows a multi-line argv entry
84
- // is cut at its first newline, so `claude` saw only the connect header, answered "I don't see
85
- // a request" and the slice stayed Planned until the stuck-slice guard blocked it.
86
- const proc = spawn('claude', [...claudeArgs, '-p'], {
83
+ const proc = spawn('claude', [...claudeArgs, '-p', inlineHeader + prompt], {
87
84
  cwd: projectDir,
88
- stdio: ['pipe', 'pipe', 'inherit'],
85
+ stdio: ['inherit', 'pipe', 'inherit'],
89
86
  env: claudeEnv,
90
87
  });
91
- proc.stdin.end(inlineHeader + prompt);
92
88
  const turn = superviseTurn(proc, { timeoutMs, label: 'Claude turn', log: (line) => console.error(`[ralph] ${line}`) });
93
89
 
94
90
  let buffer = '';
@@ -26,13 +26,11 @@ const claudeEnv = cfg.anthropicBaseUrl
26
26
 
27
27
  function runClaude(prompt) {
28
28
  return new Promise((resolve, reject) => {
29
- // Prompt on stdin, not as a `-p` argument — Windows cuts a multi-line argv entry at its first newline.
30
- const proc = spawn('claude', [...claudeArgs, '-p'], {
29
+ const proc = spawn('claude', [...claudeArgs, '-p', inlineHeader + prompt], {
31
30
  cwd: projectDir,
32
- stdio: ['pipe', 'inherit', 'inherit'],
31
+ stdio: 'inherit',
33
32
  env: claudeEnv,
34
33
  });
35
- proc.stdin.end(inlineHeader + prompt);
36
34
  proc.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`Claude exited ${code}`))));
37
35
  proc.on('error', reject);
38
36
  });
@@ -1,9 +1,9 @@
1
1
  ---
2
- name: detect-architecture-drift
2
+ name: detect-model-drift
3
3
  description: Compare the event model on the board with the code in this repository and report where they have drifted apart — fields on commands/events/read models, specifications vs tests, screens, edges, slices missing in code, and slices in code that the model doesn't have. Read-only; every finding comes with a suggested fix the user confirms first.
4
4
  ---
5
5
 
6
- # Detect Architecture Drift
6
+ # Detect Model Drift
7
7
 
8
8
  ## Step 0 — Is there a code base?
9
9
 
@@ -11,7 +11,7 @@ Drift is the gap between the board and the code, so it can only be detected wher
11
11
 
12
12
  If it is not (an empty folder, a modeling-only workspace holding just `.claude/`, `.eventmodelers/` or `.agent-modeling-kit/`), **stop and answer in one or two plain sentences**, e.g.:
13
13
 
14
- > Architecture drift can't be detected here — there is no code to compare the board against. Run this in the code base that implements the model.
14
+ > Model drift can't be detected here — there is no code to compare the board against. Run this in the code base that implements the model.
15
15
 
16
16
  Do not connect, do not read the board, do not produce a report or snippet, and do not offer other fixes.
17
17
 
@@ -150,7 +150,7 @@ Print the report below, with every finding as a `- [ ]` checkbox carrying its pr
150
150
  Name each slice and element as `[<title>](ref:<nodeId>)` (the slice border's id for a slice). The terminal shows the title, and once the report is in a board note or an element description, a click zooms the canvas to it (see `/learn-eventmodelers-api` *Linking to elements in markdown*). A slice that exists only in code has no node, so it stays plain text.
151
151
 
152
152
  ```
153
- ## Architecture Drift — <scope: board | timeline "<title>" | context "<name>">
153
+ ## Model Drift — <scope: board | timeline "<title>" | context "<name>">
154
154
  Compared: <n> slices on the board, <n> slice folders in code Analysed: <ISO timestamp>
155
155
 
156
156
  ### Slices
@@ -203,7 +203,7 @@ for it. Instead:
203
203
  and posts nothing to the board until they answer (`/wdyt` Step 4.0). Your reply here is one line —
204
204
  *"On it — looking at Registration."*
205
205
  - **a skill by name** — the message starts with `/<name>` of one of your skills (the chat panel's menu
206
- writes these: `/analyze-existing-model`, `/analyze-code-base`, `/detect-architecture-drift`, `/add-next-slice`, `/examples`, `/timeline …`,
206
+ writes these: `/analyze-existing-model`, `/analyze-code-base`, `/detect-model-drift`, `/add-next-slice`, `/examples`, `/timeline …`,
207
207
  `/html-screen …`, `/storyboard …`): the person chose that skill, so it **is** the work — create one prompt,
208
208
  *"Run /<name> <the rest of the message>"*, with the target resolved from `context=` like any other
209
209
  (selected elements, chapter), and say so in one line. Don't re-interpret it as a question. A skill that
@@ -357,7 +357,7 @@ nothing to sanitize either, since a board change is not user text.
357
357
  | Business analysis, gap spotting, posting questions | `/wdyt` |
358
358
  | Analyse the existing model structure, slice coverage, element counts | `/analyze-existing-model` |
359
359
  | Reverse-engineer the business process of an existing code base into the model, as an interview — all chapters first, then one chapter at a time | `/analyze-code-base` |
360
- | Find where the model and the code have drifted apart (fields, specs, screens, edges, missing/extra slices) and propose fixes | `/detect-architecture-drift` |
360
+ | Find where the model and the code have drifted apart (fields, specs, screens, edges, missing/extra slices) and propose fixes | `/detect-model-drift` |
361
361
  | Turn a document or image (e.g. a tender/RFP) into a chaptered event model with screens, scenarios and a written blueprint summary | `/summarize` |
362
362
  | Look up any API endpoint or element type not already covered by the skill you're executing | `/learn-eventmodelers-api` |
363
363
  | Add or rename an attribute across a chain of elements | `/attributes` |