@eventmodelers/cli 2.0.38 → 2.0.40
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 +1 -1
- package/shared/skills/learn-eventmodelers-api/references/basics-architecture-element-types.md +8 -0
- package/stacks/modeling-kit/templates/.claude/skills/prototype/assets/index.template.html +3 -3
- package/stacks/modeling-kit/templates/.claude/skills/scenario-coverage/SKILL.md +53 -0
- package/stacks/modeling-kit/templates/kit/CLAUDE.md +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "2.0.
|
|
3
|
+
"version": "2.0.40",
|
|
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": {
|
package/shared/skills/learn-eventmodelers-api/references/basics-architecture-element-types.md
CHANGED
|
@@ -29,6 +29,14 @@ MARKDOWN // Free-text markdown note — the content type a `feedback` lane
|
|
|
29
29
|
VIDEO // Embedded video (YouTube/Loom link in `data.url`). API/MCP-only — no palette button in
|
|
30
30
|
// the UI, but renders on the board like any other node. Free-floating: create it via
|
|
31
31
|
// `submit_node_events` with a position and no chapterId/cellId, same as a drawing.
|
|
32
|
+
DIAGRAM // Pinned diagram (an `svg` or `mermaid` chat snippet saved to the board): `meta.diagramKind`
|
|
33
|
+
// (`svg` | `mermaid`), `meta.diagramSource`, `meta.title`. Free-floating, view only.
|
|
34
|
+
INFOGRAPHIC // Pinned infographic poster (an `infographic` chat snippet saved to the board):
|
|
35
|
+
// `meta.infographicJson`. Free-floating, view only, a snapshot of the snippet.
|
|
36
|
+
TIMELINE_REFERENCE // Read-only view of a timeline (chapter) from ANOTHER board:
|
|
37
|
+
// `meta.data.reference = {boardId, timelineId}`. Created in the UI only. It is not a real
|
|
38
|
+
// chapter: no children, no handles, nothing can connect to it, and it is never part of a
|
|
39
|
+
// slice. Ignore it when building slices, wiring edges or counting chapters; don't edit it.
|
|
32
40
|
```
|
|
33
41
|
|
|
34
42
|
---
|
|
@@ -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: #
|
|
65
|
-
.em-ev-from {
|
|
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"
|
|
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` |
|