@eventmodelers/cli 1.0.62 → 1.0.63

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.62",
3
+ "version": "1.0.63",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -48,6 +48,7 @@ Server name: `eventmodelers`. Every tool takes `boardId` explicitly; none need `
48
48
  | `get_slice_data` | `boardId`, `contextName?`, `contextId?`, `sliceId?` | Full element graph for slices in a context | §8 `GET /slicedata` |
49
49
  | `get_spec_info` | `boardId`, `timelineId`, `elementTypes?` | EVENT/COMMAND/READMODEL nodes valid in GWT steps. Pass `elementTypes` (subset of `EVENT`/`COMMAND`/`READMODEL`) to avoid pulling the full element list when only one or two types are needed — filtered server-side, not just after a full fetch | §6 `GET .../spec-info` |
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
+ | `get_connected_nodes` | `boardId`, `nodeId`, `chapterId?`, `direction?` (`inbound`/`outbound`/`both`), `depth?`, `types?`, `includeFields?` | Neighbours of **one** node — what feeds it and what it feeds. Answers from a single anchor, unlike `get_attribute_chain` (which needs both ends of the chain as cell names up front). `depth` follows a whole chain; `types` filters the result only, never the traversal. Each neighbour carries `via`: `"edge"` for a real connection, `"layout"` when the node has none in that direction and the neighbour was inferred from the grid using auto-connect's own window (own column + adjacent one, forward-only pairs). Real edges always win. The `layout` fallback is what makes hand-built/imported chapters — which routinely carry **zero** edges — readable instead of falsely empty | — (MCP-only convenience) |
51
52
  | `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
53
  | `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
54
  | `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` |
@@ -61,16 +61,30 @@ edges: [{ id, source, target, sourceHandle, targetHandle }]
61
61
  ```
62
62
  An **inbound** edge is one where `edge.target === currentNode.id`.
63
63
 
64
- Resolve the whole walk from **one** chapter-scoped read rather than a `get_node` per hop `get_board_outline { "boardId": "$BOARD_ID", "chapterId": "$TIMELINE_ID" }` returns every node in the chapter (`{id, type, title, lane}` per column) *plus* a flat edge list, which is exactly what the traversal needs. Index it in memory and walk it locally; you only need the per-node `meta.fields` (Step 4), which one `get_nodes { "boardId": "$BOARD_ID", "chapterId": "$TIMELINE_ID" }` returns for the whole chapter in a single call.
64
+ **Prefer `get_connected_nodes`** — it does this entire walk server-side, in one call, from the target alone:
65
+ ```
66
+ mcp__eventmodelers__get_connected_nodes {
67
+ "boardId": "$BOARD_ID",
68
+ "nodeId": "<TARGET_NODE.id>",
69
+ "direction": "inbound",
70
+ "depth": 10,
71
+ "includeFields": true
72
+ }
73
+ ```
74
+ The result is already ordered by `hops` (nearest first) and carries each node's `cellName` and `fields[]`, which is everything Step 4 needs — so this replaces both the edge walk and the per-node field fetch. Stop at the node matching `SOURCE_NODE`; anything beyond it is outside the requested chain.
75
+
76
+ Each neighbour reports `via`. `"edge"` means a real connection. `"layout"` means that node had no edge in that direction and the neighbour was inferred from the grid — correct, but worth a line in your Step 5 report so the user knows the chain was read off the layout rather than off wiring. A `chapterHasEdges: false` in the summary means the whole chapter is unwired.
65
77
 
66
- Reach for a single-node fetch only for a node genuinely outside that chapter:
78
+ Reach for a single-node fetch only for a node genuinely outside the anchor's chapter:
67
79
  ```
68
80
  mcp__eventmodelers__get_node { "boardId": "$BOARD_ID", "nodeId": "$EDGE_SOURCE_ID", "projection": "edges" }
69
81
  ```
70
82
 
71
- **Fallback (no MCP):** see `references/api-fallback.md` — "3a — Use Node Edges".
83
+ **Fallback (no MCP):** see `references/api-fallback.md` — "3a — Use Node Edges". Resolve the walk from **one** chapter-scoped read rather than a `get_node` per hop: `GET .../nodes?chapterId=` returns every node with full `meta`, `node.position` and `node.parentId` in a single response — index it and walk it locally.
72
84
 
73
85
  ### 3b — Column-based fallback (if no edges)
86
+ Only needed without MCP; `get_connected_nodes` already applies this rule itself and labels the result `via: "layout"`.
87
+
74
88
  Hand-built or imported chapters frequently have **no edges at all** — every node comes back with `edges: []` and `get_board_outline`'s edge list is empty. That is not an error and not a reason to stop: in that case grid geometry *is* the chain. Use the chapter cell layout (already in memory from 3a) to find inbound neighbours:
75
89
 
76
90
  In a standard event modeling layout:
@@ -7,6 +7,8 @@ description: Business analyst exploration of an event model board. Reads all sli
7
7
 
8
8
  > **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, and `BASE_URL`. Do not proceed until the connect skill has completed.
9
9
 
10
+ Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect` skill) — the REST calls below are the fallback for sessions without MCP connected.
11
+
10
12
  This step applies the shared element rules in **`eventmodeling-core-rules`** — read it once per session if you haven't already; it defines what a COMMAND/EVENT/READMODEL/SCREEN/AUTOMATION is, the anti-patterns to reject, and the four Structural Shapes (Category I below), so this step doesn't restate them.
11
13
 
12
14
  You are a **sharp business analyst** reviewing an event model. You don't know the domain yet — you're seeing it fresh. Your job is to read the model, understand the intended flows, and ask the hard questions that developers and domain experts tend to overlook because they're too close to the problem.
@@ -26,17 +28,27 @@ If the user already provided context name in their message, use it directly.
26
28
 
27
29
  ## Step 2 — Load the model
28
30
 
29
- **A. Get all slices:**
31
+ **Prefer MCP — one call loads the whole context.** `sliceId` is optional; omitting it returns the full element graph for *every* slice in the context at once. Do **not** list slices and then fetch them one by one:
32
+
30
33
  ```
31
- GET /api/org/{orgId}/boards/{boardId}/slicedata/slices
34
+ mcp__eventmodelers__get_slice_data {
35
+ "boardId": "$BOARD_ID",
36
+ "contextName": "<context name from Step 1>",
37
+ "format": "textual"
38
+ }
32
39
  ```
33
- This returns `{ slices: [{ id, title, status }] }`.
34
40
 
35
- **B. For each slice, load its full data:**
41
+ `format` matters here because this skill reads the entire model before it writes anything. `"textual"` is a compact markdown dump and `"toon"` a token-efficient tabular encoding — both carry the same graph as `"json"` in a fraction of the tokens. Use `"json"` only when you need to read exact `x`/`y`/`width`/`height` values for the drawings in Step 4.2.
42
+
43
+ Each response contains screens, commands, events, read models, specs, scenarios, actors, automations, and the edges between them.
44
+
45
+ `mcp__eventmodelers__list_slices { "boardId": "$BOARD_ID" }` is only needed when you must scope to **one** slice and don't know its id, or to read slice statuses — not as a precursor to loading the model.
46
+
47
+ **Fallback (no MCP):**
36
48
  ```
37
- GET /api/org/{orgId}/boards/{boardId}/slicedata?contextName={contextName}&sliceId={sliceId}
49
+ GET /api/org/{orgId}/boards/{boardId}/slicedata?contextName={contextName}
38
50
  ```
39
- Load all slices in parallel. Each response contains the full element graph for that slice: screens, commands, events, read models, specs, scenarios, actors, automations.
51
+ Same shape the whole context in one request. `&sliceId={sliceId}` narrows it to one slice; `GET .../slicedata/slices` lists `{ slices: [{ id, title, status }] }`.
40
52
 
41
53
  Keep track of:
42
54
  - All slice titles and their element types
@@ -132,10 +144,30 @@ Only post questions that are **genuinely unclear or missing** — don't post obs
132
144
 
133
145
  ### 4.2 Drawings (every relational or clustered finding, always)
134
146
 
135
- Use `POST /api/org/{orgId}/boards/{boardId}/drawing/draw` (auth headers same as every other call — `x-token`, `x-board-id`, `x-user-id: wdyt`). There are two kinds no text-callout kind; a drawing never carries the question itself, only the shape of the concern:
147
+ **Prefer MCP:** `mcp__eventmodelers__create_drawing` — one call per drawing, no auth headers needed.
148
+
149
+ **Fallback (no MCP):** `POST /api/org/{orgId}/boards/{boardId}/drawing/draw` (auth headers same as every other call — `x-token`, `x-board-id`, `x-user-id: wdyt`). Same fields as the tool args below.
136
150
 
137
- - **Arrow** (`kind: "path"`, `arrowEnd: true`) the concern is about a missing or unclear relationship *between two elements* (e.g. "does this event actually reach this automation?"). Draw a straight line from one element's position to the other's. `path` is `M 0 0 L <dx> <dy>` in the box's own local coordinates; `x`/`y`/`width`/`height` describe that box in canvas space (so `width`/`height` = the delta between the two elements' positions). Get element positions from the slice data already loaded in Step 2 (or `GET .../nodes/{nodeId}` if not present).
138
- - **Group loop** (`kind: "rect"`, drawn around a computed bounding box) — the concern spans a *cluster* of elements together (e.g. "this whole flow assumes nothing ever fails"). There's no dedicated group endpoint — union the elements' own `x`/`y`/`width`/`height` (plus some padding) yourself and draw one `rect` around that box via `.../drawing/draw`. This is a visual grouping only — unrelated to the `MODEL_CONTEXT` node type; never touch a `modelContext` field to satisfy this.
151
+ There are two kindsno text-callout kind; a drawing never carries the question itself, only the shape of the concern:
152
+
153
+ - **Arrow** (`kind: "path"`, `arrowEnd: true`) — the concern is about a missing or unclear relationship *between two elements* (e.g. "does this event actually reach this automation?"). Draw a straight line from one element's position to the other's. `path` is `M 0 0 L <dx> <dy>` in the box's own local coordinates; `x`/`y`/`width`/`height` describe that box in canvas space (so `width`/`height` = the delta between the two elements' positions).
154
+ ```
155
+ mcp__eventmodelers__create_drawing {
156
+ "boardId": "$BOARD_ID", "kind": "path",
157
+ "x": <sourceX>, "y": <sourceY>, "width": <dx>, "height": <dy>,
158
+ "path": "M 0 0 L <dx> <dy>", "arrowEnd": true
159
+ }
160
+ ```
161
+ Get element positions from the slice data already loaded in Step 2. If a position is missing, fetch the nodes you need in **one** call — `mcp__eventmodelers__get_nodes { "boardId": "$BOARD_ID", "nodeIds": [<the ids>] }` — not `get_node` per element.
162
+ - **Group loop** (`kind: "rect"`, drawn around a computed bounding box) — the concern spans a *cluster* of elements together (e.g. "this whole flow assumes nothing ever fails"). There's no dedicated group endpoint — union the elements' own `x`/`y`/`width`/`height` (plus some padding) yourself and draw one `rect` around that box:
163
+ ```
164
+ mcp__eventmodelers__create_drawing {
165
+ "boardId": "$BOARD_ID", "kind": "rect",
166
+ "x": <minX - pad>, "y": <minY - pad>,
167
+ "width": <maxX - minX + 2*pad>, "height": <maxY - minY + 2*pad>
168
+ }
169
+ ```
170
+ This is a visual grouping only — unrelated to the `MODEL_CONTEXT` node type; never touch a `modelContext` field to satisfy this.
139
171
 
140
172
  Every arrow/group loop is paired with a comment on the relevant node(s) from 4.1 — the drawing makes the concern visible at a glance on the canvas itself, the comment carries the actual worded question. Post both; neither replaces the other.
141
173