@eventmodelers/cli 1.0.121 → 1.0.123
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.123",
|
|
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": {
|
|
@@ -80,11 +80,15 @@ 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
|
-
|
|
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'], {
|
|
84
87
|
cwd: projectDir,
|
|
85
|
-
stdio: ['
|
|
88
|
+
stdio: ['pipe', 'pipe', 'inherit'],
|
|
86
89
|
env: claudeEnv,
|
|
87
90
|
});
|
|
91
|
+
proc.stdin.end(inlineHeader + prompt);
|
|
88
92
|
const turn = superviseTurn(proc, { timeoutMs, label: 'Claude turn', log: (line) => console.error(`[ralph] ${line}`) });
|
|
89
93
|
|
|
90
94
|
let buffer = '';
|
|
@@ -65,6 +65,13 @@ get_planned_slice_title() {
|
|
|
65
65
|
done
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
+
# prompt.md and backend-prompt.md are instruction manuals with no request in them — handed one
|
|
69
|
+
# alone, the agent may read it as background and ask what to do. Every turn ends with the concrete
|
|
70
|
+
# request, the same one lib/ralph.js's taskRequest() appends.
|
|
71
|
+
task_request() {
|
|
72
|
+
printf '\n\n---\n\nYour task now: %s, following the instructions above. Start immediately.\n' "$1"
|
|
73
|
+
}
|
|
74
|
+
|
|
68
75
|
# Runs agent.sh with the given prompt; retries on non-zero exit
|
|
69
76
|
run_agent() {
|
|
70
77
|
local label="$1"
|
|
@@ -82,13 +89,13 @@ while [[ "$ITERATIONS" -eq 0 || "$cycle" -lt "$ITERATIONS" ]]; do
|
|
|
82
89
|
ran_something=false
|
|
83
90
|
|
|
84
91
|
if [[ "$HAS_CREDENTIALS" == true ]] && has_pending_tasks; then
|
|
85
|
-
run_agent "onTask: loading slice from board..." "$(cat "$PROMPT_FILE")"
|
|
92
|
+
run_agent "onTask: loading slice from board..." "$(cat "$PROMPT_FILE"; task_request 'process the pending tasks in tasks.json')"
|
|
86
93
|
ran_something=true
|
|
87
94
|
fi
|
|
88
95
|
|
|
89
96
|
if has_planned_slices; then
|
|
90
97
|
slice_title=$(get_planned_slice_title)
|
|
91
|
-
run_agent "onPlannedSlice: building \"$slice_title\"..." "$(cat "$BACKEND_PROMPT_FILE")"
|
|
98
|
+
run_agent "onPlannedSlice: building \"$slice_title\"..." "$(cat "$BACKEND_PROMPT_FILE"; task_request "build the Planned slice \"$slice_title\"")"
|
|
92
99
|
echo "[$(date -u +%H:%M:%S)] Slice \"$slice_title\" build complete — waiting for next slice"
|
|
93
100
|
ran_something=true
|
|
94
101
|
fi
|
|
@@ -26,11 +26,13 @@ const claudeEnv = cfg.anthropicBaseUrl
|
|
|
26
26
|
|
|
27
27
|
function runClaude(prompt) {
|
|
28
28
|
return new Promise((resolve, reject) => {
|
|
29
|
-
|
|
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'], {
|
|
30
31
|
cwd: projectDir,
|
|
31
|
-
stdio: 'inherit',
|
|
32
|
+
stdio: ['pipe', 'inherit', 'inherit'],
|
|
32
33
|
env: claudeEnv,
|
|
33
34
|
});
|
|
35
|
+
proc.stdin.end(inlineHeader + prompt);
|
|
34
36
|
proc.on('close', (code) => (code === 0 ? resolve() : reject(new Error(`Claude exited ${code}`))));
|
|
35
37
|
proc.on('error', reject);
|
|
36
38
|
});
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: detect-model-drift
|
|
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.
|
|
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. `--branch <name>` compares against that branch's code (default: the current branch's working tree). Read-only; every finding comes with a suggested fix the user confirms first.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
6
|
# Detect Model Drift
|
|
@@ -15,6 +15,8 @@ If it is not (an empty folder, a modeling-only workspace holding just `.claude/`
|
|
|
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
|
|
|
18
|
+
**With `--branch <name>`** (see Step 1), also check that the branch exists in that code base: `git rev-parse --verify <name>`, else `git fetch origin <name>` and `git rev-parse --verify origin/<name>`. Use whichever resolves as `REF`. If neither does, stop the same way in one sentence (*"There is no branch `<name>` in this repository."*).
|
|
19
|
+
|
|
18
20
|
---
|
|
19
21
|
|
|
20
22
|
> **Once Step 0 passes**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until the connect skill has completed.
|
|
@@ -34,6 +36,7 @@ From `$ARGUMENTS` and the prompt context, extract:
|
|
|
34
36
|
| `timelineId` | `context.timelineId` of the prompt (overrules the prompt's own `timeline_id`), or a timeline/chapter named in the text | whole board |
|
|
35
37
|
| `contextName` | a bounded context named in the text | all contexts |
|
|
36
38
|
| `sliceTitle` | a single slice named in the text | all slices in scope |
|
|
39
|
+
| `branch` | `--branch <name>` in `$ARGUMENTS`, or a branch named in the text | the current branch's working tree |
|
|
37
40
|
|
|
38
41
|
**If a timeline is in focus, only that timeline's slices are compared** — both on the board side and, through the slice → code mapping of Step 3, on the code side. Code that belongs to no slice in scope is not reported as "additional" in a scoped run; say so in the report footer instead of guessing.
|
|
39
42
|
|
|
@@ -52,6 +55,8 @@ Use the **full** slice data (no `projection`): you need fields with types and `i
|
|
|
52
55
|
|
|
53
56
|
Call `validate_model { boardId, chapterId }` for a scoped timeline — it already lists structural gaps on the board side (zero/multi-issuer commands, sourceless read models, missing scenarios). Those are model problems, not drift: mention them in one line, don't duplicate them as findings.
|
|
54
57
|
|
|
58
|
+
**Always read each chapter's context note before comparing.** The MARKDOWN note in the `feedback` lane of a chapter's **first column** holds the context for that chapter — architecture decisions, intended deviations, what the code is supposed to look like. For every chapter in scope, call `get_board_outline { boardId, chapterId }`, take the first column's node with `type: "MARKDOWN"` in a `feedback` lane, and read its `meta.description` with `get_node`. Judge every finding against it: a difference the note explains is intentional, not drift. A chapter without such a note is fine — carry on without it.
|
|
59
|
+
|
|
55
60
|
Index the result in memory: per slice → commands, events, read models, screens, automations, specifications, dependencies.
|
|
56
61
|
|
|
57
62
|
---
|
|
@@ -60,6 +65,8 @@ Index the result in memory: per slice → commands, events, read models, screens
|
|
|
60
65
|
|
|
61
66
|
The code base is the directory resolved in Step 0 (`$EVENTMODELERS_CODE_DIR`, else the current directory) — every path below is relative to it, and it may hold any stack. Find out which, don't assume.
|
|
62
67
|
|
|
68
|
+
**With a `branch` other than the one checked out, read the code from git, never from the working tree:** `git ls-tree -r --name-only $REF [<dir>]` lists the files, `git show $REF:<path>` reads one. That applies to everything below — `.build-kit/CLAUDE.md`, the `.build-kit/.slices` snapshot, the slice folders. Never `git checkout`/`git switch`: the working tree may hold someone's uncommitted work. Without `branch`, or when it is the current branch, read the working tree as usual.
|
|
69
|
+
|
|
63
70
|
1. Read `.build-kit/CLAUDE.md` (and `.build-kit/AGENTS.md` if present) — its *Structure* section says where slices live and how they're named (e.g. `src/slices/{slice}/` for Node, `src/main/java/.../slices/{context}/{slice}/` for Axon).
|
|
64
71
|
2. If `.build-kit/.slices/<context>/<slice>/slice.json` exists, it is the snapshot the code was **last built from** — useful for telling "the code changed" apart from "the model changed since the build" (see Step 5).
|
|
65
72
|
3. Without a build kit, infer the layout from the repo (folders named after slices, `*Command*`, `*Event*`, projection/read-model files, route/UI files). If you cannot find any slice structure, stop and tell the user what you looked at — do not fabricate a mapping.
|
|
@@ -91,7 +98,7 @@ Rules for judging, in order:
|
|
|
91
98
|
- **Obvious typos and clearly wrong flags are one finding with a direct fix** (`custoemrId` in the code vs `customerId` on the board; `idAttribute: false` on the entity's own id) — name the correct side, don't ask which it is.
|
|
92
99
|
- **Direction matters.** A mismatch with no earlier evidence has no "right" side: propose the fix in the direction the evidence points (see Step 5), and say when it is a judgement call.
|
|
93
100
|
- Don't report framework noise: generated ids, metadata/envelope fields, serialization annotations, test fixtures' helper types, routes when the slice has no screen.
|
|
94
|
-
- Don't flag what is clearly intentional (an internal slice with no screen; a read model used only by another read model).
|
|
101
|
+
- Don't flag what is clearly intentional (an internal slice with no screen; a read model used only by another read model), or what the chapter's first-column feedback note (Step 2) describes as intended.
|
|
95
102
|
- Report each underlying difference **once**, at the element where it starts; a renamed field shows up on the command and the event and the read model — that is one finding listing the chain, not three.
|
|
96
103
|
|
|
97
104
|
---
|
|
@@ -102,12 +109,14 @@ For every finding, pick who should move:
|
|
|
102
109
|
|
|
103
110
|
| Evidence | Fix goes to | How it's done |
|
|
104
111
|
|----------|-------------|---------------|
|
|
105
|
-
| Code differs from `.build-kit/.slices` snapshot, board still equals the snapshot | **Model** — the code moved on deliberately | Skill that changes the board: `/attributes` (fields), `/timeline` / `/place-element` (elements), `/eventmodeling-elaborating-scenarios` (specs), `/storyboard-screen` or `/html-screen` (screens) |
|
|
112
|
+
| Code differs from `.build-kit/.slices` snapshot (read from the same branch as the code), board still equals the snapshot | **Model** — the code moved on deliberately | Skill that changes the board: `/attributes` (fields), `/timeline` / `/place-element` (elements), `/eventmodeling-elaborating-scenarios` (specs), `/storyboard-screen` or `/html-screen` (screens — including updating every existing screen connected to a changed element, see below) |
|
|
106
113
|
| Board differs from the snapshot, code still equals it | **Code** — the model moved on | Set the slice back to `Planned` with `/update-slice-status` so the build kit picks it up again and diffs code against `slice.json` |
|
|
107
114
|
| Both moved, or no snapshot | **Judgement call** — present both options, recommend one | Recommend by which side is more specific/complete |
|
|
108
115
|
| Slice only in code | **Model** | Add the slice, via `/eventmodeling-slicing-event-models` after placing its elements |
|
|
109
116
|
| Slice missing in code, board says `Done` | **Model status** (it isn't done) | `/update-slice-status` → `Planned` |
|
|
110
117
|
|
|
118
|
+
**A model fix always includes the existing screens.** When a field, command or read model changes on the board, every SCREEN/HTML_SCREEN that shows or submits it must change with it — otherwise the drift just moves from the code into the storyboard. List each affected screen in the same finding (follow the read model → screen and screen → command edges), and update it in place: `/html-screen` with its `nodeId` (loads the current pages and edits them, plus its `meta.fields`), `/storyboard-screen` for a wireframe sketch. Never create a new screen next to an outdated one.
|
|
119
|
+
|
|
111
120
|
Never propose "fix the code" by editing it from this skill — code changes belong to the build kit (`/update-slice-status` → `Planned`).
|
|
112
121
|
|
|
113
122
|
---
|
|
@@ -151,7 +160,7 @@ Name each slice and element as `[<title>](ref:<nodeId>)` (the slice border's id
|
|
|
151
160
|
|
|
152
161
|
```
|
|
153
162
|
## Model Drift — <scope: board | timeline "<title>" | context "<name>">
|
|
154
|
-
Compared: <n> slices on the board, <n> slice folders in code Analysed: <ISO timestamp>
|
|
163
|
+
Compared: <n> slices on the board, <n> slice folders in code<, branch <name> @ <short sha>> Analysed: <ISO timestamp>
|
|
155
164
|
|
|
156
165
|
### Slices
|
|
157
166
|
- [ ] <slice> — in code, not on the board → add it to the model
|
|
@@ -178,3 +187,6 @@ Omit empty sections. Say plainly when nothing drifted.
|
|
|
178
187
|
- Read-only until confirmed — the report is the product; the fixes run as separate, ticked work.
|
|
179
188
|
- A scoped run (timeline in focus) never reports "slice only in code" for code outside the scope.
|
|
180
189
|
- One difference, one finding: follow a rename along the chain instead of listing it per element.
|
|
190
|
+
- Fixing drift on the model side means updating the existing screens connected to the changed elements too (pages and `meta.fields`), in place — not just the command/event/read model.
|
|
191
|
+
- `--branch` reads the code via `git ls-tree`/`git show` from that ref — never check it out, the working tree may hold someone's uncommitted work. No `--branch` = the working tree, as before.
|
|
192
|
+
- Always read the MARKDOWN note in the feedback lane of each chapter's first column first — it is the chapter's context, and differences it explains are not drift.
|