@eventmodelers/cli 1.0.110 → 1.0.111

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/cli.js CHANGED
@@ -1949,7 +1949,7 @@ async function ensureGlobalKit(baseUrl) {
1949
1949
  // untargeted is handed straight back to the queue for another agent to take. It says
1950
1950
  // nothing about the standalone lane — a self-directed turn is nobody's task, so an
1951
1951
  // exclusive standalone agent still works the board on its own initiative.
1952
- async function runModeling(kitDir, projectDir, { verbose = false, standalone = false, exclusive = false, worker = false, overrides = null, maxAgents = DEFAULT_MAX_AGENTS, identity = {}, localAi = null, exec = null, model = null } = {}) {
1952
+ async function runModeling(kitDir, projectDir, { codeDir = null, verbose = false, standalone = false, exclusive = false, worker = false, overrides = null, maxAgents = DEFAULT_MAX_AGENTS, identity = {}, localAi = null, exec = null, model = null } = {}) {
1953
1953
  // --worker: only prompts — no chat, and no board-change turns (it has nowhere to propose).
1954
1954
  const chat = !worker;
1955
1955
  const configLibPath = join(kitDir, 'lib', 'config.js');
@@ -2104,8 +2104,13 @@ async function runModeling(kitDir, projectDir, { verbose = false, standalone = f
2104
2104
 
2105
2105
  const claudeArgs = ['--dangerously-skip-permissions', '-p', '--input-format', 'stream-json', '--output-format', 'stream-json', '--verbose'];
2106
2106
  if (cfg.model) claudeArgs.push('--model', cfg.model);
2107
+ // The global install runs in ~/.eventmodelers/kit, away from the code base the person started
2108
+ // the agent in — hand that directory over so code-reading skills (detect-architecture-drift)
2109
+ // can still see it.
2110
+ if (codeDir) claudeArgs.push('--add-dir', codeDir);
2107
2111
  const claudeEnv = {
2108
2112
  ...process.env,
2113
+ ...(codeDir ? { EVENTMODELERS_CODE_DIR: codeDir } : {}),
2109
2114
  ...(cfg.anthropicBaseUrl ? { ANTHROPIC_BASE_URL: cfg.anthropicBaseUrl } : {}),
2110
2115
  EVENTMODELERS_TOKEN: cfg.token,
2111
2116
  // What the connect skill puts in `.mcp.json`'s x-agent-id header and every curl-fallback
@@ -3762,7 +3767,9 @@ credentialFlags(program
3762
3767
  }
3763
3768
  let projectDir = kitDir ? resolve(kitDir, '..') : null;
3764
3769
  let overrides = null;
3770
+ let codeDir = null;
3765
3771
  if (!kitDir) {
3772
+ codeDir = cwd;
3766
3773
  // The blob and the individual flags are both "explicit", so they share a
3767
3774
  // precedence tier — with a single --token/--board-id winning, since overriding one
3768
3775
  // field of a pasted blob is the only reason to pass both.
@@ -3785,7 +3792,7 @@ credentialFlags(program
3785
3792
  const runnerLabel = modelingLocalAi ? 'local model' : opts.exec ? 'one agent process per turn' : 'warm Claude process';
3786
3793
  await new Promise((res) => process.stdout.write(`▶ Starting modeling loop (${runnerLabel}) for ${shown && !shown.startsWith('..') ? shown : kitDir}...\n\n`, res));
3787
3794
  try {
3788
- await runModeling(kitDir, projectDir, { verbose: !!opts.verbose, standalone: !!opts.standalone, exclusive: !!opts.exclusive, worker: !!opts.worker, overrides, maxAgents, identity, localAi: modelingLocalAi, exec: opts.exec ?? null, model: !opts.exec && modelingLocalAi === null ? model : null });
3795
+ await runModeling(kitDir, projectDir, { codeDir, verbose: !!opts.verbose, standalone: !!opts.standalone, exclusive: !!opts.exclusive, worker: !!opts.worker, overrides, maxAgents, identity, localAi: modelingLocalAi, exec: opts.exec ?? null, model: !opts.exec && modelingLocalAi === null ? model : null });
3789
3796
  } catch (err) {
3790
3797
  console.error('[modeling] Fatal:', err);
3791
3798
  process.exit(1);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.110",
3
+ "version": "1.0.111",
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": {
@@ -1121,7 +1121,8 @@ Rule of thumb: if you are about to write "Shall I…?", "Want me to…?", "A or
1121
1121
  { kind: 'code', code: string, language?: string, title?: string } // monospaced, with a copy button
1122
1122
  { kind: 'report', chart: 'bar' | 'line' | 'pie', title?: string, unit?: string,
1123
1123
  labels: string[], // 1–50 points: x axis, or the pie slices
1124
- series: Array<{ name: string, values: number[] }> } // one number per label; bar/line up to 6 series, pie uses only the first (no negatives)
1124
+ series: Array<{ name: string, values: number[] }>, // one number per label; bar/line up to 6 series, pie uses only the first (no negatives)
1125
+ confirm?: { headline: string, yesLabel?: string, noLabel?: string } } // optional yes/no question under the diagram, like a confirm snippet
1125
1126
  ```
1126
1127
 
1127
1128
  ### How to use them
@@ -1131,7 +1132,7 @@ Rule of thumb: if you are about to write "Shall I…?", "Want me to…?", "A or
1131
1132
  - **Name elements** with `nodeId` wherever you can (`tasks`, `changes`, `link`), so the person can click through to them — in a `tasks` list, put the element's name in `description` and its id in `nodeId`.
1132
1133
  - **Answers are text.** For a `tasks` answer, match the titles (or ids) back to your list; an element the person left unticked was declined, not forgotten. A `poll` option with a `message` of your own makes the answer unambiguous.
1133
1134
  - `get_chat_session` shows your snippet on the message as `snippet`, and the person's answer is the user message after it, carrying `context.snippetReply.messageId` (your message's id) — useful to tell an answer to a snippet from a new message.
1134
- - **`report`** draws the numbers you send — it computes nothing, so aggregate first. A series whose length differs from `labels`, or a non-number, makes the whole snippet invisible. Keep `text` as a one-line summary of what the diagram shows.
1135
+ - **`report`** draws the numbers you send — it computes nothing, so aggregate first. A series whose length differs from `labels`, or a non-number, makes the whole snippet invisible. Keep `text` as a one-line summary of what the diagram shows. Add `confirm` when the diagram leads to a follow-up question ("Want me to look into the backward arrows?"): the answer comes back like a `confirm` answer, and without it the report is display only.
1135
1136
  - A snippet is shown exactly as you send it — keep secrets and tokens out of `code` and `image`.
1136
1137
 
1137
1138
  ---
@@ -215,10 +215,12 @@ mcp__eventmodelers__post_chat_message {
215
215
  "snippet": {
216
216
  "kind": "report", "chart": "pie", "title": "Slices by status", "unit": "slices",
217
217
  "labels": ["Done", "InProgress", "Planned", "Blocked"],
218
- "series": [{ "name": "Slices", "values": [12, 6, 4, 2] }]
218
+ "series": [{ "name": "Slices", "values": [12, 6, 4, 2] }],
219
+ "confirm": { "headline": "Want the full list of slices without scenarios?" }
219
220
  }
220
221
  }
221
222
  ```
223
+ - `confirm` is optional: use it when you end on a follow-up question, instead of asking it in the text; the answer arrives as the person's next chat message.
222
224
  - Only statuses with at least one slice, one number per label — the chart draws exactly what you send, so count first.
223
225
  - One snippet per message: if the person asks for more diagrams (spec coverage, element inventory per type as a `bar`),
224
226
  answer each in its own reply.
@@ -7,7 +7,7 @@ description: Compare the event model on the board with the code in this reposito
7
7
 
8
8
  ## Step 0 — Is there a code base?
9
9
 
10
- Drift is the gap between the board and the code, so it can only be detected where code exists. **Before anything else — before `connect`, before reading the board — check that the current directory is a code base**: it contains source code (e.g. `src/`, `.build-kit/`, a `package.json`, `pom.xml`, `*.csproj`, `build.gradle`, or similar project files with slice/command/event/projection code).
10
+ Drift is the gap between the board and the code, so it can only be detected where code exists. **Before anything else — before `connect`, before reading the board — resolve the directory to check**: `$EVENTMODELERS_CODE_DIR` if it is set (the agent runs from the global install and was started inside that directory — treat it as the repository root for every step below, not the current directory), otherwise the current directory. Check that it is a code base: it contains source code (e.g. `src/`, `.build-kit/`, a `package.json`, `pom.xml`, `*.csproj`, `build.gradle`, or similar project files with slice/command/event/projection code).
11
11
 
12
12
  If it is not (an empty folder, a modeling-only workspace holding just `.claude/`, `.eventmodelers/` or `.agent-modeling-kit/`), **stop and answer in one or two plain sentences**, e.g.:
13
13
 
@@ -58,7 +58,7 @@ Index the result in memory: per slice → commands, events, read models, screens
58
58
 
59
59
  ## Step 3 — Understand the code
60
60
 
61
- You are in a repository that may hold any stack. Find out which, don't assume.
61
+ The code base is the directory resolved in Step 0 (`$EVENTMODELERS_CODE_DIR`, else the current directory) — every path below is relative to it, and it may hold any stack. Find out which, don't assume.
62
62
 
63
63
  1. Read `.build-kit/CLAUDE.md` (and `.build-kit/AGENTS.md` if present) — its *Structure* section says where slices live and how they're named (e.g. `src/slices/{slice}/` for Node, `src/main/java/.../slices/{context}/{slice}/` for Axon).
64
64
  2. If `.build-kit/.slices/<context>/<slice>/slice.json` exists, it is the snapshot the code was **last built from** — useful for telling "the code changed" apart from "the model changed since the build" (see Step 5).