@eventmodelers/cli 1.0.44 → 1.0.45

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.44",
3
+ "version": "1.0.45",
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": {
@@ -41,7 +41,7 @@ automation slice = EVENT(s) → AUTOMATION → COMMAND → EVENT(s)
41
41
 
42
42
  A slice never mixes a COMMAND and a READMODEL — those are two different slice types (`state-change` and `state-view`), even when they belong to the same feature. Slices are independently deployable and only communicate with each other via events.
43
43
 
44
- Slices are not placed directly — they're **derived** from a completed model. Every COMMAND on the board implies a `state-change` slice, every READMODEL implies a `state-view` slice, every AUTOMATION implies an `automation` slice. `eventmodeling-slicing-event-models` makes that implicit structure explicit on the board once modeling is done; it never invents a slice that isn't already implied by an element that's there.
44
+ Slices are not placed directly — they're **derived** from a completed model. Every COMMAND on the board implies a `state-change` slice, every READMODEL implies a `state-view` slice, every AUTOMATION implies an `automation` slice — **except** a `linkedTo` copy (see Linked Copies below), which implies no slice of its own: it's the same underlying COMMAND/EVENT/READMODEL reused elsewhere on the board, not a second independently-deployable thing, so only the origin node's column gets a `SLICE_BORDER`. `eventmodeling-slicing-event-models` makes that implicit structure explicit on the board once modeling is done; it never invents a slice that isn't already implied by an element that's there, and skips columns whose only COMMAND/READMODEL is a linked copy.
45
45
 
46
46
  ## Elements
47
47
 
@@ -116,7 +116,7 @@ When an element's natural column is already occupied by something else, insert a
116
116
 
117
117
  A later EVENT sometimes needs to change data an earlier READMODEL already shows on a SCREEN — e.g. a cancellation affecting an "active items" view placed several columns earlier. Wiring that later EVENT straight back into the existing READMODEL is never the fix: it's a backward connection, and the platform only accepts a backward `EVENT → READMODEL` edge when the READMODEL already has a `READMODEL → AUTOMATION` edge (the todo-list pattern — see Translation Chain below). A READMODEL that only feeds a SCREEN never qualifies for that exemption.
118
118
 
119
- Instead, place a **new READMODEL node** in a new column **immediately after** the later event's column, connect that event forward into it, and give it a matching SCREEN in that same new column — same screen name/title as the earlier one, showing the updated data, optionally re-marked/highlighted via `html-screen`'s Marks feature to call out what changed. Leave the earlier READMODEL/SCREEN instance exactly as it is it's still what that earlier point in the timeline correctly showed. Never delete it, and never wire the new instance back to it: this isn't the `linkedTo` copy mechanism below (that's for reusing one fact across timelines) — it's a genuinely new node representing a genuinely later state.
119
+ Instead, place a **new READMODEL node** in a new column **immediately after** the later event's column, then link it to the earlier READMODEL instance via the `linkedTo` copy mechanism below (`link_element`) — it *is* the same read model, carried forward to a later state, not an unrelated new one, so it uses the same copy mechanism as any other reused fact. Connect the later event forward into the linked copy, then update whichever field(s) that event actually changes (e.g. `status`) on the copy — the fields it inherited from the link that the new event doesn't touch stay as copied. Give it a matching SCREEN in that same new column — same screen name/title as the earlier one, showing the updated data, optionally re-marked/highlighted via `html-screen`'s Marks feature to call out what changed. A SCREEN can never itself be a `linkedTo` copy (the mechanism only supports COMMAND/EVENT/READMODEL), so the new SCREEN is placed as a plain node matching the earlier one's title, not linked. Leave the earlier READMODEL/SCREEN instance exactly as it is — it's still what that earlier point in the timeline correctly showed. Never delete it.
120
120
 
121
121
  See `eventmodeling-identifying-outputs` Step 5g for the full placement/wiring mechanics, and `place-element` Step 6 for the column-insertion mechanics.
122
122
 
@@ -126,6 +126,8 @@ A **linked copy** is a COMMAND/EVENT/READMODEL node that mirrors another node el
126
126
 
127
127
  To make one: place a normal new node of the same type (COMMAND/EVENT/READMODEL only) at the target spot, then link it to the origin (`link_element`, or the REST `.../nodes/:nodeId/link` fallback). This replaces the new node's `meta` with a full copy of the origin's and sets `meta.linkedTo` to the origin's node id — the authoritative pointer (a `data.linkedTo` also exists but is a rendering mirror only, not the source of truth). Wire the resulting copy to its own neighbors normally afterward.
128
128
 
129
+ A linked copy is allowed to diverge from its origin afterward in the specific field(s) a newly-connected event actually drives — e.g. the "Updating a Read Model That Already Feeds a Screen" copy above, where `status` is updated post-link to the event's new value. The link establishes "this is the same underlying fact, not a duplicate" at creation time; it doesn't freeze the copy's fields identical to the origin's forever.
130
+
129
131
  Never delete the original (the node with no `linkedTo`) once copies of it exist — copies reference it, and removing it breaks every copy. `eventmodeling-checking-completeness` already treats any `linkedTo`-marked node as an intentional copy, never a duplicate or missing-slice gap to flag.
130
132
 
131
133
  See `place-element` Step 6a for the mechanical linking steps.
@@ -314,7 +314,7 @@ For each view screen S that queries this read model as its primary read model:
314
314
 
315
315
  **View screens normally share the column of the (primary) read model they display** — either because they were placed there in Step 3, or because the read model was placed into the screen's own column just now (per the check above). A screen's own position is never moved to resolve a read model placement conflict — when the shared column isn't available, the **read model** gets a new column immediately before the screen's, not the other way around (this preserves the screen's narrative order from Step 3).
316
316
 
317
- **The same rule applies to `EVENT → READMODEL`** (shared statement: `eventmodeling-core-rules`'s "Updating a Read Model That Already Feeds a Screen"). If a later event needs to update data a read model already feeds to a SCREEN, do not connect that later event back into the existing read model — the platform only accepts an `EVENT → READMODEL` backward connection when the read model already has a `READMODEL → AUTOMATION` edge (the todo-list pattern from Step 4b, `eventmodeling-designing-automation-chains`). For any read model feeding a SCREEN, resolve the update the same way Step 5c resolves multi-component screens: place a **new copy of the read model** in a new column immediately after the later event's column, connect the later event forward into that copy, and place a matching copy of the same screen there — same title, updated data, optionally re-marked/highlighted via `html-screen`'s Marks feature. Never link the new copy back to the earlier read model instance.
317
+ **The same rule applies to `EVENT → READMODEL`** (shared statement: `eventmodeling-core-rules`'s "Updating a Read Model That Already Feeds a Screen"). If a later event needs to update data a read model already feeds to a SCREEN, do not connect that later event back into the existing read model — the platform only accepts an `EVENT → READMODEL` backward connection when the read model already has a `READMODEL → AUTOMATION` edge (the todo-list pattern from Step 4b, `eventmodeling-designing-automation-chains`). For any read model feeding a SCREEN, resolve the update the same way Step 5c resolves multi-component screens: place a **new READMODEL node** in a new column immediately after the later event's column, then link it to the earlier read model instance (`link_element` — it's the same read model carried forward, not an unrelated new one; see `eventmodeling-core-rules`'s Linked Copies section). Connect the later event forward into the linked copy, then update the field(s) that event actually changes. Place a matching SCREEN in that same new column — same title, updated data, optionally re-marked/highlighted via `html-screen`'s Marks feature; a SCREEN can't be a `linkedTo` copy itself (COMMAND/EVENT/READMODEL only), so place it as a plain node matching the earlier screen's title.
318
318
 
319
319
  ### Step 5h — Wire connections after placing each READMODEL (and its SCREEN)
320
320
 
@@ -122,7 +122,7 @@ The timeline must always progress left-to-right — this is the goal to design t
122
122
 
123
123
  **`EVENT → READMODEL` has exactly one exception, and it is narrow.** A read model that already carries a `READMODEL → AUTOMATION` edge — i.e. a todo-list read model feeding an automation, per `eventmodeling-designing-automation-chains` (Step 4b) — may also be fed by a later-column event closing an item it opened earlier. That accumulator shape is what the todo-list pattern exists for, and it is confirmed against the platform API (`learn-eventmodelers-api` §3 — `POST .../connections`). **Outside that one case, the platform rejects the connection, for good reason:** without it, a read model would become a moving target for whatever screen or scenario later reaches back into it.
124
124
 
125
- For every other read model — in particular one feeding a SCREEN rather than an AUTOMATION — never connect a later event back into it, no matter how convenient. If a later event needs to update what a screen already shows, resolve it the same way Step 5c resolves multi-component screens: place a **new copy of the read model** in a new column immediately after the later event's column, connect the later event forward into that copy, and place a matching copy of the same screen there (same title, updated data, optionally re-marked/highlighted per `html-screen`'s Marks feature). Never link the new copy back to the earlier instance.
125
+ For every other read model — in particular one feeding a SCREEN rather than an AUTOMATION — never connect a later event back into it, no matter how convenient. If a later event needs to update what a screen already shows, resolve it the same way Step 5c resolves multi-component screens: place a **new READMODEL node** in a new column immediately after the later event's column, link it to the earlier instance (`link_element` — it's the same read model, not an unrelated new one; see `eventmodeling-core-rules`'s Linked Copies section), connect the later event forward into the linked copy, update the field(s) that event actually changes, and place a matching copy of the same screen there (same title, updated data, optionally re-marked/highlighted per `html-screen`'s Marks feature a SCREEN can't itself be linked, so it's a plain node matching the earlier one's title).
126
126
 
127
127
  A wide fan-in read model (many connected events, one column) is a different problem with a different fix — see "one read model per component" and the >3-events heuristic above. It is never a justification for a backward arrow. The one real signal to treat as a prunable connection regardless of column position is a **connected event that isn't actually used by any field** on the read model.
128
128
 
@@ -39,6 +39,8 @@ Walk the timeline column by column:
39
39
  - Every **READMODEL** → one `state-view` slice, named after the read model
40
40
  - Every **AUTOMATION** → one `automation` slice, named after the automation (or the command it issues)
41
41
 
42
+ **Skip any column whose only COMMAND/READMODEL node has `meta.linkedTo` set** — it's a linked copy of a node elsewhere on the board (see `eventmodeling-core-rules`'s Linked Copies and Slices sections), not a second independently-deployable thing. Only the origin node's own column gets a slice.
43
+
42
44
  ---
43
45
 
44
46
  ## Step 1: Resolve the Timeline
@@ -226,7 +226,7 @@ Use this REST call (see the curl fallback below) when you don't already have fre
226
226
  | Any | Same element type | Stop and tell the user — true conflict, no safe default. |
227
227
  | Any | Different type but not a known pairing | Stop and tell the user. |
228
228
 
229
- **A later EVENT that needs to update a READMODEL already feeding a SCREEN is not a Step 6 occupancy case — it's a backward-connection trap.** Do not `set_connection` that EVENT into the existing READMODEL, even if the existing READMODEL's column is reachable. See `eventmodeling-core-rules`'s "Updating a Read Model That Already Feeds a Screen": place a **new** READMODEL (and a matching SCREEN) in a new column immediately after the event's column instead, and connect the event forward into that new pair.
229
+ **A later EVENT that needs to update a READMODEL already feeding a SCREEN is not a Step 6 occupancy case — it's a backward-connection trap.** Do not `set_connection` that EVENT into the existing READMODEL, even if the existing READMODEL's column is reachable. See `eventmodeling-core-rules`'s "Updating a Read Model That Already Feeds a Screen": place a **new** READMODEL in a new column immediately after the event's column instead, link it to the existing READMODEL as a `linkedTo` copy (Step 6a below — it's the same read model, not an unrelated new one), connect the event forward into the linked copy, and give it a matching SCREEN in the same column (a plain node, not linked — SCREEN isn't a linkable type).
230
230
 
231
231
  **Insert immediately after** means: create the new column right after the current one, not by appending to the end. This keeps the read model visually adjacent to the event that drives it.
232
232
 
@@ -0,0 +1,67 @@
1
+ # Node.js / TypeScript Event-Sourced Service
2
+
3
+ An event-sourced backend scaffolded by [`@eventmodelers/cli`](https://www.npmjs.com/package/@eventmodelers/cli).
4
+ It uses [Emmett](https://event-driven-io.github.io/emmett/) over Postgres for the event store,
5
+ Express for the HTTP layer, and Flyway for schema migrations.
6
+
7
+ Features are built as **vertical slices** under `src/slices/`, generated from the slices on your
8
+ Eventmodelers board by the agent in `.build-kit/`.
9
+
10
+ ## Prerequisites
11
+
12
+ - Node.js 20 or later (the dev/start scripts use `node --env-file`)
13
+ - Docker and Docker Compose (for local Postgres)
14
+ - Flyway CLI on your `PATH` (for `npm run flyway:migrate`)
15
+ - [Claude Code](https://claude.com/claude-code) if you want to run the build agent
16
+
17
+ ## Getting started
18
+
19
+ 1. Start Postgres:
20
+
21
+ ```bash
22
+ docker compose up -d
23
+ ```
24
+
25
+ 2. Create your `.env`:
26
+
27
+ ```bash
28
+ cp .env.example .env
29
+ ```
30
+
31
+ Or run `./setup-env.sh` to be prompted for host, port, database, user and password.
32
+
33
+ 3. Activate the baseline migration and apply it:
34
+
35
+ ```bash
36
+ mv migrations/V1__schema.sql.example migrations/V1__schema.sql
37
+ npm install
38
+ npm run flyway:migrate
39
+ ```
40
+
41
+ `V1__schema.sql` creates the processor dead-letter queue table the runtime expects. Add your own
42
+ `V2__*.sql`, `V3__*.sql` and so on as slices introduce projections.
43
+
44
+ 4. Run the server:
45
+
46
+ ```bash
47
+ npm run build # slice routes and processors are loaded from dist/
48
+ npm run dev
49
+ ```
50
+
51
+ The API is on http://localhost:3000, with Swagger UI at http://localhost:3000/api-docs and the raw
52
+ OpenAPI document at http://localhost:3000/swagger.json.
53
+
54
+ ## Scripts
55
+
56
+ | Script | What it does |
57
+ |---|---|
58
+ | `npm run dev` | Start the server locally with `.env` loaded |
59
+ | `npm run build` | Compile TypeScript to `dist/` |
60
+ | `npm start` | Start in production mode |
61
+ | `npm test` | Run `src/**/*.test.ts` via `tsx --test` |
62
+ | `npm run flyway:migrate` | Apply pending migrations from `migrations/` |
63
+
64
+ ## Learn more
65
+
66
+ - [Eventmodelers](https://eventmodelers.ai)
67
+ - [Emmett documentation](https://event-driven-io.github.io/emmett/)