@eventmodelers/cli 1.0.41 → 1.0.43

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.41",
3
+ "version": "1.0.43",
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": {
@@ -50,7 +50,7 @@ Server name: `eventmodelers`. Every tool takes `boardId` explicitly; none need `
50
50
  | `get_board_outline` | `boardId`, `chapterId` | One chapter's structure, compact: per-column node lists (`{id, type, title, lane}`) + a flat edge list, no HTML pages / field bodies / meta. The cheap "what is where and how is it wired" read — prefer over `get_nodes` (no projection) for orientation checks | — (MCP-only convenience) |
51
51
  | `validate_model` | `boardId`, `chapterId`, `checks?[]` | Server-side Event Modeling structural checklist over one chapter — compact `findings` only. Checks: unplaced nodes, backward arrows (with the todo-list `EVENT→READMODEL` exception), zero/multi-issuer commands, sourceless read models, two-screens-in-a-column, missing scenarios. Replaces the manual per-type `get_nodes` + `get_node projection=edges` validation pass | — (MCP-only convenience) |
52
52
  | `add_scenario` | `boardId`, `timelineId`, `columnId`, `scenarios[]`, `compact?` | Append GWT scenario(s) to a column's spec node. `compact: true` returns `{specNodeId, added, scenarioCount, isNewNode}` instead of echoing every scenario back | §6 `POST .../scenarios` |
53
- | `add_storyline` | `boardId`, `timelineId`, `columnId`, `storylines[]`, `compact?` | **Experimental — only use when explicitly asked for a storyline/walkthrough.** Append storyline(s) (ordered, branchable beats over existing elements) to a column's spec node. `compact: true` suppresses the full storyline echo | §6 `POST .../storylines` |
53
+ | `add_storyline` | `boardId`, `timelineId`, `columnId`, `storylines[]`, `compact?` | Append storyline(s) (ordered, branchable beats over existing elements) to a column's spec node. Use whenever `eventmodeling-elaborating-scenarios`'s GWT-vs-storyline decision rule calls for one (e.g. a todo list's open→close lifecycle) — not only when a user explicitly names "storyline"; that skill's own per-read-model judgment is the trigger, this catalog entry isn't a stricter gate on top of it. `compact: true` suppresses the full storyline echo | §6 `POST .../storylines` |
54
54
  | `set_connection` | `boardId`, `source`, `target`, `action` (`'connect'\|'remove'`) | Add or remove a type-checked directed edge. Batch form `set_connections` takes `connections[]` (applied in order) plus `compact?` — `compact: true` returns a `{connected, existed, removed, notFound, failed, errors}` tally instead of one row per edge | — (via `edges` on §3 events) |
55
55
  | `auto_connect_node` | `boardId`, `nodeId` | Re-run auto-connect for a node | §3 `POST .../nodes/:nodeId/auto-connect` |
56
56
  | `link_element` | `boardId`, `nodeId`, `targetNodeId` | Link two existing same-type nodes: `targetNodeId` is replaced with a full copy of `nodeId`'s meta plus `meta.linkedTo`. Linking means first create, then link | §3 `POST .../nodes/:nodeId/link` |
@@ -595,11 +595,12 @@ Get valid elements for a specific slice.
595
595
 
596
596
  ---
597
597
 
598
- ### Storylines (experimental)
598
+ ### Storylines
599
599
 
600
- > **Only create a storyline when the user's request explicitly asks for one** — the word
601
- > "storyline", "walkthrough", or "narrative" (or equivalent) must appear in what they asked for.
602
- > Otherwise keep creating normal GWT scenarios via `add_scenario`/`POST .../scenarios` as before.
600
+ > **Create a storyline whenever `eventmodeling-elaborating-scenarios`'s GWT-vs-storyline decision
601
+ > rule calls for one** (e.g. a todo list's open→close lifecycle) that skill's own per-read-model
602
+ > judgment is the trigger, not a specific word in the user's request. GWT scenarios via
603
+ > `add_scenario`/`POST .../scenarios` still cover everything the decision rule doesn't.
603
604
 
604
605
  An ordered, branchable walkthrough of existing board elements ("beats"), stored alongside GWT
605
606
  scenarios on the same SCENARIO spec node, in a sibling `meta.storylines` collection.
@@ -114,7 +114,7 @@ When an element's natural column is already occupied by something else, insert a
114
114
 
115
115
  ## Linked Copies
116
116
 
117
- A **linked copy** is a COMMAND/EVENT/READMODEL node that mirrors another node elsewhere on the board — most often needed because `set_connection`/auto-connect only ever pairs nodes on the same timeline, so a node on a different timeline can't be wired to directly.
117
+ A **linked copy** is a COMMAND/EVENT/READMODEL node that mirrors another node elsewhere on the board — most often needed because `set_connection`/auto-connect only ever pairs nodes on the same timeline, so a node on a different timeline can't be wired to directly. The same marking obligation applies whenever a node is reused rather than newly wired anywhere on the board, same timeline included: never place a node that repeats another swimlane's already-recorded fact under its own unlinked identity — either connect forward to the original, or mark it a linked copy. The one exception is a translation chain's own internal EVENT (`eventmodeling-designing-automation-chains`): it is a genuine new domain fact recorded in this side's own language, not a copy, even when it shares the external EVENT's name.
118
118
 
119
119
  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.
120
120
 
@@ -45,7 +45,7 @@ Even an automation that looks like a "pure signal relay" still has a todo list
45
45
 
46
46
  1. **Translation automation** — converts the external fact into an internal one; the other system's own decision logic is out of scope. Its todo list is opened by the external EVENT — the one and only place an external EVENT may open a todo list. **It is not closed by the internal EVENT its own command produces, and gets no backward arrow.** A translation automation's job is an instantaneous, always-succeeding relay: there is no real work-in-progress window between "signal arrived" and "internal fact recorded" worth modeling as an open/close lifecycle, unlike a worker automation that can genuinely have pending items. This read model exists only to satisfy "every automation reads from a todo list," not to accumulate and drain a queue — so it stays open-ended: fed by the external EVENT, read by the automation, never closed.
47
47
  - **Three separate columns**, left to right: `[external EVENT] → [todo-list READMODEL] → [AUTOMATION + COMMAND + internal EVENT]`. Never crammed into one or two — the "one EVENT per column" rule applies here too.
48
- - **Name the internal EVENT for its business meaning, not the transport** — usually the same name as the external EVENT (e.g. external `CopyReserved` → internal `CopyReserved`; the swimlane already shows which is which), never a mechanical `<X>SignalReceived`/`<X>RequestReceived` suffix. Same for the automation/command: `Record Reservation`/`RecordReservation`, not `Record Reservation Signal`/`RecordReservationSignal`.
48
+ - **Name the internal EVENT for its business meaning, not the transport** — usually the same name as the external EVENT (e.g. external `CopyReserved` → internal `CopyReserved`; the swimlane already shows which is which), never a mechanical `<X>SignalReceived`/`<X>RequestReceived`/`<X>Synced` suffix. Same for the automation/command: `Record Reservation`/`RecordReservation`, not `Record Reservation Signal`/`RecordReservationSignal`.
49
49
  - Its command and event carry no business decision — they only exist to produce the internal fact a worker automation would need, *if one is even needed* (see below).
50
50
 
51
51
  ### Does a worker automation come after it, or does the chain stop there?
@@ -55,6 +55,8 @@ The translation automation never decides anything — it only records a fact. Wh
55
55
  - **Build a worker automation only when reacting to the internal EVENT requires a genuinely new decision on this side** — an invariant to check, a choice to make, data to compute that the internal EVENT doesn't already carry. That decision is what earns its own COMMAND, which is what earns the automation that issues it (see item 2 below for its shape).
56
56
  - **Do not build one when the internal EVENT already *is* the business-relevant fact.** If the external system already made every decision involved, and the "next" EVENT you were about to model would just restate data the internal EVENT already carries under a different name (same identity, no new field, no invariant checked, no choice made) — stop after the translation automation. That is not a second stage of the same chain; it is no chain at all, just a fact recorded once. Anything else that needs this fact reads the internal EVENT directly through a state-view READMODEL projection — it does not get an automated command reaction bolted on solely to keep a fixed "two automations" shape.
57
57
 
58
+ A `<X>Synced` event feeding a second translation on top of an already-decided fact is the most common shape of this violation — the "Synced" name is itself the tell that no new decision was made.
59
+
58
60
  *Example*: an external `ReservationPlaced` opens a translation chain and already carries `reservationId`, `copyId`, and `memberId` — the copy to reserve was chosen upstream, by the other system. Translating it into an internal `ReservationPlaced` is still required (per the rule above — an automation may never react to the external event directly). But adding a second `ReservationsToApply` todo list + `Reserve Copy` automation + `CopyReserved` event on top of it is redundant: `CopyReserved` doesn't decide anything `ReservationPlaced` didn't already decide, it's the same fact under a different name. A read model showing "reserved copies" should project directly off the internal `ReservationPlaced` event, not off a manufactured second automation stage.
59
61
 
60
62
  2. **Worker automation** (only when the check above says one is needed) — the one that does the actual work (a real domain decision the process is about, e.g. checking copy availability before issuing `ReserveCopy`). Its todo list is opened **only** by the internal EVENT the translation automation produced (this chapter's own swimlane) — never by the external EVENT directly — and closed by whatever event marks that work done. Unlike the translation stage, the worker's todo list keeps its normal open/close accumulator shape, because real pending work can sit there (it's the point where actual domain decisions happen).
@@ -105,7 +107,7 @@ mcp__eventmodelers__submit_node_events {
105
107
 
106
108
  > **Never call `drop` after using `cellId` in `node:created`.** The drop endpoint adds a second cell reference without removing the first.
107
109
 
108
- For a **translation-chain automation**, place its three columns left to right in the same pass: `[external EVENT]`, `[todo-list READMODEL]`, `[AUTOMATION + COMMAND + internal EVENT]` — the external EVENT normally already exists (placed in Step 1/brainstorming, second swimlane); if it doesn't, place it there first.
110
+ For a **translation-chain automation**, place its three columns left to right in the same pass: `[external EVENT]`, `[todo-list READMODEL]`, `[AUTOMATION + COMMAND + internal EVENT]` — the external EVENT normally already exists (placed in Step 1/brainstorming, second swimlane); if it doesn't, place it there first. **Insert these columns immediately after the external EVENT's own column** (`add_column` with `afterNodeId` set to it) — never at the timeline's start. A translation chain lives exactly where its trigger already sits in the narrative; being an "input" is not a reason to relocate it ahead of everything else.
109
111
 
110
112
  ## Wiring connections
111
113