monomind 2.0.0 → 2.0.2

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.
Files changed (35) hide show
  1. package/README.md +11 -12
  2. package/package.json +2 -2
  3. package/packages/@monomind/cli/.claude/helpers/token-tracker.cjs +10 -0
  4. package/packages/@monomind/cli/README.md +11 -12
  5. package/packages/@monomind/cli/dist/src/browser/dashboard/server.js +71 -12
  6. package/packages/@monomind/cli/dist/src/browser/dashboard/ui.html +4 -4
  7. package/packages/@monomind/cli/dist/src/commands/browse-workflow.js +2 -2
  8. package/packages/@monomind/cli/dist/src/index.js +8 -7
  9. package/packages/@monomind/cli/dist/src/mcp-tools/coherence/types.d.ts +18 -18
  10. package/packages/@monomind/cli/dist/src/mcp-tools/quality/coverage-analysis/prioritize-gaps.d.ts +12 -12
  11. package/packages/@monomind/cli/dist/src/mcp-tools/quality/security-compliance/detect-secrets.d.ts +4 -4
  12. package/packages/@monomind/cli/dist/src/orgrt/bus.d.ts +23 -0
  13. package/packages/@monomind/cli/dist/src/orgrt/bus.js +64 -0
  14. package/packages/@monomind/cli/dist/src/orgrt/daemon.d.ts +41 -0
  15. package/packages/@monomind/cli/dist/src/orgrt/daemon.js +101 -0
  16. package/packages/@monomind/cli/dist/src/orgrt/forwarder.d.ts +11 -0
  17. package/packages/@monomind/cli/dist/src/orgrt/forwarder.js +37 -0
  18. package/packages/@monomind/cli/dist/src/orgrt/mailbox.d.ts +25 -0
  19. package/packages/@monomind/cli/dist/src/orgrt/mailbox.js +39 -0
  20. package/packages/@monomind/cli/dist/src/orgrt/policy.d.ts +24 -0
  21. package/packages/@monomind/cli/dist/src/orgrt/policy.js +86 -0
  22. package/packages/@monomind/cli/dist/src/orgrt/provider.d.ts +9 -0
  23. package/packages/@monomind/cli/dist/src/orgrt/provider.js +54 -0
  24. package/packages/@monomind/cli/dist/src/orgrt/session.d.ts +23 -0
  25. package/packages/@monomind/cli/dist/src/orgrt/session.js +78 -0
  26. package/packages/@monomind/cli/dist/src/orgrt/types.d.ts +847 -0
  27. package/packages/@monomind/cli/dist/src/orgrt/types.js +51 -0
  28. package/packages/@monomind/cli/dist/src/parser.js +31 -5
  29. package/packages/@monomind/cli/dist/src/ui/collector.mjs +69 -44
  30. package/packages/@monomind/cli/dist/src/ui/dashboard.html +112 -25
  31. package/packages/@monomind/cli/dist/src/ui/orgs.html +54 -0
  32. package/packages/@monomind/cli/dist/src/ui/server.mjs +87 -12
  33. package/packages/@monomind/cli/package.json +3 -2
  34. package/packages/@monomind/cli/dist/src/consensus/vote-signer.d.ts +0 -36
  35. package/packages/@monomind/cli/dist/src/consensus/vote-signer.js +0 -88
package/README.md CHANGED
@@ -66,7 +66,7 @@ flowchart TD
66
66
  R["Reviewer"]
67
67
  M["Growth Marketer"]
68
68
  BOARD[("Shared\nTask Board")]
69
- MEM[("LanceDB\nMemory")]
69
+ MEM[("Persistent\nMemory")]
70
70
 
71
71
  U --> CO --> RO --> BOSS
72
72
  BOSS -->|spawns| W
@@ -126,7 +126,7 @@ Type "go" to save, or describe changes.
126
126
  | **Boss agent** | Coordinator type, no supervisor — owns the goal |
127
127
  | **Role agents** | Spawned on demand, specialized by task type |
128
128
  | **Task board** | Todo → Doing → Done, shared across all agents |
129
- | **Memory** | All output stored in org-scoped LanceDB namespace |
129
+ | **Memory** | All output stored in an org-scoped memory namespace |
130
130
  | **Checkpoint** | State saved every 30 min — survives crashes and restarts |
131
131
  | **Governance** | `auto` (free), `board` (approve sensitive), `strict` (approve all external actions) |
132
132
 
@@ -218,13 +218,13 @@ Open Claude Code. You now have 80+ slash commands available:
218
218
 
219
219
  ## 🧠 Memory That Persists
220
220
 
221
- Every session, every agent, every org writes to **LanceDB** — a hybrid SQLite + HNSW vector store that survives across sessions. The next time you run anything, Monomind already knows what was built, what failed, and which patterns work.
221
+ Every session, every agent, every org writes to a persistent memory store — a JSON pattern store with episodic recall that survives across sessions. The next time you run anything, Monomind already knows what was built, what failed, and which patterns work.
222
222
 
223
223
  ```mermaid
224
224
  graph TD
225
225
  L0["L0 - In-flight\nCurrent session drawers\nephemeral"]
226
226
  L1["L1 - Working\nCross-session memory\nBM25 K1=1.5, B=0.75"]
227
- L2["L2 - Long-term\nLanceDB + HNSW index\nSemantic search"]
227
+ L2["L2 - Long-term\nEpisodic store\nSemantic recall"]
228
228
  L3["L3 - Shared\nCross-agent namespace\nFederated swarm reads"]
229
229
 
230
230
  L0 -->|promoted| L1 --> L2 --> L3
@@ -256,7 +256,7 @@ Before touching any file, Monomind queries **Monograph** — a SQLite-backed kno
256
256
  # → "find all callers of validateToken()"
257
257
  ```
258
258
 
259
- 23 MCP tools. Impact analysis. Shortest-path queries. Community detection. Zero grep.
259
+ 19 default MCP tools (+27 advanced via `MONOGRAPH_MCP_ADVANCED=1`). Impact analysis. Community detection. Zero grep.
260
260
 
261
261
  ---
262
262
 
@@ -272,11 +272,11 @@ flowchart LR
272
272
  H --> I["route\nlearn\nbuild-agents"]
273
273
  H --> T["teammate-idle\ntask-completed"]
274
274
 
275
- I --> DB[("LanceDB\npatterns.json")]
275
+ I --> DB[("patterns.json\nmemory store")]
276
276
  DB -->|next session| CE
277
277
  ```
278
278
 
279
- **12 background workers** run continuously: `security` · `health` · `swarm` · `learning` · `patterns` · `git` · `performance` and more.
279
+ **15 background workers** run at session start (staleness-gated, refreshed when older than 6 hours): `security` · `health` · `swarm` · `learning` · `patterns` · `git` · `performance` and more.
280
280
 
281
281
  ---
282
282
 
@@ -338,7 +338,7 @@ Everything runs from inside Claude Code via slash commands. Here's the highlight
338
338
  | Package | npm | Purpose |
339
339
  |---|---|---|
340
340
  | `monomind` | [![npm](https://img.shields.io/npm/v/monomind?style=flat-square&color=00D2AA)](https://www.npmjs.com/package/monomind) | Umbrella — **install this one** |
341
- | `@monoes/monomindcli` | [![npm](https://img.shields.io/npm/v/@monoes/monomindcli?style=flat-square&color=4F46E5)](https://www.npmjs.com/package/@monoes/monomindcli) | CLI engine (41 commands) |
341
+ | `@monoes/monomindcli` | [![npm](https://img.shields.io/npm/v/@monoes/monomindcli?style=flat-square&color=4F46E5)](https://www.npmjs.com/package/@monoes/monomindcli) | CLI engine (31 commands) |
342
342
  | `monofence-ai` | [![npm](https://img.shields.io/npm/v/monofence-ai?style=flat-square&color=EF4444)](https://www.npmjs.com/package/monofence-ai) | AI manipulation defence |
343
343
  | `@monoes/monograph` | [![npm](https://img.shields.io/npm/v/@monoes/monograph?style=flat-square&color=F59E0B)](https://www.npmjs.com/package/@monoes/monograph) | Code knowledge graph |
344
344
 
@@ -352,13 +352,13 @@ graph TD
352
352
  MCP["MCP Server\nmonomind mcp start"]
353
353
  D["Background Workers\n(@monomind/hooks, in-process)"]
354
354
 
355
- CC <-->|"23 tools: monograph, memory, swarm"| MCP
355
+ CC <-->|"MCP tools: monograph, memory, swarm"| MCP
356
356
  MCP <--> D
357
357
 
358
- D --> ADB[("LanceDB\nSQLite + HNSW")]
358
+ D --> ADB[("Memory store\npatterns + episodes")]
359
359
  D --> MG[("Monograph\ncode graph")]
360
360
  D --> HK["Hooks\n22 event types"]
361
- D --> SW["Swarm\n6 topologies\n5 consensus algos"]
361
+ D --> SW["Swarm\n4 topologies\n3 consensus strategies"]
362
362
 
363
363
  CC -->|"Task tool - spawns agents"| AG["Agent Swarm\narchitect, coder\ntester, reviewer\nsecurity, perf"]
364
364
  AG <-->|reads and writes| ADB
@@ -380,7 +380,6 @@ graph TD
380
380
  - 📋 [All Slash Commands](https://monoes.github.io/monomind/#slash)
381
381
  - 🐛 [Issues](https://github.com/monoes/monomind/issues)
382
382
  - 💬 [Discussions](https://github.com/monoes/monomind/discussions)
383
- - 📦 [Changelog v1.11](https://github.com/monoes/monomind/blob/main/CHANGELOG-v1.11.md)
384
383
 
385
384
  ---
386
385
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "monomind",
3
- "version": "2.0.0",
3
+ "version": "2.0.2",
4
4
  "description": "Monomind - Power toolkit for Claude Code. Autonomous agent orgs, codebase knowledge graph, keyword-routed specialist prompts, and 80+ slash commands. One init, then walk away.",
5
5
  "main": "dist/index.js",
6
6
  "type": "module",
@@ -60,7 +60,7 @@
60
60
  "v1:security": "npm run security:audit && npm run security:test"
61
61
  },
62
62
  "dependencies": {
63
- "@monoes/monobrowse": "^1.0.2",
63
+ "@monoes/monobrowse": "^1.0.3",
64
64
  "@monoes/monograph": "^1.4.0",
65
65
  "mammoth": "^1.12.0",
66
66
  "pdf-parse": "^2.4.5",
@@ -14,6 +14,11 @@ const path = require('path');
14
14
  const WEB_SEARCH_COST = 0.01;
15
15
 
16
16
  const FALLBACK_PRICING = {
17
+ 'claude-fable-5': { in: 10e-6, out: 50e-6, cw: 12.5e-6, cr: 1e-6, fast: 1 },
18
+ 'claude-mythos-5': { in: 10e-6, out: 50e-6, cw: 12.5e-6, cr: 1e-6, fast: 1 },
19
+ 'claude-opus-4-8': { in: 5e-6, out: 25e-6, cw: 6.25e-6, cr: 0.5e-6, fast: 6 },
20
+ 'claude-opus-4-7': { in: 5e-6, out: 25e-6, cw: 6.25e-6, cr: 0.5e-6, fast: 6 },
21
+ 'claude-sonnet-5': { in: 3e-6, out: 15e-6, cw: 3.75e-6, cr: 0.3e-6, fast: 1 },
17
22
  'claude-opus-4-6': { in: 5e-6, out: 25e-6, cw: 6.25e-6, cr: 0.5e-6, fast: 6 },
18
23
  'claude-opus-4-5': { in: 5e-6, out: 25e-6, cw: 6.25e-6, cr: 0.5e-6, fast: 1 },
19
24
  'claude-opus-4-1': { in: 15e-6, out: 75e-6, cw: 18.75e-6, cr: 1.5e-6, fast: 1 },
@@ -32,6 +37,11 @@ const FALLBACK_PRICING = {
32
37
  };
33
38
 
34
39
  const SHORT_MODEL_NAMES = {
40
+ 'claude-fable-5': 'Fable 5',
41
+ 'claude-mythos-5': 'Mythos 5',
42
+ 'claude-opus-4-8': 'Opus 4.8',
43
+ 'claude-opus-4-7': 'Opus 4.7',
44
+ 'claude-sonnet-5': 'Sonnet 5',
35
45
  'claude-opus-4-6': 'Opus 4.6',
36
46
  'claude-opus-4-5': 'Opus 4.5',
37
47
  'claude-opus-4-1': 'Opus 4.1',
@@ -66,7 +66,7 @@ flowchart TD
66
66
  R["Reviewer"]
67
67
  M["Growth Marketer"]
68
68
  BOARD[("Shared\nTask Board")]
69
- MEM[("LanceDB\nMemory")]
69
+ MEM[("Persistent\nMemory")]
70
70
 
71
71
  U --> CO --> RO --> BOSS
72
72
  BOSS -->|spawns| W
@@ -126,7 +126,7 @@ Type "go" to save, or describe changes.
126
126
  | **Boss agent** | Coordinator type, no supervisor — owns the goal |
127
127
  | **Role agents** | Spawned on demand, specialized by task type |
128
128
  | **Task board** | Todo → Doing → Done, shared across all agents |
129
- | **Memory** | All output stored in org-scoped LanceDB namespace |
129
+ | **Memory** | All output stored in an org-scoped memory namespace |
130
130
  | **Checkpoint** | State saved every 30 min — survives crashes and restarts |
131
131
  | **Governance** | `auto` (free), `board` (approve sensitive), `strict` (approve all external actions) |
132
132
 
@@ -218,13 +218,13 @@ Open Claude Code. You now have 80+ slash commands available:
218
218
 
219
219
  ## 🧠 Memory That Persists
220
220
 
221
- Every session, every agent, every org writes to **LanceDB** — a hybrid SQLite + HNSW vector store that survives across sessions. The next time you run anything, Monomind already knows what was built, what failed, and which patterns work.
221
+ Every session, every agent, every org writes to a persistent memory store — a JSON pattern store with episodic recall that survives across sessions. The next time you run anything, Monomind already knows what was built, what failed, and which patterns work.
222
222
 
223
223
  ```mermaid
224
224
  graph TD
225
225
  L0["L0 - In-flight\nCurrent session drawers\nephemeral"]
226
226
  L1["L1 - Working\nCross-session memory\nBM25 K1=1.5, B=0.75"]
227
- L2["L2 - Long-term\nLanceDB + HNSW index\nSemantic search"]
227
+ L2["L2 - Long-term\nEpisodic store\nSemantic recall"]
228
228
  L3["L3 - Shared\nCross-agent namespace\nFederated swarm reads"]
229
229
 
230
230
  L0 -->|promoted| L1 --> L2 --> L3
@@ -256,7 +256,7 @@ Before touching any file, Monomind queries **Monograph** — a SQLite-backed kno
256
256
  # → "find all callers of validateToken()"
257
257
  ```
258
258
 
259
- 23 MCP tools. Impact analysis. Shortest-path queries. Community detection. Zero grep.
259
+ 19 default MCP tools (+27 advanced via `MONOGRAPH_MCP_ADVANCED=1`). Impact analysis. Community detection. Zero grep.
260
260
 
261
261
  ---
262
262
 
@@ -272,11 +272,11 @@ flowchart LR
272
272
  H --> I["route\nlearn\nbuild-agents"]
273
273
  H --> T["teammate-idle\ntask-completed"]
274
274
 
275
- I --> DB[("LanceDB\npatterns.json")]
275
+ I --> DB[("patterns.json\nmemory store")]
276
276
  DB -->|next session| CE
277
277
  ```
278
278
 
279
- **12 background workers** run continuously: `security` · `health` · `swarm` · `learning` · `patterns` · `git` · `performance` and more.
279
+ **15 background workers** run at session start (staleness-gated, refreshed when older than 6 hours): `security` · `health` · `swarm` · `learning` · `patterns` · `git` · `performance` and more.
280
280
 
281
281
  ---
282
282
 
@@ -338,7 +338,7 @@ Everything runs from inside Claude Code via slash commands. Here's the highlight
338
338
  | Package | npm | Purpose |
339
339
  |---|---|---|
340
340
  | `monomind` | [![npm](https://img.shields.io/npm/v/monomind?style=flat-square&color=00D2AA)](https://www.npmjs.com/package/monomind) | Umbrella — **install this one** |
341
- | `@monoes/monomindcli` | [![npm](https://img.shields.io/npm/v/@monoes/monomindcli?style=flat-square&color=4F46E5)](https://www.npmjs.com/package/@monoes/monomindcli) | CLI engine (41 commands) |
341
+ | `@monoes/monomindcli` | [![npm](https://img.shields.io/npm/v/@monoes/monomindcli?style=flat-square&color=4F46E5)](https://www.npmjs.com/package/@monoes/monomindcli) | CLI engine (31 commands) |
342
342
  | `monofence-ai` | [![npm](https://img.shields.io/npm/v/monofence-ai?style=flat-square&color=EF4444)](https://www.npmjs.com/package/monofence-ai) | AI manipulation defence |
343
343
  | `@monoes/monograph` | [![npm](https://img.shields.io/npm/v/@monoes/monograph?style=flat-square&color=F59E0B)](https://www.npmjs.com/package/@monoes/monograph) | Code knowledge graph |
344
344
 
@@ -352,13 +352,13 @@ graph TD
352
352
  MCP["MCP Server\nmonomind mcp start"]
353
353
  D["Background Workers\n(@monomind/hooks, in-process)"]
354
354
 
355
- CC <-->|"23 tools: monograph, memory, swarm"| MCP
355
+ CC <-->|"MCP tools: monograph, memory, swarm"| MCP
356
356
  MCP <--> D
357
357
 
358
- D --> ADB[("LanceDB\nSQLite + HNSW")]
358
+ D --> ADB[("Memory store\npatterns + episodes")]
359
359
  D --> MG[("Monograph\ncode graph")]
360
360
  D --> HK["Hooks\n22 event types"]
361
- D --> SW["Swarm\n6 topologies\n5 consensus algos"]
361
+ D --> SW["Swarm\n4 topologies\n3 consensus strategies"]
362
362
 
363
363
  CC -->|"Task tool - spawns agents"| AG["Agent Swarm\narchitect, coder\ntester, reviewer\nsecurity, perf"]
364
364
  AG <-->|reads and writes| ADB
@@ -380,7 +380,6 @@ graph TD
380
380
  - 📋 [All Slash Commands](https://monoes.github.io/monomind/#slash)
381
381
  - 🐛 [Issues](https://github.com/monoes/monomind/issues)
382
382
  - 💬 [Discussions](https://github.com/monoes/monomind/discussions)
383
- - 📦 [Changelog v1.11](https://github.com/monoes/monomind/blob/main/CHANGELOG-v1.11.md)
384
383
 
385
384
  ---
386
385
 
@@ -1,10 +1,27 @@
1
1
  import { createServer } from 'http';
2
- import { readFile, readdir } from 'fs/promises';
2
+ import { readFile, readdir, writeFile, rename, mkdir } from 'fs/promises';
3
3
  import { join, dirname } from 'path';
4
+ import { homedir } from 'os';
4
5
  import { fileURLToPath } from 'url';
5
6
  import { WebSocketServer } from 'ws';
6
7
  const __dirname = dirname(fileURLToPath(import.meta.url));
7
- const DEFAULT_PORT = 4242;
8
+ // 4243: the main monomind dashboard owns 4242 — keep this server off that port
9
+ const DEFAULT_PORT = 4243;
10
+ const RUNS_FILE = join(homedir(), '.monomind', 'browse-runs.json');
11
+ const MAX_PERSISTED_RUNS = 50;
12
+ // Persist recent runs so the main dashboard's /api/workflow-runs endpoint stays live.
13
+ // Atomic: write to a temp file, then rename over the target.
14
+ async function persistRuns(runs) {
15
+ try {
16
+ await mkdir(dirname(RUNS_FILE), { recursive: true });
17
+ const tmp = RUNS_FILE + '.tmp';
18
+ await writeFile(tmp, JSON.stringify(runs.slice(0, MAX_PERSISTED_RUNS), null, 2), 'utf8');
19
+ await rename(tmp, RUNS_FILE);
20
+ }
21
+ catch {
22
+ // best-effort — dashboard persistence must never break a workflow run
23
+ }
24
+ }
8
25
  async function readJsonSafe(path) {
9
26
  try {
10
27
  return JSON.parse(await readFile(path, 'utf8'));
@@ -25,19 +42,18 @@ async function readMetricsDir(root) {
25
42
  }));
26
43
  }
27
44
  catch {
28
- // metrics dir may not exist yet — daemon hasn't run
45
+ // metrics dir may not exist yet — workers write it at session start (or: hooks worker run <name>)
29
46
  }
30
47
  return out;
31
48
  }
32
49
  async function collectDashboardState(root) {
33
- const [daemonMetrics, swarmState, hiveMindState, lastRoute, autoMemory] = await Promise.all([
50
+ const [workerMetrics, swarmState, lastRoute, autoMemory] = await Promise.all([
34
51
  readMetricsDir(root),
35
52
  readJsonSafe(join(root, '.monomind', 'swarm', 'swarm-state.json')),
36
- readJsonSafe(join(root, '.monomind', 'hive-mind', 'state.json')),
37
53
  readJsonSafe(join(root, '.monomind', 'last-route.json')),
38
54
  readJsonSafe(join(root, '.monomind', 'data', 'auto-memory-store.json')),
39
55
  ]);
40
- return { daemonMetrics, swarmState, hiveMindState, lastRoute, autoMemory };
56
+ return { workerMetrics, swarmState, lastRoute, autoMemory };
41
57
  }
42
58
  let instance = null;
43
59
  export function getDashboardServer(port = DEFAULT_PORT) {
@@ -66,9 +82,9 @@ export function getDashboardServer(port = DEFAULT_PORT) {
66
82
  }
67
83
  if (req.method === 'GET' && req.url === '/api/metrics') {
68
84
  try {
69
- const { daemonMetrics, swarmState, hiveMindState, lastRoute } = await collectDashboardState(process.cwd());
85
+ const { workerMetrics, swarmState, lastRoute } = await collectDashboardState(process.cwd());
70
86
  res.writeHead(200, { 'Content-Type': 'application/json' });
71
- res.end(JSON.stringify({ daemonMetrics, swarmState, hiveMindState, lastRoute, ts: Date.now() }));
87
+ res.end(JSON.stringify({ workerMetrics, swarmState, lastRoute, ts: Date.now() }));
72
88
  }
73
89
  catch {
74
90
  res.writeHead(500, { 'Content-Type': 'application/json' });
@@ -78,12 +94,11 @@ export function getDashboardServer(port = DEFAULT_PORT) {
78
94
  }
79
95
  if (req.method === 'GET' && req.url === '/api/dashboard') {
80
96
  try {
81
- const { daemonMetrics, swarmState, hiveMindState, lastRoute, autoMemory } = await collectDashboardState(process.cwd());
82
- const daemon_workers = Object.keys(daemonMetrics).filter((k) => daemonMetrics[k] != null);
97
+ const { workerMetrics, swarmState, lastRoute, autoMemory } = await collectDashboardState(process.cwd());
98
+ const worker_metrics = Object.keys(workerMetrics).filter((k) => workerMetrics[k] != null);
83
99
  const summary = {
84
- daemon_workers,
100
+ worker_metrics,
85
101
  swarm_status: swarmState ?? null,
86
- hive_mind_decisions: hiveMindState?.decisions ?? hiveMindState ?? null,
87
102
  last_route: lastRoute ?? null,
88
103
  pattern_count: Array.isArray(autoMemory) ? autoMemory.length : 0,
89
104
  memory_health: autoMemory ? 'ok' : 'unknown',
@@ -128,9 +143,53 @@ export function getDashboardServer(port = DEFAULT_PORT) {
128
143
  ws.on('error', () => clients.delete(ws));
129
144
  });
130
145
  httpServer.listen(port);
146
+ // Maintain RunRecords from step events and persist run transitions to
147
+ // ~/.monomind/browse-runs.json so /api/workflow-runs on the main dashboard is live.
148
+ function trackRun(event) {
149
+ let run = recentRuns.find((r) => r.id === event.runId);
150
+ if (!run) {
151
+ run = {
152
+ id: event.runId,
153
+ workflowId: event.workflowId,
154
+ workflowName: event.workflowName,
155
+ status: 'running',
156
+ startedAt: event.timestamp,
157
+ itemsProcessed: 0,
158
+ itemsTotal: event.itemTotal ?? 0,
159
+ };
160
+ recentRuns.unshift(run);
161
+ if (recentRuns.length > MAX_PERSISTED_RUNS)
162
+ recentRuns.length = MAX_PERSISTED_RUNS;
163
+ }
164
+ if (event.itemTotal != null)
165
+ run.itemsTotal = event.itemTotal;
166
+ if (event.eventType === 'step_completed' && event.itemIndex != null) {
167
+ run.itemsProcessed = Math.max(run.itemsProcessed, event.itemIndex + 1);
168
+ }
169
+ if (event.eventType === 'run_completed') {
170
+ run.status = 'completed';
171
+ run.completedAt = event.timestamp;
172
+ }
173
+ else if (event.eventType === 'run_stopped') {
174
+ run.status = 'stopped';
175
+ run.completedAt = event.timestamp;
176
+ }
177
+ else if (event.eventType === 'step_failed') {
178
+ run.status = 'failed';
179
+ run.completedAt = event.timestamp;
180
+ if (event.error)
181
+ run.error = event.error;
182
+ }
183
+ // Persist on run lifecycle transitions (start/complete/stop/fail)
184
+ if (event.eventType === 'run_started' || event.eventType === 'run_completed' ||
185
+ event.eventType === 'run_stopped' || event.eventType === 'step_failed') {
186
+ void persistRuns(recentRuns);
187
+ }
188
+ }
131
189
  instance = {
132
190
  port,
133
191
  broadcast(event) {
192
+ trackRun(event);
134
193
  const msg = JSON.stringify(event);
135
194
  for (const client of clients) {
136
195
  if (client.readyState === client.OPEN)
@@ -73,7 +73,7 @@
73
73
  <div class="panels">
74
74
  <div class="panel">
75
75
  <h2>Worker Metrics</h2>
76
- <div id="panel-daemon" class="empty">loading...</div>
76
+ <div id="panel-workers" class="empty">loading...</div>
77
77
  </div>
78
78
  <div class="panel">
79
79
  <h2>Swarm Status</h2>
@@ -115,10 +115,10 @@ async function refreshDashboard() {
115
115
  }
116
116
 
117
117
  function renderDashboard(data) {
118
- const daemonEl = document.getElementById('panel-daemon');
119
- if (data.daemon_workers?.length) {
118
+ const daemonEl = document.getElementById('panel-workers');
119
+ if (data.worker_metrics?.length) {
120
120
  daemonEl.className = '';
121
- daemonEl.innerHTML = data.daemon_workers.map(w => `<span class="worker-chip">${escapeHtml(w)}</span>`).join('');
121
+ daemonEl.innerHTML = data.worker_metrics.map(w => `<span class="worker-chip">${escapeHtml(w)}</span>`).join('');
122
122
  } else {
123
123
  daemonEl.className = 'empty';
124
124
  daemonEl.textContent = 'No worker metrics yet. Workers run at session start (or: monomind hooks worker run map)';
@@ -37,7 +37,7 @@ const runSubcommand = {
37
37
  description: 'Execute a workflow JSON file',
38
38
  options: [
39
39
  { name: 'no-dashboard', type: 'boolean', description: 'Skip opening web dashboard', default: false },
40
- { name: 'port', type: 'number', description: 'Dashboard port', default: 4242 },
40
+ { name: 'port', type: 'number', description: 'Dashboard port', default: 4243 },
41
41
  { name: 'items', short: 'i', type: 'string', description: 'JSON file of input items array' },
42
42
  ],
43
43
  action: async (ctx) => {
@@ -53,7 +53,7 @@ const runSubcommand = {
53
53
  const wf = await readWorkflow(filePath).catch(e => { output.printError(e.message); return null; });
54
54
  if (!wf)
55
55
  return { success: false, exitCode: 1 };
56
- const port = ctx.flags.port ?? 4242;
56
+ const port = ctx.flags.port ?? 4243;
57
57
  const dashboard = getDashboardServer(port);
58
58
  if (!ctx.flags['no-dashboard']) {
59
59
  output.printInfo(`Dashboard: http://localhost:${dashboard.port}`);
@@ -418,13 +418,14 @@ export class CLI {
418
418
  * to the live runtime.
419
419
  */
420
420
  async initSubsystems() {
421
- // Start the @monomind/hooks WorkerManager (performance/health/swarm/git/learning/
422
- // adr/ddd/security/patterns/cache/progress) previously implemented but never invoked
423
- try {
424
- const { workerManager } = await import('@monomind/hooks');
425
- await workerManager.start();
426
- }
427
- catch { /* optional */ }
421
+ // NOTE: the @monomind/hooks WorkerManager is intentionally NOT started
422
+ // here. Workers run from the session-restore hook (6h staleness gate) and
423
+ // on demand via `monomind hooks worker run <name>`. Starting it on every
424
+ // CLI invocation scheduled staggered 1-10s timers that usually died with
425
+ // the process — but long-lived commands (browse: Chrome launch + CDP work)
426
+ // outlived the stagger, so the consolidate worker fired mid-command,
427
+ // loaded the onnxruntime embedding model, and its thread pool crashed the
428
+ // process at exit ("mutex lock failed: Invalid argument" from libc++).
428
429
  // GAP-007: SwarmCheckpointer — write checkpoint files so crashed swarms can resume
429
430
  try {
430
431
  const { SwarmCheckpointer } = await import('@monoes/memory');
@@ -183,13 +183,13 @@ export declare const AgentStateSchema: z.ZodObject<{
183
183
  vote: z.ZodOptional<z.ZodString>;
184
184
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
185
185
  }, "strip", z.ZodTypeAny, {
186
- embedding: number[];
187
186
  agentId: string;
187
+ embedding: number[];
188
188
  metadata?: Record<string, unknown> | undefined;
189
189
  vote?: string | undefined;
190
190
  }, {
191
- embedding: number[];
192
191
  agentId: string;
192
+ embedding: number[];
193
193
  metadata?: Record<string, unknown> | undefined;
194
194
  vote?: string | undefined;
195
195
  }>;
@@ -201,13 +201,13 @@ export declare const ConsensusInputSchema: z.ZodObject<{
201
201
  vote: z.ZodOptional<z.ZodString>;
202
202
  metadata: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>;
203
203
  }, "strip", z.ZodTypeAny, {
204
- embedding: number[];
205
204
  agentId: string;
205
+ embedding: number[];
206
206
  metadata?: Record<string, unknown> | undefined;
207
207
  vote?: string | undefined;
208
208
  }, {
209
- embedding: number[];
210
209
  agentId: string;
210
+ embedding: number[];
211
211
  metadata?: Record<string, unknown> | undefined;
212
212
  vote?: string | undefined;
213
213
  }>, "many">;
@@ -215,15 +215,15 @@ export declare const ConsensusInputSchema: z.ZodObject<{
215
215
  }, "strip", z.ZodTypeAny, {
216
216
  threshold: number;
217
217
  agentStates: {
218
- embedding: number[];
219
218
  agentId: string;
219
+ embedding: number[];
220
220
  metadata?: Record<string, unknown> | undefined;
221
221
  vote?: string | undefined;
222
222
  }[];
223
223
  }, {
224
224
  agentStates: {
225
- embedding: number[];
226
225
  agentId: string;
226
+ embedding: number[];
227
227
  metadata?: Record<string, unknown> | undefined;
228
228
  vote?: string | undefined;
229
229
  }[];
@@ -247,11 +247,11 @@ export declare const SimplexSchema: z.ZodObject<{
247
247
  vertices: z.ZodArray<z.ZodNumber, "many">;
248
248
  dimension: z.ZodNumber;
249
249
  }, "strip", z.ZodTypeAny, {
250
- vertices: number[];
251
250
  dimension: number;
252
- }, {
253
251
  vertices: number[];
252
+ }, {
254
253
  dimension: number;
254
+ vertices: number[];
255
255
  }>;
256
256
  export type Simplex = z.infer<typeof SimplexSchema>;
257
257
  export declare const SimplicialComplexSchema: z.ZodObject<{
@@ -260,25 +260,25 @@ export declare const SimplicialComplexSchema: z.ZodObject<{
260
260
  vertices: z.ZodArray<z.ZodNumber, "many">;
261
261
  dimension: z.ZodNumber;
262
262
  }, "strip", z.ZodTypeAny, {
263
- vertices: number[];
264
263
  dimension: number;
265
- }, {
266
264
  vertices: number[];
265
+ }, {
267
266
  dimension: number;
267
+ vertices: number[];
268
268
  }>, "many">>;
269
269
  maxDimension: z.ZodDefault<z.ZodNumber>;
270
270
  }, "strip", z.ZodTypeAny, {
271
271
  vertices: number[][];
272
272
  maxDimension: number;
273
273
  simplices?: {
274
- vertices: number[];
275
274
  dimension: number;
275
+ vertices: number[];
276
276
  }[] | undefined;
277
277
  }, {
278
278
  vertices: number[][];
279
279
  simplices?: {
280
- vertices: number[];
281
280
  dimension: number;
281
+ vertices: number[];
282
282
  }[] | undefined;
283
283
  maxDimension?: number | undefined;
284
284
  }>;
@@ -290,25 +290,25 @@ export declare const TopologyInputSchema: z.ZodObject<{
290
290
  vertices: z.ZodArray<z.ZodNumber, "many">;
291
291
  dimension: z.ZodNumber;
292
292
  }, "strip", z.ZodTypeAny, {
293
- vertices: number[];
294
293
  dimension: number;
295
- }, {
296
294
  vertices: number[];
295
+ }, {
297
296
  dimension: number;
297
+ vertices: number[];
298
298
  }>, "many">>;
299
299
  maxDimension: z.ZodDefault<z.ZodNumber>;
300
300
  }, "strip", z.ZodTypeAny, {
301
301
  vertices: number[][];
302
302
  maxDimension: number;
303
303
  simplices?: {
304
- vertices: number[];
305
304
  dimension: number;
305
+ vertices: number[];
306
306
  }[] | undefined;
307
307
  }, {
308
308
  vertices: number[][];
309
309
  simplices?: {
310
- vertices: number[];
311
310
  dimension: number;
311
+ vertices: number[];
312
312
  }[] | undefined;
313
313
  maxDimension?: number | undefined;
314
314
  }>;
@@ -317,16 +317,16 @@ export declare const TopologyInputSchema: z.ZodObject<{
317
317
  vertices: number[][];
318
318
  maxDimension: number;
319
319
  simplices?: {
320
- vertices: number[];
321
320
  dimension: number;
321
+ vertices: number[];
322
322
  }[] | undefined;
323
323
  };
324
324
  }, {
325
325
  complex: {
326
326
  vertices: number[][];
327
327
  simplices?: {
328
- vertices: number[];
329
328
  dimension: number;
329
+ vertices: number[];
330
330
  }[] | undefined;
331
331
  maxDimension?: number | undefined;
332
332
  };