@eventmodelers/cli 2.0.38 → 2.0.39

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": "2.0.38",
3
+ "version": "2.0.39",
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": {
@@ -61,8 +61,8 @@
61
61
  .em-ev b { color: #fdba74; font-weight: 600; }
62
62
  .em-ev-head { display: flex; align-items: baseline; gap: 8px; flex-wrap: wrap; cursor: pointer; }
63
63
  .em-ev-pos { font: 600 11px ui-monospace, SFMono-Regular, Menlo, monospace; color: #8a95a9; background: #0e1522; border-radius: 5px; padding: 1px 6px; }
64
- .em-ev-type { font-weight: 600; font-size: 13px; color: #fdba74; }
65
- .em-ev-from { color: #8a95a9; font-size: 12px; }
64
+ .em-ev-type { font-weight: 600; font-size: 13px; color: #1a0f05; background: #f97316; border-radius: 4px; padding: 2px 8px; box-shadow: 0 1px 2px rgba(0,0,0,.35); }
65
+ .em-ev-from { font-weight: 600; font-size: 12px; color: #fff; background: #3b82f6; border-radius: 4px; padding: 2px 8px; box-shadow: 0 1px 2px rgba(0,0,0,.35); }
66
66
  .em-ev-time { margin-left: auto; color: #6b7690; font: 11px ui-monospace, SFMono-Regular, Menlo, monospace; }
67
67
  .em-kv { display: grid; grid-template-columns: minmax(70px, max-content) 1fr; gap: 3px 14px; margin: 8px 0 2px; padding-top: 8px; border-top: 1px solid var(--p-line, #232f45); }
68
68
  .em-kv dt { color: #8a95a9; margin: 0; } .em-kv dd { margin: 0; word-break: break-word; color: #e7eaf0; } .em-kv dd.em-none { color: #4f5b73; }
@@ -360,7 +360,7 @@ function EventBrowser({ events }) {
360
360
  <div className="em-ev-head" onClick={() => setOpen(isOpen ? null : e.id)}>
361
361
  <span className="em-ev-pos">#{e.position}</span>
362
362
  <span className="em-ev-type">{e.type}</span>
363
- {e.metadata.command && <span className="em-ev-from">← {e.metadata.command}</span>}
363
+ {e.metadata.command && <span className="em-ev-from">{e.metadata.command}</span>}
364
364
  {e.metadata.automation && <span className="em-pill">automation</span>}
365
365
  {e.metadata.simulated && <span className="em-pill">simulated</span>}
366
366
  <span className="em-ev-time">{new Date(e.metadata.at).toLocaleTimeString()}</span>
@@ -0,0 +1,53 @@
1
+ ---
2
+ name: scenario-coverage
3
+ description: Calculate how much of each slice's business logic its Given/When/Then scenarios cover, for one chapter (or all), and store it on the slice's specification node as `meta.data.coverage` — percentage plus the meaningful scenarios still missing. The canvas shows the percentage on the spec lane (red < 50, orange < 70, green otherwise).
4
+ ---
5
+
6
+ # Scenario Coverage
7
+
8
+ > **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`.
9
+
10
+ Prefer `mcp__eventmodelers__*` tools when available. Only the coverage value is written; scenarios, elements and slice status are never changed.
11
+
12
+ ## Step 1 — Arguments
13
+
14
+ From `$ARGUMENTS`: the **chapter** (timeline title) to work on; none given = every chapter. If a name matches several, ask.
15
+
16
+ ## Step 2 — Read the chapter
17
+
18
+ ```
19
+ mcp__eventmodelers__get_slice_data { "boardId": "$BOARD_ID", "contextName": "<CHAPTER>", "projection": "fields", "format": "toon" }
20
+ mcp__eventmodelers__get_slice_data { "boardId": "$BOARD_ID", "contextName": "<CHAPTER>", "projection": "specs", "format": "toon" }
21
+ ```
22
+
23
+ `fields` gives each slice's elements, fields and dependencies; `specs` gives its scenarios. Find each slice's specification node (the SCENARIO / spec-lane node of its column) with `get_nodes` (`type: "SCENARIO"`) — its id is where the result is written. A slice without one: skip it and say so.
24
+
25
+ ## Step 3 — Derive the real use cases, per slice
26
+
27
+ Work out what the slice's business logic actually has to do, from its command / read model / automation, fields, dependencies and the events involved:
28
+
29
+ - the happy path(s) and meaningful variants of them,
30
+ - each business rule and **every way the business would reject or alter the outcome** (validation of a field with a rule behind it, duplicates, state preconditions, limits, authorisation that the model shows),
31
+ - every distinct event outcome of a command; for a read model, each distinct projection behaviour (what appears, changes, disappears).
32
+
33
+ **Only meaningful scenarios count — both for what exists and for what is missing.** A scenario that is technically possible but means nothing to the business is not a use case: don't invent it, don't list it as missing, and an existing scenario that only restates another one, tests a framework/technical behaviour (null checks, type errors, malformed JSON, "field is empty" with no rule behind it) or can never occur in the process adds nothing to the coverage. Ask of each candidate: *would a domain expert care that this case behaves as specified?* If not, drop it.
34
+
35
+ ## Step 4 — Calculate
36
+
37
+ `percentage = round(100 × covered meaningful use cases ÷ all meaningful use cases)`. A use case is covered when an existing, meaningful scenario specifies exactly its given / when / then outcome. A slice with no business logic to speak of (a pure pass-through) with one scenario is 100; with no use cases derivable, don't write a value. Be honest — don't round up to look good; the number guides what to model next.
38
+
39
+ For every uncovered meaningful use case add an entry to `missing`: a short `title` and, where the model lets you say it, `given`, `when`, `then` (one short plain sentence each, in the model's own vocabulary and with concrete values only if the model has them). Leave a part out rather than guess. Max 10 entries, most important first.
40
+
41
+ ## Step 5 — Store it
42
+
43
+ Read the spec node first (`get_node`) and keep its whole existing `meta`; add only `data.coverage`, preserving anything else already in `data`:
44
+
45
+ ```
46
+ "data": { "coverage": { "percentage": 78, "missing": [ { "title": "Reject a rental of an already rented bike", "given": "bike B-1 is rented", "when": "a customer rents B-1", "then": "the rental is rejected" } ] } }
47
+ ```
48
+
49
+ Send it as a `node:changed` event for the spec node (`changedAttributes: ["data"]`, `meta` = existing meta + `data`) with `mcp__eventmodelers__submit_node_events`, or via `POST <BASE_URL>/api/org/<ORG_ID>/boards/<BOARD_ID>/nodes/events` with the same body. Write coverage again on a rerun — it replaces the old value.
50
+
51
+ ## Step 6 — Report
52
+
53
+ Post a `table` snippet (columns Slice · Coverage · Missing; slice as a link to its node), plus a one-line summary: slices rated, average, the lowest three. Always include a plain `text`.
@@ -75,6 +75,7 @@ Follow `eventmodeling-information-completeness` before writing any field. It def
75
75
  | Design or update a single wireframe/sketch screen (explicit request only) | `/storyboard-screen` |
76
76
  | Business analysis, gap spotting, posting questions | `/wdyt` |
77
77
  | Analyse the existing model structure, slice coverage, element counts | `/analyze-existing-model` |
78
+ | Calculate how much of a slice's business logic its scenarios cover (stored as `meta.data.coverage`, shown on the spec lane) | `/scenario-coverage <chapter>` |
78
79
  | Reverse-engineer the business process of an existing code base into the model, as an interview — all chapters first, then one chapter at a time | `/analyze-code-base` |
79
80
  | Find what changed in the code since the last analysis (git history from the chapter note's baseline) that the model doesn't reflect, and propose fixes | `/detect-model-drift` |
80
81
  | Walk someone through a feature slice by slice, or through every slice a planned feature needs (existing, to adjust, new), as a player in the chat | `/walkthrough` |