@eventmodelers/cli 1.0.130 → 1.0.132
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/README.md
CHANGED
|
@@ -108,6 +108,7 @@ Use skills in Claude Code with `/skill-name`:
|
|
|
108
108
|
| `/wdyt` | Business analyst review of your event model |
|
|
109
109
|
| `/walkthrough` | Slice-by-slice player through a feature, or through every slice a planned feature needs (existing, to adjust, new) |
|
|
110
110
|
| `/data-journey` | Where one piece of information (e.g. the customer email) originates, is stored, transformed, used and sent out — as a table in the chat |
|
|
111
|
+
| `/stressor-analysis` | Residuality-theory stress test of one chapter: wide stressors and their residues, a stressor × element matrix that exposes hidden coupling, redesigns proposed as new slices |
|
|
111
112
|
| `/storyboard` | Build a full visual storyboard |
|
|
112
113
|
| `/html-screen` | Design individual real HTML/CSS screens (default) |
|
|
113
114
|
| `/storyboard-screen` | Design individual wireframe/sketch screens (explicit request only) |
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@eventmodelers/cli",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.132",
|
|
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": {
|
|
@@ -1124,8 +1124,9 @@ Rule of thumb: if you are about to write "Shall I…?", "Want me to…?", "A or
|
|
|
1124
1124
|
| to explain how a feature works, or walk through what a planned feature takes, slice by slice ("how does registration work?", "we need to add an email — walk me through it") | `walkthrough` | nothing — selecting a step pans the canvas |
|
|
1125
1125
|
| to show what a screen could look like, without putting it on the board | `screen` | nothing |
|
|
1126
1126
|
| to answer where one piece of information comes from and where it ends up ("where is the customer email used?") | `dataJourney` | nothing — element names pan the canvas |
|
|
1127
|
+
| to lay out rows and columns — a comparison, a matrix (stressors × elements), a short list with a few attributes | `table` | nothing — linked cells pan the canvas |
|
|
1127
1128
|
|
|
1128
|
-
`confirm`, `poll`, `tasks` and `changes` are questions: a person answers once, then they show as answered. `link`, `image`, `code`, `report`, `walkthrough`, `screen` and `
|
|
1129
|
+
`confirm`, `poll`, `tasks` and `changes` are questions: a person answers once, then they show as answered. `link`, `image`, `code`, `report`, `walkthrough`, `screen`, `dataJourney` and `table` are display only and never wait for anything.
|
|
1129
1130
|
|
|
1130
1131
|
### Shapes
|
|
1131
1132
|
```typescript
|
|
@@ -1170,6 +1171,11 @@ Rule of thumb: if you are about to write "Shall I…?", "Want me to…?", "A or
|
|
|
1170
1171
|
field?: string, // the field holding it here — names change along the way (email → customerEmail)
|
|
1171
1172
|
slice?: string,
|
|
1172
1173
|
note?: string }> } // how it is used or changed here, a few words
|
|
1174
|
+
{ kind: 'table', title?: string, caption?: string,
|
|
1175
|
+
columns: Array<string | { label: string, nodeId?: string, // 1–12; nodeId makes the header a link (a matrix with one column per element)
|
|
1176
|
+
align?: 'left' | 'center' | 'right' }>,
|
|
1177
|
+
rows: Array<Array<string | number | true | null // 1–200, one cell per column; true = check mark, null = empty
|
|
1178
|
+
| { text: string, nodeId?: string }>> } // a cell linking to an element; shown 5 rows per page
|
|
1173
1179
|
```
|
|
1174
1180
|
|
|
1175
1181
|
### How to use them
|
|
@@ -1183,6 +1189,7 @@ Rule of thumb: if you are about to write "Shall I…?", "Want me to…?", "A or
|
|
|
1183
1189
|
- **`walkthrough`** answers "how does X work?" and "walk me through what changes for Y", **one step per slice**. It opens with a summary page — the slice count (with `status`: how many exist, need adjustment, are new) above your `summary` — then shows each slice in its lanes like Slice View (screen, command / read model, events), a `new` slice sketched from its `elements` (its SCREEN rendered from the `html` you write: a real, simple page — a form, a list, a table — with inline styles only; scripts and external resources are blocked; without `html` a plain form/table is generated from the fields); each step zooms the canvas to its slice, and **Play** opens it full-screen with description, changes and rules underneath. Build it from the board, never from memory — the `walkthrough` skill (modeling kit) has the procedure. Every `nodeId`/`screenId` must be a real id from this board. Keep `text` to one line naming the feature and the number of slices.
|
|
1184
1190
|
- **`screen`** shows a mock-up in the chat — "what could the registration screen look like?", a variant to compare — without creating anything on the board (that is the `html-screen` skill's job). `html` follows the walkthrough's screen rules: body content, inline styles or one `<style>` block, no scripts, no external images, fonts or stylesheets (they are blocked), at most 16000 characters.
|
|
1185
1191
|
- **`dataJourney`** answers "where does X come from / where is X used?" for **one piece of information**, as a table: one stop per element it passes through, in flow order, each with its `role`, the field name there and the slice. A headline counts the roles ("Originates in 1 place, stored in 2 elements and used in 3 places"). Build it from the board — the `data-journey` skill (modeling kit) has the procedure; every `nodeId` must be a real id from this board, and a field the board doesn't carry is not a stop. Keep `text` to one line naming the data and where it originates.
|
|
1192
|
+
- **`table`** is for anything that is rows and columns and not a chart: a comparison of options, an incidence matrix (rows = stressors, columns = elements, `true` where it hits), a short list with a few attributes per item. It computes nothing — totals are a row you add. Put element ids in `nodeId` (header or cell) so names are links; a row longer than the columns is cut, a shorter one padded, an empty one dropped. Prefer `report` for numbers you want *seen* as a trend or share, `dataJourney` for one piece of data's path.
|
|
1186
1193
|
- A snippet is shown exactly as you send it — keep secrets and tokens out of `code` and `image`.
|
|
1187
1194
|
|
|
1188
1195
|
---
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: stressor-analysis
|
|
3
|
+
description: Residuality-theory stressor analysis of one chapter, run as a chat loop. Finds wide stressors, describes the residue of each, builds a stressor x element incidence matrix to expose hidden coupling, and proposes redesigns as new slices. Read-only until the person confirms.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Stressor analysis — what is left of the model when things go wrong
|
|
7
|
+
|
|
8
|
+
> **Before doing anything else**, invoke the `connect` skill — if not already connected — to resolve `TOKEN`, `BOARD_ID`, `ORG_ID`, and `BASE_URL`. Do not proceed until it has completed.
|
|
9
|
+
|
|
10
|
+
Prefer `mcp__eventmodelers__*` tools. See `learn-eventmodelers-api` for the curl fallback and §16 *Chat snippets* for the `tasks`, `table`, `poll` and `confirm` shapes.
|
|
11
|
+
|
|
12
|
+
The analysis runs over several chat turns: each step ends with **one** `post_chat_message` carrying one snippet, and the person's click is the next turn. In a `CHAT` turn `replyTo` = this turn's `message_id`; in a prompt turn that came from a chat, `sessionId` = `CHAT_SESSION_ID` and no `replyTo`. Find where you are from the session (`get_chat_session`): the answer to your last snippet says which step comes next.
|
|
13
|
+
|
|
14
|
+
**This skill never writes to the board** until the person says yes in Step 3 — and then only through `create_prompt`.
|
|
15
|
+
|
|
16
|
+
---
|
|
17
|
+
|
|
18
|
+
## Concepts (get these right)
|
|
19
|
+
|
|
20
|
+
- **Stressor**: anything that can happen to the system or its environment: technical, business, legal, market, people. Deliberately WIDE, far-fetched ones included. Not a risk list, not a prediction.
|
|
21
|
+
- **Residue**: what is LEFT of the system after the stressor hits: which slices still work, which state or data survives or is lost. You observe a residue; you don't build it. The fix is NOT the residue.
|
|
22
|
+
- **Goal**: change the model until every residue is acceptable. The architecture becomes the sum of those residues, so it also survives stressors nobody listed.
|
|
23
|
+
- **Incidence matrix**: stressors × elements. Elements hit by the SAME stressors are hidden-coupled.
|
|
24
|
+
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
## Step 0 — Read once
|
|
28
|
+
|
|
29
|
+
The chapter comes from `$ARGUMENTS` / the message, else the turn's `context=` (`timelineId`, selection). None and more than one chapter on the board: ask with a `poll` of the chapters (each option's `message` a complete `/stressor-analysis <chapter>` request) and end the turn.
|
|
30
|
+
|
|
31
|
+
Read once and reuse for the whole round: `get_board_outline` (gives `sliceStatus` per slice) and `get_slice_data { boardId, contextName, projection: "fields", format: "toon" }` for the chapter. Ground every statement in real element and field names; every `nodeId` you send is an id you read here.
|
|
32
|
+
|
|
33
|
+
---
|
|
34
|
+
|
|
35
|
+
## Step 1 — Stressors and their residues (`tasks`)
|
|
36
|
+
|
|
37
|
+
About **15** wide stressors. Per task: `title` = the stressor, `description` = `Residue: <what still works / what is lost>`, `nodeId` = the element most affected, `id` = `S1`, `S2`, …. `headline`: *"Tick the ones whose residue is unacceptable"*, `submitLabel`: *"These are unacceptable"*.
|
|
38
|
+
|
|
39
|
+
```
|
|
40
|
+
"snippet": { "kind": "tasks", "headline": "Tick the ones whose residue is unacceptable", "submitLabel": "These are unacceptable",
|
|
41
|
+
"tasks": [ { "id": "S1", "title": "Payment provider is down for a day", "description": "Residue: orders are placed, Order Paid never arrives — Shipping waits forever", "nodeId": "<Order Paid id>" }, … ] }
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Step 1b — Add more? (`poll`), until done
|
|
45
|
+
|
|
46
|
+
When the ticks come back, don't jump to the matrix. Acknowledge the ticks in one line and ask whether to add more stressors with a `poll`:
|
|
47
|
+
|
|
48
|
+
```
|
|
49
|
+
"snippet": { "kind": "poll", "question": "Should I add more stressors?",
|
|
50
|
+
"options": [ { "label": "Add more", "message": "Add more stressors" },
|
|
51
|
+
{ "label": "Done — build the matrix", "message": "Done with stressors, build the matrix" } ] }
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
- **Add more**: a new `tasks` list (same `headline`/`submitLabel`) of about 10 **fresh** stressors: none already offered, aimed at elements and categories (legal, people, market, data, …) the earlier rounds hit least. Ids continue the numbering (`S16`, `S17`, …). Then this poll again.
|
|
55
|
+
- **Done**: go to Step 2 with every stressor ticked across all rounds.
|
|
56
|
+
- Fewer than **5** ticked in total and the person picks Done: explain in the text that the matrix can't show coupling yet and send this poll again.
|
|
57
|
+
|
|
58
|
+
---
|
|
59
|
+
|
|
60
|
+
## Step 2 — Incidence matrix (`table`)
|
|
61
|
+
|
|
62
|
+
For each ticked stressor, list every element it hits (not just the most affected one) — from the read in Step 0, never guessed. Then one `table` snippet:
|
|
63
|
+
|
|
64
|
+
- one row per element hit at least once, sorted by hits (most first) — the hotspots on top;
|
|
65
|
+
- columns: `Element` (the cell `{text, nodeId}` as a link), `Hits` (`align: "center"`), then one column per ticked stressor, labelled `S1`, `S2` … (`align: "center"`), `true` where it hits, `null` where not;
|
|
66
|
+
- more than 10 ticked stressors: replace the stressor columns with one `Hit by` column (`"S1, S4, S9"`);
|
|
67
|
+
- `caption`: the legend, `S1 = <stressor>; S4 = …`.
|
|
68
|
+
|
|
69
|
+
```
|
|
70
|
+
"snippet": { "kind": "table", "title": "Stressors × elements", "caption": "S1 = Payment provider down; S4 = Price changes mid-checkout; …",
|
|
71
|
+
"columns": ["Element", {"label": "Hits", "align": "center"}, {"label": "S1", "align": "center"}, {"label": "S4", "align": "center"}],
|
|
72
|
+
"rows": [ [{"text": "Order Paid", "nodeId": "<id>"}, 2, true, true], [{"text": "Shipping List", "nodeId": "<id>"}, 1, true, null] ] }
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
In the text, name the **clusters** (elements hit by the same stressor pair), the shared cause behind each cluster, and the hotspots (most hits). Ask which cluster to redesign first — the matrix is this message's snippet, so the question is in the text; when the person answers in words, go on with that cluster.
|
|
76
|
+
|
|
77
|
+
---
|
|
78
|
+
|
|
79
|
+
## Step 3 — Redesign one cluster (`confirm`)
|
|
80
|
+
|
|
81
|
+
Propose new slices (translations, reconciliation todo lists, grace periods, second entry paths …) and state the **new residue** for each stressor that hit the cluster. A `confirm` snippet: `headline` = *"Add these N slices for <cluster>?"*; the slices and their new residues go in the text, kept short.
|
|
82
|
+
|
|
83
|
+
Never touch elements in non-`Created` slices without an explicit yes; name them instead ("Order Paid sits in a Done slice — I'd leave it and add a translation next to it").
|
|
84
|
+
|
|
85
|
+
## Step 4 — On yes
|
|
86
|
+
|
|
87
|
+
One `create_prompt` per new slice (`originMessageId` = the yes), phrased so the prompt turn can do it on its own (chapter, slice name, its elements and fields). Reply in one line. A no: acknowledge it and offer the next cluster.
|
|
88
|
+
|
|
89
|
+
## Step 5 — Validate
|
|
90
|
+
|
|
91
|
+
Generate a **fresh** set of stressors not used in rounds 1–3, and compare how many have an acceptable residue before vs after the redesign (the residual index) — a `tasks` list again, the person ticks the unacceptable ones, and the text states the index ("before: 6 of 12 acceptable, after: 10 of 12"). Repeat rounds until new stressors stop hitting new elements.
|
|
92
|
+
|
|
93
|
+
---
|
|
94
|
+
|
|
95
|
+
## Chat style
|
|
96
|
+
|
|
97
|
+
- Explain a residue with a before/after example if asked (same stressor, different leftover).
|
|
98
|
+
- Text ≤ 1000 characters; the detail goes in the snippet.
|
|
99
|
+
- No ids or cell addresses in the text — element names are enough.
|
|
100
|
+
|
|
101
|
+
**No chat** (run from a terminal): print the stressors with residues, ask which are unacceptable, then whether to add more (repeat until done), and print the matrix as a table instead of posting.
|
|
@@ -212,9 +212,13 @@ for it. Instead:
|
|
|
212
212
|
**one piece of information** (a field, "the customer email"): run the `/data-journey` skill **in this turn** — it only reads
|
|
213
213
|
the board, so no prompt is needed. Its `dataJourney` snippet (a table: origin, stored, transformed, used, sent — per element,
|
|
214
214
|
with the field name there) is your one reply. Without a clear subject it asks first which information.
|
|
215
|
+
- **stressor analysis** — "what breaks if …?", "stress-test this chapter", or `/stressor-analysis …`: run the
|
|
216
|
+
`/stressor-analysis` skill **in this turn** — it only reads the board until the person says yes, so no prompt is needed
|
|
217
|
+
for its steps. It is a loop over several turns (stressors as `tasks`, the incidence matrix as a `table`, a redesign as
|
|
218
|
+
`confirm`); an answer to one of its snippets continues it at the next step. Only the confirmed new slices become prompts.
|
|
215
219
|
- **a skill by name** — the message starts with `/<name>` of one of your skills (the chat panel's menu
|
|
216
|
-
writes these: `/analyze-existing-model`, `/analyze-code-base`, `/detect-model-drift`, `/
|
|
217
|
-
`/html-screen
|
|
220
|
+
writes these: `/analyze-existing-model`, `/analyze-code-base`, `/detect-model-drift`, `/timeline …`,
|
|
221
|
+
`/storyboard …`; `/add-next-slice`, `/examples`, `/html-screen …` can still be typed): the person chose that skill, so it **is** the work — create one prompt,
|
|
218
222
|
*"Run /<name> <the rest of the message>"*, with the target resolved from `context=` like any other
|
|
219
223
|
(selected elements, chapter), and say so in one line. Don't re-interpret it as a question. A skill that
|
|
220
224
|
needs something the message lacks (which attribute? which screen?) is a **clarify**: ask, with a
|
|
@@ -279,7 +283,8 @@ for it. Instead:
|
|
|
279
283
|
- a **list of things for the person to pick from** (findings, candidates, drifts, "which of these?") → `tasks`;
|
|
280
284
|
- a **pointer to an element, a picture or a command** → `link` / `image` / `code`, instead of describing it.
|
|
281
285
|
- a **screen idea** in the conversation ("what could that screen look like?") → `screen`, a sandboxed HTML mock-up in the chat; putting a screen on the board is `/html-screen` work;
|
|
282
|
-
- **where one piece of information comes from and where it is used** → `dataJourney` (the `/data-journey` skill)
|
|
286
|
+
- **where one piece of information comes from and where it is used** → `dataJourney` (the `/data-journey` skill);
|
|
287
|
+
- **rows and columns** — a comparison, a matrix, a short list with a few attributes per item → `table`.
|
|
283
288
|
Plain text stays for answers, explanations and open questions that need words. `text` is still
|
|
284
289
|
required and stays short — it is the lead-in, the snippet carries the detail. A snippet changes
|
|
285
290
|
nothing on the board: the click comes back as the next `CHAT` turn, and only then do you
|