@eventmodelers/cli 1.0.67 → 1.0.68

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
@@ -2212,15 +2212,32 @@ async function runModeling(kitDir, projectDir, verbose = false, standalone = fal
2212
2212
  }
2213
2213
  }
2214
2214
 
2215
+ // A kill names exactly one agent: {type: 'kill', id: '<agentId>', instruction: 'exit'}. Anything
2216
+ // that doesn't name this agent is ignored — a broadcast reaches every agent on the board, and
2217
+ // the older signal (the bare string "Exit") took all of them down at once. That string form is
2218
+ // gone for good, not just unhandled: Supabase's broadcast API rejects a non-object payload with
2219
+ // 422, so it never actually arrived here.
2220
+ const exitIfAddressed = (payload) => {
2221
+ if (payload?.type !== 'kill' || payload?.id !== cfg.agentId) return;
2222
+ log(`received kill (instruction: ${payload.instruction ?? 'exit'}) — shutting down`);
2223
+ process.exit(0);
2224
+ };
2225
+
2226
+ // The kill signal is broadcast on the BOARD channel (see the platform's agent-kill /
2227
+ // backoffice/killagent slices), not on the org channel this agent uses for prompts — without
2228
+ // this second subscription a modeling agent can only be stopped with a kill(1).
2229
+ realtime.subscribe(
2230
+ `board:${cfg.boardId}-slicechanged`,
2231
+ {message: exitIfAddressed},
2232
+ (status) => log(`channel "board:${cfg.boardId}-slicechanged": ${status}`),
2233
+ ).catch((err) => {
2234
+ log(`board channel subscribe failed, remote kill won't reach this agent: ${err.message}`);
2235
+ });
2236
+
2215
2237
  realtime.subscribe(
2216
2238
  channelName,
2217
2239
  {
2218
- message: (payload) => {
2219
- if (payload === 'Exit') {
2220
- log('received "Exit" — shutting down');
2221
- process.exit(0);
2222
- }
2223
- },
2240
+ message: exitIfAddressed,
2224
2241
  'prompt:created': () => {
2225
2242
  drain().catch((err) => log(`drain error: ${err.message}`));
2226
2243
  },
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@eventmodelers/cli",
3
- "version": "1.0.67",
3
+ "version": "1.0.68",
4
4
  "description": "Eventmodelers CLI — real-time Claude agent + skills for Claude Code, for any stack (Node, Supabase, Axon, Cratis, OpenCQRS, UmaDB, Kurrent, or modeling-only)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -316,11 +316,15 @@ async function startRealtimeAgent(cfg, kitDir, { agentType = 'BUILD', queueAllSt
316
316
  realtime.subscribe(
317
317
  channelName,
318
318
  {
319
+ // A kill names exactly one agent: {type: 'kill', id: '<agentId>', instruction: 'exit'}.
320
+ // Anything that doesn't name this agent is ignored — a broadcast reaches every agent on
321
+ // the board, and the older signal (the bare string "Exit") took all of them down at once.
322
+ // That string form is gone for good, not just unhandled: Supabase's broadcast API rejects
323
+ // a non-object payload with 422, so it never actually arrived here.
319
324
  message: (payload) => {
320
- if (payload === 'Exit') {
321
- console.log(`[agent] ${ts()} Received "Exit" — shutting down`);
322
- process.exit(0);
323
- }
325
+ if (payload?.type !== 'kill' || payload?.id !== cfg.agentId) return;
326
+ console.log(`[agent] ${ts()} Received kill (instruction: ${payload.instruction ?? 'exit'}) — shutting down`);
327
+ process.exit(0);
324
328
  },
325
329
  'slice:changed': (payload) => handleSliceChanged(payload, cfg, kitDir, queueAllStatuses),
326
330
  },
@@ -181,11 +181,12 @@ Steps:
181
181
  6. **If you already said it, don't say it again.** Before posting a comment — or having a
182
182
  subagent post one — read the node's existing comments. An unresolved question already
183
183
  there means that contribution is on the board.
184
- 7. **Write no progress entry.** A self-directed turn is modeling, not tracked progress —
185
- nothing goes into `progress.txt` here (that file belongs to prompt turns, which answer to
186
- someone who asked). Still promote anything reusable to `.agent-modeling-kit/AGENTS.md`
187
- (same as step 9 of a prompt turn in `.agent-modeling-kit/CLAUDE.md`), including anything a
188
- subagent reported back.
184
+ 7. **Write nothing to disk.** A self-directed turn is modeling, not tracked progress — nothing
185
+ goes into `progress.txt`, and nothing into `.agent-modeling-kit/AGENTS.md` either. You only
186
+ ever get here in a `standalone=on` session, which is ad-hoc: its kit dir is shared across
187
+ every board and nobody reads it afterwards. The board is the only place anything is kept, so
188
+ anything reusable — including what a subagent reported back — goes there, as a comment on the
189
+ node it concerns.
189
190
  8. Reply `<promise>DONE</promise>`, naming what you dispatched and what each agent did, or —
190
191
  when step 2 turned up nothing worth doing — change nothing at all and reply
191
192
  `<promise>NOOP</promise>`. A NOOP is a perfectly good outcome, and the CLI widens the gap
@@ -12,6 +12,20 @@ for their independent, self-contained slice-implementation tasks). Each user mes
12
12
  receive already IS the one prompt to handle; there's nothing to read, pre-filter, or pick
13
13
  from.
14
14
 
15
+ ### `standalone=on` is ad-hoc — write nothing to disk
16
+
17
+ The session header carries `standalone=on` or `standalone=off`. `standalone=on` is an **ad-hoc**
18
+ session: it belongs to no project, its kit dir is a `~/.eventmodelers/kit` shared by every board,
19
+ and nobody goes looking in there afterwards. So in a `standalone=on` session the **board is the
20
+ only place anything is kept** — comments, elements, slice statuses, scenarios. Write no file at
21
+ all: no `progress.txt` (step 8), no `.agent-modeling-kit/AGENTS.md` (step 9), and nothing a skill's
22
+ own instructions suggest writing down either. Anything worth keeping goes on the board, as a
23
+ comment on the node it concerns. This overrides every "write it down" instruction elsewhere in this
24
+ file and in any skill.
25
+
26
+ With `standalone=off` the session belongs to one project and the kit dir is that project's, so
27
+ steps 8 and 9 apply as written.
28
+
15
29
  You are a long-lived process handling many turns in a row. **Read this file once**, on
16
30
  the first turn (the one whose message begins with `MODE=modeling`) — don't re-read it on
17
31
  every later turn just because a new prompt came in. The same applies to other one-time
@@ -122,8 +136,8 @@ mention it in the `DONE` comment, and leave it for a self-directed turn (or for
122
136
  - If it doesn't — the prompt is ambiguous enough that any guess risks doing the wrong thing — stop instead of guessing. Skip straight to step 6 and mark the prompt `DONE` with a comment explaining what's unclear and pointing to the comment you just posted. Never leave a prompt neither progressed nor closed.
123
137
  6. **Mark the prompt as finished** — invoke `/update-prompt-status` with this turn's `prompt_id`, `newStatus=DONE`, and a `comment` that summarizes what you actually did (e.g. "Added the OrderPlaced event and wired it to the read model"). Do this once, right after the work is done — not per skill call within the turn.
124
138
  7. If this turn has a `comment_id` field, invoke `/handle-comment` with `action=resolve`, `nodeId` from the resolved `NODE_ID` (step 3), `commentId` from `comment_id`.
125
- 8. Append a progress entry to `progress.txt` see the Progress Entry Format below. Fill in the `Learnings` line with anything reusable noticed this turn (pattern, gotcha, useful context), or "none".
126
- 9. If this turn's `Learnings` line was not "none", promote it to `.agent-modeling-kit/AGENTS.md` (create it if it doesn't exist) — only add it if it's not already there.
139
+ 8. **`standalone=off` only** — append a progress entry to `progress.txt`; see the Progress Entry Format below. Fill in the `Learnings` line with anything reusable noticed this turn (pattern, gotcha, useful context), or "none". In a `standalone=on` session, skip this: that session writes no files (see Mode), so note anything worth keeping as a board comment instead.
140
+ 9. **`standalone=off` only** — if this turn's `Learnings` line was not "none", promote it to `.agent-modeling-kit/AGENTS.md` (create it if it doesn't exist) — only add it if it's not already there.
127
141
  10. Reply `<promise>DONE</promise>` and wait for the next turn.
128
142
 
129
143
 
@@ -197,7 +211,8 @@ Read `.claude/skills/<skill-name>/SKILL.md` before executing — each skill has
197
211
 
198
212
  ## Progress Entry Format
199
213
 
200
- Prompt turns only a standalone board-change turn never writes one.
214
+ `standalone=off` prompt turns only. A `standalone=on` session writes no progress file at all (see
215
+ Mode), and a self-directed board-change turn never writes one in any session.
201
216
 
202
217
  APPEND to `progress.txt` (never replace):
203
218
  ```