@eventmodelers/cli 1.0.30 → 1.0.31

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.30",
3
+ "version": "1.0.31",
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": {
@@ -51,6 +51,7 @@ Server name: `eventmodelers`. Every tool takes `boardId` explicitly; none need `
51
51
  | `add_storyline` | `boardId`, `timelineId`, `columnId`, `storylines[]` | **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 | §6 `POST .../storylines` |
52
52
  | `set_connection` | `boardId`, `source`, `target`, `action` (`'connect'\|'remove'`) | Add or remove a type-checked directed edge | — (via `edges` on §3 events) |
53
53
  | `auto_connect_node` | `boardId`, `nodeId` | Re-run auto-connect for a node | §3 `POST .../nodes/:nodeId/auto-connect` |
54
+ | `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` |
54
55
  | `add_comment` | `boardId`, `nodeId`, `text`, `type?` (`'COMMENT'\|'TASK'\|'QUESTION'`), `author?` | Add a comment — `QUESTION` flags gaps/edge cases during review | — (via comment events) |
55
56
  | `update_comment` | `boardId`, `nodeId`, `commentId`, `action` (`'resolve'\|'delete'`) | Resolve or delete a comment | — (via comment events) |
56
57
  | `create_screen` | `boardId`, `contentType` (`'image'\|'sketch'\|'html'`), `nodeId?`, `chapterId`, `cellId?`/`cellName?`, plus content fields (`imageBase64`/`mimeType`, `elements[]`, or `pages[]`/`backgroundColor`), `description?` | Create + place a new screen node (SCREEN or HTML_SCREEN) atomically, in one call | §4 `POST .../images/:id/sketch` + `image-nodes` |
@@ -342,7 +343,7 @@ interface NodeChangeEvent {
342
343
  backgroundColor?: string
343
344
  title?: string
344
345
  url?: string
345
- linkedTo?: string // origin node idmarks this node as a linked copy (see below)
346
+ linkedTo?: string // rendering mirror onlymeta.linkedTo (below) is authoritative
346
347
  // ...other node data fields
347
348
  // Do NOT set a "type" here — the server derives the node's render type from
348
349
  // meta.type automatically. Setting one yourself risks it being read as the
@@ -354,6 +355,7 @@ interface NodeChangeEvent {
354
355
  title?: string
355
356
  description?: string
356
357
  fields?: Record<string, unknown>
358
+ linkedTo?: string // origin node id — the authoritative linked-copy pointer
357
359
  // ...
358
360
  }
359
361
  edges?: Array<{
@@ -396,7 +398,7 @@ A COMMAND is driven by exactly one upstream trigger — one SCREEN or one AUTOMA
396
398
 
397
399
  **Connections (both auto-connect and `set_connection`) only ever pair nodes on the same timeline** — a node in Chapter A can never be wired directly to a node in Chapter B, even when the type pair is otherwise valid (e.g. EVENT→READMODEL). No direct cross-timeline connection is possible.
398
400
 
399
- **The supported workaround is a linked copy**: place a copy of the source EVENT into its own swimlane on the *consuming* timeline, with `node.data.linkedTo` set to the origin node's id (see `linkedTo` in the `NodeChangeEvent` shape above; `eventmodeling-checking-completeness` documents how to recognize one when reading the board — it's an intentional copy, never a duplicate to clean up). Once the copy exists on the consuming timeline, it's a same-timeline node like any other and can be wired normally (e.g. linked-EVENT→READMODEL→SCREEN) to satisfy that context's local data need. Only fall back to documenting an integration gap when a linked copy genuinely isn't the right shape for the need (e.g. the consuming context needs live/aggregate data no single event copy can represent).
401
+ **The supported workaround is a linked copy**: place a plain EVENT node into its own swimlane on the *consuming* timeline, then call `link_element` (below) to link it to the origin node. Linking means first create, then link. `eventmodeling-checking-completeness` documents how to recognize a linked copy when reading the board — it's an intentional copy, never a duplicate to clean up.
400
402
 
401
403
  **Response**:
402
404
  - `200` — `{ connected: [{edgeId, source, target, created}], skipped: [{nodeId, reason}] }`
@@ -415,6 +417,20 @@ Create a single type-checked directed edge between two existing nodes — the RE
415
417
 
416
418
  ---
417
419
 
420
+ ### POST `/api/org/:orgId/boards/:boardId/nodes/:nodeId/link`
421
+ Link two existing same-type nodes — the REST fallback for `link_element`. Linking means first create, then link: `targetNodeId` must already exist. It's replaced with a full copy of `:nodeId`'s meta (not a merge) plus `meta.linkedTo`. COMMAND/EVENT/READMODEL only; `:nodeId` must not itself already be a linked copy.
422
+
423
+ **Request body**:
424
+ ```typescript
425
+ {
426
+ targetNodeId: string // existing same-type node to convert into a linked copy
427
+ }
428
+ ```
429
+
430
+ **Response**: `200` — `{ nodeId, linkedTo, type }` · `400` — missing `targetNodeId`, type mismatch, self-link, unsupported element type, or the original is itself a linked copy · `404` — the original or `targetNodeId` doesn't exist
431
+
432
+ ---
433
+
418
434
  ## 4. Images
419
435
 
420
436
  **File**: `src/slices/change/api-images/routes.ts`
@@ -555,7 +555,9 @@ The model is **complete** when:
555
555
  ## Next Steps
556
556
 
557
557
  If completeness check passes:
558
- → Proceed to code generation
558
+ → Proceed to Step 9 (`eventmodeling-validating-event-models`) — completeness is not the
559
+ final gate; validation, slicing, and documentation (Steps 9–11) still follow before
560
+ the model is ready for code generation.
559
561
 
560
562
  If gaps found:
561
563
  → Return to appropriate step to fix
@@ -133,7 +133,7 @@ Append findings to the project's event modeling file:
133
133
  Use Write tool to add/update this section:
134
134
 
135
135
  ```markdown
136
- ## 9. Scenarios (eventmodeling-elaborating-scenarios)
136
+ ## 7. Scenarios (eventmodeling-elaborating-scenarios)
137
137
 
138
138
  ### Coverage Goals
139
139
  [From Q1: Happy path / Comprehensive / Deep]
@@ -172,10 +172,12 @@ Use Write tool to add/update this section:
172
172
 
173
173
  Update Interview Trail:
174
174
  ```markdown
175
- | 9 | eventmodeling-elaborating-scenarios | [today] | Scenario coverage, testing strategy, edge cases |
175
+ | 7 | eventmodeling-elaborating-scenarios | [today] | Scenario coverage, testing strategy, edge cases |
176
176
  ```
177
177
 
178
- At this point, EVENTMODELING.md is complete and ready for implementation!
178
+ Scenarios are done, but the model is not yet ready for implementation — Steps 8–11
179
+ (Completeness, Validation, Slicing, Documentation) still follow. Proceed to Step 8
180
+ (`eventmodeling-checking-completeness`).
179
181
 
180
182
  ---
181
183
 
@@ -809,7 +811,7 @@ After posting, tell the user:
809
811
  **Per read model — this is a separate, equally mandatory pass, not an afterthought of the command pass above:**
810
812
  - [ ] **Every READMODEL on the board has at least one view scenario** — GWT (`given`: source EVENTs, `when`: empty, `then`: the READMODEL) or a storyline. A model with dozens of command scenarios and 0 read-model scenarios is not a complete Step 7 — it's easy to walk away thinking coverage is thorough because the command side looks exhaustive, so check the read-model side explicitly before reporting this step done.
811
813
  - [ ] **Population scenario** — the view shows correct data after its source event(s)
812
- - [ ] **Removal/update scenario, where applicable** — a row disappears or changes (`expectEmptyList: true` for list-type views) after an event that supersedes it (expiry, return, archival, withdrawal, status change, etc.). `EVENT → READMODEL` is exempt from column ordering **only when the read model already feeds an AUTOMATION** (`READMODEL → AUTOMATION` edge; see `learn-eventmodelers-api` §3) — a later event connecting back to an earlier-placed read model is normal for that accumulator shape, so add the connection if it's missing rather than assuming the scenario is impossible. If the read model has no automation to feed, the backward connection is rejected — model the removal/update the forward way instead (the superseding event lives in a later column, so express it as a scenario on a read model placed in that later column, or as a new version/copy of the read model there). Only skip this scenario, with a documented gap (TASK comment), when the superseding event genuinely lives in a different chapter.
814
+ - [ ] **Removal/update scenario, where applicable** — a row disappears or changes (`expectEmptyList: true` for list-type views) after an event that supersedes it (expiry, return, archival, withdrawal, status change, etc.). `EVENT → READMODEL` is exempt from column ordering **only when the read model already feeds an AUTOMATION** (`READMODEL → AUTOMATION` edge; see `learn-eventmodelers-api` §3 and `eventmodeling-orchestrating-event-modeling`'s "No backward arrows") — a later event connecting back to an earlier-placed todo-list read model is normal for that accumulator shape, so add the connection if it's missing rather than assuming the scenario is impossible. If the read model has no automation to feed, the backward connection is rejected — by Step 5 this should already have been modeled the forward way (see `eventmodeling-identifying-outputs` Step 5g's copy pattern: a new read model + screen copy in the later event's column, never a link back). If it wasn't, write the scenario against that forward-placed copy rather than the original. Only skip this scenario, with a documented gap (TASK comment), when the superseding event genuinely lives in a different chapter.
813
815
  - [ ] **GWT vs. storyline decided per read model, not applied uniformly** — reach for a storyline wherever the *same* read model row genuinely walks through multiple states worth narrating; the rest of the read models in the same model may be correctly GWT-only. Don't default to one format for every read model just because it worked for the first one, and don't judge "multiple states" by counting *distinct connected event types* — that undercounts real candidates. **A single event type recurring with different data is just as valid a storyline driver as several different event types**: `AccountFunded($40)` then `AccountFunded($70)` walking a balance read model from $40 to $110 is exactly as strong a storyline as a multi-event lifecycle. In practice this means almost every list/aggregate read model qualifies — a titles list growing from one row to two as the same `TitleAdded`-shaped event recurs, a dashboard's counters incrementing as the same `CopyAdded` event recurs, are both genuine storylines, not "just" GWT territory. Ask "does replaying this read model's *actually connected* event(s) more than once produce an interesting accumulated/changed state?" — not "how many different event types feed this."
814
816
  - [ ] **No redundancy or contradiction between a read model's GWT scenarios and its storyline** — if both exist for the same read model, read the storyline's beats before finalizing the GWTs. A GWT that asserts the same state a beat already shows is redundant (delete it); a GWT written without tracing the same causal sequence the storyline encodes can end up asserting something the storyline's beats actually contradict (e.g. claiming two entities coexist in a view when the storyline correctly shows one superseding the other) — delete or fix it, never leave a contradiction on the board.
815
817
  - [ ] **Cross-context read models handled honestly** — if a read model's true source events live in a different chapter, `given` can't reference them (same-timeline-only, like connections); write the scenario with an empty `given` and say so explicitly in the scenario title, rather than silently omitting the scenario or fabricating a same-timeline event that isn't the real source
@@ -590,6 +590,8 @@ For each view screen S that queries this read model:
590
590
 
591
591
  **View screens go in the column immediately to the right of the read model they display** — either because they were placed there in Step 3, or because you move them here now.
592
592
 
593
+ **The same rule applies to `EVENT → READMODEL`.** 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 5b). 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 (or 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.
594
+
593
595
  ### Step 5h — Wire connections after placing each READMODEL (and its SCREEN)
594
596
 
595
597
  After `place-element` returns the READMODEL node ID, create the arrows that complete the slice:
@@ -113,7 +113,11 @@ Never leave an unplaced node on the board when proceeding to the next step.
113
113
  ### No backward arrows
114
114
  The timeline must always progress left-to-right — this is the goal to design toward, not just a validation check to run afterward. Every connection arrow — SCREEN→COMMAND, COMMAND→EVENT, READMODEL→SCREEN, READMODEL→AUTOMATION, AUTOMATION→COMMAND — must point to the right or downward (within the same column). A right-to-left arrow among these is always a layout error, full stop.
115
115
 
116
- **`EVENT → READMODEL` is the one exception and it stays an exception, not a second acceptable default.** Confirmed against the platform API (`learn-eventmodelers-api` §3`POST .../connections`): an event in a later column may legitimately connect to a read model in an earlier column, and vice versa, because a read model is a continuously-listening projection, not a point-in-time action it can be fed by an event anywhere on its timeline, including one placed after it. Always try to place a read model so its connections read forward first; reach for this exception only when a genuine roll-up's wide fan-in makes an all-forward layout impractical (see "God read models" above), not as a default way to avoid column planning. When you do rely on it, don't "fix" the wide-fan-in read model by relocating it to sit after its last source event just to eliminate the backward arrows — that column surgery is unnecessary and, for a genuine roll-up, often impossible to do cleanly without breaking other consumers. The one real signal to watch for is a **connected event that isn't actually used by any field** on the read model that's a prunable connection regardless of column position, not a column-ordering problem.
116
+ **`EVENT → READMODEL` has exactly one exception, and it is narrow.** A read model that already carries a `READMODEL AUTOMATION` edgei.e. a todo-list read model feeding an automation, per `eventmodeling-identifying-outputs` Step 5bmay 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.
117
+
118
+ 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 (or 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.
119
+
120
+ 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.
117
121
 
118
122
  Before wiring any of the five forward-only pairs, verify that `column(source) ≤ column(target)`. If this is violated:
119
123
  - Move the earlier-placed element to the correct column, OR
@@ -338,7 +342,7 @@ If FAIL: address findings and re-invoke `eventmodeling-validating-event-models`.
338
342
 
339
343
  **Optional — Production Readiness Checklist**: Invoke
340
344
  `eventmodeling-validating-event-models-checklist` when the model is destined
341
- for production. It runs 23 architectural checks across 7 phases and returns a
345
+ for production. It runs 17 architectural checks across 7 phases and returns a
342
346
  PASS / PASS WITH WARNINGS / FAIL verdict independently of Step 9. A PASS on
343
347
  Step 9 does not substitute for this checklist when production readiness is
344
348
  required.
@@ -463,6 +467,7 @@ specific needs:
463
467
  ## Quality Checklist
464
468
 
465
469
  - [ ] No elements stranded at 0,0 — every EVENT, COMMAND, READMODEL, SCREEN, and AUTOMATION has a valid `cellId` in its chapter
470
+ - [ ] No `EVENT → READMODEL` connection points backward unless the read model already has a `READMODEL → AUTOMATION` edge (todo-list pattern) — every other later-event update uses a new read model + screen copy, never a link back to the earlier instance
466
471
  - [ ] All 11 modeling steps completed — no step skipped without explicit reason
467
472
  - [ ] Every COMMAND, READMODEL, and AUTOMATION has a matching slice definition on the board
468
473
  - [ ] Every chapter has a Modeling Reasoning MARKDOWN node in its first column, written after that chapter's model was complete
@@ -17,8 +17,8 @@ Prefer `mcp__eventmodelers__*` tools when available (registered by the `connect`
17
17
  **Applies To**: Any domain - e-commerce, banking, SaaS, marketplace, healthcare, etc.
18
18
 
19
19
  **When to Use**:
20
- - After completing Step 2 (Event Plot) of 7-step event modeling
21
- - After completing Step 7 (Scenarios) before declaring model complete
20
+ - After completing Step 2 (Event Plot) of the 11-step event modeling workflow, as an early structural check
21
+ - Alongside Step 9 (Validate), as the optional production-readiness pass before declaring model complete
22
22
  - When reviewing an existing event model for production readiness
23
23
  - When suspicious of architectural issues in event design
24
24
 
@@ -311,11 +311,13 @@ Step 2: The Plot (Sequence)
311
311
 
312
312
  Fix any violations
313
313
 
314
- Step 3-7: Complete remaining steps
314
+ Step 3-8: Storyboard, Inputs, Outputs, Conway's Law, Scenarios, Completeness
315
315
 
316
- RUN eventmodeling-validating-event-models-checklist again (final validation)
316
+ Step 9: Validate (eventmodeling-validating-event-models)
317
317
 
318
- PASS Code generation
318
+ RUN eventmodeling-validating-event-models-checklist again (production-readiness pass)
319
+
320
+ PASS → Step 10: Slice, Step 11: Document Reasoning → Code generation
319
321
  FAIL → Fix identified issues
320
322
  ```
321
323
 
@@ -368,7 +370,7 @@ The principle is the same across all domains: **immutable facts as events, calcu
368
370
 
369
371
  ## Related Skills
370
372
 
371
- - **eventmodeling-orchestrating-event-modeling**: Main skill coordinating the 7-step event modeling process
373
+ - **eventmodeling-orchestrating-event-modeling**: Main skill coordinating the 11-step event modeling process
372
374
  - **eventmodeling-brainstorming-events**: Extract events from requirements (Step 1)
373
375
  - **eventmodeling-plotting-events**: Sequence events chronologically (Step 2)
374
376
  - **eventmodeling-designing-event-models**: Design your complete event model
@@ -280,6 +280,20 @@ If no matching row is found, stop and report the error — the timeline may be m
280
280
 
281
281
  ---
282
282
 
283
+ ## Step 6a — Referencing a node on a different timeline
284
+
285
+ **Connections only ever pair nodes on the same timeline** — a node in Chapter A can never be wired directly to a node in Chapter B, even for an otherwise-valid type pair (e.g. `EVENT → READMODEL`). If the element you're placing needs to connect to something that lives on a *different* timeline, do not place it and then attempt `set_connection`/auto-connect across timelines — it will fail.
286
+
287
+ Instead, create a **linked copy**: place the new node normally (Step 7, same title/type as the origin), then call `link_element` to mark it as a copy of the origin node:
288
+
289
+ ```
290
+ mcp__eventmodelers__link_element { "boardId": "<BOARD_ID>", "nodeId": "<origin-node-id>", "targetNodeId": "<newly-placed-node-id>" }
291
+ ```
292
+
293
+ (REST fallback: `POST .../nodes/:nodeId/link` with `{ "targetNodeId": "<newly-placed-node-id>" }` — see `learn-eventmodelers-api` §3.) This replaces the new node's meta with a full copy of the origin's, sets `meta.linkedTo`, and only works for COMMAND/EVENT/READMODEL. Once linked, wire the local copy to its neighbors with normal same-timeline `set_connection`/auto-connect calls. `eventmodeling-checking-completeness` treats any `linkedTo`-marked node it finds as this intentional pattern, never a duplicate to flag.
294
+
295
+ ---
296
+
283
297
  ## Step 7 — Create the node
284
298
 
285
299
  ### Step 7a — SCREEN only: create and render in one atomic call